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