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 functions that handle the database
22 *
23 ******************************************************************************/
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28
29 #include "bt_target.h"
30
31 #include "gki.h"
32
33 #include "l2cdefs.h"
34 #include "hcidefs.h"
35 #include "hcimsgs.h"
36
37 #include "sdp_api.h"
38 #include "sdpint.h"
39 #include "wbt_api.h"
40
41 #if SDP_SERVER_ENABLED == TRUE
42 /********************************************************************************/
43 /* L O C A L F U N C T I O N P R O T O T Y P E S */
44 /********************************************************************************/
45 static BOOLEAN find_uuid_in_seq (UINT8 *p , UINT32 seq_len, UINT8 *p_his_uuid,
46 UINT16 his_len, int nest_level);
47
48
49 /*******************************************************************************
50 **
51 ** Function sdp_db_service_search
52 **
53 ** Description This function searches for a record that contains the
54 ** specified UIDs. It is passed either NULL to start at the
55 ** beginning, or the previous record found.
56 **
57 ** Returns Pointer to the record, or NULL if not found.
58 **
59 *******************************************************************************/
sdp_db_service_search(tSDP_RECORD * p_rec,tSDP_UUID_SEQ * p_seq)60 tSDP_RECORD *sdp_db_service_search (tSDP_RECORD *p_rec, tSDP_UUID_SEQ *p_seq)
61 {
62 UINT16 xx, yy;
63 tSDP_ATTRIBUTE *p_attr;
64 tSDP_RECORD *p_end = &sdp_cb.server_db.record[sdp_cb.server_db.num_records];
65
66 /* If NULL, start at the beginning, else start at the first specified record */
67 if (!p_rec)
68 p_rec = &sdp_cb.server_db.record[0];
69 else
70 p_rec++;
71
72 /* Look through the records. The spec says that a match occurs if */
73 /* the record contains all the passed UUIDs in it. */
74 for ( ; p_rec < p_end; p_rec++)
75 {
76 for (yy = 0; yy < p_seq->num_uids; yy++)
77 {
78 p_attr = &p_rec->attribute[0];
79 for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++)
80 {
81 if (p_attr->type == UUID_DESC_TYPE)
82 {
83 if (sdpu_compare_uuid_arrays (p_attr->value_ptr, p_attr->len,
84 &p_seq->uuid_entry[yy].value[0],
85 p_seq->uuid_entry[yy].len))
86 break;
87 }
88 else if (p_attr->type == DATA_ELE_SEQ_DESC_TYPE)
89 {
90 if (find_uuid_in_seq (p_attr->value_ptr, p_attr->len,
91 &p_seq->uuid_entry[yy].value[0],
92 p_seq->uuid_entry[yy].len, 0))
93 break;
94 }
95 }
96 /* If any UUID was not found, on to the next record */
97 if (xx == p_rec->num_attributes)
98 break;
99 }
100
101 /* If every UUID was found in the record, return the record */
102 if (yy == p_seq->num_uids)
103 return (p_rec);
104 }
105
106 /* If here, no more records found */
107 return (NULL);
108 }
109
110 /*******************************************************************************
111 **
112 ** Function find_uuid_in_seq
113 **
114 ** Description This function searches a data element sequenct for a UUID.
115 **
116 ** Returns TRUE if found, else FALSE
117 **
118 *******************************************************************************/
find_uuid_in_seq(UINT8 * p,UINT32 seq_len,UINT8 * p_uuid,UINT16 uuid_len,int nest_level)119 static BOOLEAN find_uuid_in_seq (UINT8 *p , UINT32 seq_len, UINT8 *p_uuid,
120 UINT16 uuid_len, int nest_level)
121 {
122 UINT8 *p_end = p + seq_len;
123 UINT8 type;
124 UINT32 len;
125
126 /* A little safety check to avoid excessive recursion */
127 if (nest_level > 3)
128 return (FALSE);
129
130 while (p < p_end)
131 {
132 type = *p++;
133 p = sdpu_get_len_from_type (p, type, &len);
134 type = type >> 3;
135 if (type == UUID_DESC_TYPE)
136 {
137 if (sdpu_compare_uuid_arrays (p, len, p_uuid, uuid_len))
138 return (TRUE);
139 }
140 else if (type == DATA_ELE_SEQ_DESC_TYPE)
141 {
142 if (find_uuid_in_seq (p, len, p_uuid, uuid_len, nest_level + 1))
143 return (TRUE);
144 }
145 p = p + len;
146 }
147
148 /* If here, failed to match */
149 return (FALSE);
150 }
151
152 /*******************************************************************************
153 **
154 ** Function sdp_db_find_record
155 **
156 ** Description This function searches for a record with a specific handle
157 ** It is passed the handle of the record.
158 **
159 ** Returns Pointer to the record, or NULL if not found.
160 **
161 *******************************************************************************/
sdp_db_find_record(UINT32 handle)162 tSDP_RECORD *sdp_db_find_record (UINT32 handle)
163 {
164 tSDP_RECORD *p_rec;
165 tSDP_RECORD *p_end = &sdp_cb.server_db.record[sdp_cb.server_db.num_records];
166
167 /* Look through the records for the caller's handle */
168 for (p_rec = &sdp_cb.server_db.record[0]; p_rec < p_end; p_rec++)
169 {
170 if (p_rec->record_handle == handle)
171 return (p_rec);
172 }
173
174 /* Record with that handle not found. */
175 return (NULL);
176 }
177
178 /*******************************************************************************
179 **
180 ** Function sdp_db_find_attr_in_rec
181 **
182 ** Description This function searches a record for specific attributes.
183 ** It is passed a pointer to the record. If the record contains
184 ** the specified attribute, (the caller may specify be a range
185 ** of attributes), the attribute is returned.
186 **
187 ** Returns Pointer to the attribute, or NULL if not found.
188 **
189 *******************************************************************************/
sdp_db_find_attr_in_rec(tSDP_RECORD * p_rec,UINT16 start_attr,UINT16 end_attr)190 tSDP_ATTRIBUTE *sdp_db_find_attr_in_rec (tSDP_RECORD *p_rec, UINT16 start_attr,
191 UINT16 end_attr)
192 {
193 tSDP_ATTRIBUTE *p_at;
194 UINT16 xx;
195
196 /* Note that the attributes in a record are assumed to be in sorted order */
197 for (xx = 0, p_at = &p_rec->attribute[0]; xx < p_rec->num_attributes;
198 xx++, p_at++)
199 {
200 if ((p_at->id >= start_attr) && (p_at->id <= end_attr))
201 return (p_at);
202 }
203
204 /* No matching attribute found */
205 return (NULL);
206 }
207
208
209 /*******************************************************************************
210 **
211 ** Function sdp_compose_proto_list
212 **
213 ** Description This function is called to compose a data sequence from
214 ** protocol element list struct pointer
215 **
216 ** Returns the length of the data sequence
217 **
218 *******************************************************************************/
sdp_compose_proto_list(UINT8 * p,UINT16 num_elem,tSDP_PROTOCOL_ELEM * p_elem_list)219 static int sdp_compose_proto_list( UINT8 *p, UINT16 num_elem,
220 tSDP_PROTOCOL_ELEM *p_elem_list)
221 {
222 UINT16 xx, yy, len;
223 BOOLEAN is_rfcomm_scn;
224 UINT8 *p_head = p;
225 UINT8 *p_len;
226
227 /* First, build the protocol list. This consists of a set of data element
228 ** sequences, one for each layer. Each layer sequence consists of layer's
229 ** UUID and optional parameters
230 */
231 for (xx = 0; xx < num_elem; xx++, p_elem_list++)
232 {
233 len = 3 + (p_elem_list->num_params * 3);
234 UINT8_TO_BE_STREAM (p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
235
236 p_len = p;
237 *p++ = (UINT8) len;
238
239 UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
240 UINT16_TO_BE_STREAM (p, p_elem_list->protocol_uuid);
241
242 if (p_elem_list->protocol_uuid == UUID_PROTOCOL_RFCOMM)
243 is_rfcomm_scn = TRUE;
244 else
245 is_rfcomm_scn = FALSE;
246
247 for (yy = 0; yy < p_elem_list->num_params; yy++)
248 {
249 if (is_rfcomm_scn)
250 {
251 UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE);
252 UINT8_TO_BE_STREAM (p, p_elem_list->params[yy]);
253
254 *p_len -= 1;
255 }
256 else
257 {
258 UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
259 UINT16_TO_BE_STREAM (p, p_elem_list->params[yy]);
260 }
261 }
262 }
263 return (p - p_head);
264 }
265
266 #endif /* SDP_SERVER_ENABLED == TRUE */
267
268 /*******************************************************************************
269 **
270 ** Function SDP_CreateRecord
271 **
272 ** Description This function is called to create a record in the database.
273 ** This would be through the SDP database maintenance API. The
274 ** record is created empty, teh application should then call
275 ** "add_attribute" to add the record's attributes.
276 **
277 ** Returns Record handle if OK, else 0.
278 **
279 *******************************************************************************/
SDP_CreateRecord(void)280 UINT32 SDP_CreateRecord (void)
281 {
282 #if SDP_SERVER_ENABLED == TRUE
283 UINT32 handle;
284 UINT8 buf[4];
285 tSDP_DB *p_db = &sdp_cb.server_db;
286
287 /* First, check if there is a free record */
288 if (p_db->num_records < SDP_MAX_RECORDS)
289 {
290 memset (&p_db->record[p_db->num_records], 0,
291 sizeof (tSDP_RECORD));
292
293 /* We will use a handle of the first unreserved handle plus last record
294 ** number + 1 */
295 if (p_db->num_records)
296 handle = p_db->record[p_db->num_records - 1].record_handle + 1;
297 else
298 handle = 0x10000;
299
300 p_db->record[p_db->num_records].record_handle = handle;
301
302 p_db->num_records++;
303 SDP_TRACE_DEBUG1("SDP_CreateRecord ok, num_records:%d", p_db->num_records);
304 /* Add the first attribute (the handle) automatically */
305 UINT32_TO_BE_FIELD (buf, handle);
306 SDP_AddAttribute (handle, ATTR_ID_SERVICE_RECORD_HDL, UINT_DESC_TYPE,
307 4, buf);
308
309 return (p_db->record[p_db->num_records - 1].record_handle);
310 }
311 else SDP_TRACE_ERROR1("SDP_CreateRecord fail, exceed maximum records:%d", SDP_MAX_RECORDS);
312 #endif
313 return (0);
314 }
315
316
317 /*******************************************************************************
318 **
319 ** Function SDP_DeleteRecord
320 **
321 ** Description This function is called to add a record (or all records)
322 ** from the database. This would be through the SDP database
323 ** maintenance API.
324 **
325 ** If a record handle of 0 is passed, all records are deleted.
326 **
327 ** Returns TRUE if succeeded, else FALSE
328 **
329 *******************************************************************************/
SDP_DeleteRecord(UINT32 handle)330 BOOLEAN SDP_DeleteRecord (UINT32 handle)
331 {
332 #if SDP_SERVER_ENABLED == TRUE
333 UINT16 xx, yy, zz;
334 tSDP_RECORD *p_rec = &sdp_cb.server_db.record[0];
335
336 if (handle == 0 || sdp_cb.server_db.num_records == 0)
337 {
338 /* Delete all records in the database */
339 sdp_cb.server_db.num_records = 0;
340
341 /* require new DI record to be created in SDP_SetLocalDiRecord */
342 sdp_cb.server_db.di_primary_handle = 0;
343 sdp_cb.server_db.brcm_di_registered = 0;
344
345 return (TRUE);
346 }
347 else
348 {
349 /* Find the record in the database */
350 for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++)
351 {
352 if (p_rec->record_handle == handle)
353 {
354 /* Found it. Shift everything up one */
355 for (yy = xx; yy < sdp_cb.server_db.num_records; yy++, p_rec++)
356 {
357 *p_rec = *(p_rec + 1);
358
359 /* Adjust the attribute value pointer for each attribute */
360 for (zz = 0; zz < p_rec->num_attributes; zz++)
361 p_rec->attribute[zz].value_ptr -= sizeof(tSDP_RECORD);
362 }
363
364 sdp_cb.server_db.num_records--;
365
366 SDP_TRACE_DEBUG1("SDP_DeleteRecord ok, num_records:%d", sdp_cb.server_db.num_records);
367 /* if we're deleting the primary DI record, clear the */
368 /* value in the control block */
369 if( sdp_cb.server_db.di_primary_handle == handle )
370 {
371 sdp_cb.server_db.di_primary_handle = 0;
372 sdp_cb.server_db.brcm_di_registered = 0;
373 }
374
375 return (TRUE);
376 }
377 }
378 }
379 #endif
380 return (FALSE);
381 }
382
383
384 /*******************************************************************************
385 **
386 ** Function SDP_AddAttribute
387 **
388 ** Description This function is called to add an attribute to a record.
389 ** This would be through the SDP database maintenance API.
390 ** If the attribute already exists in the record, it is replaced
391 ** with the new value.
392 **
393 ** NOTE Attribute values must be passed as a Big Endian stream.
394 **
395 ** Returns TRUE if added OK, else FALSE
396 **
397 *******************************************************************************/
SDP_AddAttribute(UINT32 handle,UINT16 attr_id,UINT8 attr_type,UINT32 attr_len,UINT8 * p_val)398 BOOLEAN SDP_AddAttribute (UINT32 handle, UINT16 attr_id, UINT8 attr_type,
399 UINT32 attr_len, UINT8 *p_val)
400 {
401 #if SDP_SERVER_ENABLED == TRUE
402 UINT16 xx, yy, zz;
403 tSDP_RECORD *p_rec = &sdp_cb.server_db.record[0];
404
405 #if (BT_TRACE_VERBOSE == TRUE)
406 if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG)
407 {
408 if ((attr_type == UINT_DESC_TYPE) ||
409 (attr_type == TWO_COMP_INT_DESC_TYPE) ||
410 (attr_type == UUID_DESC_TYPE) ||
411 (attr_type == DATA_ELE_SEQ_DESC_TYPE) ||
412 (attr_type == DATA_ELE_ALT_DESC_TYPE))
413 {
414 UINT8 num_array[400];
415 UINT32 i;
416 UINT32 len = (attr_len > 200) ? 200 : attr_len;
417
418 num_array[0] ='\0';
419 for (i = 0; i < len; i++)
420 {
421 sprintf((char *)&num_array[i*2],"%02X",(UINT8)(p_val[i]));
422 }
423 SDP_TRACE_DEBUG6("SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, *p_val:%s",
424 handle,attr_id,attr_type,attr_len,p_val,num_array);
425 }
426 else if (attr_type == BOOLEAN_DESC_TYPE)
427 {
428 SDP_TRACE_DEBUG6("SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, *p_val:%d",
429 handle,attr_id,attr_type,attr_len,p_val,*p_val);
430 }
431 else
432 {
433 SDP_TRACE_DEBUG6("SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, *p_val:%s",
434 handle,attr_id,attr_type,attr_len,p_val,p_val);
435 }
436 }
437 #endif
438
439 /* Find the record in the database */
440 for (zz = 0; zz < sdp_cb.server_db.num_records; zz++, p_rec++)
441 {
442 if (p_rec->record_handle == handle)
443 {
444 tSDP_ATTRIBUTE *p_attr = &p_rec->attribute[0];
445
446 /* Found the record. Now, see if the attribute already exists */
447 for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++)
448 {
449 /* The attribute exists. replace it */
450 if (p_attr->id == attr_id)
451 {
452 SDP_DeleteAttribute (handle, attr_id);
453 break;
454 }
455 if (p_attr->id > attr_id)
456 break;
457 }
458
459 if (p_rec->num_attributes == SDP_MAX_REC_ATTR)
460 return (FALSE);
461
462 /* If not found, see if we can allocate a new entry */
463 if (xx == p_rec->num_attributes)
464 p_attr = &p_rec->attribute[p_rec->num_attributes];
465 else
466 {
467 /* Since the attributes are kept in sorted order, insert ours here */
468 for (yy = p_rec->num_attributes; yy > xx; yy--)
469 p_rec->attribute[yy] = p_rec->attribute[yy - 1];
470 }
471
472 p_attr->id = attr_id;
473 p_attr->type = attr_type;
474 p_attr->len = attr_len;
475
476 if (p_rec->free_pad_ptr + attr_len >= SDP_MAX_PAD_LEN)
477 {
478 /* do truncate only for text string type descriptor */
479 if (attr_type == TEXT_STR_DESC_TYPE)
480 {
481 SDP_TRACE_WARNING2("SDP_AddAttribute: attr_len:%d too long. truncate to (%d)",
482 attr_len, SDP_MAX_PAD_LEN - p_rec->free_pad_ptr );
483
484 attr_len = SDP_MAX_PAD_LEN - p_rec->free_pad_ptr;
485 p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr] = '\0';
486 p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr+1] = '\0';
487 }
488 else
489 attr_len = 0;
490 }
491
492 if ((attr_len > 0) && (p_val != 0))
493 {
494 p_attr->len = attr_len;
495 memcpy (&p_rec->attr_pad[p_rec->free_pad_ptr], p_val, (size_t)attr_len);
496 p_attr->value_ptr = &p_rec->attr_pad[p_rec->free_pad_ptr];
497 p_rec->free_pad_ptr += attr_len;
498 }
499 else if ((attr_len == 0 && p_attr->len != 0) || /* if truncate to 0 length, simply don't add */
500 p_val == 0)
501 {
502 SDP_TRACE_ERROR2("SDP_AddAttribute fail, length exceed maximum: ID %d: attr_len:%d ",
503 attr_id, attr_len );
504 p_attr->id = p_attr->type = p_attr->len = 0;
505 return (FALSE);
506 }
507 p_rec->num_attributes++;
508
509 /*** Mark DI record as used by Broadcom ***/
510 if (handle == sdp_cb.server_db.di_primary_handle &&
511 attr_id == ATTR_ID_EXT_BRCM_VERSION)
512 sdp_cb.server_db.brcm_di_registered = TRUE;
513
514 return (TRUE);
515 }
516 }
517 #endif
518 return (FALSE);
519 }
520
521
522 /*******************************************************************************
523 **
524 ** Function SDP_AddSequence
525 **
526 ** Description This function is called to add a sequence to a record.
527 ** This would be through the SDP database maintenance API.
528 ** If the sequence already exists in the record, it is replaced
529 ** with the new sequence.
530 **
531 ** NOTE Element values must be passed as a Big Endian stream.
532 **
533 ** Returns TRUE if added OK, else FALSE
534 **
535 *******************************************************************************/
SDP_AddSequence(UINT32 handle,UINT16 attr_id,UINT16 num_elem,UINT8 type[],UINT8 len[],UINT8 * p_val[])536 BOOLEAN SDP_AddSequence (UINT32 handle, UINT16 attr_id, UINT16 num_elem,
537 UINT8 type[], UINT8 len[], UINT8 *p_val[])
538 {
539 #if SDP_SERVER_ENABLED == TRUE
540 UINT16 xx;
541 UINT8 *p_buff;
542 UINT8 *p;
543 UINT8 *p_head;
544 BOOLEAN result;
545
546 if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN * 2)) == NULL)
547 {
548 SDP_TRACE_ERROR0("SDP_AddSequence cannot get a buffer!");
549 return (FALSE);
550 }
551 p = p_buff;
552
553 /* First, build the sequence */
554 for (xx = 0; xx < num_elem; xx++)
555 {
556 p_head = p;
557 switch (len[xx])
558 {
559 case 1:
560 UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_ONE_BYTE);
561 break;
562 case 2:
563 UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_TWO_BYTES);
564 break;
565 case 4:
566 UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_FOUR_BYTES);
567 break;
568 case 8:
569 UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_EIGHT_BYTES);
570 break;
571 case 16:
572 UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_SIXTEEN_BYTES);
573 break;
574 default:
575 UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_IN_NEXT_BYTE);
576 UINT8_TO_BE_STREAM (p, len[xx]);
577 break;
578 }
579
580 ARRAY_TO_BE_STREAM (p, p_val[xx], len[xx]);
581
582 if (p - p_buff > SDP_MAX_ATTR_LEN)
583 {
584 /* go back to before we add this element */
585 p = p_head;
586 if(p_head == p_buff)
587 {
588 /* the first element exceed the max length */
589 SDP_TRACE_ERROR0 ("SDP_AddSequence - too long(attribute is not added)!!");
590 GKI_freebuf(p_buff);
591 return FALSE;
592 }
593 else
594 SDP_TRACE_ERROR2 ("SDP_AddSequence - too long, add %d elements of %d", xx, num_elem);
595 break;
596 }
597 }
598 result = SDP_AddAttribute (handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,(UINT32) (p - p_buff), p_buff);
599 GKI_freebuf(p_buff);
600 return result;
601 #else /* SDP_SERVER_ENABLED == FALSE */
602 return (FALSE);
603 #endif
604 }
605
606
607 /*******************************************************************************
608 **
609 ** Function SDP_AddUuidSequence
610 **
611 ** Description This function is called to add a UUID sequence to a record.
612 ** This would be through the SDP database maintenance API.
613 ** If the sequence already exists in the record, it is replaced
614 ** with the new sequence.
615 **
616 ** Returns TRUE if added OK, else FALSE
617 **
618 *******************************************************************************/
SDP_AddUuidSequence(UINT32 handle,UINT16 attr_id,UINT16 num_uuids,UINT16 * p_uuids)619 BOOLEAN SDP_AddUuidSequence (UINT32 handle, UINT16 attr_id, UINT16 num_uuids,
620 UINT16 *p_uuids)
621 {
622 #if SDP_SERVER_ENABLED == TRUE
623 UINT16 xx;
624 UINT8 *p_buff;
625 UINT8 *p;
626 INT32 max_len = SDP_MAX_ATTR_LEN -3;
627 BOOLEAN result;
628
629 if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN * 2)) == NULL)
630 {
631 SDP_TRACE_ERROR0("SDP_AddUuidSequence cannot get a buffer!");
632 return (FALSE);
633 }
634 p = p_buff;
635
636 /* First, build the sequence */
637 for (xx = 0; xx < num_uuids ; xx++, p_uuids++)
638 {
639 UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
640 UINT16_TO_BE_STREAM (p, *p_uuids);
641
642 if((p - p_buff) > max_len)
643 {
644 SDP_TRACE_WARNING2 ("SDP_AddUuidSequence - too long, add %d uuids of %d", xx, num_uuids);
645 break;
646 }
647 }
648
649 result = SDP_AddAttribute (handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,(UINT32) (p - p_buff), p_buff);
650 GKI_freebuf(p_buff);
651 return result;
652 #else /* SDP_SERVER_ENABLED == FALSE */
653 return (FALSE);
654 #endif
655 }
656
657 /*******************************************************************************
658 **
659 ** Function SDP_AddProtocolList
660 **
661 ** Description This function is called to add a protocol descriptor list to
662 ** a record. This would be through the SDP database maintenance API.
663 ** If the protocol list already exists in the record, it is replaced
664 ** with the new list.
665 **
666 ** Returns TRUE if added OK, else FALSE
667 **
668 *******************************************************************************/
SDP_AddProtocolList(UINT32 handle,UINT16 num_elem,tSDP_PROTOCOL_ELEM * p_elem_list)669 BOOLEAN SDP_AddProtocolList (UINT32 handle, UINT16 num_elem,
670 tSDP_PROTOCOL_ELEM *p_elem_list)
671 {
672 #if SDP_SERVER_ENABLED == TRUE
673 UINT8 *p_buff;
674 int offset;
675 BOOLEAN result;
676
677 if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN * 2)) == NULL)
678 {
679 SDP_TRACE_ERROR0("SDP_AddProtocolList cannot get a buffer!");
680 return (FALSE);
681 }
682
683 offset = sdp_compose_proto_list(p_buff, num_elem, p_elem_list);
684 result = SDP_AddAttribute (handle, ATTR_ID_PROTOCOL_DESC_LIST,DATA_ELE_SEQ_DESC_TYPE, (UINT32) offset, p_buff);
685 GKI_freebuf(p_buff);
686 return result;
687 #else /* SDP_SERVER_ENABLED == FALSE */
688 return (FALSE);
689 #endif
690 }
691
692
693 /*******************************************************************************
694 **
695 ** Function SDP_AddAdditionProtoLists
696 **
697 ** Description This function is called to add a protocol descriptor list to
698 ** a record. This would be through the SDP database maintenance API.
699 ** If the protocol list already exists in the record, it is replaced
700 ** with the new list.
701 **
702 ** Returns TRUE if added OK, else FALSE
703 **
704 *******************************************************************************/
SDP_AddAdditionProtoLists(UINT32 handle,UINT16 num_elem,tSDP_PROTO_LIST_ELEM * p_proto_list)705 BOOLEAN SDP_AddAdditionProtoLists (UINT32 handle, UINT16 num_elem,
706 tSDP_PROTO_LIST_ELEM *p_proto_list)
707 {
708 #if SDP_SERVER_ENABLED == TRUE
709 UINT16 xx;
710 UINT8 *p_buff;
711 UINT8 *p;
712 UINT8 *p_len;
713 int offset;
714 BOOLEAN result;
715
716 if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN * 2)) == NULL)
717 {
718 SDP_TRACE_ERROR0("SDP_AddAdditionProtoLists cannot get a buffer!");
719 return (FALSE);
720 }
721 p = p_buff;
722
723 /* for each ProtocolDescriptorList */
724 for (xx = 0; xx < num_elem; xx++, p_proto_list++)
725 {
726 UINT8_TO_BE_STREAM (p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
727 p_len = p++;
728
729 offset = sdp_compose_proto_list(p, p_proto_list->num_elems,
730 p_proto_list->list_elem);
731 p += offset;
732
733 *p_len = (UINT8)(p - p_len - 1);
734 }
735 result = SDP_AddAttribute (handle, ATTR_ID_ADDITION_PROTO_DESC_LISTS,DATA_ELE_SEQ_DESC_TYPE,
736 (UINT32) (p - p_buff), p_buff);
737 GKI_freebuf(p_buff);
738 return result;
739
740 #else /* SDP_SERVER_ENABLED == FALSE */
741 return (FALSE);
742 #endif
743 }
744
745 /*******************************************************************************
746 **
747 ** Function SDP_AddProfileDescriptorList
748 **
749 ** Description This function is called to add a profile descriptor list to
750 ** a record. This would be through the SDP database maintenance API.
751 ** If the version already exists in the record, it is replaced
752 ** with the new one.
753 **
754 ** Returns TRUE if added OK, else FALSE
755 **
756 *******************************************************************************/
SDP_AddProfileDescriptorList(UINT32 handle,UINT16 profile_uuid,UINT16 version)757 BOOLEAN SDP_AddProfileDescriptorList (UINT32 handle, UINT16 profile_uuid,
758 UINT16 version)
759 {
760 #if SDP_SERVER_ENABLED == TRUE
761 UINT8 *p_buff;
762 UINT8 *p;
763 BOOLEAN result;
764
765 if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN)) == NULL)
766 {
767 SDP_TRACE_ERROR0("SDP_AddProfileDescriptorList cannot get a buffer!");
768 return (FALSE);
769 }
770 p = p_buff+2;
771
772 /* First, build the profile descriptor list. This consists of a data element sequence. */
773 /* The sequence consists of profile's UUID and version number */
774 UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
775 UINT16_TO_BE_STREAM (p, profile_uuid);
776
777 UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
778 UINT16_TO_BE_STREAM (p, version);
779
780 /* Add in type and length fields */
781 *p_buff = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
782 *(p_buff+1) = (UINT8) (p - (p_buff+2));
783
784 result = SDP_AddAttribute (handle, ATTR_ID_BT_PROFILE_DESC_LIST,DATA_ELE_SEQ_DESC_TYPE, (UINT32) (p - p_buff), p_buff);
785 GKI_freebuf(p_buff);
786 return result;
787
788 #else /* SDP_SERVER_ENABLED == FALSE */
789 return (FALSE);
790 #endif
791 }
792
793
794 /*******************************************************************************
795 **
796 ** Function SDP_AddLanguageBaseAttrIDList
797 **
798 ** Description This function is called to add a language base attr list to
799 ** a record. This would be through the SDP database maintenance API.
800 ** If the version already exists in the record, it is replaced
801 ** with the new one.
802 **
803 ** Returns TRUE if added OK, else FALSE
804 **
805 *******************************************************************************/
SDP_AddLanguageBaseAttrIDList(UINT32 handle,UINT16 lang,UINT16 char_enc,UINT16 base_id)806 BOOLEAN SDP_AddLanguageBaseAttrIDList (UINT32 handle, UINT16 lang,
807 UINT16 char_enc, UINT16 base_id)
808 {
809 #if SDP_SERVER_ENABLED == TRUE
810 UINT8 *p_buff;
811 UINT8 *p;
812 BOOLEAN result;
813
814 if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN)) == NULL)
815 {
816 SDP_TRACE_ERROR0("SDP_AddLanguageBaseAttrIDList cannot get a buffer!");
817 return (FALSE);
818 }
819 p = p_buff;
820
821 /* First, build the language base descriptor list. This consists of a data */
822 /* element sequence. The sequence consists of 9 bytes (3 UINt16 fields) */
823 UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
824 UINT16_TO_BE_STREAM (p, lang);
825
826 UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
827 UINT16_TO_BE_STREAM (p, char_enc);
828
829 UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
830 UINT16_TO_BE_STREAM (p, base_id);
831
832 result = SDP_AddAttribute (handle, ATTR_ID_LANGUAGE_BASE_ATTR_ID_LIST,DATA_ELE_SEQ_DESC_TYPE,
833 (UINT32) (p - p_buff), p_buff);
834 GKI_freebuf(p_buff);
835 return result;
836 #else /* SDP_SERVER_ENABLED == FALSE */
837 return (FALSE);
838 #endif
839 }
840
841
842 /*******************************************************************************
843 **
844 ** Function SDP_AddServiceClassIdList
845 **
846 ** Description This function is called to add a service list to a record.
847 ** This would be through the SDP database maintenance API.
848 ** If the service list already exists in the record, it is replaced
849 ** with the new list.
850 **
851 ** Returns TRUE if added OK, else FALSE
852 **
853 *******************************************************************************/
SDP_AddServiceClassIdList(UINT32 handle,UINT16 num_services,UINT16 * p_service_uuids)854 BOOLEAN SDP_AddServiceClassIdList (UINT32 handle, UINT16 num_services,
855 UINT16 *p_service_uuids)
856 {
857 #if SDP_SERVER_ENABLED == TRUE
858 UINT16 xx;
859 UINT8 *p_buff;
860 UINT8 *p;
861 BOOLEAN result;
862
863 if ((p_buff = (UINT8 *) GKI_getbuf(sizeof(UINT8) * SDP_MAX_ATTR_LEN * 2)) == NULL)
864 {
865 SDP_TRACE_ERROR0("SDP_AddServiceClassIdList cannot get a buffer!");
866 return (FALSE);
867 }
868 p = p_buff;
869
870 for (xx = 0; xx < num_services; xx++, p_service_uuids++)
871 {
872 UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
873 UINT16_TO_BE_STREAM (p, *p_service_uuids);
874 }
875
876 result = SDP_AddAttribute (handle, ATTR_ID_SERVICE_CLASS_ID_LIST,DATA_ELE_SEQ_DESC_TYPE,
877 (UINT32) (p - p_buff), p_buff);
878 GKI_freebuf(p_buff);
879 return result;
880 #else /* SDP_SERVER_ENABLED == FALSE */
881 return (FALSE);
882 #endif
883 }
884
885
886 /*******************************************************************************
887 **
888 ** Function SDP_DeleteAttribute
889 **
890 ** Description This function is called to delete an attribute from a record.
891 ** This would be through the SDP database maintenance API.
892 **
893 ** Returns TRUE if deleted OK, else FALSE if not found
894 **
895 *******************************************************************************/
SDP_DeleteAttribute(UINT32 handle,UINT16 attr_id)896 BOOLEAN SDP_DeleteAttribute (UINT32 handle, UINT16 attr_id)
897 {
898 #if SDP_SERVER_ENABLED == TRUE
899 UINT16 xx, yy;
900 tSDP_RECORD *p_rec = &sdp_cb.server_db.record[0];
901 UINT8 *pad_ptr;
902 UINT32 len; /* Number of bytes in the entry */
903
904 /* Find the record in the database */
905 for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++)
906 {
907 if (p_rec->record_handle == handle)
908 {
909 tSDP_ATTRIBUTE *p_attr = &p_rec->attribute[0];
910
911 SDP_TRACE_API2("Deleting attr_id 0x%04x for handle 0x%x", attr_id, handle);
912 /* Found it. Now, find the attribute */
913 for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++)
914 {
915 if (p_attr->id == attr_id)
916 {
917 pad_ptr = p_attr->value_ptr;
918 len = p_attr->len;
919
920 if (len)
921 {
922 for (yy = 0; yy < p_rec->num_attributes; yy++)
923 {
924 if( p_rec->attribute[yy].value_ptr > pad_ptr )
925 p_rec->attribute[yy].value_ptr -= len;
926 }
927 }
928
929 /* Found it. Shift everything up one */
930 p_rec->num_attributes--;
931
932 for (yy = xx; yy < p_rec->num_attributes; yy++, p_attr++)
933 {
934 *p_attr = *(p_attr + 1);
935 }
936
937 /* adjust attribute values if needed */
938 if (len)
939 {
940 xx = (p_rec->free_pad_ptr - ((pad_ptr+len) -
941 &p_rec->attr_pad[0]));
942 for( yy=0; yy<xx; yy++, pad_ptr++)
943 *pad_ptr = *(pad_ptr+len);
944 p_rec->free_pad_ptr -= len;
945 }
946 return (TRUE);
947 }
948 }
949 }
950 }
951 #endif
952 /* If here, not found */
953 return (FALSE);
954 }
955
956 /*******************************************************************************
957 **
958 ** Function SDP_ReadRecord
959 **
960 ** Description This function is called to get the raw data of the record
961 ** with the given handle from the database.
962 **
963 ** Returns -1, if the record is not found.
964 ** Otherwise, the offset (0 or 1) to start of data in p_data.
965 **
966 ** The size of data copied into p_data is in *p_data_len.
967 **
968 *******************************************************************************/
969 #if (SDP_RAW_DATA_INCLUDED == TRUE)
SDP_ReadRecord(UINT32 handle,UINT8 * p_data,INT32 * p_data_len)970 INT32 SDP_ReadRecord(UINT32 handle, UINT8 *p_data, INT32 *p_data_len)
971 {
972 INT32 len = 0; /* Number of bytes in the entry */
973 INT32 offset = -1; /* default to not found */
974 #if SDP_SERVER_ENABLED == TRUE
975 tSDP_RECORD *p_rec;
976 UINT16 start = 0;
977 UINT16 end = 0xffff;
978 tSDP_ATTRIBUTE *p_attr;
979 UINT16 rem_len;
980 UINT8 *p_rsp;
981
982 /* Find the record in the database */
983 p_rec = sdp_db_find_record(handle);
984 if(p_rec && p_data && p_data_len)
985 {
986 p_rsp = &p_data[3];
987 while ( (p_attr = sdp_db_find_attr_in_rec (p_rec, start, end)) != NULL)
988 {
989 /* Check if attribute fits. Assume 3-byte value type/length */
990 rem_len = *p_data_len - (UINT16) (p_rsp - p_data);
991
992 if (p_attr->len > (UINT32)(rem_len - 6))
993 break;
994
995 p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
996
997 /* next attr id */
998 start = p_attr->id + 1;
999 }
1000 len = (INT32) (p_rsp - p_data);
1001
1002 /* Put in the sequence header (2 or 3 bytes) */
1003 if (len > 255)
1004 {
1005 offset = 0;
1006 p_data[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
1007 p_data[1] = (UINT8) ((len - 3) >> 8);
1008 p_data[2] = (UINT8) (len - 3);
1009 }
1010 else
1011 {
1012 offset = 1;
1013
1014 p_data[1] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
1015 p_data[2] = (UINT8) (len - 3);
1016
1017 len--;
1018 }
1019 *p_data_len = len;
1020 }
1021 #endif
1022 /* If here, not found */
1023 return (offset);
1024 }
1025 #endif
1026
1027
1028
1029