diff options
author | emax <emax@FreeBSD.org> | 2003-10-12 22:04:24 +0000 |
---|---|---|
committer | emax <emax@FreeBSD.org> | 2003-10-12 22:04:24 +0000 |
commit | 41bb0e8fd2568243020852e22a6d176bccfa60cd (patch) | |
tree | 0ae0c2be63f9f9161693789721b96beb9cabcc77 /usr.sbin/bluetooth/sdpcontrol | |
parent | 66feac7937e372f502539e7d443aee80a25abe16 (diff) | |
download | FreeBSD-src-41bb0e8fd2568243020852e22a6d176bccfa60cd.zip FreeBSD-src-41bb0e8fd2568243020852e22a6d176bccfa60cd.tar.gz |
Update Bluetooth code.
Reviewed by: M. Warner Losh <imp@bsdimp.com>; John Hay <jhay@freebsd.org>
Approved by: M. Warner Losh <imp@bsdimp.com> (mentor)
Diffstat (limited to 'usr.sbin/bluetooth/sdpcontrol')
-rw-r--r-- | usr.sbin/bluetooth/sdpcontrol/Makefile | 12 | ||||
-rw-r--r-- | usr.sbin/bluetooth/sdpcontrol/sdpcontrol.8 | 100 | ||||
-rw-r--r-- | usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c | 197 | ||||
-rw-r--r-- | usr.sbin/bluetooth/sdpcontrol/sdpcontrol.h | 49 | ||||
-rw-r--r-- | usr.sbin/bluetooth/sdpcontrol/search.c | 707 |
5 files changed, 1065 insertions, 0 deletions
diff --git a/usr.sbin/bluetooth/sdpcontrol/Makefile b/usr.sbin/bluetooth/sdpcontrol/Makefile new file mode 100644 index 0000000..c0ec8d4 --- /dev/null +++ b/usr.sbin/bluetooth/sdpcontrol/Makefile @@ -0,0 +1,12 @@ +# $Id: Makefile,v 1.1 2003/09/08 02:27:27 max Exp $ +# $FreeBSD$ + +PROG= sdpcontrol +MAN= sdpcontrol.8 +SRCS= sdpcontrol.c search.c +WARNS?= 2 + +DPADD= ${LIBBLUETOOTH} ${LIBSDP} +LDADD= -lbluetooth -lsdp + +.include <bsd.prog.mk> diff --git a/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.8 b/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.8 new file mode 100644 index 0000000..a7f1f6b --- /dev/null +++ b/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.8 @@ -0,0 +1,100 @@ +.\" Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id: sdpcontrol.8,v 1.1 2003/09/08 02:27:27 max Exp $ +.\" $FreeBSD$ +.\" +.Dd September 7, 2003 +.Dt SDPCONTROL 8 +.Os +.Sh NAME +.Nm spdcontrol +.Nd SDP configuration utility +.Sh SYNOPSIS +.Nm +.Op Fl h +.Fl a Ar BD_ADDR +.Ar command +.Op Ar parameters ... +.Sh DESCRIPTION +The +.Nm +utility connects to the remote device with the specified BD_ADDR and attempts +to send query via Service Discovery Protocol (SDP). +The +.Nm +utility will use Service Search Attribute Request and will print results to +the standard output and error messages to the standard error. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl a Ar BD_ADDR +Connect to the remote device with the specified BD_ADDR. +Example: +.Fl a Li 00:01:02:03:04:05 . +.It Fl h +Display usage message and exit. +.It Ar command +One of the supported commands (see below). +Special command +.Cm help +can be used to obtain the list of all supported commands. +To get more information about specific command use +.Cm help Ar command . +.It Ar parameters +One or more optional space separated command parameters. +.El +.Sh COMMANDS +The currently supported node commands in +.Nm +are: +.Pp +.Bl -tag -offset indent -compact +.It Cm Browse +.It Cm Search +.El +.Sh CAVEAT +Currently, the +.Nm +utility only implements client side functionality. +.Pp +The +.Nm +utility only request the following attributes from the remote SDP server: +.Bl -enum -offset indent -compact +.It +Service Record Handle +.It +Service Class ID List +.It +Protocol Descriptor List +.It +Bluetooth Profile Descriptor List +.El +.Sh DIAGNOSTICS +.Ex -std +.Sh SEE ALSO +.Xr sdp 3 +.Sh AUTHORS +.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com diff --git a/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c b/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c new file mode 100644 index 0000000..b5a1a4d --- /dev/null +++ b/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.c @@ -0,0 +1,197 @@ +/* + * sdpcontrol.c + * + * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: sdpcontrol.c,v 1.1 2003/09/08 02:27:27 max Exp $ + * $FreeBSD$ + */ + +#include <assert.h> +#include <bluetooth.h> +#include <err.h> +#include <errno.h> +#include <sdp.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "sdpcontrol.h" + +/* Prototypes */ +static int do_sdp_command (bdaddr_p, int, char **); +static struct sdp_command * find_sdp_command (char const *, + struct sdp_command *); +static void print_sdp_command (struct sdp_command *); +static void usage (void); + +/* Main */ +int +main(int argc, char *argv[]) +{ + int n; + bdaddr_t bdaddr; + + memset(&bdaddr, 0, sizeof(bdaddr)); + + /* Process command line arguments */ + while ((n = getopt(argc, argv, "a:h")) != -1) { + switch (n) { + case 'a': + if (!bt_aton(optarg, &bdaddr)) { + struct hostent *he = NULL; + + if ((he = bt_gethostbyname(optarg)) == NULL) + errx(1, "%s: %s", optarg, hstrerror(h_errno)); + + memcpy(&bdaddr, he->h_addr, sizeof(bdaddr)); + } + break; + + case 'h': + default: + usage(); + /* NOT REACHED */ + } + } + + argc -= optind; + argv += optind; + + if (*argv == NULL) + usage(); + + return (do_sdp_command(&bdaddr, argc, argv)); +} + +/* Execute commands */ +static int +do_sdp_command(bdaddr_p bdaddr, int argc, char **argv) +{ + char *cmd = argv[0]; + struct sdp_command *c = NULL; + void *xs = NULL; + int e, help; + + help = 0; + if (strcasecmp(cmd, "help") == 0) { + argc --; + argv ++; + + if (argc <= 0) { + fprintf(stdout, "Supported commands:\n"); + print_sdp_command(sdp_commands); + fprintf(stdout, "\nFor more information use " \ + "'help command'\n"); + + return (OK); + } + + help = 1; + cmd = argv[0]; + } + + c = find_sdp_command(cmd, sdp_commands); + if (c == NULL) { + fprintf(stdout, "Unknown command: \"%s\"\n", cmd); + return (ERROR); + } + + if (!help) { + if (memcmp(bdaddr, NG_HCI_BDADDR_ANY, sizeof(*bdaddr)) == 0) + usage(); + + if ((xs = sdp_open(NG_HCI_BDADDR_ANY, bdaddr)) == NULL) + errx(1, "Could not create SDP session object"); + + if (sdp_error(xs) == 0) + e = (c->handler)(xs, -- argc, ++ argv); + else + e = ERROR; + } else + e = USAGE; + + switch (e) { + case OK: + case FAILED: + break; + + case ERROR: + fprintf(stdout, "Could not execute command \"%s\". %s\n", + cmd, strerror(sdp_error(xs))); + break; + + case USAGE: + fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description); + break; + + default: assert(0); break; + } + + sdp_close(xs); + + return (e); +} /* do_sdp_command */ + +/* Try to find command in specified category */ +static struct sdp_command * +find_sdp_command(char const *command, struct sdp_command *category) +{ + struct sdp_command *c = NULL; + + for (c = category; c->command != NULL; c++) { + char *c_end = strchr(c->command, ' '); + + if (c_end != NULL) { + int len = c_end - c->command; + + if (strncasecmp(command, c->command, len) == 0) + return (c); + } else if (strcasecmp(command, c->command) == 0) + return (c); + } + + return (NULL); +} /* find_sdp_command */ + +/* Print commands in specified category */ +static void +print_sdp_command(struct sdp_command *category) +{ + struct sdp_command *c = NULL; + + for (c = category; c->command != NULL; c++) + fprintf(stdout, "\t%s\n", c->command); +} /* print_sdp_command */ + +/* Usage */ +static void +usage(void) +{ + fprintf(stdout, "Usage: sdpcontrol -a BD_ADDR [-h] " \ + "cmd [p1] [..]]\n"); + exit(255); +} /* usage */ + diff --git a/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.h b/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.h new file mode 100644 index 0000000..4a1ee76f --- /dev/null +++ b/usr.sbin/bluetooth/sdpcontrol/sdpcontrol.h @@ -0,0 +1,49 @@ +/* + * sdpcontrol.h + * + * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: sdpcontrol.h,v 1.1 2003/09/08 02:27:27 max Exp $ + * $FreeBSD$ + */ + +#ifndef __SDPCONTROL_H__ +#define __SDPCONTROL_H__ + +#define OK 0 /* everything was OK */ +#define ERROR 1 /* could not execute command */ +#define FAILED 2 /* error was reported */ +#define USAGE 3 /* invalid parameters */ + +struct sdp_command { + char const *command; + char const *description; + int (*handler)(void *, int, char **); +}; + +extern struct sdp_command sdp_commands[]; + +#endif /* __SDPCONTROL_H__ */ + diff --git a/usr.sbin/bluetooth/sdpcontrol/search.c b/usr.sbin/bluetooth/sdpcontrol/search.c new file mode 100644 index 0000000..7180952 --- /dev/null +++ b/usr.sbin/bluetooth/sdpcontrol/search.c @@ -0,0 +1,707 @@ +/* + * search.c + * + * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: search.c,v 1.2 2003/09/08 17:35:15 max Exp $ + * $FreeBSD$ + */ + +#include <bluetooth.h> +#include <ctype.h> +#include <sdp.h> +#include <stdio.h> +#include <stdlib.h> +#include "sdpcontrol.h" + +/* List of the attributes we are looking for */ +static u_int32_t attrs[] = +{ + SDP_ATTR_RANGE( SDP_ATTR_SERVICE_RECORD_HANDLE, + SDP_ATTR_SERVICE_RECORD_HANDLE), + SDP_ATTR_RANGE( SDP_ATTR_SERVICE_CLASS_ID_LIST, + SDP_ATTR_SERVICE_CLASS_ID_LIST), + SDP_ATTR_RANGE( SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST, + SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST), + SDP_ATTR_RANGE( SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST, + SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST) +}; +#define attrs_len (sizeof(attrs)/sizeof(attrs[0])) + +/* Buffer for the attributes */ +#define NRECS 25 /* request this much records from the SDP server */ +#define BSIZE 256 /* one attribute buffer size */ +static u_int8_t buffer[NRECS * attrs_len][BSIZE]; + +/* SDP attributes */ +static sdp_attr_t values[NRECS * attrs_len]; +#define values_len (sizeof(values)/sizeof(values[0])) + +/* + * Print Service Class ID List + * + * The ServiceClassIDList attribute consists of a data element sequence in + * which each data element is a UUID representing the service classes that + * a given service record conforms to. The UUIDs are listed in order from + * the most specific class to the most general class. The ServiceClassIDList + * must contain at least one service class UUID. + */ + +static void +print_service_class_id_list(u_int8_t const *start, u_int8_t const *end) +{ + u_int32_t type, len, value; + + if (end - start < 2) { + fprintf(stderr, "Invalid Service Class ID List. " \ + "Too short, len=%d\n", end - start); + return; + } + + SDP_GET8(type, start); + switch (type) { + case SDP_DATA_SEQ8: + SDP_GET8(len, start); + break; + + case SDP_DATA_SEQ16: + SDP_GET16(len, start); + break; + + case SDP_DATA_SEQ32: + SDP_GET32(len, start); + break; + + default: + fprintf(stderr, "Invalid Service Class ID List. " \ + "Not a sequence, type=%#x\n", type); + return; + /* NOT REACHED */ + } + + while (start < end) { + SDP_GET8(type, start); + switch (type) { + case SDP_DATA_UUID16: + SDP_GET16(value, start); + fprintf(stdout, "\t%s (%#4.4x)\n", + sdp_uuid2desc(value), value); + break; + + case SDP_DATA_UUID32: + SDP_GET32(value, start); + fprintf(stdout, "\t%#8.8x\n", value); + break; + + case SDP_DATA_UUID128: { + int128_t uuid; + + SDP_GET128(&uuid, start); + fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n", + *(u_int32_t *)&uuid.b[0], + *(u_int16_t *)&uuid.b[4], + *(u_int16_t *)&uuid.b[6], + *(u_int16_t *)&uuid.b[8], + *(u_int16_t *)&uuid.b[10], + *(u_int32_t *)&uuid.b[12]); + } break; + + default: + fprintf(stderr, "Invalid Service Class ID List. " \ + "Not a UUID, type=%#x\n", type); + return; + /* NOT REACHED */ + } + } +} /* print_service_class_id_list */ + +/* + * Print Protocol Descriptor List + * + * If the ProtocolDescriptorList describes a single stack, it takes the form + * of a data element sequence in which each element of the sequence is a + * protocol descriptor. Each protocol descriptor is, in turn, a data element + * sequence whose first element is a UUID identifying the protocol and whose + * successive elements are protocol-specific parameters. The protocol + * descriptors are listed in order from the lowest layer protocol to the + * highest layer protocol used to gain access to the service. If it is possible + * for more than one kind of protocol stack to be used to gain access to the + * service, the ProtocolDescriptorList takes the form of a data element + * alternative where each member is a data element sequence as described above. + */ + +static void +print_protocol_descriptor(u_int8_t const *start, u_int8_t const *end) +{ + union { + uint8_t uint8; + uint16_t uint16; + uint32_t uint32; + uint64_t uint64; + int128_t int128; + } value; + u_int32_t type, len, param; + + /* Get Protocol UUID */ + SDP_GET8(type, start); + switch (type) { + case SDP_DATA_UUID16: + SDP_GET16(value.uint16, start); + fprintf(stdout, "\t%s (%#4.4x)\n", sdp_uuid2desc(value.uint16), + value.uint16); + break; + + case SDP_DATA_UUID32: + SDP_GET32(value.uint32, start); + fprintf(stdout, "\t%#8.8x\n", value.uint32); + break; + + case SDP_DATA_UUID128: + SDP_GET128(&value.int128, start); + fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n", + *(u_int32_t *)&value.int128.b[0], + *(u_int16_t *)&value.int128.b[4], + *(u_int16_t *)&value.int128.b[6], + *(u_int16_t *)&value.int128.b[8], + *(u_int16_t *)&value.int128.b[10], + *(u_int32_t *)&value.int128.b[12]); + break; + + default: + fprintf(stderr, "Invalid Protocol Descriptor. " \ + "Not a UUID, type=%#x\n", type); + return; + /* NOT REACHED */ + } + + /* Protocol specific parameters */ + for (param = 1; start < end; param ++) { + fprintf(stdout, "\t\tProtocol specific parameter #%d: ", param); + + SDP_GET8(type, start); + switch (type) { + case SDP_DATA_NIL: + fprintf(stdout, "nil\n"); + break; + + case SDP_DATA_UINT8: + case SDP_DATA_INT8: + case SDP_DATA_BOOL: + SDP_GET8(value.uint8, start); + fprintf(stdout, "u/int8/bool %u\n", value.uint8); + break; + + case SDP_DATA_UINT16: + case SDP_DATA_INT16: + case SDP_DATA_UUID16: + SDP_GET16(value.uint16, start); + fprintf(stdout, "u/int/uuid16 %u\n", value.uint16); + break; + + case SDP_DATA_UINT32: + case SDP_DATA_INT32: + case SDP_DATA_UUID32: + SDP_GET32(value.uint32, start); + fprintf(stdout, "u/int/uuid32 %u\n", value.uint32); + break; + + case SDP_DATA_UINT64: + case SDP_DATA_INT64: + SDP_GET64(value.uint64, start); + fprintf(stdout, "u/int64 %llu\n", value.uint64); + break; + + case SDP_DATA_UINT128: + case SDP_DATA_INT128: + case SDP_DATA_UUID128: + SDP_GET128(&value.int128, start); + fprintf(stdout, "u/int/uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n", + *(u_int32_t *)&value.int128.b[0], + *(u_int16_t *)&value.int128.b[4], + *(u_int16_t *)&value.int128.b[6], + *(u_int16_t *)&value.int128.b[8], + *(u_int16_t *)&value.int128.b[10], + *(u_int32_t *)&value.int128.b[12]); + break; + + case SDP_DATA_STR8: + case SDP_DATA_URL8: + SDP_GET8(len, start); + fprintf(stdout, "%*.*s\n", len, len, (char *) start); + start += len; + break; + + case SDP_DATA_STR16: + case SDP_DATA_URL16: + SDP_GET16(len, start); + fprintf(stdout, "%*.*s\n", len, len, (char *) start); + start += len; + break; + + case SDP_DATA_STR32: + case SDP_DATA_URL32: + SDP_GET32(len, start); + fprintf(stdout, "%*.*s\n", len, len, (char *) start); + start += len; + break; + + case SDP_DATA_SEQ8: + case SDP_DATA_ALT8: + SDP_GET8(len, start); + for (; len > 0; start ++, len --) + fprintf(stdout, "%#2.2x ", *start); + fprintf(stdout, "\n"); + break; + + case SDP_DATA_SEQ16: + case SDP_DATA_ALT16: + SDP_GET16(len, start); + for (; len > 0; start ++, len --) + fprintf(stdout, "%#2.2x ", *start); + fprintf(stdout, "\n"); + break; + + case SDP_DATA_SEQ32: + case SDP_DATA_ALT32: + SDP_GET32(len, start); + for (; len > 0; start ++, len --) + fprintf(stdout, "%#2.2x ", *start); + fprintf(stdout, "\n"); + break; + + default: + fprintf(stderr, "Invalid Protocol Descriptor. " \ + "Unknown data type: %#02x\n", type); + return; + /* NOT REACHED */ + } + } +} /* print_protocol_descriptor */ + +static void +print_protocol_descriptor_list(u_int8_t const *start, u_int8_t const *end) +{ + u_int32_t type, len; + + if (end - start < 2) { + fprintf(stderr, "Invalid Protocol Descriptor List. " \ + "Too short, len=%d\n", end - start); + return; + } + + SDP_GET8(type, start); + switch (type) { + case SDP_DATA_SEQ8: + SDP_GET8(len, start); + break; + + case SDP_DATA_SEQ16: + SDP_GET16(len, start); + break; + + case SDP_DATA_SEQ32: + SDP_GET32(len, start); + break; + + default: + fprintf(stderr, "Invalid Protocol Descriptor List. " \ + "Not a sequence, type=%#x\n", type); + return; + /* NOT REACHED */ + } + + while (start < end) { + SDP_GET8(type, start); + switch (type) { + case SDP_DATA_SEQ8: + SDP_GET8(len, start); + break; + + case SDP_DATA_SEQ16: + SDP_GET16(len, start); + break; + + case SDP_DATA_SEQ32: + SDP_GET32(len, start); + break; + + default: + fprintf(stderr, "Invalid Protocol Descriptor List. " \ + "Not a sequence, type=%#x\n", type); + return; + /* NOT REACHED */ + } + + print_protocol_descriptor(start, start + len); + start += len; + } +} /* print_protocol_descriptor_list */ + +/* + * Print Bluetooth Profile Descriptor List + * + * The BluetoothProfileDescriptorList attribute consists of a data element + * sequence in which each element is a profile descriptor that contains + * information about a Bluetooth profile to which the service represented by + * this service record conforms. Each profile descriptor is a data element + * sequence whose first element is the UUID assigned to the profile and whose + * second element is a 16-bit profile version number. Each version of a profile + * is assigned a 16-bit unsigned integer profile version number, which consists + * of two 8-bit fields. The higher-order 8 bits contain the major version + * number field and the lower-order 8 bits contain the minor version number + * field. + */ + +static void +print_bluetooth_profile_descriptor_list(u_int8_t const *start, u_int8_t const *end) +{ + u_int32_t type, len, value; + + if (end - start < 2) { + fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \ + "Too short, len=%d\n", end - start); + return; + } + + SDP_GET8(type, start); + switch (type) { + case SDP_DATA_SEQ8: + SDP_GET8(len, start); + break; + + case SDP_DATA_SEQ16: + SDP_GET16(len, start); + break; + + case SDP_DATA_SEQ32: + SDP_GET32(len, start); + break; + + default: + fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \ + "Not a sequence, type=%#x\n", type); + return; + /* NOT REACHED */ + } + + while (start < end) { + SDP_GET8(type, start); + switch (type) { + case SDP_DATA_SEQ8: + SDP_GET8(len, start); + break; + + case SDP_DATA_SEQ16: + SDP_GET16(len, start); + break; + + case SDP_DATA_SEQ32: + SDP_GET32(len, start); + break; + + default: + fprintf(stderr, "Invalid Bluetooth Profile " \ + "Descriptor List. " \ + "Not a sequence, type=%#x\n", type); + return; + /* NOT REACHED */ + } + + /* Get UUID */ + SDP_GET8(type, start); + switch (type) { + case SDP_DATA_UUID16: + SDP_GET16(value, start); + fprintf(stdout, "\t%s (%#4.4x) ", + sdp_uuid2desc(value), value); + break; + + case SDP_DATA_UUID32: + SDP_GET32(value, start); + fprintf(stdout, "\t%#8.8x ", value); + break; + + case SDP_DATA_UUID128: { + int128_t uuid; + + SDP_GET128(&uuid, start); + fprintf(stdout, "\t%#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x ", + *(u_int32_t *)&uuid.b[0], + *(u_int16_t *)&uuid.b[4], + *(u_int16_t *)&uuid.b[6], + *(u_int16_t *)&uuid.b[8], + *(u_int16_t *)&uuid.b[10], + *(u_int32_t *)&uuid.b[12]); + } break; + + default: + fprintf(stderr, "Invalid Bluetooth Profile " \ + "Descriptor List. " \ + "Not a UUID, type=%#x\n", type); + return; + /* NOT REACHED */ + } + + /* Get version */ + SDP_GET8(type, start); + if (type != SDP_DATA_UINT16) { + fprintf(stderr, "Invalid Bluetooth Profile " \ + "Descriptor List. " \ + "Invalid version type=%#x\n", type); + return; + } + + SDP_GET16(value, start); + fprintf(stdout, "ver. %d.%d\n", + (value >> 8) & 0xff, value & 0xff); + } +} /* print_bluetooth_profile_descriptor_list */ + +/* Perform SDP search command */ +static int +do_sdp_search(void *xs, int argc, char **argv) +{ + char *ep = NULL; + int32_t n, type, value; + u_int16_t service; + + /* Parse command line arguments */ + switch (argc) { + case 1: + n = strtoul(argv[0], &ep, 16); + if (*ep != 0) { + switch (tolower(argv[0][0])) { + case 'c': /* CIP/CTP */ + switch (tolower(argv[0][1])) { + case 'i': + service = SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS; + break; + + case 't': + service = SDP_SERVICE_CLASS_CORDLESS_TELEPHONY; + break; + + default: + return (USAGE); + /* NOT REACHED */ + } + break; + + case 'd': /* DialUp Networking */ + service = SDP_SERVICE_CLASS_DIALUP_NETWORKING; + break; + + case 'f': /* Fax/OBEX File Transfer */ + switch (tolower(argv[0][1])) { + case 'a': + service = SDP_SERVICE_CLASS_FAX; + break; + + case 't': + service = SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER; + break; + + default: + return (USAGE); + /* NOT REACHED */ + } + break; + + case 'g': /* GN */ + service = SDP_SERVICE_CLASS_GN; + break; + + case 'h': /* Headset/HID */ + switch (tolower(argv[0][1])) { + case 'i': + service = SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE; + break; + + case 's': + service = SDP_SERVICE_CLASS_HEADSET; + break; + + default: + return (USAGE); + /* NOT REACHED */ + } + break; + + case 'l': /* LAN Access Using PPP */ + service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP; + break; + + case 'n': /* NAP */ + service = SDP_SERVICE_CLASS_NAP; + break; + + case 'o': /* OBEX Object Push */ + service = SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH; + break; + + case 's': /* Serial Port */ + service = SDP_SERVICE_CLASS_SERIAL_PORT; + break; + + default: + return (USAGE); + /* NOT REACHED */ + } + } else + service = (u_int16_t) n; + break; + + default: + return (USAGE); + } + + if (service < SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER) + return (USAGE); + + /* Initialize attribute values array */ + for (n = 0; n < values_len; n ++) { + values[n].flags = SDP_ATTR_INVALID; + values[n].attr = 0; + values[n].vlen = BSIZE; + values[n].value = buffer[n]; + } + + /* Do SDP Service Search Attribute Request */ + n = sdp_search(xs, 1, &service, attrs_len, attrs, values_len, values); + if (n != 0) + return (ERROR); + + /* Print attributes values */ + for (n = 0; n < values_len; n ++) { + if (values[n].flags != SDP_ATTR_OK) + break; + + switch (values[n].attr) { + case SDP_ATTR_SERVICE_RECORD_HANDLE: + fprintf(stdout, "\n"); + if (values[n].vlen == 5) { + SDP_GET8(type, values[n].value); + if (type == SDP_DATA_UINT32) { + SDP_GET32(value, values[n].value); + fprintf(stdout, "Record Handle: " \ + "%#8.8x\n", value); + } else + fprintf(stderr, "Invalid type=%#x " \ + "Record Handle " \ + "attribute!\n", type); + } else + fprintf(stderr, "Invalid size=%d for Record " \ + "Handle attribute\n", + values[n].vlen); + break; + + case SDP_ATTR_SERVICE_CLASS_ID_LIST: + fprintf(stdout, "Service Class ID List:\n"); + print_service_class_id_list(values[n].value, + values[n].value + values[n].vlen); + break; + + case SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST: + fprintf(stdout, "Protocol Descriptor List:\n"); + print_protocol_descriptor_list(values[n].value, + values[n].value + values[n].vlen); + break; + + case SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST: + fprintf(stdout, "Bluetooth Profile Descriptor List:\n"); + print_bluetooth_profile_descriptor_list(values[n].value, + values[n].value + values[n].vlen); + break; + + default: + fprintf(stderr, "Unexpected attribute ID=%#4.4x\n", + values[n].attr); + break; + } + } + + return (OK); +} /* do_sdp_search */ + +/* Perform SDP browse command */ +static int +do_sdp_browse(void *xs, int argc, char **argv) +{ +#undef _STR +#undef STR +#define _STR(x) #x +#define STR(x) _STR(x) + + static char const * const av[] = { + STR(SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP), + NULL + }; + + switch (argc) { + case 0: + argc = 1; + argv = (char **) av; + /* FALL THROUGH */ + case 1: + return (do_sdp_search(xs, argc, argv)); + } + + return (USAGE); +} /* do_sdp_browse */ + +/* List of SDP commands */ +struct sdp_command sdp_commands[] = { +{ +"Browse [<Group>]", +"Browse for services. The <Group> parameter is a 16-bit UUID of the group\n" \ +"to browse. If omitted <Group> is set to Public Browse Group.\n\n" \ +"\t<Group> - xxxx; 16-bit UUID of the group to browse\n", +do_sdp_browse +}, +{ +"Search <Service>", +"Search for the <Service>. The <Service> parameter is a 16-bit UUID of the\n" \ +"service to search for. For some services it is possible to use service name\n"\ +"instead of service UUID\n\n" \ +"\t<Service> - xxxx; 16-bit UUID of the service to search for\n\n" \ +"\tKnown service names\n" \ +"\t===================\n" \ +"\tCIP - Common ISDN Access\n" \ +"\tCTP - Cordless Telephony\n" \ +"\tDUN - DialUp Networking\n" \ +"\tFAX - Fax\n" \ +"\tFTRN - OBEX File Transfer\n" \ +"\tGN - GN\n" \ +"\tHID - Human Interface Device\n" \ +"\tHSET - Headset\n" \ +"\tLAN - LAN Access Using PPP\n" \ +"\tNAP - Network Access Point\n" \ +"\tOPUSH - OBEX Object Push\n" \ +"\tSP - Serial Port\n", +do_sdp_search +}, +{ NULL, NULL, NULL } +}; + |