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