OSDN Git Service

DO NOT MERGE Fix unexpected behavior in SDP
[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 <cutils/log.h>
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdio.h>
31
32 #include "bt_common.h"
33 #include "bt_types.h"
34 #include "bt_utils.h"
35 #include "btu.h"
36
37 #include "l2cdefs.h"
38 #include "hcidefs.h"
39 #include "hcimsgs.h"
40
41 #include "sdp_api.h"
42 #include "sdpint.h"
43
44
45 #if SDP_SERVER_ENABLED == TRUE
46
47 extern fixed_queue_t *btu_general_alarm_queue;
48
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
53
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,
59                                     UINT8 *p_req_end);
60
61 static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
62                                       UINT16 param_len, UINT8 *p_req,
63                                       UINT8 *p_req_end);
64
65 static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
66                                              UINT16 param_len, UINT8 *p_req,
67                                              UINT8 *p_req_end);
68
69
70 /********************************************************************************/
71 /*                  E R R O R   T E X T   S T R I N G S                         */
72 /*                                                                              */
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
78 #endif
79
80 #ifndef SDP_TEXT_BAD_PDU
81 #define SDP_TEXT_BAD_PDU        NULL
82 #endif
83
84 #ifndef SDP_TEXT_BAD_UUID_LIST
85 #define SDP_TEXT_BAD_UUID_LIST  NULL
86 #endif
87
88 #ifndef SDP_TEXT_BAD_HANDLE
89 #define SDP_TEXT_BAD_HANDLE     NULL
90 #endif
91
92 #ifndef SDP_TEXT_BAD_ATTR_LIST
93 #define SDP_TEXT_BAD_ATTR_LIST  NULL
94 #endif
95
96 #ifndef SDP_TEXT_BAD_CONT_LEN
97 #define SDP_TEXT_BAD_CONT_LEN   NULL
98 #endif
99
100 #ifndef SDP_TEXT_BAD_CONT_INX
101 #define SDP_TEXT_BAD_CONT_INX   NULL
102 #endif
103
104 #ifndef SDP_TEXT_BAD_MAX_RECORDS_LIST
105 #define SDP_TEXT_BAD_MAX_RECORDS_LIST   NULL
106 #endif
107
108 /*******************************************************************************
109 **
110 ** Function         sdp_server_handle_client_req
111 **
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.
115 **
116 ** Returns          void
117 **
118 *******************************************************************************/
119 void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg)
120 {
121     UINT8   *p_req     = (UINT8 *) (p_msg + 1) + p_msg->offset;
122     UINT8   *p_req_end = p_req + p_msg->len;
123     UINT8   pdu_id;
124     UINT16  trans_num, param_len;
125
126
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);
130
131     /* The first byte in the message is the pdu type */
132     pdu_id = *p_req++;
133
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);
137
138     if ((p_req + param_len) != p_req_end)
139     {
140         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_PDU_SIZE, SDP_TEXT_BAD_HEADER);
141         return;
142     }
143
144     switch (pdu_id)
145     {
146     case SDP_PDU_SERVICE_SEARCH_REQ:
147         process_service_search (p_ccb, trans_num, param_len, p_req, p_req_end);
148         break;
149
150     case SDP_PDU_SERVICE_ATTR_REQ:
151         process_service_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end);
152         break;
153
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);
156         break;
157
158     default:
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);
161         break;
162     }
163 }
164
165
166
167 /*******************************************************************************
168 **
169 ** Function         process_service_search
170 **
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.
174 **
175 ** Returns          void
176 **
177 *******************************************************************************/
178 static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
179                                     UINT16 param_len, UINT8 *p_req,
180                                     UINT8 *p_req_end)
181 {
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;
189     UNUSED(p_req_end);
190
191     p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
192
193     if ((!p_req) || (!uid_seq.num_uids))
194     {
195         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
196         return;
197     }
198
199     /* Get the max replies we can send. Cap it at our max anyways. */
200     BE_STREAM_TO_UINT16 (max_replies, p_req);
201
202     if (max_replies > SDP_MAX_RECORDS)
203         max_replies = SDP_MAX_RECORDS;
204
205
206     if ((!p_req) || (p_req > p_req_end))
207     {
208         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_RECORDS_LIST);
209         return;
210     }
211
212
213     /* Get a list of handles that match the UUIDs given to us */
214     for (num_rsp_handles = 0; num_rsp_handles < max_replies; )
215     {
216         p_rec = sdp_db_service_search (p_rec, &uid_seq);
217
218         if (p_rec)
219             rsp_handles[num_rsp_handles++] = p_rec->record_handle;
220         else
221             break;
222     }
223
224     /* Check if this is a continuation request */
225     if (*p_req)
226     {
227         if (*p_req++ != SDP_CONTINUATION_LEN || (p_req >= p_req_end))
228         {
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         {
237             sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
238                                      SDP_TEXT_BAD_CONT_INX);
239             return;
240         }
241
242         rem_handles = num_rsp_handles - cont_offset;    /* extract the remaining handles */
243     }
244     else
245     {
246         rem_handles = num_rsp_handles;
247         cont_offset = 0;
248         p_ccb->cont_offset = 0;
249     }
250
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);
253
254     if (rem_handles <= cur_handles)
255         cur_handles = rem_handles;
256     else /* Continuation is set */
257     {
258         p_ccb->cont_offset += cur_handles;
259         is_cont = TRUE;
260     }
261
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;
266
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);
270
271     /* Skip the length, we need to add it at the end */
272     p_rsp_param_len = p_rsp;
273     p_rsp += 2;
274
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);
278
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]);
284
285     if (is_cont)
286     {
287         UINT8_TO_BE_STREAM  (p_rsp, SDP_CONTINUATION_LEN);
288         UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
289     }
290     else
291         UINT8_TO_BE_STREAM (p_rsp, 0);
292
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);
296
297     /* Set the length of the SDP data in the buffer */
298     p_buf->len = p_rsp - p_rsp_start;
299
300
301     /* Send the buffer through L2CAP */
302     L2CA_DataWrite (p_ccb->connection_id, p_buf);
303 }
304
305
306 /*******************************************************************************
307 **
308 ** Function         process_service_attr_req
309 **
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.
313 **
314 ** Returns          void
315 **
316 *******************************************************************************/
317 static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
318                                       UINT16 param_len, UINT8 *p_req,
319                                       UINT8 *p_req_end)
320 {
321     UINT16          max_list_len, len_to_send, cont_offset;
322     INT16           rem_len;
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;
326     UINT32          rec_handle;
327     tSDP_RECORD     *p_rec;
328     tSDP_ATTRIBUTE  *p_attr;
329     BOOLEAN         is_cont = FALSE;
330     UINT16          attr_len;
331
332     /* Extract the record handle */
333     BE_STREAM_TO_UINT32 (rec_handle, p_req);
334
335     if (p_req > p_req_end)
336     {
337         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
338         return;
339     }
340
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);
343
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;
346
347     p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
348
349     if ((!p_req) || (!attr_seq.num_attr) || (p_req > p_req_end))
350     {
351         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
352         return;
353     }
354
355     memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
356
357     /* Find a record with the record handle */
358     p_rec = sdp_db_find_record (rec_handle);
359     if (!p_rec)
360     {
361         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
362         return;
363     }
364
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");
368         return;
369     }
370
371     /* Free and reallocate buffer */
372     osi_free(p_ccb->rsp_list);
373     p_ccb->rsp_list = (UINT8 *)osi_malloc(max_list_len);
374
375     /* Check if this is a continuation request */
376     if (*p_req) {
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);
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     {
408         p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
409
410         if (p_attr)
411         {
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]);
414
415             /* just in case */
416             if (rem_len <= 0)
417             {
418                 p_ccb->cont_info.next_attr_index = xx;
419                 p_ccb->cont_info.next_attr_start_id = p_attr->id;
420                 break;
421             }
422
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)
426             {
427                 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
428                                                          &p_ccb->cont_info.attr_offset);
429
430                 /* If the partial attrib could not been fully added yet */
431                 if (p_ccb->cont_info.attr_offset != attr_len)
432                     break;
433                 else /* If the partial attrib has been added in full by now */
434                     p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
435             }
436             else if (rem_len < attr_len) /* Not enough space for attr... so add partially */
437             {
438                 if (attr_len >= SDP_MAX_ATTR_LEN)
439                 {
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);
442                     return;
443                 }
444
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);
448
449                 p_ccb->cont_info.next_attr_index = xx;
450                 p_ccb->cont_info.next_attr_start_id = p_attr->id;
451                 break;
452             }
453             else /* build the whole attribute */
454                 p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
455
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)
458             {
459                 /* Update for next time through */
460                 attr_seq.attr_entry[xx].start = p_attr->id + 1;
461
462                 xx--;
463             }
464         }
465     }
466     /* If all the attributes have been accomodated in p_rsp,
467        reset next_attr_index */
468     if (xx == attr_seq.num_attr)
469         p_ccb->cont_info.next_attr_index = 0;
470
471     len_to_send = (UINT16) (p_rsp - &p_ccb->rsp_list[0]);
472     cont_offset = 0;
473
474     if (!is_cont)
475     {
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         {
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);
483         }
484         else
485         {
486             cont_offset = 1;
487
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);
490
491             p_ccb->list_len--;
492             len_to_send--;
493         }
494     }
495
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;
500
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);
504
505     /* Skip the parameter length, add it when we know the length */
506     p_rsp_param_len = p_rsp;
507     p_rsp += 2;
508
509     UINT16_TO_BE_STREAM (p_rsp, len_to_send);
510
511     memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
512     p_rsp += len_to_send;
513
514     p_ccb->cont_offset += len_to_send;
515
516     /* If anything left to send, continuation needed */
517     if (p_ccb->cont_offset < p_ccb->list_len)
518     {
519         is_cont = TRUE;
520
521         UINT8_TO_BE_STREAM  (p_rsp, SDP_CONTINUATION_LEN);
522         UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
523     }
524     else
525         UINT8_TO_BE_STREAM (p_rsp, 0);
526
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);
530
531     /* Set the length of the SDP data in the buffer */
532     p_buf->len = p_rsp - p_rsp_start;
533
534
535     /* Send the buffer through L2CAP */
536     L2CA_DataWrite (p_ccb->connection_id, p_buf);
537 }
538
539
540
541 /*******************************************************************************
542 **
543 ** Function         process_service_search_attr_req
544 **
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.
548 **
549 ** Returns          void
550 **
551 *******************************************************************************/
552 static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
553                                              UINT16 param_len, UINT8 *p_req,
554                                              UINT8 *p_req_end)
555 {
556     UINT16         max_list_len;
557     INT16          rem_len;
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;
562     tSDP_RECORD    *p_rec;
563     tSDP_ATTR_SEQ   attr_seq, attr_seq_sav;
564     tSDP_ATTRIBUTE *p_attr;
565     BOOLEAN         maxxed_out = FALSE, is_cont = FALSE;
566     UINT8           *p_seq_start;
567     UINT16          seq_len, attr_len;
568     UNUSED(p_req_end);
569
570     /* Extract the UUID sequence to search for */
571     p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
572
573     if ((!p_req) || (!uid_seq.num_uids))
574     {
575         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
576         return;
577     }
578
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);
581
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;
584
585     p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
586
587     if ((!p_req) || (!attr_seq.num_attr))
588     {
589         sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
590         return;
591     }
592
593     memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
594
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");
598         return;
599     }
600
601     /* Free and reallocate buffer */
602     osi_free(p_ccb->rsp_list);
603     p_ccb->rsp_list = (UINT8 *)osi_malloc(max_list_len);
604
605     /* Check if this is a continuation request */
606     if (*p_req) {
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);
610             return;
611         }
612         BE_STREAM_TO_UINT16(cont_offset, p_req);
613
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);
617             return;
618         }
619         is_cont = TRUE;
620
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;
625     } else {
626         p_ccb->cont_offset = 0;
627         p_rsp = &p_ccb->rsp_list[3];    /* Leave space for data elem descr */
628
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;
634     }
635
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))
638     {
639         /* Allow space for attribute sequence type and length */
640         p_seq_start = p_rsp;
641         if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE)
642         {
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]);
645             if (rem_len < 3)
646             {
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;
650                 break;
651             }
652             p_rsp += 3;
653         }
654
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++)
657         {
658             p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
659
660             if (p_attr)
661             {
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]);
664
665                 /* just in case */
666                 if (rem_len <= 0)
667                 {
668                     p_ccb->cont_info.next_attr_index = xx;
669                     p_ccb->cont_info.next_attr_start_id = p_attr->id;
670                     maxxed_out = TRUE;
671                     break;
672                 }
673
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)
677                 {
678                     p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
679                                                              &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                     {
684                         maxxed_out = TRUE;
685                         break;
686                     }
687                     else /* If the partial attrib has been added in full by now */
688                         p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
689                 }
690                 else if (rem_len < attr_len) /* Not enough space for attr... so add partially */
691                 {
692                     if (attr_len >= SDP_MAX_ATTR_LEN)
693                     {
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);
696                         return;
697                     }
698
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);
702
703                     p_ccb->cont_info.next_attr_index = xx;
704                     p_ccb->cont_info.next_attr_start_id = p_attr->id;
705                     maxxed_out = TRUE;
706                     break;
707                 }
708                 else /* build the whole attribute */
709                     p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
710
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)
713                 {
714                     /* Update for next time through */
715                     attr_seq.attr_entry[xx].start = p_attr->id + 1;
716
717                     xx--;
718                 }
719             }
720         }
721
722         /* Go back and put the type and length into the buffer */
723         if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE)
724         {
725             seq_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav);
726             if (seq_len != 0)
727             {
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);
730
731                 if (maxxed_out)
732                     p_ccb->cont_info.last_attr_seq_desc_sent = TRUE;
733             }
734             else
735                 p_rsp = p_seq_start;
736         }
737
738         if (maxxed_out)
739             break;
740
741         /* Restore the attr_seq to look for in the next sdp record */
742         memcpy(&attr_seq, &attr_seq_sav, sizeof(tSDP_ATTR_SEQ)) ;
743
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;
748     }
749
750     /* response length */
751     len_to_send = (UINT16) (p_rsp - &p_ccb->rsp_list[0]);
752     cont_offset = 0;
753
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
764     //
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.
768     //
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);
772       return;
773     }
774
775     /* If first response, insert sequence header */
776     if (!is_cont)
777     {
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)
782         {
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);
786         }
787         else
788         {
789             cont_offset = 1;
790
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);
793
794             p_ccb->list_len--;
795             len_to_send--;
796         }
797     }
798
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;
803
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);
807
808     /* Skip the parameter length, add it when we know the length */
809     p_rsp_param_len = p_rsp;
810     p_rsp += 2;
811
812     /* Stream the list length to send */
813     UINT16_TO_BE_STREAM (p_rsp, len_to_send);
814
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;
818
819     p_ccb->cont_offset += len_to_send;
820
821     /* If anything left to send, continuation needed */
822     if (p_ccb->cont_offset < p_ccb->list_len)
823     {
824         is_cont = TRUE;
825
826         UINT8_TO_BE_STREAM  (p_rsp, SDP_CONTINUATION_LEN);
827         UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
828     }
829     else
830         UINT8_TO_BE_STREAM (p_rsp, 0);
831
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);
835
836     /* Set the length of the SDP data in the buffer */
837     p_buf->len = p_rsp - p_rsp_start;
838
839
840     /* Send the buffer through L2CAP */
841     L2CA_DataWrite (p_ccb->connection_id, p_buf);
842 }
843
844 #endif  /* SDP_SERVER_ENABLED == TRUE */