Home | History | Annotate | Download | only in sdp
      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 <cutils/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  ******************************************************************************/
    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  ******************************************************************************/
    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  ******************************************************************************/
    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         p_rsp = sdpu_build_partial_attrib_entry(p_rsp, p_attr, rem_len,
    425                                                 &p_ccb->cont_info.attr_offset);
    426 
    427         /* If the partial attrib could not been fully added yet */
    428         if (p_ccb->cont_info.attr_offset != attr_len)
    429           break;
    430         else /* If the partial attrib has been added in full by now */
    431           p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
    432       } else if (rem_len <
    433                  attr_len) /* Not enough space for attr... so add partially */
    434       {
    435         if (attr_len >= SDP_MAX_ATTR_LEN) {
    436           SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d",
    437                           max_list_len, attr_len);
    438           sdpu_build_n_send_error(p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
    439           return;
    440         }
    441 
    442         /* add the partial attribute if possible */
    443         p_rsp = sdpu_build_partial_attrib_entry(
    444             p_rsp, p_attr, (uint16_t)rem_len, &p_ccb->cont_info.attr_offset);
    445 
    446         p_ccb->cont_info.next_attr_index = xx;
    447         p_ccb->cont_info.next_attr_start_id = p_attr->id;
    448         break;
    449       } else /* build the whole attribute */
    450         p_rsp = sdpu_build_attrib_entry(p_rsp, p_attr);
    451 
    452       /* If doing a range, stick with this one till no more attributes found */
    453       if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end) {
    454         /* Update for next time through */
    455         attr_seq.attr_entry[xx].start = p_attr->id + 1;
    456 
    457         xx--;
    458       }
    459     }
    460   }
    461   /* If all the attributes have been accomodated in p_rsp,
    462      reset next_attr_index */
    463   if (xx == attr_seq.num_attr) p_ccb->cont_info.next_attr_index = 0;
    464 
    465   len_to_send = (uint16_t)(p_rsp - &p_ccb->rsp_list[0]);
    466   cont_offset = 0;
    467 
    468   if (!is_cont) {
    469     p_ccb->list_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav) + 3;
    470     /* Put in the sequence header (2 or 3 bytes) */
    471     if (p_ccb->list_len > 255) {
    472       p_ccb->rsp_list[0] =
    473           (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
    474       p_ccb->rsp_list[1] = (uint8_t)((p_ccb->list_len - 3) >> 8);
    475       p_ccb->rsp_list[2] = (uint8_t)(p_ccb->list_len - 3);
    476     } else {
    477       cont_offset = 1;
    478 
    479       p_ccb->rsp_list[1] =
    480           (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
    481       p_ccb->rsp_list[2] = (uint8_t)(p_ccb->list_len - 3);
    482 
    483       p_ccb->list_len--;
    484       len_to_send--;
    485     }
    486   }
    487 
    488   /* Get a buffer to use to build the response */
    489   BT_HDR* p_buf = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
    490   p_buf->offset = L2CAP_MIN_OFFSET;
    491   p_rsp = p_rsp_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
    492 
    493   /* Start building a rsponse */
    494   UINT8_TO_BE_STREAM(p_rsp, SDP_PDU_SERVICE_ATTR_RSP);
    495   UINT16_TO_BE_STREAM(p_rsp, trans_num);
    496 
    497   /* Skip the parameter length, add it when we know the length */
    498   p_rsp_param_len = p_rsp;
    499   p_rsp += 2;
    500 
    501   UINT16_TO_BE_STREAM(p_rsp, len_to_send);
    502 
    503   memcpy(p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
    504   p_rsp += len_to_send;
    505 
    506   p_ccb->cont_offset += len_to_send;
    507 
    508   /* If anything left to send, continuation needed */
    509   if (p_ccb->cont_offset < p_ccb->list_len) {
    510     is_cont = true;
    511 
    512     UINT8_TO_BE_STREAM(p_rsp, SDP_CONTINUATION_LEN);
    513     UINT16_TO_BE_STREAM(p_rsp, p_ccb->cont_offset);
    514   } else
    515     UINT8_TO_BE_STREAM(p_rsp, 0);
    516 
    517   /* Go back and put the parameter length into the buffer */
    518   rsp_param_len = p_rsp - p_rsp_param_len - 2;
    519   UINT16_TO_BE_STREAM(p_rsp_param_len, rsp_param_len);
    520 
    521   /* Set the length of the SDP data in the buffer */
    522   p_buf->len = p_rsp - p_rsp_start;
    523 
    524   /* Send the buffer through L2CAP */
    525   L2CA_DataWrite(p_ccb->connection_id, p_buf);
    526 }
    527 
    528 /*******************************************************************************
    529  *
    530  * Function         process_service_search_attr_req
    531  *
    532  * Description      This function handles a combined service search and
    533  *                  attribute read request from the client. It builds a reply
    534  *                  message with info from the database, and sends the reply
    535  *                  back to the client.
    536  *
    537  * Returns          void
    538  *
    539  ******************************************************************************/
    540 static void process_service_search_attr_req(tCONN_CB* p_ccb, uint16_t trans_num,
    541                                             uint16_t param_len, uint8_t* p_req,
    542                                             uint8_t* p_req_end) {
    543   uint16_t max_list_len;
    544   int16_t rem_len;
    545   uint16_t len_to_send, cont_offset;
    546   tSDP_UUID_SEQ uid_seq;
    547   uint8_t *p_rsp, *p_rsp_start, *p_rsp_param_len;
    548   uint16_t rsp_param_len, xx;
    549   tSDP_RECORD* p_rec;
    550   tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
    551   tSDP_ATTRIBUTE* p_attr;
    552   bool maxxed_out = false, is_cont = false;
    553   uint8_t* p_seq_start;
    554   uint16_t seq_len, attr_len;
    555 
    556   /* Extract the UUID sequence to search for */
    557   p_req = sdpu_extract_uid_seq(p_req, param_len, &uid_seq);
    558 
    559   if ((!p_req) || (!uid_seq.num_uids) ||
    560       (p_req + sizeof(uint16_t) > p_req_end)) {
    561     sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
    562                             SDP_TEXT_BAD_UUID_LIST);
    563     return;
    564   }
    565 
    566   /* Get the max list length we can send. Cap it at our max list length. */
    567   BE_STREAM_TO_UINT16(max_list_len, p_req);
    568 
    569   if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN))
    570     max_list_len = p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN;
    571 
    572   param_len = static_cast<uint16_t>(p_req_end - p_req);
    573   p_req = sdpu_extract_attr_seq(p_req, param_len, &attr_seq);
    574 
    575   if ((!p_req) || (!attr_seq.num_attr) ||
    576       (p_req + sizeof(uint8_t) > p_req_end)) {
    577     sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
    578                             SDP_TEXT_BAD_ATTR_LIST);
    579     return;
    580   }
    581 
    582   memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ));
    583 
    584   if (max_list_len < 4) {
    585     sdpu_build_n_send_error(p_ccb, trans_num, SDP_ILLEGAL_PARAMETER, NULL);
    586     android_errorWriteLog(0x534e4554, "68817966");
    587     return;
    588   }
    589 
    590   /* Free and reallocate buffer */
    591   osi_free(p_ccb->rsp_list);
    592   p_ccb->rsp_list = (uint8_t*)osi_malloc(max_list_len);
    593 
    594   /* Check if this is a continuation request */
    595   if (*p_req) {
    596     if (*p_req++ != SDP_CONTINUATION_LEN ||
    597         (p_req + sizeof(uint16_t) > p_req_end)) {
    598       sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
    599                               SDP_TEXT_BAD_CONT_LEN);
    600       return;
    601     }
    602     BE_STREAM_TO_UINT16(cont_offset, p_req);
    603 
    604     if (cont_offset != p_ccb->cont_offset) {
    605       sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
    606                               SDP_TEXT_BAD_CONT_INX);
    607       return;
    608     }
    609     is_cont = true;
    610 
    611     /* Initialise for continuation response */
    612     p_rsp = &p_ccb->rsp_list[0];
    613     attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start =
    614         p_ccb->cont_info.next_attr_start_id;
    615   } else {
    616     p_ccb->cont_offset = 0;
    617     p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
    618 
    619     /* Reset continuation parameters in p_ccb */
    620     p_ccb->cont_info.prev_sdp_rec = NULL;
    621     p_ccb->cont_info.next_attr_index = 0;
    622     p_ccb->cont_info.last_attr_seq_desc_sent = false;
    623     p_ccb->cont_info.attr_offset = 0;
    624   }
    625 
    626   /* Get a list of handles that match the UUIDs given to us */
    627   for (p_rec = sdp_db_service_search(p_ccb->cont_info.prev_sdp_rec, &uid_seq);
    628        p_rec; p_rec = sdp_db_service_search(p_rec, &uid_seq)) {
    629     /* Allow space for attribute sequence type and length */
    630     p_seq_start = p_rsp;
    631     if (!p_ccb->cont_info.last_attr_seq_desc_sent) {
    632       /* See if there is enough room to include a new service in the current
    633        * response */
    634       rem_len = max_list_len - (int16_t)(p_rsp - &p_ccb->rsp_list[0]);
    635       if (rem_len < 3) {
    636         /* Not enough room. Update continuation info for next response */
    637         p_ccb->cont_info.next_attr_index = 0;
    638         p_ccb->cont_info.next_attr_start_id = attr_seq.attr_entry[0].start;
    639         break;
    640       }
    641       p_rsp += 3;
    642     }
    643 
    644     /* Get a list of handles that match the UUIDs given to us */
    645     for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++) {
    646       p_attr = sdp_db_find_attr_in_rec(p_rec, attr_seq.attr_entry[xx].start,
    647                                        attr_seq.attr_entry[xx].end);
    648 
    649       if (p_attr) {
    650         /* Check if attribute fits. Assume 3-byte value type/length */
    651         rem_len = max_list_len - (int16_t)(p_rsp - &p_ccb->rsp_list[0]);
    652 
    653         /* just in case */
    654         if (rem_len <= 0) {
    655           p_ccb->cont_info.next_attr_index = xx;
    656           p_ccb->cont_info.next_attr_start_id = p_attr->id;
    657           maxxed_out = true;
    658           break;
    659         }
    660 
    661         attr_len = sdpu_get_attrib_entry_len(p_attr);
    662         /* if there is a partial attribute pending to be sent */
    663         if (p_ccb->cont_info.attr_offset) {
    664           p_rsp = sdpu_build_partial_attrib_entry(
    665               p_rsp, p_attr, rem_len, &p_ccb->cont_info.attr_offset);
    666 
    667           /* If the partial attrib could not been fully added yet */
    668           if (p_ccb->cont_info.attr_offset != attr_len) {
    669             maxxed_out = true;
    670             break;
    671           } else /* If the partial attrib has been added in full by now */
    672             p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
    673         } else if (rem_len <
    674                    attr_len) /* Not enough space for attr... so add partially */
    675         {
    676           if (attr_len >= SDP_MAX_ATTR_LEN) {
    677             SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d",
    678                             max_list_len, attr_len);
    679             sdpu_build_n_send_error(p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
    680             return;
    681           }
    682 
    683           /* add the partial attribute if possible */
    684           p_rsp = sdpu_build_partial_attrib_entry(
    685               p_rsp, p_attr, (uint16_t)rem_len, &p_ccb->cont_info.attr_offset);
    686 
    687           p_ccb->cont_info.next_attr_index = xx;
    688           p_ccb->cont_info.next_attr_start_id = p_attr->id;
    689           maxxed_out = true;
    690           break;
    691         } else /* build the whole attribute */
    692           p_rsp = sdpu_build_attrib_entry(p_rsp, p_attr);
    693 
    694         /* If doing a range, stick with this one till no more attributes found
    695          */
    696         if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end) {
    697           /* Update for next time through */
    698           attr_seq.attr_entry[xx].start = p_attr->id + 1;
    699 
    700           xx--;
    701         }
    702       }
    703     }
    704 
    705     /* Go back and put the type and length into the buffer */
    706     if (!p_ccb->cont_info.last_attr_seq_desc_sent) {
    707       seq_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav);
    708       if (seq_len != 0) {
    709         UINT8_TO_BE_STREAM(p_seq_start,
    710                            (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
    711         UINT16_TO_BE_STREAM(p_seq_start, seq_len);
    712 
    713         if (maxxed_out) p_ccb->cont_info.last_attr_seq_desc_sent = true;
    714       } else
    715         p_rsp = p_seq_start;
    716     }
    717 
    718     if (maxxed_out) break;
    719 
    720     /* Restore the attr_seq to look for in the next sdp record */
    721     memcpy(&attr_seq, &attr_seq_sav, sizeof(tSDP_ATTR_SEQ));
    722 
    723     /* Reset the next attr index */
    724     p_ccb->cont_info.next_attr_index = 0;
    725     p_ccb->cont_info.prev_sdp_rec = p_rec;
    726     p_ccb->cont_info.last_attr_seq_desc_sent = false;
    727   }
    728 
    729   /* response length */
    730   len_to_send = (uint16_t)(p_rsp - &p_ccb->rsp_list[0]);
    731   cont_offset = 0;
    732 
    733   // The current SDP server design has a critical flaw where it can run into
    734   // an infinite request/response loop with the client. Here's the scenario:
    735   // - client makes SDP request
    736   // - server returns the first fragment of the response with a continuation
    737   //   token
    738   // - an SDP record is deleted from the server
    739   // - client issues another request with previous continuation token
    740   // - server has nothing to send back because the record is unavailable but
    741   //   in the first fragment, it had specified more response bytes than are
    742   //   now available
    743   // - server sends back no additional response bytes and returns the same
    744   //   continuation token
    745   // - client issues another request with the continuation token, and the
    746   //   process repeats
    747   //
    748   // We work around this design flaw here by checking if we will make forward
    749   // progress (i.e. we will send > 0 response bytes) on a continued request.
    750   // If not, we must have run into the above situation and we tell the peer an
    751   // error occurred.
    752   //
    753   // TODO(sharvil): rewrite SDP server.
    754   if (is_cont && len_to_send == 0) {
    755     sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, NULL);
    756     return;
    757   }
    758 
    759   /* If first response, insert sequence header */
    760   if (!is_cont) {
    761     /* Get the total list length for requested uid and attribute sequence */
    762     p_ccb->list_len = sdpu_get_list_len(&uid_seq, &attr_seq_sav) + 3;
    763     /* Put in the sequence header (2 or 3 bytes) */
    764     if (p_ccb->list_len > 255) {
    765       p_ccb->rsp_list[0] =
    766           (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
    767       p_ccb->rsp_list[1] = (uint8_t)((p_ccb->list_len - 3) >> 8);
    768       p_ccb->rsp_list[2] = (uint8_t)(p_ccb->list_len - 3);
    769     } else {
    770       cont_offset = 1;
    771 
    772       p_ccb->rsp_list[1] =
    773           (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
    774       p_ccb->rsp_list[2] = (uint8_t)(p_ccb->list_len - 3);
    775 
    776       p_ccb->list_len--;
    777       len_to_send--;
    778     }
    779   }
    780 
    781   /* Get a buffer to use to build the response */
    782   BT_HDR* p_buf = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE);
    783   p_buf->offset = L2CAP_MIN_OFFSET;
    784   p_rsp = p_rsp_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
    785 
    786   /* Start building a rsponse */
    787   UINT8_TO_BE_STREAM(p_rsp, SDP_PDU_SERVICE_SEARCH_ATTR_RSP);
    788   UINT16_TO_BE_STREAM(p_rsp, trans_num);
    789 
    790   /* Skip the parameter length, add it when we know the length */
    791   p_rsp_param_len = p_rsp;
    792   p_rsp += 2;
    793 
    794   /* Stream the list length to send */
    795   UINT16_TO_BE_STREAM(p_rsp, len_to_send);
    796 
    797   /* copy from rsp_list to the actual buffer to be sent */
    798   memcpy(p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
    799   p_rsp += len_to_send;
    800 
    801   p_ccb->cont_offset += len_to_send;
    802 
    803   /* If anything left to send, continuation needed */
    804   if (p_ccb->cont_offset < p_ccb->list_len) {
    805     is_cont = true;
    806 
    807     UINT8_TO_BE_STREAM(p_rsp, SDP_CONTINUATION_LEN);
    808     UINT16_TO_BE_STREAM(p_rsp, p_ccb->cont_offset);
    809   } else
    810     UINT8_TO_BE_STREAM(p_rsp, 0);
    811 
    812   /* Go back and put the parameter length into the buffer */
    813   rsp_param_len = p_rsp - p_rsp_param_len - 2;
    814   UINT16_TO_BE_STREAM(p_rsp_param_len, rsp_param_len);
    815 
    816   /* Set the length of the SDP data in the buffer */
    817   p_buf->len = p_rsp - p_rsp_start;
    818 
    819   /* Send the buffer through L2CAP */
    820   L2CA_DataWrite(p_ccb->connection_id, p_buf);
    821 }
    822 
    823 #endif /* SDP_SERVER_ENABLED == TRUE */
    824