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