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