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 buff[SDP_MAX_ATTR_LEN * 2];
542 UINT8 *p;
543 UINT8 *p_head;
544
545 p = buff;
546 /* First, build the sequence */
547 for (xx = 0; xx < num_elem; xx++)
548 {
549 p_head = p;
550 switch (len[xx])
551 {
552 case 1:
553 UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_ONE_BYTE);
554 break;
555 case 2:
556 UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_TWO_BYTES);
557 break;
558 case 4:
559 UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_FOUR_BYTES);
560 break;
561 case 8:
562 UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_EIGHT_BYTES);
563 break;
564 case 16:
565 UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_SIXTEEN_BYTES);
566 break;
567 default:
568 UINT8_TO_BE_STREAM (p, (type[xx] << 3) | SIZE_IN_NEXT_BYTE);
569 UINT8_TO_BE_STREAM (p, len[xx]);
570 break;
571 }
572
573 ARRAY_TO_BE_STREAM (p, p_val[xx], len[xx]);
574
575 if (p - buff > SDP_MAX_ATTR_LEN)
576 {
577 /* go back to before we add this element */
578 p = p_head;
579 if(p_head == buff)
580 {
581 /* the first element exceed the max length */
582 SDP_TRACE_ERROR0 ("SDP_AddSequence - too long(attribute is not added)!!");
583 return FALSE;
584 }
585 else
586 SDP_TRACE_ERROR2 ("SDP_AddSequence - too long, add %d elements of %d", xx, num_elem);
587 break;
588 }
589 }
590
591 return (SDP_AddAttribute (handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,
592 (UINT32) (p - buff), buff));
593 #else /* SDP_SERVER_ENABLED == FALSE */
594 return (FALSE);
595 #endif
596 }
597
598
599 /*******************************************************************************
600 **
601 ** Function SDP_AddUuidSequence
602 **
603 ** Description This function is called to add a UUID sequence to a record.
604 ** This would be through the SDP database maintenance API.
605 ** If the sequence already exists in the record, it is replaced
606 ** with the new sequence.
607 **
608 ** Returns TRUE if added OK, else FALSE
609 **
610 *******************************************************************************/
SDP_AddUuidSequence(UINT32 handle,UINT16 attr_id,UINT16 num_uuids,UINT16 * p_uuids)611 BOOLEAN SDP_AddUuidSequence (UINT32 handle, UINT16 attr_id, UINT16 num_uuids,
612 UINT16 *p_uuids)
613 {
614 #if SDP_SERVER_ENABLED == TRUE
615 UINT16 xx;
616 UINT8 buff[SDP_MAX_ATTR_LEN * 2];
617 UINT8 *p = buff;
618 INT32 max_len = SDP_MAX_ATTR_LEN -3;
619
620 /* First, build the sequence */
621 for (xx = 0; xx < num_uuids ; xx++, p_uuids++)
622 {
623 UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
624 UINT16_TO_BE_STREAM (p, *p_uuids);
625
626 if((p - buff) > max_len)
627 {
628 SDP_TRACE_WARNING2 ("SDP_AddUuidSequence - too long, add %d uuids of %d", xx, num_uuids);
629 break;
630 }
631 }
632
633 return (SDP_AddAttribute (handle, attr_id, DATA_ELE_SEQ_DESC_TYPE,
634 (UINT32) (p - buff), buff));
635 #else /* SDP_SERVER_ENABLED == FALSE */
636 return (FALSE);
637 #endif
638 }
639
640 /*******************************************************************************
641 **
642 ** Function SDP_AddProtocolList
643 **
644 ** Description This function is called to add a protocol descriptor list to
645 ** a record. This would be through the SDP database maintenance API.
646 ** If the protocol list already exists in the record, it is replaced
647 ** with the new list.
648 **
649 ** Returns TRUE if added OK, else FALSE
650 **
651 *******************************************************************************/
SDP_AddProtocolList(UINT32 handle,UINT16 num_elem,tSDP_PROTOCOL_ELEM * p_elem_list)652 BOOLEAN SDP_AddProtocolList (UINT32 handle, UINT16 num_elem,
653 tSDP_PROTOCOL_ELEM *p_elem_list)
654 {
655 #if SDP_SERVER_ENABLED == TRUE
656 UINT8 buff[SDP_MAX_ATTR_LEN * 2];
657 int offset;
658
659 offset = sdp_compose_proto_list(buff, num_elem, p_elem_list);
660
661 return (SDP_AddAttribute (handle, ATTR_ID_PROTOCOL_DESC_LIST,
662 DATA_ELE_SEQ_DESC_TYPE, (UINT32) offset, buff));
663 #else /* SDP_SERVER_ENABLED == FALSE */
664 return (FALSE);
665 #endif
666 }
667
668
669 /*******************************************************************************
670 **
671 ** Function SDP_AddAdditionProtoLists
672 **
673 ** Description This function is called to add a protocol descriptor list to
674 ** a record. This would be through the SDP database maintenance API.
675 ** If the protocol list already exists in the record, it is replaced
676 ** with the new list.
677 **
678 ** Returns TRUE if added OK, else FALSE
679 **
680 *******************************************************************************/
SDP_AddAdditionProtoLists(UINT32 handle,UINT16 num_elem,tSDP_PROTO_LIST_ELEM * p_proto_list)681 BOOLEAN SDP_AddAdditionProtoLists (UINT32 handle, UINT16 num_elem,
682 tSDP_PROTO_LIST_ELEM *p_proto_list)
683 {
684 #if SDP_SERVER_ENABLED == TRUE
685 UINT16 xx;
686 UINT8 buff[SDP_MAX_ATTR_LEN * 2];
687 UINT8 *p = buff;
688 UINT8 *p_len;
689 int offset;
690
691 /* for each ProtocolDescriptorList */
692 for (xx = 0; xx < num_elem; xx++, p_proto_list++)
693 {
694 UINT8_TO_BE_STREAM (p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
695 p_len = p++;
696
697 offset = sdp_compose_proto_list(p, p_proto_list->num_elems,
698 p_proto_list->list_elem);
699 p += offset;
700
701 *p_len = (UINT8)(p - p_len - 1);
702 }
703
704 return (SDP_AddAttribute (handle, ATTR_ID_ADDITION_PROTO_DESC_LISTS,
705 DATA_ELE_SEQ_DESC_TYPE, (UINT32) (p - buff), buff));
706 #else /* SDP_SERVER_ENABLED == FALSE */
707 return (FALSE);
708 #endif
709 }
710
711 /*******************************************************************************
712 **
713 ** Function SDP_AddProfileDescriptorList
714 **
715 ** Description This function is called to add a profile descriptor list to
716 ** a record. This would be through the SDP database maintenance API.
717 ** If the version already exists in the record, it is replaced
718 ** with the new one.
719 **
720 ** Returns TRUE if added OK, else FALSE
721 **
722 *******************************************************************************/
SDP_AddProfileDescriptorList(UINT32 handle,UINT16 profile_uuid,UINT16 version)723 BOOLEAN SDP_AddProfileDescriptorList (UINT32 handle, UINT16 profile_uuid,
724 UINT16 version)
725 {
726 #if SDP_SERVER_ENABLED == TRUE
727 UINT8 buff[SDP_MAX_ATTR_LEN];
728 UINT8 *p = &buff[2];
729
730 /* First, build the profile descriptor list. This consists of a data element sequence. */
731 /* The sequence consists of profile's UUID and version number */
732 UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
733 UINT16_TO_BE_STREAM (p, profile_uuid);
734
735 UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
736 UINT16_TO_BE_STREAM (p, version);
737
738 /* Add in type and length fields */
739 buff[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
740 buff[1] = (UINT8) (p - &buff[2]);
741
742 return (SDP_AddAttribute (handle, ATTR_ID_BT_PROFILE_DESC_LIST,
743 DATA_ELE_SEQ_DESC_TYPE, (UINT32) (p - buff), buff));
744 #else /* SDP_SERVER_ENABLED == FALSE */
745 return (FALSE);
746 #endif
747 }
748
749
750 /*******************************************************************************
751 **
752 ** Function SDP_AddLanguageBaseAttrIDList
753 **
754 ** Description This function is called to add a language base attr list to
755 ** a record. This would be through the SDP database maintenance API.
756 ** If the version already exists in the record, it is replaced
757 ** with the new one.
758 **
759 ** Returns TRUE if added OK, else FALSE
760 **
761 *******************************************************************************/
SDP_AddLanguageBaseAttrIDList(UINT32 handle,UINT16 lang,UINT16 char_enc,UINT16 base_id)762 BOOLEAN SDP_AddLanguageBaseAttrIDList (UINT32 handle, UINT16 lang,
763 UINT16 char_enc, UINT16 base_id)
764 {
765 #if SDP_SERVER_ENABLED == TRUE
766 UINT8 buff[SDP_MAX_ATTR_LEN];
767 UINT8 *p = buff;
768
769 /* First, build the language base descriptor list. This consists of a data */
770 /* element sequence. The sequence consists of 9 bytes (3 UINt16 fields) */
771 UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
772 UINT16_TO_BE_STREAM (p, lang);
773
774 UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
775 UINT16_TO_BE_STREAM (p, char_enc);
776
777 UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES);
778 UINT16_TO_BE_STREAM (p, base_id);
779
780 return (SDP_AddAttribute (handle, ATTR_ID_LANGUAGE_BASE_ATTR_ID_LIST,
781 DATA_ELE_SEQ_DESC_TYPE, (UINT32) (p - buff), buff));
782 #else /* SDP_SERVER_ENABLED == FALSE */
783 return (FALSE);
784 #endif
785 }
786
787
788 /*******************************************************************************
789 **
790 ** Function SDP_AddServiceClassIdList
791 **
792 ** Description This function is called to add a service list to a record.
793 ** This would be through the SDP database maintenance API.
794 ** If the service list already exists in the record, it is replaced
795 ** with the new list.
796 **
797 ** Returns TRUE if added OK, else FALSE
798 **
799 *******************************************************************************/
SDP_AddServiceClassIdList(UINT32 handle,UINT16 num_services,UINT16 * p_service_uuids)800 BOOLEAN SDP_AddServiceClassIdList (UINT32 handle, UINT16 num_services,
801 UINT16 *p_service_uuids)
802 {
803 #if SDP_SERVER_ENABLED == TRUE
804 UINT16 xx;
805 UINT8 buff[SDP_MAX_ATTR_LEN * 2];
806 UINT8 *p = buff;
807
808 for (xx = 0; xx < num_services; xx++, p_service_uuids++)
809 {
810 UINT8_TO_BE_STREAM (p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES);
811 UINT16_TO_BE_STREAM (p, *p_service_uuids);
812 }
813
814 return (SDP_AddAttribute (handle, ATTR_ID_SERVICE_CLASS_ID_LIST,
815 DATA_ELE_SEQ_DESC_TYPE, (UINT32) (p - buff), buff));
816 #else /* SDP_SERVER_ENABLED == FALSE */
817 return (FALSE);
818 #endif
819 }
820
821
822 /*******************************************************************************
823 **
824 ** Function SDP_DeleteAttribute
825 **
826 ** Description This function is called to delete an attribute from a record.
827 ** This would be through the SDP database maintenance API.
828 **
829 ** Returns TRUE if deleted OK, else FALSE if not found
830 **
831 *******************************************************************************/
SDP_DeleteAttribute(UINT32 handle,UINT16 attr_id)832 BOOLEAN SDP_DeleteAttribute (UINT32 handle, UINT16 attr_id)
833 {
834 #if SDP_SERVER_ENABLED == TRUE
835 UINT16 xx, yy;
836 tSDP_RECORD *p_rec = &sdp_cb.server_db.record[0];
837 UINT8 *pad_ptr;
838 UINT32 len; /* Number of bytes in the entry */
839
840 /* Find the record in the database */
841 for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++)
842 {
843 if (p_rec->record_handle == handle)
844 {
845 tSDP_ATTRIBUTE *p_attr = &p_rec->attribute[0];
846
847 SDP_TRACE_API2("Deleting attr_id 0x%04x for handle 0x%x", attr_id, handle);
848 /* Found it. Now, find the attribute */
849 for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++)
850 {
851 if (p_attr->id == attr_id)
852 {
853 pad_ptr = p_attr->value_ptr;
854 len = p_attr->len;
855
856 if (len)
857 {
858 for (yy = 0; yy < p_rec->num_attributes; yy++)
859 {
860 if( p_rec->attribute[yy].value_ptr > pad_ptr )
861 p_rec->attribute[yy].value_ptr -= len;
862 }
863 }
864
865 /* Found it. Shift everything up one */
866 p_rec->num_attributes--;
867
868 for (yy = xx; yy < p_rec->num_attributes; yy++, p_attr++)
869 {
870 *p_attr = *(p_attr + 1);
871 }
872
873 /* adjust attribute values if needed */
874 if (len)
875 {
876 xx = (p_rec->free_pad_ptr - ((pad_ptr+len) -
877 &p_rec->attr_pad[0]));
878 for( yy=0; yy<xx; yy++, pad_ptr++)
879 *pad_ptr = *(pad_ptr+len);
880 p_rec->free_pad_ptr -= len;
881 }
882 return (TRUE);
883 }
884 }
885 }
886 }
887 #endif
888 /* If here, not found */
889 return (FALSE);
890 }
891
892 /*******************************************************************************
893 **
894 ** Function SDP_ReadRecord
895 **
896 ** Description This function is called to get the raw data of the record
897 ** with the given handle from the database.
898 **
899 ** Returns -1, if the record is not found.
900 ** Otherwise, the offset (0 or 1) to start of data in p_data.
901 **
902 ** The size of data copied into p_data is in *p_data_len.
903 **
904 *******************************************************************************/
905 #if (SDP_RAW_DATA_INCLUDED == TRUE)
SDP_ReadRecord(UINT32 handle,UINT8 * p_data,INT32 * p_data_len)906 INT32 SDP_ReadRecord(UINT32 handle, UINT8 *p_data, INT32 *p_data_len)
907 {
908 INT32 len = 0; /* Number of bytes in the entry */
909 INT32 offset = -1; /* default to not found */
910 #if SDP_SERVER_ENABLED == TRUE
911 tSDP_RECORD *p_rec;
912 UINT16 start = 0;
913 UINT16 end = 0xffff;
914 tSDP_ATTRIBUTE *p_attr;
915 UINT16 rem_len;
916 UINT8 *p_rsp;
917
918 /* Find the record in the database */
919 p_rec = sdp_db_find_record(handle);
920 if(p_rec && p_data && p_data_len)
921 {
922 p_rsp = &p_data[3];
923 while ( (p_attr = sdp_db_find_attr_in_rec (p_rec, start, end)) != NULL)
924 {
925 /* Check if attribute fits. Assume 3-byte value type/length */
926 rem_len = *p_data_len - (UINT16) (p_rsp - p_data);
927
928 if (p_attr->len > (UINT32)(rem_len - 6))
929 break;
930
931 p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
932
933 /* next attr id */
934 start = p_attr->id + 1;
935 }
936 len = (INT32) (p_rsp - p_data);
937
938 /* Put in the sequence header (2 or 3 bytes) */
939 if (len > 255)
940 {
941 offset = 0;
942 p_data[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
943 p_data[1] = (UINT8) ((len - 3) >> 8);
944 p_data[2] = (UINT8) (len - 3);
945 }
946 else
947 {
948 offset = 1;
949
950 p_data[1] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
951 p_data[2] = (UINT8) (len - 3);
952
953 len--;
954 }
955 *p_data_len = len;
956 }
957 #endif
958 /* If here, not found */
959 return (offset);
960 }
961 #endif
962
963
964
965