1 /* 2 * search.c 3 * 4 * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $Id: search.c,v 1.2 2003/09/08 17:35:15 max Exp $ 29 * $FreeBSD$ 30 */ 31 32 #include <netinet/in.h> 33 #define L2CAP_SOCKET_CHECKED 34 #include <bluetooth.h> 35 #include <ctype.h> 36 #include <sdp.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include "sdpcontrol.h" 40 41 /* List of the attributes we are looking for */ 42 static uint32_t attrs[] = 43 { 44 SDP_ATTR_RANGE( SDP_ATTR_SERVICE_RECORD_HANDLE, 45 SDP_ATTR_SERVICE_RECORD_HANDLE), 46 SDP_ATTR_RANGE( SDP_ATTR_SERVICE_CLASS_ID_LIST, 47 SDP_ATTR_SERVICE_CLASS_ID_LIST), 48 SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, 49 SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST), 50 SDP_ATTR_RANGE( SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST, 51 SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST) 52 }; 53 #define attrs_len (sizeof(attrs)/sizeof(attrs[0])) 54 55 /* Buffer for the attributes */ 56 #define NRECS 25 /* request this much records from the SDP server */ 57 #define BSIZE 256 /* one attribute buffer size */ 58 static uint8_t buffer[NRECS * attrs_len][BSIZE]; 59 60 /* SDP attributes */ 61 static sdp_attr_t values[NRECS * attrs_len]; 62 #define values_len (sizeof(values)/sizeof(values[0])) 63 64 /* 65 * Print Service Class ID List 66 * 67 * The ServiceClassIDList attribute consists of a data element sequence in 68 * which each data element is a UUID representing the service classes that 69 * a given service record conforms to. The UUIDs are listed in order from 70 * the most specific class to the most general class. The ServiceClassIDList 71 * must contain at least one service class UUID. 72 */ 73 74 static void 75 print_service_class_id_list(uint8_t const *start, uint8_t const *end) 76 { 77 uint32_t type, len, value; 78 79 if (end - start < 2) { 80 fprintf(stderr, "Invalid Service Class ID List. " \ 81 "Too short, len=%zd\n", end - start); 82 return; 83 } 84 85 SDP_GET8(type, start); 86 switch (type) { 87 case SDP_DATA_SEQ8: 88 SDP_GET8(len, start); 89 break; 90 91 case SDP_DATA_SEQ16: 92 SDP_GET16(len, start); 93 break; 94 95 case SDP_DATA_SEQ32: 96 SDP_GET32(len, start); 97 break; 98 99 default: 100 fprintf(stderr, "Invalid Service Class ID List. " \ 101 "Not a sequence, type=%#x\n", type); 102 return; 103 /* NOT REACHED */ 104 } 105 106 if (len > (end - start)) { 107 fprintf(stderr, "Invalid Service Class ID List. " \ 108 "Too long len=%d\n", len); 109 return; 110 } 111 112 while (start < end) { 113 SDP_GET8(type, start); 114 switch (type) { 115 case SDP_DATA_UUID16: 116 SDP_GET16(value, start); 117 fprintf(stdout, "\t%s (%#4.4x)\n", 118 sdp_uuid2desc(value), value); 119 break; 120 121 case SDP_DATA_UUID32: 122 SDP_GET32(value, start); 123 fprintf(stdout, "\t%#8.8x\n", value); 124 break; 125 126 case SDP_DATA_UUID128: { 127 int128_t uuid; 128 129 SDP_GET_UUID128(&uuid, start); 130 fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n", 131 ntohl(*(uint32_t *)&uuid.b[0]), 132 ntohs(*(uint16_t *)&uuid.b[4]), 133 ntohs(*(uint16_t *)&uuid.b[6]), 134 ntohs(*(uint16_t *)&uuid.b[8]), 135 ntohs(*(uint16_t *)&uuid.b[10]), 136 ntohl(*(uint32_t *)&uuid.b[12])); 137 } break; 138 139 default: 140 fprintf(stderr, "Invalid Service Class ID List. " \ 141 "Not a UUID, type=%#x\n", type); 142 return; 143 /* NOT REACHED */ 144 } 145 } 146 } /* print_service_class_id_list */ 147 148 /* 149 * Print Protocol Descriptor List 150 * 151 * If the ProtocolDescriptorList describes a single stack, it takes the form 152 * of a data element sequence in which each element of the sequence is a 153 * protocol descriptor. Each protocol descriptor is, in turn, a data element 154 * sequence whose first element is a UUID identifying the protocol and whose 155 * successive elements are protocol-specific parameters. The protocol 156 * descriptors are listed in order from the lowest layer protocol to the 157 * highest layer protocol used to gain access to the service. If it is possible 158 * for more than one kind of protocol stack to be used to gain access to the 159 * service, the ProtocolDescriptorList takes the form of a data element 160 * alternative where each member is a data element sequence as described above. 161 */ 162 163 static void 164 print_protocol_descriptor(uint8_t const *start, uint8_t const *end) 165 { 166 union { 167 uint8_t uint8; 168 uint16_t uint16; 169 uint32_t uint32; 170 uint64_t uint64; 171 int128_t int128; 172 } value; 173 uint32_t type, len, param; 174 175 /* Get Protocol UUID */ 176 SDP_GET8(type, start); 177 switch (type) { 178 case SDP_DATA_UUID16: 179 SDP_GET16(value.uint16, start); 180 fprintf(stdout, "\t%s (%#4.4x)\n", sdp_uuid2desc(value.uint16), 181 value.uint16); 182 break; 183 184 case SDP_DATA_UUID32: 185 SDP_GET32(value.uint32, start); 186 fprintf(stdout, "\t%#8.8x\n", value.uint32); 187 break; 188 189 case SDP_DATA_UUID128: 190 SDP_GET_UUID128(&value.int128, start); 191 fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n", 192 ntohl(*(uint32_t *)&value.int128.b[0]), 193 ntohs(*(uint16_t *)&value.int128.b[4]), 194 ntohs(*(uint16_t *)&value.int128.b[6]), 195 ntohs(*(uint16_t *)&value.int128.b[8]), 196 ntohs(*(uint16_t *)&value.int128.b[10]), 197 ntohl(*(uint32_t *)&value.int128.b[12])); 198 break; 199 200 default: 201 fprintf(stderr, "Invalid Protocol Descriptor. " \ 202 "Not a UUID, type=%#x\n", type); 203 return; 204 /* NOT REACHED */ 205 } 206 207 /* Protocol specific parameters */ 208 for (param = 1; start < end; param ++) { 209 fprintf(stdout, "\t\tProtocol specific parameter #%d: ", param); 210 211 SDP_GET8(type, start); 212 switch (type) { 213 case SDP_DATA_NIL: 214 fprintf(stdout, "nil\n"); 215 break; 216 217 case SDP_DATA_UINT8: 218 case SDP_DATA_INT8: 219 case SDP_DATA_BOOL: 220 SDP_GET8(value.uint8, start); 221 fprintf(stdout, "u/int8/bool %u\n", value.uint8); 222 break; 223 224 case SDP_DATA_UINT16: 225 case SDP_DATA_INT16: 226 case SDP_DATA_UUID16: 227 SDP_GET16(value.uint16, start); 228 fprintf(stdout, "u/int/uuid16 %u\n", value.uint16); 229 break; 230 231 case SDP_DATA_UINT32: 232 case SDP_DATA_INT32: 233 case SDP_DATA_UUID32: 234 SDP_GET32(value.uint32, start); 235 fprintf(stdout, "u/int/uuid32 %u\n", value.uint32); 236 break; 237 238 case SDP_DATA_UINT64: 239 case SDP_DATA_INT64: 240 SDP_GET64(value.uint64, start); 241 fprintf(stdout, "u/int64 %ju\n", value.uint64); 242 break; 243 244 case SDP_DATA_UINT128: 245 case SDP_DATA_INT128: 246 SDP_GET128(&value.int128, start); 247 fprintf(stdout, "u/int128 %#8.8x%8.8x%8.8x%8.8x\n", 248 *(uint32_t *)&value.int128.b[0], 249 *(uint32_t *)&value.int128.b[4], 250 *(uint32_t *)&value.int128.b[8], 251 *(uint32_t *)&value.int128.b[12]); 252 break; 253 254 case SDP_DATA_UUID128: 255 SDP_GET_UUID128(&value.int128, start); 256 fprintf(stdout, "uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n", 257 ntohl(*(uint32_t *)&value.int128.b[0]), 258 ntohs(*(uint16_t *)&value.int128.b[4]), 259 ntohs(*(uint16_t *)&value.int128.b[6]), 260 ntohs(*(uint16_t *)&value.int128.b[8]), 261 ntohs(*(uint16_t *)&value.int128.b[10]), 262 ntohl(*(uint32_t *)&value.int128.b[12])); 263 break; 264 265 case SDP_DATA_STR8: 266 case SDP_DATA_URL8: 267 SDP_GET8(len, start); 268 for (; start < end && len > 0; start ++, len --) 269 fprintf(stdout, "%c", *start); 270 fprintf(stdout, "\n"); 271 break; 272 273 case SDP_DATA_STR16: 274 case SDP_DATA_URL16: 275 SDP_GET16(len, start); 276 for (; start < end && len > 0; start ++, len --) 277 fprintf(stdout, "%c", *start); 278 fprintf(stdout, "\n"); 279 break; 280 281 case SDP_DATA_STR32: 282 case SDP_DATA_URL32: 283 SDP_GET32(len, start); 284 for (; start < end && len > 0; start ++, len --) 285 fprintf(stdout, "%c", *start); 286 fprintf(stdout, "\n"); 287 break; 288 289 case SDP_DATA_SEQ8: 290 case SDP_DATA_ALT8: 291 SDP_GET8(len, start); 292 for (; start < end && len > 0; start ++, len --) 293 fprintf(stdout, "%#2.2x ", *start); 294 fprintf(stdout, "\n"); 295 break; 296 297 case SDP_DATA_SEQ16: 298 case SDP_DATA_ALT16: 299 SDP_GET16(len, start); 300 for (; start < end && len > 0; start ++, len --) 301 fprintf(stdout, "%#2.2x ", *start); 302 fprintf(stdout, "\n"); 303 break; 304 305 case SDP_DATA_SEQ32: 306 case SDP_DATA_ALT32: 307 SDP_GET32(len, start); 308 for (; start < end && len > 0; start ++, len --) 309 fprintf(stdout, "%#2.2x ", *start); 310 fprintf(stdout, "\n"); 311 break; 312 313 default: 314 fprintf(stderr, "Invalid Protocol Descriptor. " \ 315 "Unknown data type: %#02x\n", type); 316 return; 317 /* NOT REACHED */ 318 } 319 } 320 } /* print_protocol_descriptor */ 321 322 static void 323 print_protocol_descriptor_list(uint8_t const *start, uint8_t const *end) 324 { 325 uint32_t type, len; 326 327 if (end - start < 2) { 328 fprintf(stderr, "Invalid Protocol Descriptor List. " \ 329 "Too short, len=%zd\n", end - start); 330 return; 331 } 332 333 SDP_GET8(type, start); 334 switch (type) { 335 case SDP_DATA_SEQ8: 336 SDP_GET8(len, start); 337 break; 338 339 case SDP_DATA_SEQ16: 340 SDP_GET16(len, start); 341 break; 342 343 case SDP_DATA_SEQ32: 344 SDP_GET32(len, start); 345 break; 346 347 default: 348 fprintf(stderr, "Invalid Protocol Descriptor List. " \ 349 "Not a sequence, type=%#x\n", type); 350 return; 351 /* NOT REACHED */ 352 } 353 354 if (len > (end - start)) { 355 fprintf(stderr, "Invalid Protocol Descriptor List. " \ 356 "Too long, len=%d\n", len); 357 return; 358 } 359 360 while (start < end) { 361 SDP_GET8(type, start); 362 switch (type) { 363 case SDP_DATA_SEQ8: 364 SDP_GET8(len, start); 365 break; 366 367 case SDP_DATA_SEQ16: 368 SDP_GET16(len, start); 369 break; 370 371 case SDP_DATA_SEQ32: 372 SDP_GET32(len, start); 373 break; 374 375 default: 376 fprintf(stderr, "Invalid Protocol Descriptor List. " \ 377 "Not a sequence, type=%#x\n", type); 378 return; 379 /* NOT REACHED */ 380 } 381 382 if (len > (end - start)) { 383 fprintf(stderr, "Invalid Protocol Descriptor List. " \ 384 "Too long, len=%d\n", len); 385 return; 386 } 387 388 print_protocol_descriptor(start, start + len); 389 start += len; 390 } 391 } /* print_protocol_descriptor_list */ 392 393 /* 394 * Print Bluetooth Profile Descriptor List 395 * 396 * The BluetoothProfileDescriptorList attribute consists of a data element 397 * sequence in which each element is a profile descriptor that contains 398 * information about a Bluetooth profile to which the service represented by 399 * this service record conforms. Each profile descriptor is a data element 400 * sequence whose first element is the UUID assigned to the profile and whose 401 * second element is a 16-bit profile version number. Each version of a profile 402 * is assigned a 16-bit unsigned integer profile version number, which consists 403 * of two 8-bit fields. The higher-order 8 bits contain the major version 404 * number field and the lower-order 8 bits contain the minor version number 405 * field. 406 */ 407 408 static void 409 print_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end) 410 { 411 uint32_t type, len, value; 412 413 if (end - start < 2) { 414 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \ 415 "Too short, len=%zd\n", end - start); 416 return; 417 } 418 419 SDP_GET8(type, start); 420 switch (type) { 421 case SDP_DATA_SEQ8: 422 SDP_GET8(len, start); 423 break; 424 425 case SDP_DATA_SEQ16: 426 SDP_GET16(len, start); 427 break; 428 429 case SDP_DATA_SEQ32: 430 SDP_GET32(len, start); 431 break; 432 433 default: 434 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \ 435 "Not a sequence, type=%#x\n", type); 436 return; 437 /* NOT REACHED */ 438 } 439 440 if (len > (end - start)) { 441 fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \ 442 "Too long, len=%d\n", len); 443 return; 444 } 445 446 while (start < end) { 447 SDP_GET8(type, start); 448 switch (type) { 449 case SDP_DATA_SEQ8: 450 SDP_GET8(len, start); 451 break; 452 453 case SDP_DATA_SEQ16: 454 SDP_GET16(len, start); 455 break; 456 457 case SDP_DATA_SEQ32: 458 SDP_GET32(len, start); 459 break; 460 461 default: 462 fprintf(stderr, "Invalid Bluetooth Profile " \ 463 "Descriptor List. " \ 464 "Not a sequence, type=%#x\n", type); 465 return; 466 /* NOT REACHED */ 467 } 468 469 if (len > (end - start)) { 470 fprintf(stderr, "Invalid Bluetooth Profile " \ 471 "Descriptor List. " \ 472 "Too long, len=%d\n", len); 473 return; 474 } 475 476 /* Get UUID */ 477 SDP_GET8(type, start); 478 switch (type) { 479 case SDP_DATA_UUID16: 480 SDP_GET16(value, start); 481 fprintf(stdout, "\t%s (%#4.4x) ", 482 sdp_uuid2desc(value), value); 483 break; 484 485 case SDP_DATA_UUID32: 486 SDP_GET32(value, start); 487 fprintf(stdout, "\t%#8.8x ", value); 488 break; 489 490 case SDP_DATA_UUID128: { 491 int128_t uuid; 492 493 SDP_GET_UUID128(&uuid, start); 494 fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x ", 495 ntohl(*(uint32_t *)&uuid.b[0]), 496 ntohs(*(uint16_t *)&uuid.b[4]), 497 ntohs(*(uint16_t *)&uuid.b[6]), 498 ntohs(*(uint16_t *)&uuid.b[8]), 499 ntohs(*(uint16_t *)&uuid.b[10]), 500 ntohl(*(uint32_t *)&uuid.b[12])); 501 } break; 502 503 default: 504 fprintf(stderr, "Invalid Bluetooth Profile " \ 505 "Descriptor List. " \ 506 "Not a UUID, type=%#x\n", type); 507 return; 508 /* NOT REACHED */ 509 } 510 511 /* Get version */ 512 SDP_GET8(type, start); 513 if (type != SDP_DATA_UINT16) { 514 fprintf(stderr, "Invalid Bluetooth Profile " \ 515 "Descriptor List. " \ 516 "Invalid version type=%#x\n", type); 517 return; 518 } 519 520 SDP_GET16(value, start); 521 fprintf(stdout, "ver. %d.%d\n", 522 (value >> 8) & 0xff, value & 0xff); 523 } 524 } /* print_bluetooth_profile_descriptor_list */ 525 526 /* Perform SDP search command */ 527 static int 528 do_sdp_search(void *xs, int argc, char **argv) 529 { 530 char *ep = NULL; 531 int32_t n, type, value; 532 uint16_t service; 533 534 /* Parse command line arguments */ 535 switch (argc) { 536 case 1: 537 n = strtoul(argv[0], &ep, 16); 538 if (*ep != 0) { 539 switch (tolower(argv[0][0])) { 540 case 'c': /* CIP/CTP */ 541 switch (tolower(argv[0][1])) { 542 case 'i': 543 service = SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS; 544 break; 545 546 case 't': 547 service = SDP_SERVICE_CLASS_CORDLESS_TELEPHONY; 548 break; 549 550 default: 551 return (USAGE); 552 /* NOT REACHED */ 553 } 554 break; 555 556 case 'd': /* DialUp Networking */ 557 service = SDP_SERVICE_CLASS_DIALUP_NETWORKING; 558 break; 559 560 case 'f': /* Fax/OBEX File Transfer */ 561 switch (tolower(argv[0][1])) { 562 case 'a': 563 service = SDP_SERVICE_CLASS_FAX; 564 break; 565 566 case 't': 567 service = SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER; 568 break; 569 570 default: 571 return (USAGE); 572 /* NOT REACHED */ 573 } 574 break; 575 576 case 'g': /* GN */ 577 service = SDP_SERVICE_CLASS_GN; 578 break; 579 580 case 'h': /* Headset/HID */ 581 switch (tolower(argv[0][1])) { 582 case 'i': 583 service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE; 584 break; 585 586 case 's': 587 service = SDP_SERVICE_CLASS_HEADSET; 588 break; 589 590 default: 591 return (USAGE); 592 /* NOT REACHED */ 593 } 594 break; 595 596 case 'l': /* LAN Access Using PPP */ 597 service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP; 598 break; 599 600 case 'n': /* NAP */ 601 service = SDP_SERVICE_CLASS_NAP; 602 break; 603 604 case 'o': /* OBEX Object Push */ 605 service = SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH; 606 break; 607 608 case 's': /* Serial Port */ 609 service = SDP_SERVICE_CLASS_SERIAL_PORT; 610 break; 611 612 default: 613 return (USAGE); 614 /* NOT REACHED */ 615 } 616 } else 617 service = (uint16_t) n; 618 break; 619 620 default: 621 return (USAGE); 622 } 623 624 /* Initialize attribute values array */ 625 for (n = 0; n < values_len; n ++) { 626 values[n].flags = SDP_ATTR_INVALID; 627 values[n].attr = 0; 628 values[n].vlen = BSIZE; 629 values[n].value = buffer[n]; 630 } 631 632 /* Do SDP Service Search Attribute Request */ 633 n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values); 634 if (n != 0) 635 return (ERROR); 636 637 /* Print attributes values */ 638 for (n = 0; n < values_len; n ++) { 639 if (values[n].flags != SDP_ATTR_OK) 640 break; 641 642 switch (values[n].attr) { 643 case SDP_ATTR_SERVICE_RECORD_HANDLE: 644 fprintf(stdout, "\n"); 645 if (values[n].vlen == 5) { 646 SDP_GET8(type, values[n].value); 647 if (type == SDP_DATA_UINT32) { 648 SDP_GET32(value, values[n].value); 649 fprintf(stdout, "Record Handle: " \ 650 "%#8.8x\n", value); 651 } else 652 fprintf(stderr, "Invalid type=%#x " \ 653 "Record Handle " \ 654 "attribute!\n", type); 655 } else 656 fprintf(stderr, "Invalid size=%d for Record " \ 657 "Handle attribute\n", 658 values[n].vlen); 659 break; 660 661 case SDP_ATTR_SERVICE_CLASS_ID_LIST: 662 fprintf(stdout, "Service Class ID List:\n"); 663 print_service_class_id_list(values[n].value, 664 values[n].value + values[n].vlen); 665 break; 666 667 case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: 668 fprintf(stdout, "Protocol Descriptor List:\n"); 669 print_protocol_descriptor_list(values[n].value, 670 values[n].value + values[n].vlen); 671 break; 672 673 case SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST: 674 fprintf(stdout, "Bluetooth Profile Descriptor List:\n"); 675 print_bluetooth_profile_descriptor_list(values[n].value, 676 values[n].value + values[n].vlen); 677 break; 678 679 default: 680 fprintf(stderr, "Unexpected attribute ID=%#4.4x\n", 681 values[n].attr); 682 break; 683 } 684 } 685 686 return (OK); 687 } /* do_sdp_search */ 688 689 /* Perform SDP browse command */ 690 static int 691 do_sdp_browse(void *xs, int argc, char **argv) 692 { 693 #undef _STR 694 #undef STR 695 #define _STR(x) #x 696 #define STR(x) _STR(x) 697 698 static char const * const av[] = { 699 STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP), 700 NULL 701 }; 702 703 switch (argc) { 704 case 0: 705 argc = 1; 706 argv = (char **) av; 707 /* FALL THROUGH */ 708 case 1: 709 return (do_sdp_search(xs, argc, argv)); 710 } 711 712 return (USAGE); 713 } /* do_sdp_browse */ 714 715 /* List of SDP commands */ 716 struct sdp_command sdp_commands[] = { 717 { 718 "Browse [<Group>]", 719 "Browse for services. The <Group> parameter is a 16-bit UUID of the group\n" \ 720 "to browse. If omitted <Group> is set to Public Browse Group.\n\n" \ 721 "\t<Group> - xxxx; 16-bit UUID of the group to browse\n", 722 do_sdp_browse 723 }, 724 { 725 "Search <Service>", 726 "Search for the <Service>. The <Service> parameter is a 16-bit UUID of the\n" \ 727 "service to search for. For some services it is possible to use service name\n"\ 728 "instead of service UUID\n\n" \ 729 "\t<Service> - xxxx; 16-bit UUID of the service to search for\n\n" \ 730 "\tKnown service names\n" \ 731 "\t===================\n" \ 732 "\tCIP - Common ISDN Access\n" \ 733 "\tCTP - Cordless Telephony\n" \ 734 "\tDUN - DialUp Networking\n" \ 735 "\tFAX - Fax\n" \ 736 "\tFTRN - OBEX File Transfer\n" \ 737 "\tGN - GN\n" \ 738 "\tHID - Human Interface Device\n" \ 739 "\tHSET - Headset\n" \ 740 "\tLAN - LAN Access Using PPP\n" \ 741 "\tNAP - Network Access Point\n" \ 742 "\tOPUSH - OBEX Object Push\n" \ 743 "\tSP - Serial Port\n", 744 do_sdp_search 745 }, 746 { NULL, NULL, NULL } 747 }; 748 749