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