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