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