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 ******************************************************************************/
30 #include "bt_common.h"
43 #if SDP_SERVER_ENABLED == TRUE
45 extern fixed_queue_t *btu_general_alarm_queue;
47 /* Maximum number of bytes to reserve out of SDP MTU for response data */
48 #define SDP_MAX_SERVICE_RSPHDR_LEN 12
49 #define SDP_MAX_SERVATTR_RSPHDR_LEN 10
50 #define SDP_MAX_ATTR_RSPHDR_LEN 10
52 /********************************************************************************/
53 /* L O C A L F U N C T I O N P R O T O T Y P E S */
54 /********************************************************************************/
55 static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
56 UINT16 param_len, UINT8 *p_req,
59 static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
60 UINT16 param_len, UINT8 *p_req,
63 static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
64 UINT16 param_len, UINT8 *p_req,
68 /********************************************************************************/
69 /* E R R O R T E X T S T R I N G S */
71 /* The default is to have no text string, but we allow the strings to be */
72 /* configured in target.h if people want them. */
73 /********************************************************************************/
74 #ifndef SDP_TEXT_BAD_HEADER
75 #define SDP_TEXT_BAD_HEADER NULL
78 #ifndef SDP_TEXT_BAD_PDU
79 #define SDP_TEXT_BAD_PDU NULL
82 #ifndef SDP_TEXT_BAD_UUID_LIST
83 #define SDP_TEXT_BAD_UUID_LIST NULL
86 #ifndef SDP_TEXT_BAD_HANDLE
87 #define SDP_TEXT_BAD_HANDLE NULL
90 #ifndef SDP_TEXT_BAD_ATTR_LIST
91 #define SDP_TEXT_BAD_ATTR_LIST NULL
94 #ifndef SDP_TEXT_BAD_CONT_LEN
95 #define SDP_TEXT_BAD_CONT_LEN NULL
98 #ifndef SDP_TEXT_BAD_CONT_INX
99 #define SDP_TEXT_BAD_CONT_INX NULL
102 #ifndef SDP_TEXT_BAD_MAX_RECORDS_LIST
103 #define SDP_TEXT_BAD_MAX_RECORDS_LIST NULL
106 /*******************************************************************************
108 ** Function sdp_server_handle_client_req
110 ** Description This is the main dispatcher of the SDP server. It is called
111 ** when any data is received from L2CAP, and dispatches the
112 ** request to the appropriate handler.
116 *******************************************************************************/
117 void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg)
119 UINT8 *p_req = (UINT8 *) (p_msg + 1) + p_msg->offset;
120 UINT8 *p_req_end = p_req + p_msg->len;
122 UINT16 trans_num, param_len;
125 /* Start inactivity timer */
126 alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
127 sdp_conn_timer_timeout, p_ccb, btu_general_alarm_queue);
129 /* The first byte in the message is the pdu type */
132 /* Extract the transaction number and parameter length */
133 BE_STREAM_TO_UINT16 (trans_num, p_req);
134 BE_STREAM_TO_UINT16 (param_len, p_req);
136 if ((p_req + param_len) != p_req_end)
138 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_PDU_SIZE, SDP_TEXT_BAD_HEADER);
144 case SDP_PDU_SERVICE_SEARCH_REQ:
145 process_service_search (p_ccb, trans_num, param_len, p_req, p_req_end);
148 case SDP_PDU_SERVICE_ATTR_REQ:
149 process_service_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end);
152 case SDP_PDU_SERVICE_SEARCH_ATTR_REQ:
153 process_service_search_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end);
157 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_PDU);
158 SDP_TRACE_WARNING ("SDP - server got unknown PDU: 0x%x", pdu_id);
165 /*******************************************************************************
167 ** Function process_service_search
169 ** Description This function handles a service search request from the
170 ** client. It builds a reply message with info from the database,
171 ** and sends the reply back to the client.
175 *******************************************************************************/
176 static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
177 UINT16 param_len, UINT8 *p_req,
180 UINT16 max_replies, cur_handles, rem_handles, cont_offset;
181 tSDP_UUID_SEQ uid_seq;
182 UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
183 UINT16 rsp_param_len, num_rsp_handles, xx;
184 UINT32 rsp_handles[SDP_MAX_RECORDS] = {0};
185 tSDP_RECORD *p_rec = NULL;
187 BOOLEAN is_cont = FALSE;
190 p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
192 if ((!p_req) || (!uid_seq.num_uids))
194 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
198 /* Get the max replies we can send. Cap it at our max anyways. */
199 BE_STREAM_TO_UINT16 (max_replies, p_req);
201 if (max_replies > SDP_MAX_RECORDS)
202 max_replies = SDP_MAX_RECORDS;
205 if ((!p_req) || (p_req > p_req_end))
207 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_RECORDS_LIST);
212 /* Get a list of handles that match the UUIDs given to us */
213 for (num_rsp_handles = 0; num_rsp_handles < max_replies; )
215 p_rec = sdp_db_service_search (p_rec, &uid_seq);
218 rsp_handles[num_rsp_handles++] = p_rec->record_handle;
223 /* Check if this is a continuation request */
226 if (*p_req++ != SDP_CONTINUATION_LEN || (p_req >= p_req_end))
228 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
229 SDP_TEXT_BAD_CONT_LEN);
232 BE_STREAM_TO_UINT16 (cont_offset, p_req);
234 if (cont_offset != p_ccb->cont_offset)
236 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
237 SDP_TEXT_BAD_CONT_INX);
241 rem_handles = num_rsp_handles - cont_offset; /* extract the remaining handles */
245 rem_handles = num_rsp_handles;
247 p_ccb->cont_offset = 0;
250 /* Calculate how many handles will fit in one PDU */
251 cur_handles = (UINT16)((p_ccb->rem_mtu_size - SDP_MAX_SERVICE_RSPHDR_LEN) / 4);
253 if (rem_handles <= cur_handles)
254 cur_handles = rem_handles;
255 else /* Continuation is set */
257 p_ccb->cont_offset += cur_handles;
261 /* Get a buffer to use to build the response */
262 p_buf = (BT_HDR *)osi_getbuf(SDP_DATA_BUF_SIZE);
265 SDP_TRACE_ERROR ("SDP - no buf for search rsp");
268 p_buf->offset = L2CAP_MIN_OFFSET;
269 p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
271 /* Start building a rsponse */
272 UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_SEARCH_RSP);
273 UINT16_TO_BE_STREAM (p_rsp, trans_num);
275 /* Skip the length, we need to add it at the end */
276 p_rsp_param_len = p_rsp;
279 /* Put in total and current number of handles, and handles themselves */
280 UINT16_TO_BE_STREAM (p_rsp, num_rsp_handles);
281 UINT16_TO_BE_STREAM (p_rsp, cur_handles);
283 /* SDP_TRACE_DEBUG("SDP Service Rsp: tothdl %d, curhdlr %d, start %d, end %d, cont %d",
284 num_rsp_handles, cur_handles, cont_offset,
285 cont_offset + cur_handles-1, is_cont); */
286 for (xx = cont_offset; xx < cont_offset + cur_handles; xx++)
287 UINT32_TO_BE_STREAM (p_rsp, rsp_handles[xx]);
291 UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
292 UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
295 UINT8_TO_BE_STREAM (p_rsp, 0);
297 /* Go back and put the parameter length into the buffer */
298 rsp_param_len = p_rsp - p_rsp_param_len - 2;
299 UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
301 /* Set the length of the SDP data in the buffer */
302 p_buf->len = p_rsp - p_rsp_start;
305 /* Send the buffer through L2CAP */
306 L2CA_DataWrite (p_ccb->connection_id, p_buf);
310 /*******************************************************************************
312 ** Function process_service_attr_req
314 ** Description This function handles an attribute request from the client.
315 ** It builds a reply message with info from the database,
316 ** and sends the reply back to the client.
320 *******************************************************************************/
321 static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
322 UINT16 param_len, UINT8 *p_req,
325 UINT16 max_list_len, len_to_send, cont_offset;
327 tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
328 UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
329 UINT16 rsp_param_len, xx;
332 tSDP_ATTRIBUTE *p_attr;
334 BOOLEAN is_cont = FALSE;
337 /* Extract the record handle */
338 BE_STREAM_TO_UINT32 (rec_handle, p_req);
340 if (p_req > p_req_end)
342 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
346 /* Get the max list length we can send. Cap it at MTU size minus overhead */
347 BE_STREAM_TO_UINT16 (max_list_len, p_req);
349 if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN))
350 max_list_len = p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN;
352 p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
354 if ((!p_req) || (!attr_seq.num_attr) || (p_req > p_req_end))
356 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
360 memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
362 /* Find a record with the record handle */
363 p_rec = sdp_db_find_record (rec_handle);
366 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
370 /* Check if this is a continuation request */
373 /* Free and reallocate buffer */
374 osi_freebuf(p_ccb->rsp_list);
375 p_ccb->rsp_list = (UINT8 *)osi_getbuf(max_list_len);
376 if (*p_req++ != SDP_CONTINUATION_LEN)
378 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN);
381 BE_STREAM_TO_UINT16 (cont_offset, p_req);
383 if (cont_offset != p_ccb->cont_offset)
385 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_INX);
389 if (!p_ccb->rsp_list)
391 sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
396 /* Initialise for continuation response */
397 p_rsp = &p_ccb->rsp_list[0];
398 attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start = p_ccb->cont_info.next_attr_start_id;
402 /* Get a scratch buffer to store response */
403 if (!p_ccb->rsp_list || (osi_get_buf_size(p_ccb->rsp_list) < max_list_len))
405 /* Free and reallocate if the earlier allocated buffer is small */
406 osi_freebuf(p_ccb->rsp_list);
407 p_ccb->rsp_list = (UINT8 *)osi_getbuf (max_list_len);
408 if (p_ccb->rsp_list == NULL)
410 SDP_TRACE_ERROR ("SDP - no scratch buf for search rsp");
415 p_ccb->cont_offset = 0;
416 p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
418 /* Reset continuation parameters in p_ccb */
419 p_ccb->cont_info.prev_sdp_rec = NULL;
420 p_ccb->cont_info.next_attr_index = 0;
421 p_ccb->cont_info.attr_offset = 0;
424 /* Search for attributes that match the list given to us */
425 for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++)
427 p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
431 /* Check if attribute fits. Assume 3-byte value type/length */
432 rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
437 p_ccb->cont_info.next_attr_index = xx;
438 p_ccb->cont_info.next_attr_start_id = p_attr->id;
442 attr_len = sdpu_get_attrib_entry_len(p_attr);
443 /* if there is a partial attribute pending to be sent */
444 if (p_ccb->cont_info.attr_offset)
446 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
447 &p_ccb->cont_info.attr_offset);
449 /* If the partial attrib could not been fully added yet */
450 if (p_ccb->cont_info.attr_offset != attr_len)
452 else /* If the partial attrib has been added in full by now */
453 p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
455 else if (rem_len < attr_len) /* Not enough space for attr... so add partially */
457 if (attr_len >= SDP_MAX_ATTR_LEN)
459 SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d", max_list_len, attr_len);
460 sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
464 /* add the partial attribute if possible */
465 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, (UINT16)rem_len,
466 &p_ccb->cont_info.attr_offset);
468 p_ccb->cont_info.next_attr_index = xx;
469 p_ccb->cont_info.next_attr_start_id = p_attr->id;
472 else /* build the whole attribute */
473 p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
475 /* If doing a range, stick with this one till no more attributes found */
476 if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end)
478 /* Update for next time through */
479 attr_seq.attr_entry[xx].start = p_attr->id + 1;
485 /* If all the attributes have been accomodated in p_rsp,
486 reset next_attr_index */
487 if (xx == attr_seq.num_attr)
488 p_ccb->cont_info.next_attr_index = 0;
490 len_to_send = (UINT16) (p_rsp - &p_ccb->rsp_list[0]);
495 p_ccb->list_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav) + 3;
496 /* Put in the sequence header (2 or 3 bytes) */
497 if (p_ccb->list_len > 255)
499 p_ccb->rsp_list[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
500 p_ccb->rsp_list[1] = (UINT8) ((p_ccb->list_len - 3) >> 8);
501 p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
507 p_ccb->rsp_list[1] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
508 p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
515 /* Get a buffer to use to build the response */
516 p_buf = (BT_HDR *)osi_getbuf(SDP_DATA_BUF_SIZE);
519 SDP_TRACE_ERROR ("SDP - no buf for search rsp");
522 p_buf->offset = L2CAP_MIN_OFFSET;
523 p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
525 /* Start building a rsponse */
526 UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_ATTR_RSP);
527 UINT16_TO_BE_STREAM (p_rsp, trans_num);
529 /* Skip the parameter length, add it when we know the length */
530 p_rsp_param_len = p_rsp;
533 UINT16_TO_BE_STREAM (p_rsp, len_to_send);
535 memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
536 p_rsp += len_to_send;
538 p_ccb->cont_offset += len_to_send;
540 /* If anything left to send, continuation needed */
541 if (p_ccb->cont_offset < p_ccb->list_len)
545 UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
546 UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
549 UINT8_TO_BE_STREAM (p_rsp, 0);
551 /* Go back and put the parameter length into the buffer */
552 rsp_param_len = p_rsp - p_rsp_param_len - 2;
553 UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
555 /* Set the length of the SDP data in the buffer */
556 p_buf->len = p_rsp - p_rsp_start;
559 /* Send the buffer through L2CAP */
560 L2CA_DataWrite (p_ccb->connection_id, p_buf);
565 /*******************************************************************************
567 ** Function process_service_search_attr_req
569 ** Description This function handles a combined service search and attribute
570 ** read request from the client. It builds a reply message with
571 ** info from the database, and sends the reply back to the client.
575 *******************************************************************************/
576 static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
577 UINT16 param_len, UINT8 *p_req,
582 UINT16 len_to_send, cont_offset;
583 tSDP_UUID_SEQ uid_seq;
584 UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
585 UINT16 rsp_param_len, xx;
587 tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
588 tSDP_ATTRIBUTE *p_attr;
590 BOOLEAN maxxed_out = FALSE, is_cont = FALSE;
592 UINT16 seq_len, attr_len;
595 /* Extract the UUID sequence to search for */
596 p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
598 if ((!p_req) || (!uid_seq.num_uids))
600 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
604 /* Get the max list length we can send. Cap it at our max list length. */
605 BE_STREAM_TO_UINT16 (max_list_len, p_req);
607 if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN))
608 max_list_len = p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN;
610 p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
612 if ((!p_req) || (!attr_seq.num_attr))
614 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
618 memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
620 /* Check if this is a continuation request */
623 /* Free and reallocate buffer */
624 osi_freebuf(p_ccb->rsp_list);
625 p_ccb->rsp_list = (UINT8 *)osi_getbuf (max_list_len);
626 if (p_ccb->rsp_list == NULL)
628 SDP_TRACE_ERROR ("SDP - no scratch buf for search rsp");
632 if (*p_req++ != SDP_CONTINUATION_LEN)
634 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN);
637 BE_STREAM_TO_UINT16 (cont_offset, p_req);
639 if (cont_offset != p_ccb->cont_offset)
641 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_INX);
645 if (!p_ccb->rsp_list)
647 sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
652 /* Initialise for continuation response */
653 p_rsp = &p_ccb->rsp_list[0];
654 attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start = p_ccb->cont_info.next_attr_start_id;
658 /* Get a scratch buffer to store response */
659 if (!p_ccb->rsp_list || (osi_get_buf_size(p_ccb->rsp_list) < max_list_len))
661 /* Free and reallocate if the earlier allocated buffer is small */
662 osi_freebuf(p_ccb->rsp_list);
663 p_ccb->rsp_list = (UINT8 *)osi_getbuf (max_list_len);
664 if (p_ccb->rsp_list == NULL)
666 SDP_TRACE_ERROR ("SDP - no scratch buf for search rsp");
671 p_ccb->cont_offset = 0;
672 p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
674 /* Reset continuation parameters in p_ccb */
675 p_ccb->cont_info.prev_sdp_rec = NULL;
676 p_ccb->cont_info.next_attr_index = 0;
677 p_ccb->cont_info.last_attr_seq_desc_sent = FALSE;
678 p_ccb->cont_info.attr_offset = 0;
681 /* Get a list of handles that match the UUIDs given to us */
682 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))
684 /* Allow space for attribute sequence type and length */
686 if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE)
688 /* See if there is enough room to include a new service in the current response */
689 rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
692 /* Not enough room. Update continuation info for next response */
693 p_ccb->cont_info.next_attr_index = 0;
694 p_ccb->cont_info.next_attr_start_id = attr_seq.attr_entry[0].start;
700 /* Get a list of handles that match the UUIDs given to us */
701 for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++)
703 p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
707 /* Check if attribute fits. Assume 3-byte value type/length */
708 rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
713 p_ccb->cont_info.next_attr_index = xx;
714 p_ccb->cont_info.next_attr_start_id = p_attr->id;
719 attr_len = sdpu_get_attrib_entry_len(p_attr);
720 /* if there is a partial attribute pending to be sent */
721 if (p_ccb->cont_info.attr_offset)
723 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
724 &p_ccb->cont_info.attr_offset);
726 /* If the partial attrib could not been fully added yet */
727 if (p_ccb->cont_info.attr_offset != attr_len)
732 else /* If the partial attrib has been added in full by now */
733 p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
735 else if (rem_len < attr_len) /* Not enough space for attr... so add partially */
737 if (attr_len >= SDP_MAX_ATTR_LEN)
739 SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d", max_list_len, attr_len);
740 sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
744 /* add the partial attribute if possible */
745 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, (UINT16)rem_len,
746 &p_ccb->cont_info.attr_offset);
748 p_ccb->cont_info.next_attr_index = xx;
749 p_ccb->cont_info.next_attr_start_id = p_attr->id;
753 else /* build the whole attribute */
754 p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
756 /* If doing a range, stick with this one till no more attributes found */
757 if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end)
759 /* Update for next time through */
760 attr_seq.attr_entry[xx].start = p_attr->id + 1;
767 /* Go back and put the type and length into the buffer */
768 if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE)
770 seq_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav);
773 UINT8_TO_BE_STREAM (p_seq_start, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
774 UINT16_TO_BE_STREAM (p_seq_start, seq_len);
777 p_ccb->cont_info.last_attr_seq_desc_sent = TRUE;
786 /* Restore the attr_seq to look for in the next sdp record */
787 memcpy(&attr_seq, &attr_seq_sav, sizeof(tSDP_ATTR_SEQ)) ;
789 /* Reset the next attr index */
790 p_ccb->cont_info.next_attr_index = 0;
791 p_ccb->cont_info.prev_sdp_rec = p_rec;
792 p_ccb->cont_info.last_attr_seq_desc_sent = FALSE;
795 /* response length */
796 len_to_send = (UINT16) (p_rsp - &p_ccb->rsp_list[0]);
799 // The current SDP server design has a critical flaw where it can run into an infinite
800 // request/response loop with the client. Here's the scenario:
801 // - client makes SDP request
802 // - server returns the first fragment of the response with a continuation token
803 // - an SDP record is deleted from the server
804 // - client issues another request with previous continuation token
805 // - server has nothing to send back because the record is unavailable but in the
806 // first fragment, it had specified more response bytes than are now available
807 // - server sends back no additional response bytes and returns the same continuation token
808 // - client issues another request with the continuation token, and the process repeats
810 // We work around this design flaw here by checking if we will make forward progress
811 // (i.e. we will send > 0 response bytes) on a continued request. If not, we must have
812 // run into the above situation and we tell the peer an error occurred.
814 // TODO(sharvil): rewrite SDP server.
815 if (is_cont && len_to_send == 0) {
816 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, NULL);
820 /* If first response, insert sequence header */
823 /* Get the total list length for requested uid and attribute sequence */
824 p_ccb->list_len = sdpu_get_list_len(&uid_seq, &attr_seq_sav) + 3;
825 /* Put in the sequence header (2 or 3 bytes) */
826 if (p_ccb->list_len > 255)
828 p_ccb->rsp_list[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
829 p_ccb->rsp_list[1] = (UINT8) ((p_ccb->list_len - 3) >> 8);
830 p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
836 p_ccb->rsp_list[1] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
837 p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
844 /* Get a buffer to use to build the response */
845 p_buf = (BT_HDR *)osi_getbuf(SDP_DATA_BUF_SIZE);
848 SDP_TRACE_ERROR ("SDP - no buf for search rsp");
851 p_buf->offset = L2CAP_MIN_OFFSET;
852 p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
854 /* Start building a rsponse */
855 UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_SEARCH_ATTR_RSP);
856 UINT16_TO_BE_STREAM (p_rsp, trans_num);
858 /* Skip the parameter length, add it when we know the length */
859 p_rsp_param_len = p_rsp;
862 /* Stream the list length to send */
863 UINT16_TO_BE_STREAM (p_rsp, len_to_send);
865 /* copy from rsp_list to the actual buffer to be sent */
866 memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
867 p_rsp += len_to_send;
869 p_ccb->cont_offset += len_to_send;
871 /* If anything left to send, continuation needed */
872 if (p_ccb->cont_offset < p_ccb->list_len)
876 UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
877 UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
880 UINT8_TO_BE_STREAM (p_rsp, 0);
882 /* Go back and put the parameter length into the buffer */
883 rsp_param_len = p_rsp - p_rsp_param_len - 2;
884 UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
886 /* Set the length of the SDP data in the buffer */
887 p_buf->len = p_rsp - p_rsp_start;
890 /* Send the buffer through L2CAP */
891 L2CA_DataWrite (p_ccb->connection_id, p_buf);
894 #endif /* SDP_SERVER_ENABLED == TRUE */