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