Home | History | Annotate | Download | only in sdp
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 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 SDP discovery functions
     22  *
     23  ******************************************************************************/
     24 
     25 #include <stdlib.h>
     26 #include <string.h>
     27 #include <stdio.h>
     28 
     29 #include "bt_target.h"
     30 #include "bt_common.h"
     31 #include "l2cdefs.h"
     32 #include "hcidefs.h"
     33 #include "hcimsgs.h"
     34 #include "sdp_api.h"
     35 #include "sdpint.h"
     36 #include "btu.h"
     37 #include "btm_api.h"
     38 
     39 
     40 #ifndef SDP_DEBUG_RAW
     41 #define SDP_DEBUG_RAW       FALSE
     42 #endif
     43 
     44 /********************************************************************************/
     45 /*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
     46 /********************************************************************************/
     47 #if SDP_CLIENT_ENABLED == TRUE
     48 static void          process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply);
     49 static void          process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply);
     50 static void          process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply);
     51 static UINT8         *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end);
     52 static tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda);
     53 static UINT8         *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
     54                                 UINT16 attr_id, tSDP_DISC_ATTR *p_parent_attr, UINT8 nest_level);
     55 
     56 /* Safety check in case we go crazy */
     57 #define MAX_NEST_LEVELS     5
     58 
     59 extern fixed_queue_t *btu_general_alarm_queue;
     60 
     61 /*******************************************************************************
     62 **
     63 ** Function         sdpu_build_uuid_seq
     64 **
     65 ** Description      This function builds a UUID sequence from the list of
     66 **                  passed UUIDs. It is also passed the address of the output
     67 **                  buffer.
     68 **
     69 ** Returns          Pointer to next byte in the output buffer.
     70 **
     71 *******************************************************************************/
     72 static UINT8 *sdpu_build_uuid_seq (UINT8 *p_out, UINT16 num_uuids, tSDP_UUID *p_uuid_list)
     73 {
     74     UINT16  xx;
     75     UINT8   *p_len;
     76 
     77     /* First thing is the data element header */
     78     UINT8_TO_BE_STREAM  (p_out, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
     79 
     80     /* Remember where the length goes. Leave space for it. */
     81     p_len = p_out;
     82     p_out += 1;
     83 
     84     /* Now, loop through and put in all the UUID(s) */
     85     for (xx = 0; xx < num_uuids; xx++, p_uuid_list++)
     86     {
     87         if (p_uuid_list->len == 2)
     88         {
     89             UINT8_TO_BE_STREAM  (p_out, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
     90             UINT16_TO_BE_STREAM (p_out, p_uuid_list->uu.uuid16);
     91         }
     92         else if (p_uuid_list->len == 4)
     93         {
     94             UINT8_TO_BE_STREAM  (p_out, (UUID_DESC_TYPE << 3) | SIZE_FOUR_BYTES);
     95             UINT32_TO_BE_STREAM (p_out, p_uuid_list->uu.uuid32);
     96         }
     97         else
     98         {
     99             UINT8_TO_BE_STREAM (p_out, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES);
    100             ARRAY_TO_BE_STREAM (p_out, p_uuid_list->uu.uuid128, p_uuid_list->len);
    101         }
    102     }
    103 
    104     /* Now, put in the length */
    105     xx = (UINT16)(p_out - p_len - 1);
    106     UINT8_TO_BE_STREAM (p_len, xx);
    107 
    108     return (p_out);
    109 }
    110 
    111 /*******************************************************************************
    112 **
    113 ** Function         sdp_snd_service_search_req
    114 **
    115 ** Description      Send a service search request to the SDP server.
    116 **
    117 ** Returns          void
    118 **
    119 *******************************************************************************/
    120 static void sdp_snd_service_search_req(tCONN_CB *p_ccb, UINT8 cont_len, UINT8 * p_cont)
    121 {
    122     UINT8           *p, *p_start, *p_param_len;
    123     BT_HDR          *p_cmd = (BT_HDR *) osi_malloc(SDP_DATA_BUF_SIZE);
    124     UINT16          param_len;
    125 
    126     /* Prepare the buffer for sending the packet to L2CAP */
    127     p_cmd->offset = L2CAP_MIN_OFFSET;
    128     p = p_start = (UINT8 *)(p_cmd + 1) + L2CAP_MIN_OFFSET;
    129 
    130     /* Build a service search request packet */
    131     UINT8_TO_BE_STREAM  (p, SDP_PDU_SERVICE_SEARCH_REQ);
    132     UINT16_TO_BE_STREAM (p, p_ccb->transaction_id);
    133     p_ccb->transaction_id++;
    134 
    135     /* Skip the length, we need to add it at the end */
    136     p_param_len = p;
    137     p += 2;
    138 
    139     /* Build the UID sequence. */
    140 #if (defined(SDP_BROWSE_PLUS) && SDP_BROWSE_PLUS == TRUE)
    141     p = sdpu_build_uuid_seq (p, 1, &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx]);
    142 #else
    143     p = sdpu_build_uuid_seq (p, p_ccb->p_db->num_uuid_filters, p_ccb->p_db->uuid_filters);
    144 #endif
    145 
    146     /* Set max service record count */
    147     UINT16_TO_BE_STREAM (p, sdp_cb.max_recs_per_search);
    148 
    149     /* Set continuation state */
    150     UINT8_TO_BE_STREAM (p, cont_len);
    151 
    152     /* if this is not the first request */
    153     if(cont_len && p_cont)
    154     {
    155         memcpy(p, p_cont, cont_len);
    156         p += cont_len;
    157     }
    158 
    159     /* Go back and put the parameter length into the buffer */
    160     param_len = (UINT16)(p - p_param_len - 2);
    161     UINT16_TO_BE_STREAM (p_param_len, param_len);
    162 
    163     p_ccb->disc_state = SDP_DISC_WAIT_HANDLES;
    164 
    165     /* Set the length of the SDP data in the buffer */
    166     p_cmd->len = (UINT16)(p - p_start);
    167 
    168 #if (SDP_DEBUG_RAW == TRUE)
    169     SDP_TRACE_WARNING("sdp_snd_service_search_req cont_len :%d disc_state:%d",cont_len, p_ccb->disc_state);
    170 #endif
    171 
    172 
    173     L2CA_DataWrite (p_ccb->connection_id, p_cmd);
    174 
    175     /* Start inactivity timer */
    176     alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
    177                        sdp_conn_timer_timeout, p_ccb, btu_general_alarm_queue);
    178 }
    179 
    180 /*******************************************************************************
    181 **
    182 ** Function         sdp_disc_connected
    183 **
    184 ** Description      This function is called when an SDP discovery attempt is
    185 **                  connected.
    186 **
    187 ** Returns          void
    188 **
    189 *******************************************************************************/
    190 void sdp_disc_connected (tCONN_CB *p_ccb)
    191 {
    192     if (p_ccb->is_attr_search)
    193     {
    194         p_ccb->disc_state = SDP_DISC_WAIT_SEARCH_ATTR;
    195 
    196         process_service_search_attr_rsp (p_ccb, NULL);
    197     }
    198     else
    199     {
    200         /* First step is to get a list of the handles from the server. */
    201         /* We are not searching for a specific attribute, so we will   */
    202         /* first search for the service, then get all attributes of it */
    203 
    204         p_ccb->num_handles = 0;
    205         sdp_snd_service_search_req(p_ccb, 0, NULL);
    206     }
    207 
    208 }
    209 
    210 /*******************************************************************************
    211 **
    212 ** Function         sdp_disc_server_rsp
    213 **
    214 ** Description      This function is called when there is a response from
    215 **                  the server.
    216 **
    217 ** Returns          void
    218 **
    219 *******************************************************************************/
    220 void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg)
    221 {
    222     UINT8           *p, rsp_pdu;
    223     BOOLEAN         invalid_pdu = TRUE;
    224 
    225 #if (SDP_DEBUG_RAW == TRUE)
    226     SDP_TRACE_WARNING("sdp_disc_server_rsp disc_state:%d", p_ccb->disc_state);
    227 #endif
    228 
    229     /* stop inactivity timer when we receive a response */
    230     alarm_cancel(p_ccb->sdp_conn_timer);
    231 
    232     /* Got a reply!! Check what we got back */
    233     p = (UINT8 *)(p_msg + 1) + p_msg->offset;
    234 
    235     BE_STREAM_TO_UINT8 (rsp_pdu, p);
    236 
    237     p_msg->len--;
    238 
    239     switch (rsp_pdu)
    240     {
    241     case SDP_PDU_SERVICE_SEARCH_RSP:
    242         if (p_ccb->disc_state == SDP_DISC_WAIT_HANDLES)
    243         {
    244             process_service_search_rsp (p_ccb, p);
    245             invalid_pdu = FALSE;
    246         }
    247         break;
    248 
    249     case SDP_PDU_SERVICE_ATTR_RSP:
    250         if (p_ccb->disc_state == SDP_DISC_WAIT_ATTR)
    251         {
    252             process_service_attr_rsp (p_ccb, p);
    253             invalid_pdu = FALSE;
    254         }
    255         break;
    256 
    257     case SDP_PDU_SERVICE_SEARCH_ATTR_RSP:
    258         if (p_ccb->disc_state == SDP_DISC_WAIT_SEARCH_ATTR)
    259         {
    260             process_service_search_attr_rsp (p_ccb, p);
    261             invalid_pdu = FALSE;
    262         }
    263         break;
    264     }
    265 
    266     if (invalid_pdu)
    267     {
    268         SDP_TRACE_WARNING ("SDP - Unexp. PDU: %d in state: %d", rsp_pdu, p_ccb->disc_state);
    269         sdp_disconnect (p_ccb, SDP_GENERIC_ERROR);
    270     }
    271 }
    272 
    273 /******************************************************************************
    274 **
    275 ** Function         process_service_search_rsp
    276 **
    277 ** Description      This function is called when there is a search response from
    278 **                  the server.
    279 **
    280 ** Returns          void
    281 **
    282 *******************************************************************************/
    283 static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    284 {
    285     UINT16      xx;
    286     UINT16      total, cur_handles, orig;
    287     UINT8       cont_len;
    288 
    289     /* Skip transaction, and param len */
    290     p_reply += 4;
    291     BE_STREAM_TO_UINT16 (total, p_reply);
    292     BE_STREAM_TO_UINT16 (cur_handles, p_reply);
    293 
    294     orig = p_ccb->num_handles;
    295     p_ccb->num_handles += cur_handles;
    296     if (p_ccb->num_handles == 0)
    297     {
    298         SDP_TRACE_WARNING ("SDP - Rcvd ServiceSearchRsp, no matches");
    299         sdp_disconnect (p_ccb, SDP_NO_RECS_MATCH);
    300         return;
    301     }
    302 
    303     /* Save the handles that match. We will can only process a certain number. */
    304     if (total > sdp_cb.max_recs_per_search)
    305         total = sdp_cb.max_recs_per_search;
    306     if (p_ccb->num_handles > sdp_cb.max_recs_per_search)
    307         p_ccb->num_handles = sdp_cb.max_recs_per_search;
    308 
    309     for (xx = orig; xx < p_ccb->num_handles; xx++)
    310         BE_STREAM_TO_UINT32 (p_ccb->handles[xx], p_reply);
    311 
    312     BE_STREAM_TO_UINT8 (cont_len, p_reply);
    313     if(cont_len != 0)
    314     {
    315         if(cont_len > SDP_MAX_CONTINUATION_LEN)
    316         {
    317             sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE);
    318             return;
    319         }
    320         /* stay in the same state */
    321         sdp_snd_service_search_req(p_ccb, cont_len, p_reply);
    322     }
    323     else
    324     {
    325         /* change state */
    326         p_ccb->disc_state = SDP_DISC_WAIT_ATTR;
    327 
    328         /* Kick off the first attribute request */
    329         process_service_attr_rsp (p_ccb, NULL);
    330     }
    331 }
    332 
    333 /*******************************************************************************
    334 **
    335 ** Function         sdp_copy_raw_data
    336 **
    337 ** Description      copy the raw data
    338 **
    339 **
    340 ** Returns          void
    341 **
    342 *******************************************************************************/
    343 #if (SDP_RAW_DATA_INCLUDED == TRUE)
    344 static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
    345 {
    346     unsigned int    cpy_len;
    347     UINT32          list_len;
    348     UINT8           *p;
    349     UINT8           type;
    350 
    351 #if (SDP_DEBUG_RAW == TRUE)
    352     UINT8 num_array[SDP_MAX_LIST_BYTE_COUNT];
    353     UINT32 i;
    354 
    355     for (i = 0; i < p_ccb->list_len; i++)
    356     {
    357         sprintf((char *)&num_array[i*2],"%02X",(UINT8)(p_ccb->rsp_list[i]));
    358     }
    359     SDP_TRACE_WARNING("result :%s",num_array);
    360 #endif
    361 
    362     if(p_ccb->p_db->raw_data)
    363     {
    364         cpy_len = p_ccb->p_db->raw_size - p_ccb->p_db->raw_used;
    365         list_len = p_ccb->list_len;
    366         p = &p_ccb->rsp_list[0];
    367 
    368         if(offset)
    369         {
    370             type = *p++;
    371             p = sdpu_get_len_from_type (p, type, &list_len);
    372         }
    373         if(list_len && list_len < cpy_len )
    374         {
    375             cpy_len = list_len;
    376         }
    377 #if (SDP_DEBUG_RAW == TRUE)
    378         SDP_TRACE_WARNING("list_len :%d cpy_len:%d raw_size:%d raw_used:%d",
    379             list_len, cpy_len, p_ccb->p_db->raw_size, p_ccb->p_db->raw_used);
    380 #endif
    381         memcpy (&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len);
    382         p_ccb->p_db->raw_used += cpy_len;
    383     }
    384 }
    385 #endif
    386 
    387 /*******************************************************************************
    388 **
    389 ** Function         process_service_attr_rsp
    390 **
    391 ** Description      This function is called when there is a attribute response from
    392 **                  the server.
    393 **
    394 ** Returns          void
    395 **
    396 *******************************************************************************/
    397 static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    398 {
    399     UINT8           *p_start, *p_param_len;
    400     UINT16          param_len, list_byte_count;
    401     BOOLEAN         cont_request_needed = FALSE;
    402 
    403 #if (SDP_DEBUG_RAW == TRUE)
    404     SDP_TRACE_WARNING("process_service_attr_rsp raw inc:%d",
    405         SDP_RAW_DATA_INCLUDED);
    406 #endif
    407     /* If p_reply is NULL, we were called after the records handles were read */
    408     if (p_reply)
    409     {
    410 #if (SDP_DEBUG_RAW == TRUE)
    411         SDP_TRACE_WARNING("ID & len: 0x%02x-%02x-%02x-%02x",
    412             p_reply[0], p_reply[1], p_reply[2], p_reply[3]);
    413 #endif
    414         /* Skip transaction ID and length */
    415         p_reply += 4;
    416 
    417         BE_STREAM_TO_UINT16 (list_byte_count, p_reply);
    418 #if (SDP_DEBUG_RAW == TRUE)
    419         SDP_TRACE_WARNING("list_byte_count:%d", list_byte_count);
    420 #endif
    421 
    422         /* Copy the response to the scratchpad. First, a safety check on the length */
    423         if ((p_ccb->list_len + list_byte_count) > SDP_MAX_LIST_BYTE_COUNT)
    424         {
    425             sdp_disconnect (p_ccb, SDP_INVALID_PDU_SIZE);
    426             return;
    427         }
    428 
    429 #if (SDP_DEBUG_RAW == TRUE)
    430         SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d",
    431             p_ccb->list_len, list_byte_count);
    432 #endif
    433         if (p_ccb->rsp_list == NULL)
    434             p_ccb->rsp_list = (UINT8 *)osi_malloc(SDP_MAX_LIST_BYTE_COUNT);
    435         memcpy(&p_ccb->rsp_list[p_ccb->list_len], p_reply, list_byte_count);
    436         p_ccb->list_len += list_byte_count;
    437         p_reply         += list_byte_count;
    438 #if (SDP_DEBUG_RAW == TRUE)
    439         SDP_TRACE_WARNING("list_len: %d(attr_rsp)", p_ccb->list_len);
    440 
    441         /* Check if we need to request a continuation */
    442         SDP_TRACE_WARNING("*p_reply:%d(%d)", *p_reply, SDP_MAX_CONTINUATION_LEN);
    443 #endif
    444         if (*p_reply)
    445         {
    446             if (*p_reply > SDP_MAX_CONTINUATION_LEN)
    447             {
    448                 sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE);
    449                 return;
    450             }
    451             cont_request_needed = TRUE;
    452         }
    453         else
    454         {
    455 
    456 #if (SDP_RAW_DATA_INCLUDED == TRUE)
    457             SDP_TRACE_WARNING("process_service_attr_rsp");
    458             sdp_copy_raw_data (p_ccb, FALSE);
    459 #endif
    460 
    461             /* Save the response in the database. Stop on any error */
    462             if (!save_attr_seq (p_ccb, &p_ccb->rsp_list[0], &p_ccb->rsp_list[p_ccb->list_len]))
    463             {
    464                 sdp_disconnect (p_ccb, SDP_DB_FULL);
    465                 return;
    466             }
    467             p_ccb->list_len = 0;
    468             p_ccb->cur_handle++;
    469         }
    470     }
    471 
    472     /* Now, ask for the next handle. Re-use the buffer we just got. */
    473     if (p_ccb->cur_handle < p_ccb->num_handles)
    474     {
    475         BT_HDR  *p_msg = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
    476         UINT8   *p;
    477 
    478         p_msg->offset = L2CAP_MIN_OFFSET;
    479         p = p_start = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET;
    480 
    481         /* Get all the attributes from the server */
    482         UINT8_TO_BE_STREAM  (p, SDP_PDU_SERVICE_ATTR_REQ);
    483         UINT16_TO_BE_STREAM (p, p_ccb->transaction_id);
    484         p_ccb->transaction_id++;
    485 
    486         /* Skip the length, we need to add it at the end */
    487         p_param_len = p;
    488         p += 2;
    489 
    490         UINT32_TO_BE_STREAM (p, p_ccb->handles[p_ccb->cur_handle]);
    491 
    492         /* Max attribute byte count */
    493         UINT16_TO_BE_STREAM (p, sdp_cb.max_attr_list_size);
    494 
    495         /* If no attribute filters, build a wildcard attribute sequence */
    496         if (p_ccb->p_db->num_attr_filters)
    497             p = sdpu_build_attrib_seq (p, p_ccb->p_db->attr_filters, p_ccb->p_db->num_attr_filters);
    498         else
    499             p = sdpu_build_attrib_seq (p, NULL, 0);
    500 
    501         /* Was this a continuation request ? */
    502         if (cont_request_needed)
    503         {
    504             memcpy (p, p_reply, *p_reply + 1);
    505             p += *p_reply + 1;
    506         }
    507         else
    508             UINT8_TO_BE_STREAM (p, 0);
    509 
    510         /* Go back and put the parameter length into the buffer */
    511         param_len = (UINT16)(p - p_param_len - 2);
    512         UINT16_TO_BE_STREAM (p_param_len, param_len);
    513 
    514         /* Set the length of the SDP data in the buffer */
    515         p_msg->len = (UINT16)(p - p_start);
    516 
    517 
    518         L2CA_DataWrite (p_ccb->connection_id, p_msg);
    519 
    520         /* Start inactivity timer */
    521         alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
    522                            sdp_conn_timer_timeout, p_ccb,
    523                            btu_general_alarm_queue);
    524     }
    525     else
    526     {
    527         sdp_disconnect (p_ccb, SDP_SUCCESS);
    528         return;
    529     }
    530 }
    531 
    532 
    533 /*******************************************************************************
    534 **
    535 ** Function         process_service_search_attr_rsp
    536 **
    537 ** Description      This function is called when there is a search attribute
    538 **                  response from the server.
    539 **
    540 ** Returns          void
    541 **
    542 *******************************************************************************/
    543 static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply)
    544 {
    545     UINT8           *p, *p_start, *p_end, *p_param_len;
    546     UINT8           type;
    547     UINT32          seq_len;
    548     UINT16          param_len, lists_byte_count = 0;
    549     BOOLEAN         cont_request_needed = FALSE;
    550 
    551 #if (SDP_DEBUG_RAW == TRUE)
    552     SDP_TRACE_WARNING("process_service_search_attr_rsp");
    553 #endif
    554     /* If p_reply is NULL, we were called for the initial read */
    555     if (p_reply)
    556     {
    557 #if (SDP_DEBUG_RAW == TRUE)
    558         SDP_TRACE_WARNING("ID & len: 0x%02x-%02x-%02x-%02x",
    559             p_reply[0], p_reply[1], p_reply[2], p_reply[3]);
    560 #endif
    561         /* Skip transaction ID and length */
    562         p_reply += 4;
    563 
    564         BE_STREAM_TO_UINT16 (lists_byte_count, p_reply);
    565 #if (SDP_DEBUG_RAW == TRUE)
    566         SDP_TRACE_WARNING("lists_byte_count:%d", lists_byte_count);
    567 #endif
    568 
    569         /* Copy the response to the scratchpad. First, a safety check on the length */
    570         if ((p_ccb->list_len + lists_byte_count) > SDP_MAX_LIST_BYTE_COUNT)
    571         {
    572             sdp_disconnect (p_ccb, SDP_INVALID_PDU_SIZE);
    573             return;
    574         }
    575 
    576 #if (SDP_DEBUG_RAW == TRUE)
    577         SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d",
    578             p_ccb->list_len, lists_byte_count);
    579 #endif
    580         if (p_ccb->rsp_list == NULL)
    581             p_ccb->rsp_list = (UINT8 *)osi_malloc(SDP_MAX_LIST_BYTE_COUNT);
    582         memcpy (&p_ccb->rsp_list[p_ccb->list_len], p_reply, lists_byte_count);
    583         p_ccb->list_len += lists_byte_count;
    584         p_reply         += lists_byte_count;
    585 #if (SDP_DEBUG_RAW == TRUE)
    586         SDP_TRACE_WARNING("list_len: %d(search_attr_rsp)", p_ccb->list_len);
    587 
    588         /* Check if we need to request a continuation */
    589         SDP_TRACE_WARNING("*p_reply:%d(%d)", *p_reply, SDP_MAX_CONTINUATION_LEN);
    590 #endif
    591         if (*p_reply)
    592         {
    593             if (*p_reply > SDP_MAX_CONTINUATION_LEN)
    594             {
    595                 sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE);
    596                 return;
    597             }
    598 
    599             cont_request_needed = TRUE;
    600         }
    601     }
    602 
    603 #if (SDP_DEBUG_RAW == TRUE)
    604     SDP_TRACE_WARNING("cont_request_needed:%d", cont_request_needed);
    605 #endif
    606     /* If continuation request (or first time request) */
    607     if ((cont_request_needed) || (!p_reply))
    608     {
    609         BT_HDR  *p_msg = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
    610         UINT8   *p;
    611 
    612         p_msg->offset = L2CAP_MIN_OFFSET;
    613         p = p_start = (UINT8 *)(p_msg + 1) + L2CAP_MIN_OFFSET;
    614 
    615         /* Build a service search request packet */
    616         UINT8_TO_BE_STREAM  (p, SDP_PDU_SERVICE_SEARCH_ATTR_REQ);
    617         UINT16_TO_BE_STREAM (p, p_ccb->transaction_id);
    618         p_ccb->transaction_id++;
    619 
    620         /* Skip the length, we need to add it at the end */
    621         p_param_len = p;
    622         p += 2;
    623 
    624         /* Build the UID sequence. */
    625 #if (defined(SDP_BROWSE_PLUS) && SDP_BROWSE_PLUS == TRUE)
    626         p = sdpu_build_uuid_seq (p, 1, &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx]);
    627 #else
    628         p = sdpu_build_uuid_seq (p, p_ccb->p_db->num_uuid_filters, p_ccb->p_db->uuid_filters);
    629 #endif
    630 
    631         /* Max attribute byte count */
    632         UINT16_TO_BE_STREAM (p, sdp_cb.max_attr_list_size);
    633 
    634         /* If no attribute filters, build a wildcard attribute sequence */
    635         if (p_ccb->p_db->num_attr_filters)
    636             p = sdpu_build_attrib_seq (p, p_ccb->p_db->attr_filters, p_ccb->p_db->num_attr_filters);
    637         else
    638             p = sdpu_build_attrib_seq (p, NULL, 0);
    639 
    640         /* No continuation for first request */
    641         if (p_reply)
    642         {
    643             memcpy (p, p_reply, *p_reply + 1);
    644             p += *p_reply + 1;
    645         }
    646         else
    647             UINT8_TO_BE_STREAM (p, 0);
    648 
    649         /* Go back and put the parameter length into the buffer */
    650         param_len = p - p_param_len - 2;
    651         UINT16_TO_BE_STREAM (p_param_len, param_len);
    652 
    653         /* Set the length of the SDP data in the buffer */
    654         p_msg->len = p - p_start;
    655 
    656 
    657         L2CA_DataWrite (p_ccb->connection_id, p_msg);
    658 
    659         /* Start inactivity timer */
    660         alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
    661                            sdp_conn_timer_timeout, p_ccb,
    662                            btu_general_alarm_queue);
    663 
    664         return;
    665     }
    666 
    667 
    668     /*******************************************************************/
    669     /* We now have the full response, which is a sequence of sequences */
    670     /*******************************************************************/
    671 
    672 #if (SDP_RAW_DATA_INCLUDED == TRUE)
    673     SDP_TRACE_WARNING("process_service_search_attr_rsp");
    674     sdp_copy_raw_data (p_ccb, TRUE);
    675 #endif
    676 
    677     p = &p_ccb->rsp_list[0];
    678 
    679     /* The contents is a sequence of attribute sequences */
    680     type = *p++;
    681 
    682     if ((type >> 3) != DATA_ELE_SEQ_DESC_TYPE)
    683     {
    684         SDP_TRACE_WARNING ("SDP - Wrong type: 0x%02x in attr_rsp", type);
    685         return;
    686     }
    687     p = sdpu_get_len_from_type (p, type, &seq_len);
    688 
    689     p_end = &p_ccb->rsp_list[p_ccb->list_len];
    690 
    691     if ((p + seq_len) != p_end)
    692     {
    693         sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE);
    694         return;
    695     }
    696 
    697     while (p < p_end)
    698     {
    699         p = save_attr_seq (p_ccb, p, &p_ccb->rsp_list[p_ccb->list_len]);
    700         if (!p)
    701         {
    702             sdp_disconnect (p_ccb, SDP_DB_FULL);
    703             return;
    704         }
    705     }
    706 
    707     /* Since we got everything we need, disconnect the call */
    708     sdp_disconnect (p_ccb, SDP_SUCCESS);
    709 }
    710 
    711 /*******************************************************************************
    712 **
    713 ** Function         save_attr_seq
    714 **
    715 ** Description      This function is called when there is a response from
    716 **                  the server.
    717 **
    718 ** Returns          pointer to next byte or NULL if error
    719 **
    720 *******************************************************************************/
    721 static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end)
    722 {
    723     UINT32      seq_len, attr_len;
    724     UINT16      attr_id;
    725     UINT8       type, *p_seq_end;
    726     tSDP_DISC_REC *p_rec;
    727 
    728     type = *p++;
    729 
    730     if ((type >> 3) != DATA_ELE_SEQ_DESC_TYPE)
    731     {
    732         SDP_TRACE_WARNING ("SDP - Wrong type: 0x%02x in attr_rsp", type);
    733         return (NULL);
    734     }
    735 
    736     p = sdpu_get_len_from_type (p, type, &seq_len);
    737     if ((p + seq_len) > p_msg_end)
    738     {
    739         SDP_TRACE_WARNING ("SDP - Bad len in attr_rsp %d", seq_len);
    740         return (NULL);
    741     }
    742 
    743     /* Create a record */
    744     p_rec = add_record (p_ccb->p_db, p_ccb->device_address);
    745     if (!p_rec)
    746     {
    747         SDP_TRACE_WARNING ("SDP - DB full add_record");
    748         return (NULL);
    749     }
    750 
    751     p_seq_end = p + seq_len;
    752 
    753     while (p < p_seq_end)
    754     {
    755         /* First get the attribute ID */
    756         type = *p++;
    757         p = sdpu_get_len_from_type (p, type, &attr_len);
    758         if (((type >> 3) != UINT_DESC_TYPE) || (attr_len != 2))
    759         {
    760             SDP_TRACE_WARNING ("SDP - Bad type: 0x%02x or len: %d in attr_rsp", type, attr_len);
    761             return (NULL);
    762         }
    763         BE_STREAM_TO_UINT16 (attr_id, p);
    764 
    765         /* Now, add the attribute value */
    766         p = add_attr (p, p_ccb->p_db, p_rec, attr_id, NULL, 0);
    767 
    768         if (!p)
    769         {
    770             SDP_TRACE_WARNING ("SDP - DB full add_attr");
    771             return (NULL);
    772         }
    773     }
    774 
    775     return (p);
    776 }
    777 
    778 
    779 /*******************************************************************************
    780 **
    781 ** Function         add_record
    782 **
    783 ** Description      This function allocates space for a record from the DB.
    784 **
    785 ** Returns          pointer to next byte in data stream
    786 **
    787 *******************************************************************************/
    788 tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda)
    789 {
    790     tSDP_DISC_REC   *p_rec;
    791 
    792     /* See if there is enough space in the database */
    793     if (p_db->mem_free < sizeof (tSDP_DISC_REC))
    794         return (NULL);
    795 
    796     p_rec = (tSDP_DISC_REC *) p_db->p_free_mem;
    797     p_db->p_free_mem += sizeof (tSDP_DISC_REC);
    798     p_db->mem_free   -= sizeof (tSDP_DISC_REC);
    799 
    800     p_rec->p_first_attr = NULL;
    801     p_rec->p_next_rec   = NULL;
    802 
    803     memcpy (p_rec->remote_bd_addr, p_bda, BD_ADDR_LEN);
    804 
    805     /* Add the record to the end of chain */
    806     if (!p_db->p_first_rec)
    807         p_db->p_first_rec = p_rec;
    808     else
    809     {
    810         tSDP_DISC_REC   *p_rec1 = p_db->p_first_rec;
    811 
    812         while (p_rec1->p_next_rec)
    813             p_rec1 = p_rec1->p_next_rec;
    814 
    815         p_rec1->p_next_rec = p_rec;
    816     }
    817 
    818     return (p_rec);
    819 }
    820 
    821 #define SDP_ADDITIONAL_LIST_MASK        0x80
    822 /*******************************************************************************
    823 **
    824 ** Function         add_attr
    825 **
    826 ** Description      This function allocates space for an attribute from the DB
    827 **                  and copies the data into it.
    828 **
    829 ** Returns          pointer to next byte in data stream
    830 **
    831 *******************************************************************************/
    832 static UINT8 *add_attr (UINT8 *p, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec,
    833                         UINT16 attr_id, tSDP_DISC_ATTR *p_parent_attr, UINT8 nest_level)
    834 {
    835     tSDP_DISC_ATTR  *p_attr;
    836     UINT32          attr_len;
    837     UINT32          total_len;
    838     UINT16          attr_type;
    839     UINT16          id;
    840     UINT8           type;
    841     UINT8           *p_end;
    842     UINT8           is_additional_list = nest_level & SDP_ADDITIONAL_LIST_MASK;
    843 
    844     nest_level &= ~(SDP_ADDITIONAL_LIST_MASK);
    845 
    846     type = *p++;
    847     p = sdpu_get_len_from_type (p, type, &attr_len);
    848 
    849     attr_len &= SDP_DISC_ATTR_LEN_MASK;
    850     attr_type = (type >> 3) & 0x0f;
    851 
    852     /* See if there is enough space in the database */
    853     if (attr_len > 4)
    854         total_len = attr_len - 4 + (UINT16)sizeof (tSDP_DISC_ATTR);
    855     else
    856         total_len = sizeof (tSDP_DISC_ATTR);
    857 
    858     /* Ensure it is a multiple of 4 */
    859     total_len = (total_len + 3) & ~3;
    860 
    861     /* See if there is enough space in the database */
    862     if (p_db->mem_free < total_len)
    863         return (NULL);
    864 
    865     p_attr                = (tSDP_DISC_ATTR *) p_db->p_free_mem;
    866     p_attr->attr_id       = attr_id;
    867     p_attr->attr_len_type = (UINT16)attr_len | (attr_type << 12);
    868     p_attr->p_next_attr = NULL;
    869 
    870     /* Store the attribute value */
    871     switch (attr_type)
    872     {
    873     case UINT_DESC_TYPE:
    874         if( (is_additional_list != 0) && (attr_len == 2) )
    875         {
    876             BE_STREAM_TO_UINT16 (id, p);
    877             if(id != ATTR_ID_PROTOCOL_DESC_LIST)
    878                 p -= 2;
    879             else
    880             {
    881                 /* Reserve the memory for the attribute now, as we need to add sub-attributes */
    882                 p_db->p_free_mem += sizeof (tSDP_DISC_ATTR);
    883                 p_db->mem_free   -= sizeof (tSDP_DISC_ATTR);
    884                 p_end             = p + attr_len;
    885                 total_len         = 0;
    886 
    887                 /* SDP_TRACE_DEBUG ("SDP - attr nest level:%d(list)", nest_level); */
    888                 if (nest_level >= MAX_NEST_LEVELS)
    889                 {
    890                     SDP_TRACE_ERROR ("SDP - attr nesting too deep");
    891                     return (p_end);
    892                 }
    893 
    894                 /* Now, add the list entry */
    895                 p = add_attr (p, p_db, p_rec, ATTR_ID_PROTOCOL_DESC_LIST, p_attr, (UINT8)(nest_level + 1));
    896 
    897                 break;
    898             }
    899         }
    900         /* Case falls through */
    901 
    902     case TWO_COMP_INT_DESC_TYPE:
    903         switch (attr_len)
    904         {
    905         case 1:
    906             p_attr->attr_value.v.u8 = *p++;
    907             break;
    908         case 2:
    909             BE_STREAM_TO_UINT16 (p_attr->attr_value.v.u16, p);
    910             break;
    911         case 4:
    912             BE_STREAM_TO_UINT32 (p_attr->attr_value.v.u32, p);
    913             break;
    914         default:
    915             BE_STREAM_TO_ARRAY (p, p_attr->attr_value.v.array, (INT32)attr_len);
    916             break;
    917         }
    918         break;
    919 
    920     case UUID_DESC_TYPE:
    921         switch (attr_len)
    922         {
    923         case 2:
    924             BE_STREAM_TO_UINT16 (p_attr->attr_value.v.u16, p);
    925             break;
    926         case 4:
    927             BE_STREAM_TO_UINT32 (p_attr->attr_value.v.u32, p);
    928             if (p_attr->attr_value.v.u32 < 0x10000)
    929             {
    930                 attr_len = 2;
    931                 p_attr->attr_len_type = (UINT16)attr_len | (attr_type << 12);
    932                 p_attr->attr_value.v.u16 = (UINT16) p_attr->attr_value.v.u32;
    933 
    934             }
    935             break;
    936         case 16:
    937             /* See if we can compress his UUID down to 16 or 32bit UUIDs */
    938             if (sdpu_is_base_uuid (p))
    939             {
    940                 if ((p[0] == 0) && (p[1] == 0))
    941                 {
    942                     p_attr->attr_len_type = (p_attr->attr_len_type & ~SDP_DISC_ATTR_LEN_MASK) | 2;
    943                     p += 2;
    944                     BE_STREAM_TO_UINT16 (p_attr->attr_value.v.u16, p);
    945                     p += MAX_UUID_SIZE - 4;
    946                 }
    947                 else
    948                 {
    949                     p_attr->attr_len_type = (p_attr->attr_len_type & ~SDP_DISC_ATTR_LEN_MASK) | 4;
    950                     BE_STREAM_TO_UINT32 (p_attr->attr_value.v.u32, p);
    951                     p += MAX_UUID_SIZE - 4;
    952                 }
    953             }
    954             else
    955             {
    956                  /* coverity[overrun-local] */
    957                  /*
    958                     Event overrun-local: Overrun of static array "p_attr->attr_value.v.array" of size 4 at position 15 with index variable "ijk"
    959                     False-positive: SDP uses scratch buffer to hold the attribute value.
    960                     The actual size of tSDP_DISC_ATVAL does not matter.
    961                     If the array size in tSDP_DISC_ATVAL is increase, we would increase the system RAM usage unnecessarily
    962                 */
    963                 BE_STREAM_TO_ARRAY (p, p_attr->attr_value.v.array, (INT32)attr_len);
    964             }
    965             break;
    966         default:
    967             SDP_TRACE_WARNING ("SDP - bad len in UUID attr: %d", attr_len);
    968             return (p + attr_len);
    969         }
    970         break;
    971 
    972     case DATA_ELE_SEQ_DESC_TYPE:
    973     case DATA_ELE_ALT_DESC_TYPE:
    974         /* Reserve the memory for the attribute now, as we need to add sub-attributes */
    975         p_db->p_free_mem += sizeof (tSDP_DISC_ATTR);
    976         p_db->mem_free   -= sizeof (tSDP_DISC_ATTR);
    977         p_end             = p + attr_len;
    978         total_len         = 0;
    979 
    980         /* SDP_TRACE_DEBUG ("SDP - attr nest level:%d", nest_level); */
    981         if (nest_level >= MAX_NEST_LEVELS)
    982         {
    983             SDP_TRACE_ERROR ("SDP - attr nesting too deep");
    984             return (p_end);
    985         }
    986         if(is_additional_list != 0 || attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS)
    987             nest_level |= SDP_ADDITIONAL_LIST_MASK;
    988         /* SDP_TRACE_DEBUG ("SDP - attr nest level:0x%x(finish)", nest_level); */
    989 
    990         while (p < p_end)
    991         {
    992             /* Now, add the list entry */
    993             p = add_attr (p, p_db, p_rec, 0, p_attr, (UINT8)(nest_level + 1));
    994 
    995             if (!p)
    996                 return (NULL);
    997         }
    998         break;
    999 
   1000     case TEXT_STR_DESC_TYPE:
   1001     case URL_DESC_TYPE:
   1002         BE_STREAM_TO_ARRAY (p, p_attr->attr_value.v.array, (INT32)attr_len);
   1003         break;
   1004 
   1005     case BOOLEAN_DESC_TYPE:
   1006         switch (attr_len)
   1007         {
   1008         case 1:
   1009             p_attr->attr_value.v.u8 = *p++;
   1010             break;
   1011         default:
   1012             SDP_TRACE_WARNING ("SDP - bad len in boolean attr: %d", attr_len);
   1013             return (p + attr_len);
   1014         }
   1015         break;
   1016 
   1017     default:    /* switch (attr_type) */
   1018         break;
   1019     }
   1020 
   1021     p_db->p_free_mem += total_len;
   1022     p_db->mem_free   -= total_len;
   1023 
   1024     /* Add the attribute to the end of the chain */
   1025     if (!p_parent_attr)
   1026     {
   1027         if (!p_rec->p_first_attr)
   1028             p_rec->p_first_attr = p_attr;
   1029         else
   1030         {
   1031             tSDP_DISC_ATTR  *p_attr1 = p_rec->p_first_attr;
   1032 
   1033             while (p_attr1->p_next_attr)
   1034                 p_attr1 = p_attr1->p_next_attr;
   1035 
   1036             p_attr1->p_next_attr = p_attr;
   1037         }
   1038     }
   1039     else
   1040     {
   1041         if (!p_parent_attr->attr_value.v.p_sub_attr)
   1042         {
   1043             p_parent_attr->attr_value.v.p_sub_attr = p_attr;
   1044             /* SDP_TRACE_DEBUG ("parent:0x%x(id:%d), ch:0x%x(id:%d)",
   1045                 p_parent_attr, p_parent_attr->attr_id, p_attr, p_attr->attr_id); */
   1046         }
   1047         else
   1048         {
   1049             tSDP_DISC_ATTR  *p_attr1 = p_parent_attr->attr_value.v.p_sub_attr;
   1050             /* SDP_TRACE_DEBUG ("parent:0x%x(id:%d), ch1:0x%x(id:%d)",
   1051                 p_parent_attr, p_parent_attr->attr_id, p_attr1, p_attr1->attr_id); */
   1052 
   1053             while (p_attr1->p_next_attr)
   1054                 p_attr1 = p_attr1->p_next_attr;
   1055 
   1056             p_attr1->p_next_attr = p_attr;
   1057             /* SDP_TRACE_DEBUG ("new ch:0x%x(id:%d)", p_attr, p_attr->attr_id); */
   1058         }
   1059     }
   1060 
   1061     return (p);
   1062 }
   1063 
   1064 #endif  /* CLIENT_ENABLED == TRUE */
   1065