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