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