394 lines
11 KiB
Groff
394 lines
11 KiB
Groff
.\" $NetBSD: sdp_data.3,v 1.3 2009/05/21 09:23:50 wiz Exp $
|
|
.\"
|
|
.\" Copyright (c) 2009 The NetBSD Foundation, Inc.
|
|
.\" All rights reserved.
|
|
.\"
|
|
.\" This code is derived from software contributed to The NetBSD Foundation
|
|
.\" by Iain Hibbert.
|
|
.\"
|
|
.\" 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.
|
|
.\"
|
|
.Dd May 7, 2009
|
|
.Dt SDP_DATA 3
|
|
.Os
|
|
.Sh NAME
|
|
.Nm sdp_match_uuid16
|
|
.Nm sdp_get_data
|
|
.Nm sdp_get_attr
|
|
.Nm sdp_get_uuid
|
|
.Nm sdp_get_bool
|
|
.Nm sdp_get_seq
|
|
.Nm sdp_get_alt
|
|
.Nm sdp_get_uint
|
|
.Nm sdp_get_int
|
|
.Nm sdp_get_str
|
|
.Nm sdp_get_url
|
|
.Nm sdp_put_data
|
|
.Nm sdp_put_attr
|
|
.Nm sdp_put_uuid
|
|
.Nm sdp_put_uuid16
|
|
.Nm sdp_put_uuid32
|
|
.Nm sdp_put_uuid128
|
|
.Nm sdp_put_bool
|
|
.Nm sdp_put_uint
|
|
.Nm sdp_put_uint8
|
|
.Nm sdp_put_uint16
|
|
.Nm sdp_put_uint32
|
|
.Nm sdp_put_uint64
|
|
.Nm sdp_put_int
|
|
.Nm sdp_put_int8
|
|
.Nm sdp_put_int16
|
|
.Nm sdp_put_int32
|
|
.Nm sdp_put_int64
|
|
.Nm sdp_put_seq
|
|
.Nm sdp_put_alt
|
|
.Nm sdp_put_str
|
|
.Nm sdp_put_url
|
|
.Nm sdp_set_bool
|
|
.Nm sdp_set_uint
|
|
.Nm sdp_set_int
|
|
.Nm sdp_set_seq
|
|
.Nm sdp_set_alt
|
|
.Nm sdp_data_size
|
|
.Nm sdp_data_type
|
|
.Nm sdp_data_valid
|
|
.Nm sdp_data_print
|
|
.Nd Service Discovery Protocol data manipulation routines
|
|
.Sh LIBRARY
|
|
.Lb libbluetooth
|
|
.Sh SYNOPSIS
|
|
.In sdp.h
|
|
.Vt extern const uuid_t BLUETOOTH_BASE_UUID ;
|
|
.Ft bool
|
|
.Fn sdp_match_uuid16 "sdp_data_t *data" "uint16_t uuid"
|
|
.Ft bool
|
|
.Fn sdp_get_data "sdp_data_t *data" "sdp_data_t *value"
|
|
.Ft bool
|
|
.Fn sdp_get_attr "sdp_data_t *data" "uint16_t *attr" "sdp_data_t *value"
|
|
.Ft bool
|
|
.Fn sdp_get_uuid "sdp_data_t *data" "uuid_t *uuid"
|
|
.Ft bool
|
|
.Fn sdp_get_bool "sdp_data_t *data" "bool *value"
|
|
.Ft bool
|
|
.Fn sdp_get_seq "sdp_data_t *data" "sdp_data_t *seq"
|
|
.Ft bool
|
|
.Fn sdp_get_alt "sdp_data_t *data" "sdp_data_t *alt"
|
|
.Ft bool
|
|
.Fn sdp_get_uint "sdp_data_t *data" "uintmax_t *value"
|
|
.Ft bool
|
|
.Fn sdp_get_int "sdp_data_t *data" "intmax_t *value"
|
|
.Ft bool
|
|
.Fn sdp_get_str "sdp_data_t *data" "char **str" "size_t *length"
|
|
.Ft bool
|
|
.Fn sdp_get_url "sdp_data_t *data" "char **url" "size_t *length"
|
|
.Ft bool
|
|
.Fn sdp_put_data "sdp_data_t *data" "sdp_data_t *value"
|
|
.Ft bool
|
|
.Fn sdp_put_attr "sdp_data_t *data" "uint16_t attr" "sdp_data_t *value"
|
|
.Ft bool
|
|
.Fn sdp_put_uuid "sdp_data_t *data" "const uuid_t *value"
|
|
.Ft bool
|
|
.Fn sdp_put_uuid16 "sdp_data_t *data" "uint16_t value"
|
|
.Ft bool
|
|
.Fn sdp_put_uuid32 "sdp_data_t *data" "uint32_t value"
|
|
.Ft bool
|
|
.Fn sdp_put_uuid128 "sdp_data_t *data" "const uuid_t *value"
|
|
.Ft bool
|
|
.Fn sdp_put_bool "sdp_data_t *data" "bool value"
|
|
.Ft bool
|
|
.Fn sdp_put_uint "sdp_data_t *data" "uintmax_t value"
|
|
.Ft bool
|
|
.Fn sdp_put_uint8 "sdp_data_t *data" "uint8_t value"
|
|
.Ft bool
|
|
.Fn sdp_put_uint16 "sdp_data_t *data" "uint16_t value"
|
|
.Ft bool
|
|
.Fn sdp_put_uint32 "sdp_data_t *data" "uint32_t value"
|
|
.Ft bool
|
|
.Fn sdp_put_int "sdp_data_t *data" "intmax_t value"
|
|
.Ft bool
|
|
.Fn sdp_put_int8 "sdp_data_t *data" "int8_t value"
|
|
.Ft bool
|
|
.Fn sdp_put_int16 "sdp_data_t *data" "int16_t value"
|
|
.Ft bool
|
|
.Fn sdp_put_int32 "sdp_data_t *data" "int32_t value"
|
|
.Ft bool
|
|
.Fn sdp_put_seq "sdp_data_t *data" "ssize_t length"
|
|
.Ft bool
|
|
.Fn sdp_put_alt "sdp_data_t *data" "ssize_t length"
|
|
.Ft bool
|
|
.Fn sdp_put_str "sdp_data_t *data" "const char *str" "ssize_t length"
|
|
.Ft bool
|
|
.Fn sdp_put_url "sdp_data_t *data" "const char *url" "ssize_t length"
|
|
.Ft bool
|
|
.Fn sdp_set_bool "const sdp_data_t *data" "bool value"
|
|
.Ft bool
|
|
.Fn sdp_set_uint "const sdp_data_t *data" "uintmax_t value"
|
|
.Ft bool
|
|
.Fn sdp_set_int "const sdp_data_t *data" "intmax_t value"
|
|
.Ft bool
|
|
.Fn sdp_set_seq "const sdp_data_t *data" "ssize_t length"
|
|
.Ft ssize_t
|
|
.Fn sdp_data_size "const sdp_data_t *data"
|
|
.Ft int
|
|
.Fn sdp_data_type "const sdp_data_t *data"
|
|
.Ft bool
|
|
.Fn sdp_data_valid "const sdp_data_t *data"
|
|
.Ft void
|
|
.Fn sdp_data_print "const sdp_data_t *data" "int indent"
|
|
.Sh DESCRIPTION
|
|
These routines provide for the manipulation of Service Discovery
|
|
Protocol data buffers.
|
|
An SDP data buffer type is defined as:
|
|
.Bd -literal -offset indent
|
|
typedef struct {
|
|
uint8_t *next;
|
|
uint8_t *end;
|
|
} sdp_data_t;
|
|
.Ed
|
|
.Pp
|
|
Where
|
|
.Fa next
|
|
points to the next available byte, and
|
|
.Fa end
|
|
points to the first address past end of the data area, such that
|
|
.Qq end = next + length .
|
|
.Pp
|
|
The SDP data consists of byte streams describing data elements, where
|
|
a data element is a typed data representation consisting of a header
|
|
field and a data field.
|
|
The header field consists of type and size descriptors, and the data
|
|
field is a sequence of bytes whose length is specified in the size
|
|
descriptor and whose content is specified by the type descriptor.
|
|
For instance, the byte sequence
|
|
.Qq 0x09, 0x01, 0x00
|
|
describes an 16-bit unsigned integer element (type 0x09) with
|
|
value of 0x0100.
|
|
.Pp
|
|
Data element types including signed and unsigned integers, boolean,
|
|
string, sequence and alternative lists are defined in the
|
|
.In sdp.h
|
|
include file.
|
|
See the
|
|
.Qq Service Discovery Protocol
|
|
chapters of the
|
|
.Qq Bluetooth Core Specifications
|
|
for more information.
|
|
.Pp
|
|
To reduce the burden of storing and transferring 128-bit UUID values, a
|
|
range of UUID values has been pre-allocated for assignment to often-used,
|
|
registered purposes.
|
|
The first UUID in this pre-allocated range is known as the
|
|
.Qq Bluetooth Base UUID ,
|
|
defined in the
|
|
.Qq Bluetooth Assigned Numbers
|
|
document and declared in
|
|
.In sdp.h
|
|
as
|
|
.Vt const uuid_t BLUETOOTH_BASE_UUID ;
|
|
.Pp
|
|
The data manipulation routines are arranged into major groups
|
|
by function:
|
|
.Bl -hang
|
|
.It The Fn sdp_match_uuid16
|
|
routine examines the next data element in the data buffer for
|
|
an element of type UUID that matches the Bluetooth short alias
|
|
UUID with 16-bit value given.
|
|
If the UUID matches, the function will return
|
|
.Dv true
|
|
and the
|
|
.Fa next
|
|
field of the SDP data buffer will be advanced to the next element.
|
|
Otherwise
|
|
.Dv false
|
|
will be returned.
|
|
.It The Fn sdp_get_xxxx
|
|
routines examine the next data element in the data buffer for an
|
|
element of the given type.
|
|
If the type matches, the function will extract the typed value to
|
|
the address given and advance the
|
|
.Fa next
|
|
field of the SDP data buffer to the next element then return
|
|
.Dv true .
|
|
Otherwise
|
|
.Dv false
|
|
will be returned.
|
|
Note, these functions will not modify the
|
|
.Fa data
|
|
argument unless the correct type was found, and will update the
|
|
.Fa data
|
|
argument first to allow discarding in the case where a
|
|
.Dv sdp_data_t
|
|
was being returned.
|
|
.It The Fn sdp_put_xxxx
|
|
routines will attempt to write a data element of the given type
|
|
and value to the data buffer.
|
|
If the data buffer is too small to contain the encoded data element,
|
|
the function will return
|
|
.Dv false ,
|
|
otherwise
|
|
.Dv true
|
|
will be returned and the
|
|
.Fa next
|
|
field of the SDP data pointer will be advanced.
|
|
In the case of
|
|
.Fn sdp_put_seq
|
|
and
|
|
.Fn sdp_put_alt ,
|
|
the
|
|
.Fa length
|
|
argument may be -1, in which case the generated sequence header will
|
|
describe all the remaining buffer space.
|
|
For
|
|
.Fn sdp_put_str
|
|
and
|
|
.Fn sdp_put_url
|
|
the
|
|
.Fa length
|
|
argument may be -1 in which case the string pointer is treated as
|
|
nul terminated.
|
|
.It The Fn sdp_set_xxxx
|
|
routines examine the SDP data buffer for a data element of the given
|
|
type, and replace the content with the passed value.
|
|
If the next data element in the buffer is not of the appropriate
|
|
type, the function will return
|
|
.Dv false ,
|
|
otherwise
|
|
.Dv true
|
|
will be returned and the value updated.
|
|
In the case of
|
|
.Fn sdp_set_seq
|
|
and
|
|
.Fn sdp_set_alt ,
|
|
the
|
|
.Fa length
|
|
argument may be -1, in which case the sequence header will be
|
|
adjusted to describe the entire data space where possible.
|
|
.It The Fn sdp_data_xxxx
|
|
routines include various functions to provide information about
|
|
the data stream such as
|
|
.Fn sdp_data_size
|
|
to return the size of the next data element, and
|
|
.Fn sdp_data_type
|
|
to return the type of the next data element.
|
|
.Fn sdp_data_valid
|
|
can be used to ensure that the entire data buffer contains
|
|
valid SDP data elements and that all of the elements are contained
|
|
exactly within the data buffer.
|
|
Finally,
|
|
.Fn sdp_data_print
|
|
will print the data buffer in human readable format.
|
|
.El
|
|
.Sh EXAMPLES
|
|
To parse a ServiceAttribute response obtained from a remote server
|
|
using
|
|
.Xr sdp_service_attribute 3 ,
|
|
examining various attribute values:
|
|
.Bd -literal
|
|
sdp_data_t rsp, val;
|
|
uint16_t attr;
|
|
uintmax_t handle;
|
|
|
|
/* rsp contains remote response */
|
|
|
|
/* discard sequence header */
|
|
if (!sdp_get_seq(\*[Am]rsp, \*[Am]rsp))
|
|
err(EXIT_FAILURE, "response is not a sequence");
|
|
|
|
while (sdp_get_attr(\*[Am]rsp, \*[Am]attr, \*[Am]val)) {
|
|
switch(attr) {
|
|
case SDP_ATTR_SERVICE_RECORD_HANDLE:
|
|
sdp_get_uint(\*[Am]val, \*[Am]handle);
|
|
printf("ServiceRecordHandle: 0x%08x\\n", handle);
|
|
break;
|
|
|
|
case SDP_ATTR_PROFILE_DESCRIPTOR_LIST:
|
|
printf("ProfileDescriptorList:\\n");
|
|
sdp_data_print(\*[Am]val, 0);
|
|
break;
|
|
|
|
default:
|
|
printf("uninteresting attribute 0x%04x\\n", attr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
.Ed
|
|
The following code creates a ProtocolDataList attribute value for a service
|
|
using the L2CAP and RFCOMM protocols and illustrates how to construct sequences
|
|
of known and unknown length.
|
|
.Bd -literal
|
|
uint8_t buf[SIZE];
|
|
sdp_data_t seq;
|
|
uint16_t psm;
|
|
uint8_t channel;
|
|
|
|
seq.next = buf;
|
|
seq.end = buf + sizeof(buf);
|
|
sdp_put_seq(\*[Am]seq, -1);
|
|
|
|
sdp_put_seq(\*[Am]seq, 6);
|
|
sdp_put_uuid16(\*[Am]seq, SDP_UUID_PROTOCOL_L2CAP);
|
|
sdp_put_uint16(\*[Am]seq, psm);
|
|
|
|
sdp_put_seq(\*[Am]seq, 5);
|
|
sdp_put_uuid16(\*[Am]seq, SDP_UUID_PROTOCOL_RFCOMM);
|
|
sdp_put_uint8(\*[Am]seq, channel);
|
|
|
|
seq.end = seq.next;
|
|
seq.next = buf;
|
|
sdp_set_seq(\*[Am]seq, -1);
|
|
.Ed
|
|
.Pp
|
|
Note that although
|
|
.Dv SIZE
|
|
is assumed to be large enough to contain the entire sequence
|
|
in this case, the
|
|
.Fn sdp_put_xxxx
|
|
routines will not overflow the buffer area or write partial data.
|
|
.Pp
|
|
The encoded data stream will be stored in a space efficient
|
|
manner where possible.
|
|
In the above example, it is known that the data element sequence
|
|
containing the L2CAP UUID will be 8 bytes long overall since the
|
|
container length of 6 can be stored in a single byte.
|
|
But, because the value of
|
|
.Dv SIZE
|
|
is unknown, the overall length of the ProtocolDataList may vary
|
|
depending if 8, 16 or 32 bits were needed to represent the original
|
|
buffer size.
|
|
.Fn sdp_seq_seq
|
|
will only modify the content, not the size of the header.
|
|
.Sh SEE ALSO
|
|
.Xr sdpquery 1 ,
|
|
.Xr bluetooth 3 ,
|
|
.Xr sdp 3 ,
|
|
.Xr uuid 3 ,
|
|
.Xr sdpd 8
|
|
.Pp
|
|
The
|
|
.Qq Service Discovery Protocol
|
|
section of the Bluetooth Core specifications, available at
|
|
.Qq http://www.bluetooth.com/
|
|
.Sh HISTORY
|
|
These SDP data parsing and manipulation functions first appeared in
|
|
.Nx 6.0 .
|