1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include "qemu/osdep.h"
21#include "qemu/error-report.h"
22#include "qemu-common.h"
23#include "qemu/host-utils.h"
24#include "hw/bt.h"
25
26struct bt_l2cap_sdp_state_s {
27 struct bt_l2cap_conn_params_s *channel;
28
29 struct sdp_service_record_s {
30 int match;
31
32 int *uuid;
33 int uuids;
34 struct sdp_service_attribute_s {
35 int match;
36
37 int attribute_id;
38 int len;
39 void *pair;
40 } *attribute_list;
41 int attributes;
42 } *service_list;
43 int services;
44};
45
46static ssize_t sdp_datalen(const uint8_t **element, ssize_t *left)
47{
48 uint32_t len = *(*element) ++ & SDP_DSIZE_MASK;
49
50 if (!*left)
51 return -1;
52 (*left) --;
53
54 if (len < SDP_DSIZE_NEXT1)
55 return 1 << len;
56 else if (len == SDP_DSIZE_NEXT1) {
57 if (*left < 1)
58 return -1;
59 (*left) --;
60
61 return *(*element) ++;
62 } else if (len == SDP_DSIZE_NEXT2) {
63 if (*left < 2)
64 return -1;
65 (*left) -= 2;
66
67 len = (*(*element) ++) << 8;
68 return len | (*(*element) ++);
69 } else {
70 if (*left < 4)
71 return -1;
72 (*left) -= 4;
73
74 len = (*(*element) ++) << 24;
75 len |= (*(*element) ++) << 16;
76 len |= (*(*element) ++) << 8;
77 return len | (*(*element) ++);
78 }
79}
80
81static const uint8_t bt_base_uuid[12] = {
82 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
83};
84
85static int sdp_uuid_match(struct sdp_service_record_s *record,
86 const uint8_t *uuid, ssize_t datalen)
87{
88 int *lo, hi, val;
89
90 if (datalen == 16 || datalen == 4) {
91 if (datalen == 16 && memcmp(uuid + 4, bt_base_uuid, 12))
92 return 0;
93
94 if (uuid[0] | uuid[1])
95 return 0;
96 uuid += 2;
97 }
98
99 val = (uuid[0] << 8) | uuid[1];
100 lo = record->uuid;
101 hi = record->uuids;
102 while (hi >>= 1)
103 if (lo[hi] <= val)
104 lo += hi;
105
106 return *lo == val;
107}
108
109#define CONTINUATION_PARAM_SIZE (1 + sizeof(int))
110#define MAX_PDU_OUT_SIZE 96
111#define PDU_HEADER_SIZE 5
112#define MAX_RSP_PARAM_SIZE (MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE - \
113 CONTINUATION_PARAM_SIZE)
114
115static int sdp_svc_match(struct bt_l2cap_sdp_state_s *sdp,
116 const uint8_t **req, ssize_t *len)
117{
118 size_t datalen;
119 int i;
120
121 if ((**req & ~SDP_DSIZE_MASK) != SDP_DTYPE_UUID)
122 return 1;
123
124 datalen = sdp_datalen(req, len);
125 if (datalen != 2 && datalen != 4 && datalen != 16)
126 return 1;
127
128 for (i = 0; i < sdp->services; i ++)
129 if (sdp_uuid_match(&sdp->service_list[i], *req, datalen))
130 sdp->service_list[i].match = 1;
131
132 (*req) += datalen;
133 (*len) -= datalen;
134
135 return 0;
136}
137
138static ssize_t sdp_svc_search(struct bt_l2cap_sdp_state_s *sdp,
139 uint8_t *rsp, const uint8_t *req, ssize_t len)
140{
141 ssize_t seqlen;
142 int i, count, start, end, max;
143 int32_t handle;
144
145
146 for (i = 0; i < sdp->services; i ++)
147 sdp->service_list[i].match = 0;
148
149 if (len < 1)
150 return -SDP_INVALID_SYNTAX;
151 if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
152 seqlen = sdp_datalen(&req, &len);
153 if (seqlen < 3 || len < seqlen)
154 return -SDP_INVALID_SYNTAX;
155 len -= seqlen;
156 while (seqlen)
157 if (sdp_svc_match(sdp, &req, &seqlen))
158 return -SDP_INVALID_SYNTAX;
159 } else {
160 if (sdp_svc_match(sdp, &req, &len)) {
161 return -SDP_INVALID_SYNTAX;
162 }
163 }
164
165 if (len < 3)
166 return -SDP_INVALID_SYNTAX;
167 max = (req[0] << 8) | req[1];
168 req += 2;
169 len -= 2;
170
171 if (*req) {
172 if (len <= sizeof(int))
173 return -SDP_INVALID_SYNTAX;
174 len -= sizeof(int);
175 memcpy(&start, req + 1, sizeof(int));
176 } else
177 start = 0;
178
179 if (len > 1)
180 return -SDP_INVALID_SYNTAX;
181
182
183 len = 4;
184 count = 0;
185 end = start;
186 for (i = 0; i < sdp->services; i ++)
187 if (sdp->service_list[i].match) {
188 if (count >= start && count < max && len + 4 < MAX_RSP_PARAM_SIZE) {
189 handle = i;
190 memcpy(rsp + len, &handle, 4);
191 len += 4;
192 end = count + 1;
193 }
194
195 count ++;
196 }
197
198 rsp[0] = count >> 8;
199 rsp[1] = count & 0xff;
200 rsp[2] = (end - start) >> 8;
201 rsp[3] = (end - start) & 0xff;
202
203 if (end < count) {
204 rsp[len ++] = sizeof(int);
205 memcpy(rsp + len, &end, sizeof(int));
206 len += 4;
207 } else
208 rsp[len ++] = 0;
209
210 return len;
211}
212
213static int sdp_attr_match(struct sdp_service_record_s *record,
214 const uint8_t **req, ssize_t *len)
215{
216 int i, start, end;
217
218 if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) {
219 (*req) ++;
220 if (*len < 3)
221 return 1;
222
223 start = (*(*req) ++) << 8;
224 start |= *(*req) ++;
225 end = start;
226 *len -= 3;
227 } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) {
228 (*req) ++;
229 if (*len < 5)
230 return 1;
231
232 start = (*(*req) ++) << 8;
233 start |= *(*req) ++;
234 end = (*(*req) ++) << 8;
235 end |= *(*req) ++;
236 *len -= 5;
237 } else
238 return 1;
239
240 for (i = 0; i < record->attributes; i ++)
241 if (record->attribute_list[i].attribute_id >= start &&
242 record->attribute_list[i].attribute_id <= end)
243 record->attribute_list[i].match = 1;
244
245 return 0;
246}
247
248static ssize_t sdp_attr_get(struct bt_l2cap_sdp_state_s *sdp,
249 uint8_t *rsp, const uint8_t *req, ssize_t len)
250{
251 ssize_t seqlen;
252 int i, start, end, max;
253 int32_t handle;
254 struct sdp_service_record_s *record;
255 uint8_t *lst;
256
257
258 if (len < 7)
259 return -SDP_INVALID_SYNTAX;
260 memcpy(&handle, req, 4);
261 req += 4;
262 len -= 4;
263
264 if (handle < 0 || handle > sdp->services)
265 return -SDP_INVALID_RECORD_HANDLE;
266 record = &sdp->service_list[handle];
267
268 for (i = 0; i < record->attributes; i ++)
269 record->attribute_list[i].match = 0;
270
271 max = (req[0] << 8) | req[1];
272 req += 2;
273 len -= 2;
274 if (max < 0x0007)
275 return -SDP_INVALID_SYNTAX;
276
277 if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
278 seqlen = sdp_datalen(&req, &len);
279 if (seqlen < 3 || len < seqlen)
280 return -SDP_INVALID_SYNTAX;
281 len -= seqlen;
282
283 while (seqlen)
284 if (sdp_attr_match(record, &req, &seqlen))
285 return -SDP_INVALID_SYNTAX;
286 } else {
287 if (sdp_attr_match(record, &req, &len)) {
288 return -SDP_INVALID_SYNTAX;
289 }
290 }
291
292 if (len < 1)
293 return -SDP_INVALID_SYNTAX;
294
295 if (*req) {
296 if (len <= sizeof(int))
297 return -SDP_INVALID_SYNTAX;
298 len -= sizeof(int);
299 memcpy(&start, req + 1, sizeof(int));
300 } else
301 start = 0;
302
303 if (len > 1)
304 return -SDP_INVALID_SYNTAX;
305
306
307 lst = rsp + 2;
308 max = MIN(max, MAX_RSP_PARAM_SIZE);
309 len = 3 - start;
310 end = 0;
311 for (i = 0; i < record->attributes; i ++)
312 if (record->attribute_list[i].match) {
313 if (len >= 0 && len + record->attribute_list[i].len < max) {
314 memcpy(lst + len, record->attribute_list[i].pair,
315 record->attribute_list[i].len);
316 end = len + record->attribute_list[i].len;
317 }
318 len += record->attribute_list[i].len;
319 }
320 if (0 >= start) {
321 lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
322 lst[1] = (len + start - 3) >> 8;
323 lst[2] = (len + start - 3) & 0xff;
324 }
325
326 rsp[0] = end >> 8;
327 rsp[1] = end & 0xff;
328
329 if (end < len) {
330 len = end + start;
331 lst[end ++] = sizeof(int);
332 memcpy(lst + end, &len, sizeof(int));
333 end += sizeof(int);
334 } else
335 lst[end ++] = 0;
336
337 return end + 2;
338}
339
340static int sdp_svc_attr_match(struct bt_l2cap_sdp_state_s *sdp,
341 const uint8_t **req, ssize_t *len)
342{
343 int i, j, start, end;
344 struct sdp_service_record_s *record;
345
346 if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) {
347 (*req) ++;
348 if (*len < 3)
349 return 1;
350
351 start = (*(*req) ++) << 8;
352 start |= *(*req) ++;
353 end = start;
354 *len -= 3;
355 } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) {
356 (*req) ++;
357 if (*len < 5)
358 return 1;
359
360 start = (*(*req) ++) << 8;
361 start |= *(*req) ++;
362 end = (*(*req) ++) << 8;
363 end |= *(*req) ++;
364 *len -= 5;
365 } else
366 return 1;
367
368 for (i = 0; i < sdp->services; i ++)
369 if ((record = &sdp->service_list[i])->match)
370 for (j = 0; j < record->attributes; j ++)
371 if (record->attribute_list[j].attribute_id >= start &&
372 record->attribute_list[j].attribute_id <= end)
373 record->attribute_list[j].match = 1;
374
375 return 0;
376}
377
378static ssize_t sdp_svc_search_attr_get(struct bt_l2cap_sdp_state_s *sdp,
379 uint8_t *rsp, const uint8_t *req, ssize_t len)
380{
381 ssize_t seqlen;
382 int i, j, start, end, max;
383 struct sdp_service_record_s *record;
384 uint8_t *lst;
385
386
387 for (i = 0; i < sdp->services; i ++) {
388 sdp->service_list[i].match = 0;
389 for (j = 0; j < sdp->service_list[i].attributes; j ++)
390 sdp->service_list[i].attribute_list[j].match = 0;
391 }
392
393 if (len < 1)
394 return -SDP_INVALID_SYNTAX;
395 if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
396 seqlen = sdp_datalen(&req, &len);
397 if (seqlen < 3 || len < seqlen)
398 return -SDP_INVALID_SYNTAX;
399 len -= seqlen;
400
401 while (seqlen)
402 if (sdp_svc_match(sdp, &req, &seqlen))
403 return -SDP_INVALID_SYNTAX;
404 } else {
405 if (sdp_svc_match(sdp, &req, &len)) {
406 return -SDP_INVALID_SYNTAX;
407 }
408 }
409
410 if (len < 3)
411 return -SDP_INVALID_SYNTAX;
412 max = (req[0] << 8) | req[1];
413 req += 2;
414 len -= 2;
415 if (max < 0x0007)
416 return -SDP_INVALID_SYNTAX;
417
418 if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
419 seqlen = sdp_datalen(&req, &len);
420 if (seqlen < 3 || len < seqlen)
421 return -SDP_INVALID_SYNTAX;
422 len -= seqlen;
423
424 while (seqlen)
425 if (sdp_svc_attr_match(sdp, &req, &seqlen))
426 return -SDP_INVALID_SYNTAX;
427 } else {
428 if (sdp_svc_attr_match(sdp, &req, &len)) {
429 return -SDP_INVALID_SYNTAX;
430 }
431 }
432
433 if (len < 1)
434 return -SDP_INVALID_SYNTAX;
435
436 if (*req) {
437 if (len <= sizeof(int))
438 return -SDP_INVALID_SYNTAX;
439 len -= sizeof(int);
440 memcpy(&start, req + 1, sizeof(int));
441 } else
442 start = 0;
443
444 if (len > 1)
445 return -SDP_INVALID_SYNTAX;
446
447
448
449
450
451
452 lst = rsp + 2;
453 max = MIN(max, MAX_RSP_PARAM_SIZE);
454 len = 3 - start;
455 end = 0;
456 for (i = 0; i < sdp->services; i ++)
457 if ((record = &sdp->service_list[i])->match) {
458 len += 3;
459 seqlen = len;
460 for (j = 0; j < record->attributes; j ++)
461 if (record->attribute_list[j].match) {
462 if (len >= 0)
463 if (len + record->attribute_list[j].len < max) {
464 memcpy(lst + len, record->attribute_list[j].pair,
465 record->attribute_list[j].len);
466 end = len + record->attribute_list[j].len;
467 }
468 len += record->attribute_list[j].len;
469 }
470 if (seqlen == len)
471 len -= 3;
472 else if (seqlen >= 3 && seqlen < max) {
473 lst[seqlen - 3] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
474 lst[seqlen - 2] = (len - seqlen) >> 8;
475 lst[seqlen - 1] = (len - seqlen) & 0xff;
476 }
477 }
478 if (len == 3 - start)
479 len -= 3;
480 else if (0 >= start) {
481 lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
482 lst[1] = (len + start - 3) >> 8;
483 lst[2] = (len + start - 3) & 0xff;
484 }
485
486 rsp[0] = end >> 8;
487 rsp[1] = end & 0xff;
488
489 if (end < len) {
490 len = end + start;
491 lst[end ++] = sizeof(int);
492 memcpy(lst + end, &len, sizeof(int));
493 end += sizeof(int);
494 } else
495 lst[end ++] = 0;
496
497 return end + 2;
498}
499
500static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len)
501{
502 struct bt_l2cap_sdp_state_s *sdp = opaque;
503 enum bt_sdp_cmd pdu_id;
504 uint8_t rsp[MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE], *sdu_out;
505 int transaction_id, plen;
506 int err = 0;
507 int rsp_len = 0;
508
509 if (len < 5) {
510 error_report("%s: short SDP PDU (%iB).", __func__, len);
511 return;
512 }
513
514 pdu_id = *data ++;
515 transaction_id = (data[0] << 8) | data[1];
516 plen = (data[2] << 8) | data[3];
517 data += 4;
518 len -= 5;
519
520 if (len != plen) {
521 error_report("%s: wrong SDP PDU length (%iB != %iB).",
522 __func__, plen, len);
523 err = SDP_INVALID_PDU_SIZE;
524 goto respond;
525 }
526
527 switch (pdu_id) {
528 case SDP_SVC_SEARCH_REQ:
529 rsp_len = sdp_svc_search(sdp, rsp, data, len);
530 pdu_id = SDP_SVC_SEARCH_RSP;
531 break;
532
533 case SDP_SVC_ATTR_REQ:
534 rsp_len = sdp_attr_get(sdp, rsp, data, len);
535 pdu_id = SDP_SVC_ATTR_RSP;
536 break;
537
538 case SDP_SVC_SEARCH_ATTR_REQ:
539 rsp_len = sdp_svc_search_attr_get(sdp, rsp, data, len);
540 pdu_id = SDP_SVC_SEARCH_ATTR_RSP;
541 break;
542
543 case SDP_ERROR_RSP:
544 case SDP_SVC_ATTR_RSP:
545 case SDP_SVC_SEARCH_RSP:
546 case SDP_SVC_SEARCH_ATTR_RSP:
547 default:
548 error_report("%s: unexpected SDP PDU ID %02x.",
549 __func__, pdu_id);
550 err = SDP_INVALID_SYNTAX;
551 break;
552 }
553
554 if (rsp_len < 0) {
555 err = -rsp_len;
556 rsp_len = 0;
557 }
558
559respond:
560 if (err) {
561 pdu_id = SDP_ERROR_RSP;
562 rsp[rsp_len ++] = err >> 8;
563 rsp[rsp_len ++] = err & 0xff;
564 }
565
566 sdu_out = sdp->channel->sdu_out(sdp->channel, rsp_len + PDU_HEADER_SIZE);
567
568 sdu_out[0] = pdu_id;
569 sdu_out[1] = transaction_id >> 8;
570 sdu_out[2] = transaction_id & 0xff;
571 sdu_out[3] = rsp_len >> 8;
572 sdu_out[4] = rsp_len & 0xff;
573 memcpy(sdu_out + PDU_HEADER_SIZE, rsp, rsp_len);
574
575 sdp->channel->sdu_submit(sdp->channel);
576}
577
578static void bt_l2cap_sdp_close_ch(void *opaque)
579{
580 struct bt_l2cap_sdp_state_s *sdp = opaque;
581 int i;
582
583 for (i = 0; i < sdp->services; i ++) {
584 g_free(sdp->service_list[i].attribute_list[0].pair);
585 g_free(sdp->service_list[i].attribute_list);
586 g_free(sdp->service_list[i].uuid);
587 }
588 g_free(sdp->service_list);
589 g_free(sdp);
590}
591
592struct sdp_def_service_s {
593 uint16_t class_uuid;
594 struct sdp_def_attribute_s {
595 uint16_t id;
596 struct sdp_def_data_element_s {
597 uint8_t type;
598 union {
599 uint32_t uint;
600 const char *str;
601 struct sdp_def_data_element_s *list;
602 } value;
603 } data;
604 } attributes[];
605};
606
607
608
609static int sdp_attr_max_size(struct sdp_def_data_element_s *element,
610 int *uuids)
611{
612 int type = element->type & ~SDP_DSIZE_MASK;
613 int len;
614
615 if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_UUID ||
616 type == SDP_DTYPE_BOOL) {
617 if (type == SDP_DTYPE_UUID)
618 (*uuids) ++;
619 return 1 + (1 << (element->type & SDP_DSIZE_MASK));
620 }
621
622 if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) {
623 if (element->type & SDP_DSIZE_MASK) {
624 for (len = 0; element->value.str[len] |
625 element->value.str[len + 1]; len ++);
626 return len;
627 } else
628 return 2 + strlen(element->value.str);
629 }
630
631 if (type != SDP_DTYPE_SEQ)
632 exit(-1);
633 len = 2;
634 element = element->value.list;
635 while (element->type)
636 len += sdp_attr_max_size(element ++, uuids);
637 if (len > 255)
638 exit (-1);
639
640 return len;
641}
642
643static int sdp_attr_write(uint8_t *data,
644 struct sdp_def_data_element_s *element, int **uuid)
645{
646 int type = element->type & ~SDP_DSIZE_MASK;
647 int len = 0;
648
649 if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_BOOL) {
650 data[len ++] = element->type;
651 if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_1)
652 data[len ++] = (element->value.uint >> 0) & 0xff;
653 else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_2) {
654 data[len ++] = (element->value.uint >> 8) & 0xff;
655 data[len ++] = (element->value.uint >> 0) & 0xff;
656 } else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_4) {
657 data[len ++] = (element->value.uint >> 24) & 0xff;
658 data[len ++] = (element->value.uint >> 16) & 0xff;
659 data[len ++] = (element->value.uint >> 8) & 0xff;
660 data[len ++] = (element->value.uint >> 0) & 0xff;
661 }
662
663 return len;
664 }
665
666 if (type == SDP_DTYPE_UUID) {
667 *(*uuid) ++ = element->value.uint;
668
669 data[len ++] = element->type;
670 data[len ++] = (element->value.uint >> 24) & 0xff;
671 data[len ++] = (element->value.uint >> 16) & 0xff;
672 data[len ++] = (element->value.uint >> 8) & 0xff;
673 data[len ++] = (element->value.uint >> 0) & 0xff;
674 memcpy(data + len, bt_base_uuid, 12);
675
676 return len + 12;
677 }
678
679 data[0] = type | SDP_DSIZE_NEXT1;
680 if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) {
681 if (element->type & SDP_DSIZE_MASK)
682 for (len = 0; element->value.str[len] |
683 element->value.str[len + 1]; len ++);
684 else
685 len = strlen(element->value.str);
686 memcpy(data + 2, element->value.str, data[1] = len);
687
688 return len + 2;
689 }
690
691 len = 2;
692 element = element->value.list;
693 while (element->type)
694 len += sdp_attr_write(data + len, element ++, uuid);
695 data[1] = len - 2;
696
697 return len;
698}
699
700static int sdp_attributeid_compare(const struct sdp_service_attribute_s *a,
701 const struct sdp_service_attribute_s *b)
702{
703 return (int) b->attribute_id - a->attribute_id;
704}
705
706static int sdp_uuid_compare(const int *a, const int *b)
707{
708 return *a - *b;
709}
710
711static void sdp_service_record_build(struct sdp_service_record_s *record,
712 struct sdp_def_service_s *def, int handle)
713{
714 int len = 0;
715 uint8_t *data;
716 int *uuid;
717
718 record->uuids = 0;
719 while (def->attributes[record->attributes].data.type) {
720 len += 3;
721 len += sdp_attr_max_size(&def->attributes[record->attributes ++].data,
722 &record->uuids);
723 }
724
725 assert(len > 0);
726 record->uuids = pow2ceil(record->uuids);
727 record->attribute_list =
728 g_malloc0(record->attributes * sizeof(*record->attribute_list));
729 record->uuid =
730 g_malloc0(record->uuids * sizeof(*record->uuid));
731 data = g_malloc(len);
732
733 record->attributes = 0;
734 uuid = record->uuid;
735 while (def->attributes[record->attributes].data.type) {
736 int attribute_id = def->attributes[record->attributes].id;
737 record->attribute_list[record->attributes].pair = data;
738 record->attribute_list[record->attributes].attribute_id = attribute_id;
739
740 len = 0;
741 data[len ++] = SDP_DTYPE_UINT | SDP_DSIZE_2;
742 data[len ++] = attribute_id >> 8;
743 data[len ++] = attribute_id & 0xff;
744 len += sdp_attr_write(data + len,
745 &def->attributes[record->attributes].data, &uuid);
746
747
748 if (def->attributes[record->attributes].id == SDP_ATTR_RECORD_HANDLE)
749 def->attributes[record->attributes].data.value.uint = handle;
750
751
752
753 record->attribute_list[record->attributes ++].len = len;
754 data += len;
755 }
756
757
758
759
760
761 qsort(record->attribute_list, record->attributes,
762 sizeof(*record->attribute_list),
763 (void *) sdp_attributeid_compare);
764 assert(record->attribute_list[0].pair == data);
765
766
767 qsort(record->uuid, record->uuids,
768 sizeof(*record->uuid),
769 (void *) sdp_uuid_compare);
770}
771
772static void sdp_service_db_build(struct bt_l2cap_sdp_state_s *sdp,
773 struct sdp_def_service_s **service)
774{
775 sdp->services = 0;
776 while (service[sdp->services])
777 sdp->services ++;
778 sdp->service_list =
779 g_malloc0(sdp->services * sizeof(*sdp->service_list));
780
781 sdp->services = 0;
782 while (*service) {
783 sdp_service_record_build(&sdp->service_list[sdp->services],
784 *service, sdp->services);
785 service ++;
786 sdp->services ++;
787 }
788}
789
790#define LAST { .type = 0 }
791#define SERVICE(name, attrs) \
792 static struct sdp_def_service_s glue(glue(sdp_service_, name), _s) = { \
793 .attributes = { attrs { .data = LAST } }, \
794 };
795#define ATTRIBUTE(attrid, val) { .id = glue(SDP_ATTR_, attrid), .data = val },
796#define UINT8(val) { \
797 .type = SDP_DTYPE_UINT | SDP_DSIZE_1, \
798 .value.uint = val, \
799 },
800#define UINT16(val) { \
801 .type = SDP_DTYPE_UINT | SDP_DSIZE_2, \
802 .value.uint = val, \
803 },
804#define UINT32(val) { \
805 .type = SDP_DTYPE_UINT | SDP_DSIZE_4, \
806 .value.uint = val, \
807 },
808#define UUID128(val) { \
809 .type = SDP_DTYPE_UUID | SDP_DSIZE_16, \
810 .value.uint = val, \
811 },
812#define SDP_TRUE { \
813 .type = SDP_DTYPE_BOOL | SDP_DSIZE_1, \
814 .value.uint = 1, \
815 },
816#define SDP_FALSE { \
817 .type = SDP_DTYPE_BOOL | SDP_DSIZE_1, \
818 .value.uint = 0, \
819 },
820#define STRING(val) { \
821 .type = SDP_DTYPE_STRING, \
822 .value.str = val, \
823 },
824#define ARRAY(...) { \
825 .type = SDP_DTYPE_STRING | SDP_DSIZE_2, \
826 .value.str = (char []) { __VA_ARGS__, 0, 0 }, \
827 },
828#define URL(val) { \
829 .type = SDP_DTYPE_URL, \
830 .value.str = val, \
831 },
832#if 1
833#define LIST(val) { \
834 .type = SDP_DTYPE_SEQ, \
835 .value.list = (struct sdp_def_data_element_s []) { val LAST }, \
836 },
837#endif
838
839
840
841
842SERVICE(hid,
843 ATTRIBUTE(RECORD_HANDLE, UINT32(0))
844 ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(HID_SVCLASS_ID)))
845 ATTRIBUTE(RECORD_STATE, UINT32(1))
846 ATTRIBUTE(PROTO_DESC_LIST, LIST(
847 LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_HID_CTRL))
848 LIST(UUID128(HIDP_UUID))
849 ))
850 ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
851 ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
852 UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
853 ))
854 ATTRIBUTE(PFILE_DESC_LIST, LIST(
855 LIST(UUID128(HID_PROFILE_ID) UINT16(0x0100))
856 ))
857 ATTRIBUTE(DOC_URL, URL("http://bellard.org/qemu/user-doc.html"))
858 ATTRIBUTE(SVCNAME_PRIMARY, STRING("QEMU Bluetooth HID"))
859 ATTRIBUTE(SVCDESC_PRIMARY, STRING("QEMU Keyboard/Mouse"))
860 ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU"))
861
862
863 ATTRIBUTE(DEVICE_RELEASE_NUMBER, UINT16(0x0091))
864 ATTRIBUTE(PARSER_VERSION, UINT16(0x0111))
865
866 ATTRIBUTE(DEVICE_SUBCLASS, UINT8(0x40))
867 ATTRIBUTE(COUNTRY_CODE, UINT8(0x15))
868 ATTRIBUTE(VIRTUAL_CABLE, SDP_TRUE)
869 ATTRIBUTE(RECONNECT_INITIATE, SDP_FALSE)
870
871 ATTRIBUTE(DESCRIPTOR_LIST, LIST(
872 LIST(UINT8(0x22) ARRAY(
873 0x05, 0x01,
874 0x09, 0x06,
875 0xa1, 0x01,
876 0x75, 0x01,
877 0x95, 0x08,
878 0x05, 0x07,
879 0x19, 0xe0,
880 0x29, 0xe7,
881 0x15, 0x00,
882 0x25, 0x01,
883 0x81, 0x02,
884 0x95, 0x01,
885 0x75, 0x08,
886 0x81, 0x01,
887 0x95, 0x05,
888 0x75, 0x01,
889 0x05, 0x08,
890 0x19, 0x01,
891 0x29, 0x05,
892 0x91, 0x02,
893 0x95, 0x01,
894 0x75, 0x03,
895 0x91, 0x01,
896 0x95, 0x06,
897 0x75, 0x08,
898 0x15, 0x00,
899 0x25, 0xff,
900 0x05, 0x07,
901 0x19, 0x00,
902 0x29, 0xff,
903 0x81, 0x00,
904 0xc0
905 ))))
906 ATTRIBUTE(LANG_ID_BASE_LIST, LIST(
907 LIST(UINT16(0x0409) UINT16(0x0100))
908 ))
909 ATTRIBUTE(SDP_DISABLE, SDP_FALSE)
910 ATTRIBUTE(BATTERY_POWER, SDP_TRUE)
911 ATTRIBUTE(REMOTE_WAKEUP, SDP_TRUE)
912 ATTRIBUTE(BOOT_DEVICE, SDP_TRUE)
913 ATTRIBUTE(SUPERVISION_TIMEOUT, UINT16(0x0c80))
914 ATTRIBUTE(NORMALLY_CONNECTABLE, SDP_TRUE)
915 ATTRIBUTE(PROFILE_VERSION, UINT16(0x0100))
916)
917
918SERVICE(sdp,
919 ATTRIBUTE(RECORD_HANDLE, UINT32(0))
920 ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(SDP_SERVER_SVCLASS_ID)))
921 ATTRIBUTE(RECORD_STATE, UINT32(1))
922 ATTRIBUTE(PROTO_DESC_LIST, LIST(
923 LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP))
924 LIST(UUID128(SDP_UUID))
925 ))
926 ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
927 ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
928 UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
929 ))
930 ATTRIBUTE(PFILE_DESC_LIST, LIST(
931 LIST(UUID128(SDP_SERVER_PROFILE_ID) UINT16(0x0100))
932 ))
933 ATTRIBUTE(DOC_URL, URL("http://bellard.org/qemu/user-doc.html"))
934 ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU"))
935
936
937 ATTRIBUTE(VERSION_NUM_LIST, LIST(UINT16(0x0100)))
938 ATTRIBUTE(SVCDB_STATE , UINT32(1))
939)
940
941SERVICE(pnp,
942 ATTRIBUTE(RECORD_HANDLE, UINT32(0))
943 ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(PNP_INFO_SVCLASS_ID)))
944 ATTRIBUTE(RECORD_STATE, UINT32(1))
945 ATTRIBUTE(PROTO_DESC_LIST, LIST(
946 LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP))
947 LIST(UUID128(SDP_UUID))
948 ))
949 ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
950 ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
951 UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
952 ))
953 ATTRIBUTE(PFILE_DESC_LIST, LIST(
954 LIST(UUID128(PNP_INFO_PROFILE_ID) UINT16(0x0100))
955 ))
956 ATTRIBUTE(DOC_URL, URL("http://bellard.org/qemu/user-doc.html"))
957 ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU"))
958
959
960 ATTRIBUTE(SPECIFICATION_ID, UINT16(0x0100))
961 ATTRIBUTE(VERSION, UINT16(0x0100))
962 ATTRIBUTE(PRIMARY_RECORD, SDP_TRUE)
963)
964
965static int bt_l2cap_sdp_new_ch(struct bt_l2cap_device_s *dev,
966 struct bt_l2cap_conn_params_s *params)
967{
968 struct bt_l2cap_sdp_state_s *sdp = g_malloc0(sizeof(*sdp));
969 struct sdp_def_service_s *services[] = {
970 &sdp_service_sdp_s,
971 &sdp_service_hid_s,
972 &sdp_service_pnp_s,
973 NULL,
974 };
975
976 sdp->channel = params;
977 sdp->channel->opaque = sdp;
978 sdp->channel->close = bt_l2cap_sdp_close_ch;
979 sdp->channel->sdu_in = bt_l2cap_sdp_sdu_in;
980
981 sdp_service_db_build(sdp, services);
982
983 return 0;
984}
985
986void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev)
987{
988 bt_l2cap_psm_register(dev, BT_PSM_SDP,
989 MAX_PDU_OUT_SIZE, bt_l2cap_sdp_new_ch);
990}
991