OSDN Git Service

a8790e8c6100589d8cf7be522a08f8d3408f37b5
[android-x86/system-bt.git] / stack / sdp / sdp_server.c
1 /******************************************************************************
2  *
3  *  Copyright (C) 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 <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29
30 #include "bt_common.h"
31 #include "bt_types.h"
32 #include "bt_utils.h"
33 #include "btu.h"
34
35 #include "l2cdefs.h"
36 #include "hcidefs.h"
37 #include "hcimsgs.h"
38
39 #include "sdp_api.h"
40 #include "sdpint.h"
41
42
43 #if SDP_SERVER_ENABLED == TRUE
44
45 extern fixed_queue_t *btu_general_alarm_queue;
46
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
51
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,
57                                     UINT8 *p_req_end);
58
59 static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
60                                       UINT16 param_len, UINT8 *p_req,
61                                       UINT8 *p_req_end);
62
63 static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
64                                              UINT16 param_len, UINT8 *p_req,
65                                              UINT8 *p_req_end);
66
67
68 /********************************************************************************/
69 /*                  E R R O R   T E X T   S T R I N G S                         */
70 /*                                                                              */
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
76 #endif
77
78 #ifndef SDP_TEXT_BAD_PDU
79 #define SDP_TEXT_BAD_PDU        NULL
80 #endif
81
82 #ifndef SDP_TEXT_BAD_UUID_LIST
83 #define SDP_TEXT_BAD_UUID_LIST  NULL
84 #endif
85
86 #ifndef SDP_TEXT_BAD_HANDLE
87 #define SDP_TEXT_BAD_HANDLE     NULL
88 #endif
89
90 #ifndef SDP_TEXT_BAD_ATTR_LIST
91 #define SDP_TEXT_BAD_ATTR_LIST  NULL
92 #endif
93
94 #ifndef SDP_TEXT_BAD_CONT_LEN
95 #define SDP_TEXT_BAD_CONT_LEN   NULL
96 #endif
97
98 #ifndef SDP_TEXT_BAD_CONT_INX
99 #define SDP_TEXT_BAD_CONT_INX   NULL
100 #endif
101
102 #ifndef SDP_TEXT_BAD_MAX_RECORDS_LIST
103 #define SDP_TEXT_BAD_MAX_RECORDS_LIST   NULL
104 #endif
105
106 /*******************************************************************************
107 **
108 ** Function         sdp_server_handle_client_req
109 **
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.
113 **
114 ** Returns          void
115 **
116 *******************************************************************************/
117 void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg)
118 {
119     UINT8   *p_req     = (UINT8 *) (p_msg + 1) + p_msg->offset;
120     UINT8   *p_req_end = p_req + p_msg->len;
121     UINT8   pdu_id;
122     UINT16  trans_num, param_len;
123
124
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);
128
129     /* The first byte in the message is the pdu type */
130     pdu_id = *p_req++;
131
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);
135
136     if ((p_req + param_len) != p_req_end)
137     {
138         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_PDU_SIZE, SDP_TEXT_BAD_HEADER);
139         return;
140     }
141
142     switch (pdu_id)
143     {
144     case SDP_PDU_SERVICE_SEARCH_REQ:
145         process_service_search (p_ccb, trans_num, param_len, p_req, p_req_end);
146         break;
147
148     case SDP_PDU_SERVICE_ATTR_REQ:
149         process_service_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end);
150         break;
151
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);
154         break;
155
156     default:
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);
159         break;
160     }
161 }
162
163
164
165 /*******************************************************************************
166 **
167 ** Function         process_service_search
168 **
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.
172 **
173 ** Returns          void
174 **
175 *******************************************************************************/
176 static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
177                                     UINT16 param_len, UINT8 *p_req,
178                                     UINT8 *p_req_end)
179 {
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;
186     BT_HDR         *p_buf;
187     BOOLEAN         is_cont = FALSE;
188     UNUSED(p_req_end);
189
190     p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
191
192     if ((!p_req) || (!uid_seq.num_uids))
193     {
194         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
195         return;
196     }
197
198     /* Get the max replies we can send. Cap it at our max anyways. */
199     BE_STREAM_TO_UINT16 (max_replies, p_req);
200
201     if (max_replies > SDP_MAX_RECORDS)
202         max_replies = SDP_MAX_RECORDS;
203
204
205     if ((!p_req) || (p_req > p_req_end))
206     {
207         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_RECORDS_LIST);
208         return;
209     }
210
211
212     /* Get a list of handles that match the UUIDs given to us */
213     for (num_rsp_handles = 0; num_rsp_handles < max_replies; )
214     {
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     {
226         if (*p_req++ != SDP_CONTINUATION_LEN || (p_req >= p_req_end))
227         {
228             sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
229                                      SDP_TEXT_BAD_CONT_LEN);
230             return;
231         }
232         BE_STREAM_TO_UINT16 (cont_offset, p_req);
233
234         if (cont_offset != p_ccb->cont_offset)
235         {
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 = num_rsp_handles - cont_offset;    /* extract the remaining handles */
242     }
243     else
244     {
245         rem_handles = num_rsp_handles;
246         cont_offset = 0;
247         p_ccb->cont_offset = 0;
248     }
249
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);
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     p_buf = (BT_HDR *)osi_getbuf(SDP_DATA_BUF_SIZE);
263     if (p_buf == NULL)
264     {
265         SDP_TRACE_ERROR ("SDP - no buf for search rsp");
266         return;
267     }
268     p_buf->offset = L2CAP_MIN_OFFSET;
269     p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
270
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);
274
275     /* Skip the length, we need to add it at the end */
276     p_rsp_param_len = p_rsp;
277     p_rsp += 2;
278
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);
282
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]);
288
289     if (is_cont)
290     {
291         UINT8_TO_BE_STREAM  (p_rsp, SDP_CONTINUATION_LEN);
292         UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
293     }
294     else
295         UINT8_TO_BE_STREAM (p_rsp, 0);
296
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);
300
301     /* Set the length of the SDP data in the buffer */
302     p_buf->len = p_rsp - p_rsp_start;
303
304
305     /* Send the buffer through L2CAP */
306     L2CA_DataWrite (p_ccb->connection_id, p_buf);
307 }
308
309
310 /*******************************************************************************
311 **
312 ** Function         process_service_attr_req
313 **
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.
317 **
318 ** Returns          void
319 **
320 *******************************************************************************/
321 static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
322                                       UINT16 param_len, UINT8 *p_req,
323                                       UINT8 *p_req_end)
324 {
325     UINT16          max_list_len, len_to_send, cont_offset;
326     INT16           rem_len;
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;
330     UINT32          rec_handle;
331     tSDP_RECORD     *p_rec;
332     tSDP_ATTRIBUTE  *p_attr;
333     BT_HDR          *p_buf;
334     BOOLEAN         is_cont = FALSE;
335     UINT16          attr_len;
336
337     /* Extract the record handle */
338     BE_STREAM_TO_UINT32 (rec_handle, p_req);
339
340     if (p_req > p_req_end)
341     {
342         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
343         return;
344     }
345
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);
348
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;
351
352     p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
353
354     if ((!p_req) || (!attr_seq.num_attr) || (p_req > p_req_end))
355     {
356         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
357         return;
358     }
359
360     memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
361
362     /* Find a record with the record handle */
363     p_rec = sdp_db_find_record (rec_handle);
364     if (!p_rec)
365     {
366         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
367         return;
368     }
369
370     /* Check if this is a continuation request */
371     if (*p_req)
372     {
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)
377         {
378             sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN);
379             return;
380         }
381         BE_STREAM_TO_UINT16 (cont_offset, p_req);
382
383         if (cont_offset != p_ccb->cont_offset)
384         {
385             sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_INX);
386             return;
387         }
388
389         if (!p_ccb->rsp_list)
390         {
391             sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
392             return;
393         }
394         is_cont = TRUE;
395
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;
399     }
400     else
401     {
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))
404         {
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)
409             {
410                 SDP_TRACE_ERROR ("SDP - no scratch buf for search rsp");
411                 return;
412             }
413         }
414
415         p_ccb->cont_offset = 0;
416         p_rsp = &p_ccb->rsp_list[3];            /* Leave space for data elem descr */
417
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;
422     }
423
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++)
426     {
427         p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
428
429         if (p_attr)
430         {
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]);
433
434             /* just in case */
435             if (rem_len <= 0)
436             {
437                 p_ccb->cont_info.next_attr_index = xx;
438                 p_ccb->cont_info.next_attr_start_id = p_attr->id;
439                 break;
440             }
441
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)
445             {
446                 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
447                                                          &p_ccb->cont_info.attr_offset);
448
449                 /* If the partial attrib could not been fully added yet */
450                 if (p_ccb->cont_info.attr_offset != attr_len)
451                     break;
452                 else /* If the partial attrib has been added in full by now */
453                     p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
454             }
455             else if (rem_len < attr_len) /* Not enough space for attr... so add partially */
456             {
457                 if (attr_len >= SDP_MAX_ATTR_LEN)
458                 {
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);
461                     return;
462                 }
463
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);
467
468                 p_ccb->cont_info.next_attr_index = xx;
469                 p_ccb->cont_info.next_attr_start_id = p_attr->id;
470                 break;
471             }
472             else /* build the whole attribute */
473                 p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
474
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)
477             {
478                 /* Update for next time through */
479                 attr_seq.attr_entry[xx].start = p_attr->id + 1;
480
481                 xx--;
482             }
483         }
484     }
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;
489
490     len_to_send = (UINT16) (p_rsp - &p_ccb->rsp_list[0]);
491     cont_offset = 0;
492
493     if (!is_cont)
494     {
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)
498         {
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);
502         }
503         else
504         {
505             cont_offset = 1;
506
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);
509
510             p_ccb->list_len--;
511             len_to_send--;
512         }
513     }
514
515     /* Get a buffer to use to build the response */
516     p_buf = (BT_HDR *)osi_getbuf(SDP_DATA_BUF_SIZE);
517     if (p_buf == NULL)
518     {
519         SDP_TRACE_ERROR ("SDP - no buf for search rsp");
520         return;
521     }
522     p_buf->offset = L2CAP_MIN_OFFSET;
523     p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
524
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);
528
529     /* Skip the parameter length, add it when we know the length */
530     p_rsp_param_len = p_rsp;
531     p_rsp += 2;
532
533     UINT16_TO_BE_STREAM (p_rsp, len_to_send);
534
535     memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
536     p_rsp += len_to_send;
537
538     p_ccb->cont_offset += len_to_send;
539
540     /* If anything left to send, continuation needed */
541     if (p_ccb->cont_offset < p_ccb->list_len)
542     {
543         is_cont = TRUE;
544
545         UINT8_TO_BE_STREAM  (p_rsp, SDP_CONTINUATION_LEN);
546         UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
547     }
548     else
549         UINT8_TO_BE_STREAM (p_rsp, 0);
550
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);
554
555     /* Set the length of the SDP data in the buffer */
556     p_buf->len = p_rsp - p_rsp_start;
557
558
559     /* Send the buffer through L2CAP */
560     L2CA_DataWrite (p_ccb->connection_id, p_buf);
561 }
562
563
564
565 /*******************************************************************************
566 **
567 ** Function         process_service_search_attr_req
568 **
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.
572 **
573 ** Returns          void
574 **
575 *******************************************************************************/
576 static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
577                                              UINT16 param_len, UINT8 *p_req,
578                                              UINT8 *p_req_end)
579 {
580     UINT16         max_list_len;
581     INT16          rem_len;
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;
586     tSDP_RECORD    *p_rec;
587     tSDP_ATTR_SEQ   attr_seq, attr_seq_sav;
588     tSDP_ATTRIBUTE *p_attr;
589     BT_HDR         *p_buf;
590     BOOLEAN         maxxed_out = FALSE, is_cont = FALSE;
591     UINT8           *p_seq_start;
592     UINT16          seq_len, attr_len;
593     UNUSED(p_req_end);
594
595     /* Extract the UUID sequence to search for */
596     p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
597
598     if ((!p_req) || (!uid_seq.num_uids))
599     {
600         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
601         return;
602     }
603
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);
606
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;
609
610     p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
611
612     if ((!p_req) || (!attr_seq.num_attr))
613     {
614         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
615         return;
616     }
617
618     memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
619
620     /* Check if this is a continuation request */
621     if (*p_req)
622     {
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)
627         {
628             SDP_TRACE_ERROR ("SDP - no scratch buf for search rsp");
629             return;
630         }
631
632         if (*p_req++ != SDP_CONTINUATION_LEN)
633         {
634             sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN);
635             return;
636         }
637         BE_STREAM_TO_UINT16 (cont_offset, p_req);
638
639         if (cont_offset != p_ccb->cont_offset)
640         {
641             sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_INX);
642             return;
643         }
644
645         if (!p_ccb->rsp_list)
646         {
647             sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
648             return;
649         }
650         is_cont = TRUE;
651
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;
655     }
656     else
657     {
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))
660         {
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)
665             {
666                 SDP_TRACE_ERROR ("SDP - no scratch buf for search rsp");
667                 return;
668             }
669         }
670
671         p_ccb->cont_offset = 0;
672         p_rsp = &p_ccb->rsp_list[3];            /* Leave space for data elem descr */
673
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;
679     }
680
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))
683     {
684         /* Allow space for attribute sequence type and length */
685         p_seq_start = p_rsp;
686         if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE)
687         {
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]);
690             if (rem_len < 3)
691             {
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;
695                 break;
696             }
697             p_rsp += 3;
698         }
699
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++)
702         {
703             p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
704
705             if (p_attr)
706             {
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]);
709
710                 /* just in case */
711                 if (rem_len <= 0)
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                 }
718
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)
722                 {
723                     p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
724                                                              &p_ccb->cont_info.attr_offset);
725
726                     /* If the partial attrib could not been fully added yet */
727                     if (p_ccb->cont_info.attr_offset != attr_len)
728                     {
729                         maxxed_out = TRUE;
730                         break;
731                     }
732                     else /* If the partial attrib has been added in full by now */
733                         p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
734                 }
735                 else if (rem_len < attr_len) /* Not enough space for attr... so add partially */
736                 {
737                     if (attr_len >= SDP_MAX_ATTR_LEN)
738                     {
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);
741                         return;
742                     }
743
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);
747
748                     p_ccb->cont_info.next_attr_index = xx;
749                     p_ccb->cont_info.next_attr_start_id = p_attr->id;
750                     maxxed_out = TRUE;
751                     break;
752                 }
753                 else /* build the whole attribute */
754                     p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
755
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)
758                 {
759                     /* Update for next time through */
760                     attr_seq.attr_entry[xx].start = p_attr->id + 1;
761
762                     xx--;
763                 }
764             }
765         }
766
767         /* Go back and put the type and length into the buffer */
768         if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE)
769         {
770             seq_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav);
771             if (seq_len != 0)
772             {
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);
775
776                 if (maxxed_out)
777                     p_ccb->cont_info.last_attr_seq_desc_sent = TRUE;
778             }
779             else
780                 p_rsp = p_seq_start;
781         }
782
783         if (maxxed_out)
784             break;
785
786         /* Restore the attr_seq to look for in the next sdp record */
787         memcpy(&attr_seq, &attr_seq_sav, sizeof(tSDP_ATTR_SEQ)) ;
788
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;
793     }
794
795     /* response length */
796     len_to_send = (UINT16) (p_rsp - &p_ccb->rsp_list[0]);
797     cont_offset = 0;
798
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
809     //
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.
813     //
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);
817       return;
818     }
819
820     /* If first response, insert sequence header */
821     if (!is_cont)
822     {
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)
827         {
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);
831         }
832         else
833         {
834             cont_offset = 1;
835
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);
838
839             p_ccb->list_len--;
840             len_to_send--;
841         }
842     }
843
844     /* Get a buffer to use to build the response */
845     p_buf = (BT_HDR *)osi_getbuf(SDP_DATA_BUF_SIZE);
846     if (p_buf == NULL)
847     {
848         SDP_TRACE_ERROR ("SDP - no buf for search rsp");
849         return;
850     }
851     p_buf->offset = L2CAP_MIN_OFFSET;
852     p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
853
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);
857
858     /* Skip the parameter length, add it when we know the length */
859     p_rsp_param_len = p_rsp;
860     p_rsp += 2;
861
862     /* Stream the list length to send */
863     UINT16_TO_BE_STREAM (p_rsp, len_to_send);
864
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;
868
869     p_ccb->cont_offset += len_to_send;
870
871     /* If anything left to send, continuation needed */
872     if (p_ccb->cont_offset < p_ccb->list_len)
873     {
874         is_cont = TRUE;
875
876         UINT8_TO_BE_STREAM  (p_rsp, SDP_CONTINUATION_LEN);
877         UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
878     }
879     else
880         UINT8_TO_BE_STREAM (p_rsp, 0);
881
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);
885
886     /* Set the length of the SDP data in the buffer */
887     p_buf->len = p_rsp - p_rsp_start;
888
889
890     /* Send the buffer through L2CAP */
891     L2CA_DataWrite (p_ccb->connection_id, p_buf);
892 }
893
894 #endif  /* SDP_SERVER_ENABLED == TRUE */