OSDN Git Service

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