1121054Semax/* 2121054Semax * search.c 3121054Semax * 4121054Semax * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5121054Semax * All rights reserved. 6121054Semax * 7121054Semax * Redistribution and use in source and binary forms, with or without 8121054Semax * modification, are permitted provided that the following conditions 9121054Semax * are met: 10121054Semax * 1. Redistributions of source code must retain the above copyright 11121054Semax * notice, this list of conditions and the following disclaimer. 12121054Semax * 2. Redistributions in binary form must reproduce the above copyright 13121054Semax * notice, this list of conditions and the following disclaimer in the 14121054Semax * documentation and/or other materials provided with the distribution. 15121054Semax * 16121054Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17121054Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18121054Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19121054Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20121054Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21121054Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22121054Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23121054Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24121054Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25121054Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26121054Semax * SUCH DAMAGE. 27121054Semax * 28121054Semax * $Id: search.c,v 1.2 2003/09/08 17:35:15 max Exp $ 29121054Semax * $FreeBSD$ 30121054Semax */ 31121054Semax 32146691Semax#include <netinet/in.h> 33121054Semax#include <bluetooth.h> 34121054Semax#include <ctype.h> 35121054Semax#include <sdp.h> 36121054Semax#include <stdio.h> 37121054Semax#include <stdlib.h> 38121054Semax#include "sdpcontrol.h" 39121054Semax 40121054Semax/* List of the attributes we are looking for */ 41124317Semaxstatic uint32_t attrs[] = 42121054Semax{ 43121054Semax SDP_ATTR_RANGE( SDP_ATTR_SERVICE_RECORD_HANDLE, 44121054Semax SDP_ATTR_SERVICE_RECORD_HANDLE), 45121054Semax SDP_ATTR_RANGE( SDP_ATTR_SERVICE_CLASS_ID_LIST, 46121054Semax SDP_ATTR_SERVICE_CLASS_ID_LIST), 47121054Semax SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, 48121054Semax SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST), 49121054Semax SDP_ATTR_RANGE( SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST, 50121054Semax SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST) 51121054Semax}; 52121054Semax#define attrs_len (sizeof(attrs)/sizeof(attrs[0])) 53121054Semax 54121054Semax/* Buffer for the attributes */ 55121054Semax#define NRECS 25 /* request this much records from the SDP server */ 56121054Semax#define BSIZE 256 /* one attribute buffer size */ 57124317Semaxstatic uint8_t buffer[NRECS * attrs_len][BSIZE]; 58121054Semax 59121054Semax/* SDP attributes */ 60121054Semaxstatic sdp_attr_t values[NRECS * attrs_len]; 61121054Semax#define values_len (sizeof(values)/sizeof(values[0])) 62121054Semax 63121054Semax/* 64121054Semax * Print Service Class ID List 65121054Semax * 66121054Semax * The ServiceClassIDList attribute consists of a data element sequence in 67121054Semax * which each data element is a UUID representing the service classes that 68121054Semax * a given service record conforms to. The UUIDs are listed in order from 69121054Semax * the most specific class to the most general class. The ServiceClassIDList 70121054Semax * must contain at least one service class UUID. 71121054Semax */ 72121054Semax 73121054Semaxstatic void 74124317Semaxprint_service_class_id_list(uint8_t const *start, uint8_t const *end) 75121054Semax{ 76124317Semax uint32_t type, len, value; 77121054Semax 78121054Semax if (end - start < 2) { 79121054Semax fprintf(stderr, "Invalid Service Class ID List. " \ 80128076Semax "Too short, len=%zd\n", end - start); 81121054Semax return; 82121054Semax } 83121054Semax 84121054Semax SDP_GET8(type, start); 85121054Semax switch (type) { 86121054Semax case SDP_DATA_SEQ8: 87121054Semax SDP_GET8(len, start); 88121054Semax break; 89121054Semax 90121054Semax case SDP_DATA_SEQ16: 91121054Semax SDP_GET16(len, start); 92121054Semax break; 93121054Semax 94121054Semax case SDP_DATA_SEQ32: 95121054Semax SDP_GET32(len, start); 96121054Semax break; 97121054Semax 98121054Semax default: 99121054Semax fprintf(stderr, "Invalid Service Class ID List. " \ 100121054Semax "Not a sequence, type=%#x\n", type); 101121054Semax return; 102121054Semax /* NOT REACHED */ 103121054Semax } 104121054Semax 105121054Semax while (start < end) { 106121054Semax SDP_GET8(type, start); 107121054Semax switch (type) { 108121054Semax case SDP_DATA_UUID16: 109121054Semax SDP_GET16(value, start); 110121054Semax fprintf(stdout, "\t%s (%#4.4x)\n", 111121054Semax sdp_uuid2desc(value), value); 112121054Semax break; 113121054Semax 114121054Semax case SDP_DATA_UUID32: 115121054Semax SDP_GET32(value, start); 116121054Semax fprintf(stdout, "\t%#8.8x\n", value); 117121054Semax break; 118121054Semax 119121054Semax case SDP_DATA_UUID128: { 120121054Semax int128_t uuid; 121121054Semax 122146691Semax SDP_GET_UUID128(&uuid, start); 123121054Semax fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n", 124146691Semax ntohl(*(uint32_t *)&uuid.b[0]), 125146691Semax ntohs(*(uint16_t *)&uuid.b[4]), 126146691Semax ntohs(*(uint16_t *)&uuid.b[6]), 127146691Semax ntohs(*(uint16_t *)&uuid.b[8]), 128146691Semax ntohs(*(uint16_t *)&uuid.b[10]), 129146691Semax ntohl(*(uint32_t *)&uuid.b[12])); 130121054Semax } break; 131121054Semax 132121054Semax default: 133121054Semax fprintf(stderr, "Invalid Service Class ID List. " \ 134121054Semax "Not a UUID, type=%#x\n", type); 135121054Semax return; 136121054Semax /* NOT REACHED */ 137121054Semax } 138121054Semax } 139121054Semax} /* print_service_class_id_list */ 140121054Semax 141121054Semax/* 142121054Semax * Print Protocol Descriptor List 143121054Semax * 144121054Semax * If the ProtocolDescriptorList describes a single stack, it takes the form 145121054Semax * of a data element sequence in which each element of the sequence is a 146121054Semax * protocol descriptor. Each protocol descriptor is, in turn, a data element 147121054Semax * sequence whose first element is a UUID identifying the protocol and whose 148121054Semax * successive elements are protocol-specific parameters. The protocol 149121054Semax * descriptors are listed in order from the lowest layer protocol to the 150121054Semax * highest layer protocol used to gain access to the service. If it is possible 151121054Semax * for more than one kind of protocol stack to be used to gain access to the 152121054Semax * service, the ProtocolDescriptorList takes the form of a data element 153121054Semax * alternative where each member is a data element sequence as described above. 154121054Semax */ 155121054Semax 156121054Semaxstatic void 157124317Semaxprint_protocol_descriptor(uint8_t const *start, uint8_t const *end) 158121054Semax{ 159121054Semax union { 160121054Semax uint8_t uint8; 161121054Semax uint16_t uint16; 162121054Semax uint32_t uint32; 163121054Semax uint64_t uint64; 164121054Semax int128_t int128; 165121054Semax } value; 166124317Semax uint32_t type, len, param; 167121054Semax 168121054Semax /* Get Protocol UUID */ 169121054Semax SDP_GET8(type, start); 170121054Semax switch (type) { 171121054Semax case SDP_DATA_UUID16: 172121054Semax SDP_GET16(value.uint16, start); 173121054Semax fprintf(stdout, "\t%s (%#4.4x)\n", sdp_uuid2desc(value.uint16), 174121054Semax value.uint16); 175121054Semax break; 176121054Semax 177121054Semax case SDP_DATA_UUID32: 178121054Semax SDP_GET32(value.uint32, start); 179121054Semax fprintf(stdout, "\t%#8.8x\n", value.uint32); 180121054Semax break; 181121054Semax 182121054Semax case SDP_DATA_UUID128: 183146691Semax SDP_GET_UUID128(&value.int128, start); 184121054Semax fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n", 185146691Semax ntohl(*(uint32_t *)&value.int128.b[0]), 186146691Semax ntohs(*(uint16_t *)&value.int128.b[4]), 187146691Semax ntohs(*(uint16_t *)&value.int128.b[6]), 188146691Semax ntohs(*(uint16_t *)&value.int128.b[8]), 189146691Semax ntohs(*(uint16_t *)&value.int128.b[10]), 190146691Semax ntohl(*(uint32_t *)&value.int128.b[12])); 191121054Semax break; 192121054Semax 193121054Semax default: 194121054Semax fprintf(stderr, "Invalid Protocol Descriptor. " \ 195121054Semax "Not a UUID, type=%#x\n", type); 196121054Semax return; 197121054Semax /* NOT REACHED */ 198121054Semax } 199121054Semax 200121054Semax /* Protocol specific parameters */ 201121054Semax for (param = 1; start < end; param ++) { 202121054Semax fprintf(stdout, "\t\tProtocol specific parameter #%d: ", param); 203121054Semax 204121054Semax SDP_GET8(type, start); 205121054Semax switch (type) { 206121054Semax case SDP_DATA_NIL: 207121054Semax fprintf(stdout, "nil\n"); 208121054Semax break; 209121054Semax 210121054Semax case SDP_DATA_UINT8: 211121054Semax case SDP_DATA_INT8: 212121054Semax case SDP_DATA_BOOL: 213121054Semax SDP_GET8(value.uint8, start); 214121054Semax fprintf(stdout, "u/int8/bool %u\n", value.uint8); 215121054Semax break; 216121054Semax 217121054Semax case SDP_DATA_UINT16: 218121054Semax case SDP_DATA_INT16: 219121054Semax case SDP_DATA_UUID16: 220121054Semax SDP_GET16(value.uint16, start); 221121054Semax fprintf(stdout, "u/int/uuid16 %u\n", value.uint16); 222121054Semax break; 223121054Semax 224121054Semax case SDP_DATA_UINT32: 225121054Semax case SDP_DATA_INT32: 226121054Semax case SDP_DATA_UUID32: 227121054Semax SDP_GET32(value.uint32, start); 228121054Semax fprintf(stdout, "u/int/uuid32 %u\n", value.uint32); 229121054Semax break; 230121054Semax 231121054Semax case SDP_DATA_UINT64: 232121054Semax case SDP_DATA_INT64: 233121054Semax SDP_GET64(value.uint64, start); 234128076Semax fprintf(stdout, "u/int64 %ju\n", value.uint64); 235121054Semax break; 236121054Semax 237121054Semax case SDP_DATA_UINT128: 238121054Semax case SDP_DATA_INT128: 239121054Semax SDP_GET128(&value.int128, start); 240146691Semax fprintf(stdout, "u/int128 %#8.8x%8.8x%8.8x%8.8x\n", 241124317Semax *(uint32_t *)&value.int128.b[0], 242146691Semax *(uint32_t *)&value.int128.b[4], 243146691Semax *(uint32_t *)&value.int128.b[8], 244124317Semax *(uint32_t *)&value.int128.b[12]); 245121054Semax break; 246121054Semax 247146691Semax case SDP_DATA_UUID128: 248146691Semax SDP_GET_UUID128(&value.int128, start); 249146691Semax fprintf(stdout, "uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n", 250146691Semax ntohl(*(uint32_t *)&value.int128.b[0]), 251146691Semax ntohs(*(uint16_t *)&value.int128.b[4]), 252146691Semax ntohs(*(uint16_t *)&value.int128.b[6]), 253146691Semax ntohs(*(uint16_t *)&value.int128.b[8]), 254146691Semax ntohs(*(uint16_t *)&value.int128.b[10]), 255146691Semax ntohl(*(uint32_t *)&value.int128.b[12])); 256146691Semax break; 257146691Semax 258121054Semax case SDP_DATA_STR8: 259121054Semax case SDP_DATA_URL8: 260121054Semax SDP_GET8(len, start); 261121054Semax fprintf(stdout, "%*.*s\n", len, len, (char *) start); 262121054Semax start += len; 263121054Semax break; 264121054Semax 265121054Semax case SDP_DATA_STR16: 266121054Semax case SDP_DATA_URL16: 267121054Semax SDP_GET16(len, start); 268121054Semax fprintf(stdout, "%*.*s\n", len, len, (char *) start); 269121054Semax start += len; 270121054Semax break; 271121054Semax 272121054Semax case SDP_DATA_STR32: 273121054Semax case SDP_DATA_URL32: 274121054Semax SDP_GET32(len, start); 275121054Semax fprintf(stdout, "%*.*s\n", len, len, (char *) start); 276121054Semax start += len; 277121054Semax break; 278121054Semax 279121054Semax case SDP_DATA_SEQ8: 280121054Semax case SDP_DATA_ALT8: 281121054Semax SDP_GET8(len, start); 282121054Semax for (; len > 0; start ++, len --) 283121054Semax fprintf(stdout, "%#2.2x ", *start); 284121054Semax fprintf(stdout, "\n"); 285121054Semax break; 286121054Semax 287121054Semax case SDP_DATA_SEQ16: 288121054Semax case SDP_DATA_ALT16: 289121054Semax SDP_GET16(len, start); 290121054Semax for (; len > 0; start ++, len --) 291121054Semax fprintf(stdout, "%#2.2x ", *start); 292121054Semax fprintf(stdout, "\n"); 293121054Semax break; 294121054Semax 295121054Semax case SDP_DATA_SEQ32: 296121054Semax case SDP_DATA_ALT32: 297121054Semax SDP_GET32(len, start); 298121054Semax for (; len > 0; start ++, len --) 299121054Semax fprintf(stdout, "%#2.2x ", *start); 300121054Semax fprintf(stdout, "\n"); 301121054Semax break; 302121054Semax 303121054Semax default: 304121054Semax fprintf(stderr, "Invalid Protocol Descriptor. " \ 305121054Semax "Unknown data type: %#02x\n", type); 306121054Semax return; 307121054Semax /* NOT REACHED */ 308121054Semax } 309121054Semax } 310121054Semax} /* print_protocol_descriptor */ 311121054Semax 312121054Semaxstatic void 313124317Semaxprint_protocol_descriptor_list(uint8_t const *start, uint8_t const *end) 314121054Semax{ 315124317Semax uint32_t type, len; 316121054Semax 317121054Semax if (end - start < 2) { 318121054Semax fprintf(stderr, "Invalid Protocol Descriptor List. " \ 319128076Semax "Too short, len=%zd\n", end - start); 320121054Semax return; 321121054Semax } 322121054Semax 323121054Semax SDP_GET8(type, start); 324121054Semax switch (type) { 325121054Semax case SDP_DATA_SEQ8: 326121054Semax SDP_GET8(len, start); 327121054Semax break; 328121054Semax 329121054Semax case SDP_DATA_SEQ16: 330121054Semax SDP_GET16(len, start); 331121054Semax break; 332121054Semax 333121054Semax case SDP_DATA_SEQ32: 334121054Semax SDP_GET32(len, start); 335121054Semax break; 336121054Semax 337121054Semax default: 338121054Semax fprintf(stderr, "Invalid Protocol Descriptor List. " \ 339121054Semax "Not a sequence, type=%#x\n", type); 340121054Semax return; 341121054Semax /* NOT REACHED */ 342121054Semax } 343121054Semax 344121054Semax while (start < end) { 345121054Semax SDP_GET8(type, start); 346121054Semax switch (type) { 347121054Semax case SDP_DATA_SEQ8: 348121054Semax SDP_GET8(len, start); 349121054Semax break; 350121054Semax 351121054Semax case SDP_DATA_SEQ16: 352121054Semax SDP_GET16(len, start); 353121054Semax break; 354121054Semax 355121054Semax case SDP_DATA_SEQ32: 356121054Semax SDP_GET32(len, start); 357121054Semax break; 358121054Semax 359121054Semax default: 360121054Semax fprintf(stderr, "Invalid Protocol Descriptor List. " \ 361121054Semax "Not a sequence, type=%#x\n", type); 362121054Semax return; 363121054Semax /* NOT REACHED */ 364121054Semax } 365121054Semax 366121054Semax print_protocol_descriptor(start, start + len); 367121054Semax start += len; 368121054Semax } 369121054Semax} /* print_protocol_descriptor_list */ 370121054Semax 371121054Semax/* 372121054Semax * Print Bluetooth Profile Descriptor List 373121054Semax * 374121054Semax * The BluetoothProfileDescriptorList attribute consists of a data element 375121054Semax * sequence in which each element is a profile descriptor that contains 376121054Semax * information about a Bluetooth profile to which the service represented by 377121054Semax * this service record conforms. Each profile descriptor is a data element 378121054Semax * sequence whose first element is the UUID assigned to the profile and whose 379121054Semax * second element is a 16-bit profile version number. Each version of a profile 380121054Semax * is assigned a 16-bit unsigned integer profile version number, which consists 381121054Semax * of two 8-bit fields. The higher-order 8 bits contain the major version 382121054Semax * number field and the lower-order 8 bits contain the minor version number 383121054Semax * field. 384121054Semax */ 385121054Semax 386121054Semaxstatic void 387124317Semaxprint_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end) 388121054Semax{ 389124317Semax uint32_t type, len, value; 390121054Semax 391121054Semax if (end - start < 2) { 392121054Semax fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \ 393128076Semax "Too short, len=%zd\n", end - start); 394121054Semax return; 395121054Semax } 396121054Semax 397121054Semax SDP_GET8(type, start); 398121054Semax switch (type) { 399121054Semax case SDP_DATA_SEQ8: 400121054Semax SDP_GET8(len, start); 401121054Semax break; 402121054Semax 403121054Semax case SDP_DATA_SEQ16: 404121054Semax SDP_GET16(len, start); 405121054Semax break; 406121054Semax 407121054Semax case SDP_DATA_SEQ32: 408121054Semax SDP_GET32(len, start); 409121054Semax break; 410121054Semax 411121054Semax default: 412121054Semax fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \ 413121054Semax "Not a sequence, type=%#x\n", type); 414121054Semax return; 415121054Semax /* NOT REACHED */ 416121054Semax } 417121054Semax 418121054Semax while (start < end) { 419121054Semax SDP_GET8(type, start); 420121054Semax switch (type) { 421121054Semax case SDP_DATA_SEQ8: 422121054Semax SDP_GET8(len, start); 423121054Semax break; 424121054Semax 425121054Semax case SDP_DATA_SEQ16: 426121054Semax SDP_GET16(len, start); 427121054Semax break; 428121054Semax 429121054Semax case SDP_DATA_SEQ32: 430121054Semax SDP_GET32(len, start); 431121054Semax break; 432121054Semax 433121054Semax default: 434121054Semax fprintf(stderr, "Invalid Bluetooth Profile " \ 435121054Semax "Descriptor List. " \ 436121054Semax "Not a sequence, type=%#x\n", type); 437121054Semax return; 438121054Semax /* NOT REACHED */ 439121054Semax } 440121054Semax 441121054Semax /* Get UUID */ 442121054Semax SDP_GET8(type, start); 443121054Semax switch (type) { 444121054Semax case SDP_DATA_UUID16: 445121054Semax SDP_GET16(value, start); 446121054Semax fprintf(stdout, "\t%s (%#4.4x) ", 447121054Semax sdp_uuid2desc(value), value); 448121054Semax break; 449121054Semax 450121054Semax case SDP_DATA_UUID32: 451121054Semax SDP_GET32(value, start); 452121054Semax fprintf(stdout, "\t%#8.8x ", value); 453121054Semax break; 454121054Semax 455121054Semax case SDP_DATA_UUID128: { 456121054Semax int128_t uuid; 457121054Semax 458146691Semax SDP_GET_UUID128(&uuid, start); 459121054Semax fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x ", 460146691Semax ntohl(*(uint32_t *)&uuid.b[0]), 461146691Semax ntohs(*(uint16_t *)&uuid.b[4]), 462146691Semax ntohs(*(uint16_t *)&uuid.b[6]), 463146691Semax ntohs(*(uint16_t *)&uuid.b[8]), 464146691Semax ntohs(*(uint16_t *)&uuid.b[10]), 465146691Semax ntohl(*(uint32_t *)&uuid.b[12])); 466121054Semax } break; 467121054Semax 468121054Semax default: 469121054Semax fprintf(stderr, "Invalid Bluetooth Profile " \ 470121054Semax "Descriptor List. " \ 471121054Semax "Not a UUID, type=%#x\n", type); 472121054Semax return; 473121054Semax /* NOT REACHED */ 474121054Semax } 475121054Semax 476121054Semax /* Get version */ 477121054Semax SDP_GET8(type, start); 478121054Semax if (type != SDP_DATA_UINT16) { 479121054Semax fprintf(stderr, "Invalid Bluetooth Profile " \ 480121054Semax "Descriptor List. " \ 481121054Semax "Invalid version type=%#x\n", type); 482121054Semax return; 483121054Semax } 484121054Semax 485121054Semax SDP_GET16(value, start); 486121054Semax fprintf(stdout, "ver. %d.%d\n", 487121054Semax (value >> 8) & 0xff, value & 0xff); 488121054Semax } 489121054Semax} /* print_bluetooth_profile_descriptor_list */ 490121054Semax 491121054Semax/* Perform SDP search command */ 492121054Semaxstatic int 493121054Semaxdo_sdp_search(void *xs, int argc, char **argv) 494121054Semax{ 495121054Semax char *ep = NULL; 496121054Semax int32_t n, type, value; 497124317Semax uint16_t service; 498121054Semax 499121054Semax /* Parse command line arguments */ 500121054Semax switch (argc) { 501121054Semax case 1: 502121054Semax n = strtoul(argv[0], &ep, 16); 503121054Semax if (*ep != 0) { 504121054Semax switch (tolower(argv[0][0])) { 505121054Semax case 'c': /* CIP/CTP */ 506121054Semax switch (tolower(argv[0][1])) { 507121054Semax case 'i': 508121054Semax service = SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS; 509121054Semax break; 510121054Semax 511121054Semax case 't': 512121054Semax service = SDP_SERVICE_CLASS_CORDLESS_TELEPHONY; 513121054Semax break; 514121054Semax 515121054Semax default: 516121054Semax return (USAGE); 517121054Semax /* NOT REACHED */ 518121054Semax } 519121054Semax break; 520121054Semax 521121054Semax case 'd': /* DialUp Networking */ 522121054Semax service = SDP_SERVICE_CLASS_DIALUP_NETWORKING; 523121054Semax break; 524121054Semax 525121054Semax case 'f': /* Fax/OBEX File Transfer */ 526121054Semax switch (tolower(argv[0][1])) { 527121054Semax case 'a': 528121054Semax service = SDP_SERVICE_CLASS_FAX; 529121054Semax break; 530121054Semax 531121054Semax case 't': 532121054Semax service = SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER; 533121054Semax break; 534121054Semax 535121054Semax default: 536121054Semax return (USAGE); 537121054Semax /* NOT REACHED */ 538121054Semax } 539121054Semax break; 540121054Semax 541121054Semax case 'g': /* GN */ 542121054Semax service = SDP_SERVICE_CLASS_GN; 543121054Semax break; 544121054Semax 545121054Semax case 'h': /* Headset/HID */ 546121054Semax switch (tolower(argv[0][1])) { 547121054Semax case 'i': 548121054Semax service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE; 549121054Semax break; 550121054Semax 551121054Semax case 's': 552121054Semax service = SDP_SERVICE_CLASS_HEADSET; 553121054Semax break; 554121054Semax 555121054Semax default: 556121054Semax return (USAGE); 557121054Semax /* NOT REACHED */ 558121054Semax } 559121054Semax break; 560121054Semax 561121054Semax case 'l': /* LAN Access Using PPP */ 562121054Semax service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP; 563121054Semax break; 564121054Semax 565121054Semax case 'n': /* NAP */ 566121054Semax service = SDP_SERVICE_CLASS_NAP; 567121054Semax break; 568121054Semax 569121054Semax case 'o': /* OBEX Object Push */ 570121054Semax service = SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH; 571121054Semax break; 572121054Semax 573121054Semax case 's': /* Serial Port */ 574121054Semax service = SDP_SERVICE_CLASS_SERIAL_PORT; 575121054Semax break; 576121054Semax 577121054Semax default: 578121054Semax return (USAGE); 579121054Semax /* NOT REACHED */ 580121054Semax } 581121054Semax } else 582124317Semax service = (uint16_t) n; 583121054Semax break; 584121054Semax 585121054Semax default: 586121054Semax return (USAGE); 587121054Semax } 588121054Semax 589121054Semax /* Initialize attribute values array */ 590121054Semax for (n = 0; n < values_len; n ++) { 591121054Semax values[n].flags = SDP_ATTR_INVALID; 592121054Semax values[n].attr = 0; 593121054Semax values[n].vlen = BSIZE; 594121054Semax values[n].value = buffer[n]; 595121054Semax } 596121054Semax 597121054Semax /* Do SDP Service Search Attribute Request */ 598121054Semax n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values); 599121054Semax if (n != 0) 600121054Semax return (ERROR); 601121054Semax 602121054Semax /* Print attributes values */ 603121054Semax for (n = 0; n < values_len; n ++) { 604121054Semax if (values[n].flags != SDP_ATTR_OK) 605121054Semax break; 606121054Semax 607121054Semax switch (values[n].attr) { 608121054Semax case SDP_ATTR_SERVICE_RECORD_HANDLE: 609121054Semax fprintf(stdout, "\n"); 610121054Semax if (values[n].vlen == 5) { 611121054Semax SDP_GET8(type, values[n].value); 612121054Semax if (type == SDP_DATA_UINT32) { 613121054Semax SDP_GET32(value, values[n].value); 614121054Semax fprintf(stdout, "Record Handle: " \ 615121054Semax "%#8.8x\n", value); 616121054Semax } else 617121054Semax fprintf(stderr, "Invalid type=%#x " \ 618121054Semax "Record Handle " \ 619121054Semax "attribute!\n", type); 620121054Semax } else 621121054Semax fprintf(stderr, "Invalid size=%d for Record " \ 622121054Semax "Handle attribute\n", 623121054Semax values[n].vlen); 624121054Semax break; 625121054Semax 626121054Semax case SDP_ATTR_SERVICE_CLASS_ID_LIST: 627121054Semax fprintf(stdout, "Service Class ID List:\n"); 628121054Semax print_service_class_id_list(values[n].value, 629121054Semax values[n].value + values[n].vlen); 630121054Semax break; 631121054Semax 632121054Semax case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: 633121054Semax fprintf(stdout, "Protocol Descriptor List:\n"); 634121054Semax print_protocol_descriptor_list(values[n].value, 635121054Semax values[n].value + values[n].vlen); 636121054Semax break; 637121054Semax 638121054Semax case SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST: 639121054Semax fprintf(stdout, "Bluetooth Profile Descriptor List:\n"); 640121054Semax print_bluetooth_profile_descriptor_list(values[n].value, 641121054Semax values[n].value + values[n].vlen); 642121054Semax break; 643121054Semax 644121054Semax default: 645121054Semax fprintf(stderr, "Unexpected attribute ID=%#4.4x\n", 646121054Semax values[n].attr); 647121054Semax break; 648121054Semax } 649121054Semax } 650121054Semax 651121054Semax return (OK); 652121054Semax} /* do_sdp_search */ 653121054Semax 654121054Semax/* Perform SDP browse command */ 655121054Semaxstatic int 656121054Semaxdo_sdp_browse(void *xs, int argc, char **argv) 657121054Semax{ 658121054Semax#undef _STR 659121054Semax#undef STR 660121054Semax#define _STR(x) #x 661121054Semax#define STR(x) _STR(x) 662121054Semax 663121054Semax static char const * const av[] = { 664121054Semax STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP), 665121054Semax NULL 666121054Semax }; 667121054Semax 668121054Semax switch (argc) { 669121054Semax case 0: 670121054Semax argc = 1; 671121054Semax argv = (char **) av; 672121054Semax /* FALL THROUGH */ 673121054Semax case 1: 674121054Semax return (do_sdp_search(xs, argc, argv)); 675121054Semax } 676121054Semax 677121054Semax return (USAGE); 678121054Semax} /* do_sdp_browse */ 679121054Semax 680121054Semax/* List of SDP commands */ 681121054Semaxstruct sdp_command sdp_commands[] = { 682121054Semax{ 683121054Semax"Browse [<Group>]", 684121054Semax"Browse for services. The <Group> parameter is a 16-bit UUID of the group\n" \ 685121054Semax"to browse. If omitted <Group> is set to Public Browse Group.\n\n" \ 686121054Semax"\t<Group> - xxxx; 16-bit UUID of the group to browse\n", 687121054Semaxdo_sdp_browse 688121054Semax}, 689121054Semax{ 690121054Semax"Search <Service>", 691121054Semax"Search for the <Service>. The <Service> parameter is a 16-bit UUID of the\n" \ 692121054Semax"service to search for. For some services it is possible to use service name\n"\ 693121054Semax"instead of service UUID\n\n" \ 694121054Semax"\t<Service> - xxxx; 16-bit UUID of the service to search for\n\n" \ 695121054Semax"\tKnown service names\n" \ 696121054Semax"\t===================\n" \ 697121054Semax"\tCIP - Common ISDN Access\n" \ 698121054Semax"\tCTP - Cordless Telephony\n" \ 699121054Semax"\tDUN - DialUp Networking\n" \ 700121054Semax"\tFAX - Fax\n" \ 701121054Semax"\tFTRN - OBEX File Transfer\n" \ 702121054Semax"\tGN - GN\n" \ 703121054Semax"\tHID - Human Interface Device\n" \ 704121054Semax"\tHSET - Headset\n" \ 705121054Semax"\tLAN - LAN Access Using PPP\n" \ 706121054Semax"\tNAP - Network Access Point\n" \ 707121054Semax"\tOPUSH - OBEX Object Push\n" \ 708121054Semax"\tSP - Serial Port\n", 709121054Semaxdo_sdp_search 710121054Semax}, 711121054Semax{ NULL, NULL, NULL } 712121054Semax}; 713121054Semax 714