summaryrefslogtreecommitdiffstats
path: root/lib/libsdp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libsdp')
-rw-r--r--lib/libsdp/Makefile36
-rw-r--r--lib/libsdp/sdp-int.h62
-rw-r--r--lib/libsdp/sdp.3415
-rw-r--r--lib/libsdp/sdp.h677
-rw-r--r--lib/libsdp/search.c421
-rw-r--r--lib/libsdp/service.c237
-rw-r--r--lib/libsdp/session.c177
-rw-r--r--lib/libsdp/util.c457
8 files changed, 2482 insertions, 0 deletions
diff --git a/lib/libsdp/Makefile b/lib/libsdp/Makefile
new file mode 100644
index 0000000..5f205c8
--- /dev/null
+++ b/lib/libsdp/Makefile
@@ -0,0 +1,36 @@
+# $Id: Makefile,v 1.2 2003/09/07 20:34:19 max Exp $
+# $FreeBSD$
+
+LIB= sdp
+MAN= sdp.3
+
+WARNS?= 2
+CFLAGS+= -I${.CURDIR}
+
+SHLIB_MAJOR= 3
+
+SRCS= search.c service.c session.c util.c
+INCS= sdp.h
+
+MLINKS+= sdp.3 SDP_GET8.3
+MLINKS+= sdp.3 SDP_GET16.3
+MLINKS+= sdp.3 SDP_GET32.3
+MLINKS+= sdp.3 SDP_GET64.3
+MLINKS+= sdp.3 SDP_GET128.3
+MLINKS+= sdp.3 SDP_PUT8.3
+MLINKS+= sdp.3 SDP_PUT16.3
+MLINKS+= sdp.3 SDP_PUT32.3
+MLINKS+= sdp.3 SDP_PUT64.3
+MLINKS+= sdp.3 SDP_PUT128.3
+MLINKS+= sdp.3 sdp_open.3
+MLINKS+= sdp.3 sdp_open_local.3
+MLINKS+= sdp.3 sdp_close.3
+MLINKS+= sdp.3 sdp_error.3
+MLINKS+= sdp.3 sdp_search.3
+MLINKS+= sdp.3 sdp_attr2desc.3
+MLINKS+= sdp.3 sdp_uuid2desc.3
+MLINKS+= sdp.3 sdp_register_service.3
+MLINKS+= sdp.3 sdp_unregister_service.3
+MLINKS+= sdp.3 sdp_change_service.3
+
+.include <bsd.lib.mk>
diff --git a/lib/libsdp/sdp-int.h b/lib/libsdp/sdp-int.h
new file mode 100644
index 0000000..d8a064d
--- /dev/null
+++ b/lib/libsdp/sdp-int.h
@@ -0,0 +1,62 @@
+/*
+ * sdp-int.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: sdp-int.h,v 1.1 2003/09/01 23:01:07 max Exp $
+ * $FreeBSD$
+ */
+
+#ifndef _SDP_INT_H_
+#define _SDP_INT_H_
+
+__BEGIN_DECLS
+
+/*
+ * SDP session
+ */
+
+struct sdp_session {
+ uint16_t flags;
+#define SDP_SESSION_LOCAL (1 << 0)
+ uint16_t tid; /* current session transaction ID (tid) */
+ uint16_t omtu; /* outgoing MTU (req buffer size) */
+ uint16_t imtu; /* incoming MTU (rsp buffer size) */
+ uint8_t *req; /* request buffer (start) */
+ uint8_t *req_e; /* request buffer (end) */
+ uint8_t *rsp; /* response buffer (start) */
+ uint8_t *rsp_e; /* response buffer (end) */
+ uint32_t cslen; /* continuation state length */
+ uint8_t cs[16];/* continuation state */
+ int32_t s; /* L2CAP socket */
+ int32_t error; /* last error code */
+};
+typedef struct sdp_session sdp_session_t;
+typedef struct sdp_session * sdp_session_p;
+
+__END_DECLS
+
+#endif /* ndef _SDP_INT_H_ */
+
diff --git a/lib/libsdp/sdp.3 b/lib/libsdp/sdp.3
new file mode 100644
index 0000000..c51b6f9
--- /dev/null
+++ b/lib/libsdp/sdp.3
@@ -0,0 +1,415 @@
+.\" 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: sdp.3,v 1.1 2003/09/07 20:34:19 max Exp $
+.\" $FreeBSD$
+.\"
+.Dd May 27, 2005
+.Dt SDP 3
+.Os
+.Sh NAME
+.Nm SDP_GET8 ,
+.Nm SDP_GET16 ,
+.Nm SDP_GET32 ,
+.Nm SDP_GET64 ,
+.Nm SDP_GET128 ,
+.Nm SDP_GET_UUID128 ,
+.Nm SDP_PUT8 ,
+.Nm SDP_PUT16 ,
+.Nm SDP_PUT32 ,
+.Nm SDP_PUT64 ,
+.Nm SDP_PUT128 ,
+.Nm SDP_PUT_UUID128 ,
+.Nm sdp_open ,
+.Nm sdp_open_local ,
+.Nm sdp_close ,
+.Nm sdp_error ,
+.Nm sdp_search ,
+.Nm sdp_attr2desc ,
+.Nm sdp_uuid2desc
+.Nd Bluetooth SDP routines
+.Sh LIBRARY
+.Lb libsdp
+.Sh SYNOPSIS
+.In bluetooth.h
+.In sdp.h
+.Fn SDP_GET8 "b" "cp"
+.Fn SDP_GET16 "s" "cp"
+.Fn SDP_GET32 "l" "cp"
+.Fn SDP_GET64 "l" "cp"
+.Fn SDP_GET128 "l" "cp"
+.Fn SDP_GET_UUID128 "l" "cp"
+.Fn SDP_PUT8 "b" "cp"
+.Fn SDP_PUT16 "s" "cp"
+.Fn SDP_PUT32 "l" "cp"
+.Fn SDP_PUT64 "l" "cp"
+.Fn SDP_PUT128 "l" "cp"
+.Fn SDP_PUT_UUID128 "l" "cp"
+.Ft "void *"
+.Fn sdp_open "bdaddr_t const *l" "bdaddr_t const *r"
+.Ft "void *"
+.Fn sdp_open_local "char const *control"
+.Ft int32_t
+.Fn sdp_close "void *xs"
+.Ft int32_t
+.Fn sdp_error "void *xs"
+.Ft int32_t
+.Fo sdp_search
+.Fa "void *xs" "uint32_t plen" "uint16_t const *pp" "uint32_t alen"
+.Fa "uint32_t const *ap" "uint32_t vlen" "sdp_attr_t *vp"
+.Fc
+.Ft "char const * const"
+.Fn sdp_attr2desc "uint16_t attr"
+.Ft "char const * const"
+.Fn sdp_uuid2desc "uint16_t uuid"
+.Ft int32_t
+.Fo sdp_register_service
+.Fa "void *xss" "uint16_t uuid" "bdaddr_p const bdaddr" "uint8_t const *data"
+.Fa "uint32_t datalen" "uint32_t *handle"
+.Fc
+.Ft int32_t
+.Fn sdp_unregister_service "void *xss" "uint32_t handle"
+.Ft int32_t
+.Fo sdp_change_service
+.Fa "void *xss" "uint32_t handle" "uint8_t const *data" "uint32_t datalen"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn SDP_GET8 ,
+.Fn SDP_GET16 ,
+.Fn SDP_GET32 ,
+.Fn SDP_GET64
+and
+.Fn SDP_GET128
+macros are used to get byte, short, long, long long and 128-bit integer
+from the buffer pointed by
+.Fa cp
+pointer.
+The pointer is automatically advanced.
+.Pp
+The
+.Fn SDP_PUT8 ,
+.Fn SDP_PUT16 ,
+.Fn SDP_PUT32 ,
+.Fn SDP_PUT64
+and
+.Fn SDP_PUT128
+macros are used to put byte, short, long, long long and 128-bit integer
+into the buffer pointed by
+.Fa cp
+pointer.
+The pointer is automatically advanced.
+.Pp
+.Fn SDP_GET_UUID128
+and
+.Fn SDP_PUT_UUID128
+macros are used to get and put 128-bit UUID into the buffer pointed by
+.Fa cp
+pointer.
+The pointer is automatically advanced.
+.Pp
+The
+.Fn sdp_open
+and
+.Fn sdp_open_local
+functions each return a pointer to an opaque object describing SDP session.
+The
+.Fa l
+argument passed to
+.Fn sdp_open
+function should point to a source BD_ADDR.
+If source BD_ADDR is
+.Dv NULL
+then source address
+.Dv NG_HCI_BDADDR_ANY
+is used.
+The
+.Fa r
+argument passed to
+.Fn sdp_open
+function should point to a
+.Pf non- Dv NULL
+remote BD_ADDR.
+Remote BD_ADDR cannot be
+.Dv NG_HCI_BDADDR_ANY .
+The
+.Fn sdp_open_local
+function takes path to the control socket and opens a connection to a local
+SDP server.
+If path to the control socket is
+.Dv NULL
+then default
+.Pa /var/run/sdp
+path will be used.
+.Pp
+The
+.Fn sdp_close
+function terminates active SDP session and deletes SDP session object.
+The
+.Fa xs
+parameter should point to a valid SDP session object created with
+.Fn sdp_open
+or
+.Fn sdp_open_local .
+.Pp
+The
+.Fn sdp_error
+function returns last error that is stored inside SDP session object.
+The
+.Fa xs
+parameter should point to a valid SDP session object created with
+.Fn sdp_open
+or
+.Fn sdp_open_local .
+The error value returned can be converted to a human readable message by
+calling
+.Xr strerror 3
+function.
+.Pp
+The
+.Fn sdp_search
+function is used to perform SDP Service Search Attribute Request.
+The
+.Fa xs
+parameter should point to a valid SDP session object created with
+.Fn sdp_open
+or
+.Fn sdp_open_local .
+The
+.Fa pp
+parameter is a Service Search Pattern - an array of one or more Service
+Class IDs.
+The maximum number of Service Class IDs in the array is 12.
+The
+.Fa plen
+parameter is the length of the Service Search pattern.
+The
+.Fa ap
+parameter is an Attribute ID Range List - an array of one or more SDP Attribute
+ID Range.
+Each attribute ID Range is encoded as a 32-bit unsigned integer data
+element, where the high order 16 bits are interpreted as the beginning
+attribute ID of the range and the low order 16 bits are interpreted as the
+ending attribute ID of the range.
+The attribute IDs contained in the Attribute ID Ranges List must be listed in
+ascending order without duplication of any attribute ID values.
+Note that all attributes may be requested by specifying a range of
+0x0000-0xFFFF.
+The
+.Fa alen
+parameter is the length of the Attribute ID Ranges List.
+The
+.Fn SDP_ATTR_RANGE "lo" "hi"
+macro can be used to prepare Attribute ID Range.
+The
+.Fa vp
+parameter should be an array of
+.Vt sdp_attr_t
+structures.
+Each
+.Vt sdp_attr_t
+structure describes single SDP attribute and defined as follows:
+.Bd -literal -offset indent
+struct sdp_attr {
+ uint16_t flags;
+#define SDP_ATTR_OK (0 << 0)
+#define SDP_ATTR_INVALID (1 << 0)
+#define SDP_ATTR_TRUNCATED (1 << 1)
+ uint16_t attr; /* SDP_ATTR_xxx */
+ uint32_t vlen; /* length of the value[] in bytes */
+ uint8_t *value; /* base pointer */
+};
+typedef struct sdp_attr sdp_attr_t;
+typedef struct sdp_attr * sdp_attr_p;
+.Ed
+.Pp
+The caller of the
+.Fn sdp_search
+function is expected to prepare the array of
+.Vt sdp_attr
+structures and for each element of the array both
+.Va vlen
+and
+.Va value
+must be set.
+The
+.Fn sdp_search
+function will fill each
+.Vt sdp_attr_t
+structure with attribute and value, i.e., it will set
+.Va flags ,
+.Va attr
+and
+.Va vlen
+fields.
+The actual value of the attribute will be copied into
+.Va value
+buffer.
+Note: attributes are returned in the order they appear in the Service Search
+Attribute Response.
+SDP server could return several attributes for the same record.
+In this case the order of the attributes will be: all attributes for the first
+records, then all attributes for the secord record etc.
+.Pp
+The
+.Fn sdp_attr2desc
+and
+.Fn sdp_uuid2desc
+functions each take a numeric attribute ID/UUID value and convert it to a
+human readable description.
+.Pp
+The
+.Fn sdp_register_service
+function
+is used to register service with the local SDP server.
+The
+.Fa xss
+parameter should point to a valid SDP session object obtained from
+.Fn sdp_open_local .
+The
+.Fa uuid
+parameter is a SDP Service Class ID for the service to be registered.
+The
+.Fa bdaddr
+parameter should point to a valid BD_ADDR.
+The service will be only advertised if request was received by the local device
+with
+.Fa bdaddr .
+If
+.Fa bdaddr
+is set to
+.Dv NG_HCI_BDADDR_ANY
+then the service will be advertised to any remote devices that queries for it.
+The
+.Fa data
+and
+.Fa datalen
+parameters specify data and size of the data for the service.
+Upon successful return
+.Fn sdp_register_service
+will populate
+.Fa handle
+with the SDP record handle.
+This parameter is optional and can be set to
+.Dv NULL .
+.Pp
+The
+.Fn sdp_unregister_service
+function
+is used to unregister service with the local SDP server.
+The
+.Fa xss
+parameter should point to a valid SDP session object obtained from
+.Fn sdp_open_local .
+The
+.Fa handle
+parameter should contain a valid SDP record handle of the service to be
+unregistered.
+.Pp
+The
+.Fn sdp_change_service
+function is used to change data associated with the existing service on
+the local SDP server.
+The
+.Fa xss
+parameter should point to a valid SDP session object obtained from
+.Fn sdp_open_local .
+The
+.Fa handle
+parameter should contain a valid SDP record handle of the service to be changed.
+The
+.Fa data
+and
+.Fa datalen
+parameters specify data and size of the data for the service.
+.Sh CAVEAT
+When registering services with the local SDP server the application must
+keep the SDP session open.
+If SDP session is closed then the local SDP server will remove all services
+that were registered over the session.
+The application is allowed to change or unregister service if it was registered
+over the same session.
+.Sh EXAMPLES
+The following example shows how to get
+.Dv SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST
+attribute for the
+.Dv SDP_SERVICE_CLASS_SERIAL_PORT
+service from the remote device.
+.Bd -literal -offset indent
+bdaddr_t remote;
+uint8_t buffer[1024];
+void *ss = NULL;
+uint16_t serv = SDP_SERVICE_CLASS_SERIAL_PORT;
+uint32_t attr = SDP_ATTR_RANGE(
+ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
+sdp_attr_t proto = { SDP_ATTR_INVALID,0,sizeof(buffer),buffer };
+
+/* Obtain/set remote BDADDR here */
+
+if ((ss = sdp_open(NG_HCI_BDADDR_ANY, remote)) == NULL)
+ /* exit ENOMEM */
+if (sdp_error(ss) != 0)
+ /* exit sdp_error(ss) */
+
+if (sdp_search(ss, 1, &serv, 1, &attr, 1, &proto) != 0)
+ /* exit sdp_error(ss) */
+
+if (proto.flags != SDP_ATTR_OK)
+ /* exit see proto.flags for details */
+
+/* If we got here then we have attribute value in proto.value */
+.Ed
+.Sh DIAGNOSTICS
+Both
+.Fn sdp_open
+and
+.Fn sdp_open_local
+will return
+.Dv NULL
+if memory allocation for the new SDP session object fails.
+If the new SDP object was created then caller is still expected to call
+.Fn sdp_error
+to check if there was connection error.
+.Pp
+The
+.Fn sdp_search ,
+.Fn sdp_register_service ,
+.Fn sdp_unregister_service
+and
+.Fn sdp_change_service
+functions return non-zero value on error.
+The caller is expected to call
+.Fn sdp_error
+to find out more about error.
+.Sh SEE ALSO
+.Xr bluetooth 3 ,
+.Xr strerror 3 ,
+.Xr sdpcontrol 8 ,
+.Xr sdpd 8
+.Sh AUTHORS
+.An Maksim Yevmenkin Aq m_evmenkin@yahoo.com
+.Sh BUGS
+Most likely.
+Please report bugs if found.
diff --git a/lib/libsdp/sdp.h b/lib/libsdp/sdp.h
new file mode 100644
index 0000000..8d78ae8
--- /dev/null
+++ b/lib/libsdp/sdp.h
@@ -0,0 +1,677 @@
+/*
+ * sdp.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: sdp.h,v 1.3 2003/09/05 00:33:59 max Exp $
+ * $FreeBSD$
+ */
+
+#ifndef _SDP_H_
+#define _SDP_H_
+
+__BEGIN_DECLS
+
+/*
+ * Data representation (page 349)
+ */
+
+/* Nil, the null type */
+#define SDP_DATA_NIL 0x00
+
+/* Unsigned integer */
+#define SDP_DATA_UINT8 0x08
+#define SDP_DATA_UINT16 0x09
+#define SDP_DATA_UINT32 0x0A
+#define SDP_DATA_UINT64 0x0B
+#define SDP_DATA_UINT128 0x0C
+
+/* Signed two's-complement integer */
+#define SDP_DATA_INT8 0x10
+#define SDP_DATA_INT16 0x11
+#define SDP_DATA_INT32 0x12
+#define SDP_DATA_INT64 0x13
+#define SDP_DATA_INT128 0x14
+
+/* UUID, a universally unique identifier */
+#define SDP_DATA_UUID16 0x19
+#define SDP_DATA_UUID32 0x1A
+#define SDP_DATA_UUID128 0x1C
+
+/* Text string */
+#define SDP_DATA_STR8 0x25
+#define SDP_DATA_STR16 0x26
+#define SDP_DATA_STR32 0x27
+
+/* Boolean */
+#define SDP_DATA_BOOL 0x28
+
+/*
+ * Data element sequence.
+ * A data element whose data field is a sequence of data elements
+ */
+#define SDP_DATA_SEQ8 0x35
+#define SDP_DATA_SEQ16 0x36
+#define SDP_DATA_SEQ32 0x37
+
+/*
+ * Data element alternative.
+ * A data element whose data field is a sequence of data elements from
+ * which one data element is to be selected.
+ */
+#define SDP_DATA_ALT8 0x3D
+#define SDP_DATA_ALT16 0x3E
+#define SDP_DATA_ALT32 0x3F
+
+/* URL, a uniform resource locator */
+#define SDP_DATA_URL8 0x45
+#define SDP_DATA_URL16 0x46
+#define SDP_DATA_URL32 0x47
+
+/*
+ * Protocols UUID (short) https://www.bluetooth.org/assigned-numbers/service_discovery.php
+ * BASE UUID 00000000-0000-1000-8000-00805F9B34FB
+ */
+
+#define SDP_UUID_PROTOCOL_SDP 0x0001
+#define SDP_UUID_PROTOCOL_UDP 0x0002
+#define SDP_UUID_PROTOCOL_RFCOMM 0x0003
+#define SDP_UUID_PROTOCOL_TCP 0x0004
+#define SDP_UUID_PROTOCOL_TCS_BIN 0x0005
+#define SDP_UUID_PROTOCOL_TCS_AT 0x0006
+#define SDP_UUID_PROTOCOL_OBEX 0x0008
+#define SDP_UUID_PROTOCOL_IP 0x0009
+#define SDP_UUID_PROTOCOL_FTP 0x000A
+#define SDP_UUID_PROTOCOL_HTTP 0x000C
+#define SDP_UUID_PROTOCOL_WSP 0x000E
+#define SDP_UUID_PROTOCOL_BNEP 0x000F
+#define SDP_UUID_PROTOCOL_UPNP 0x0010
+#define SDP_UUID_PROTOCOL_HIDP 0x0011
+#define SDP_UUID_PROTOCOL_HARDCOPY_CONTROL_CHANNEL 0x0012
+#define SDP_UUID_PROTOCOL_HARDCOPY_DATA_CHANNEL 0x0014
+#define SDP_UUID_PROTOCOL_HARDCOPY_NOTIFICATION 0x0016
+#define SDP_UUID_PROTOCOL_AVCTP 0x0017
+#define SDP_UUID_PROTOCOL_AVDTP 0x0019
+#define SDP_UUID_PROTOCOL_CMPT 0x001B
+#define SDP_UUID_PROTOCOL_UDI_C_PLANE 0x001D
+#define SDP_UUID_PROTOCOL_L2CAP 0x0100
+
+/*
+ * Service class IDs https://www.bluetooth.org/assigned-numbers/service_discovery.php
+ */
+
+#define SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER 0x1000
+#define SDP_SERVICE_CLASS_BROWSE_GROUP_DESCRIPTOR 0x1001
+#define SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP 0x1002
+#define SDP_SERVICE_CLASS_SERIAL_PORT 0x1101
+#define SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP 0x1102
+#define SDP_SERVICE_CLASS_DIALUP_NETWORKING 0x1103
+#define SDP_SERVICE_CLASS_IR_MC_SYNC 0x1104
+#define SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH 0x1105
+#define SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER 0x1106
+#define SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND 0x1107
+#define SDP_SERVICE_CLASS_HEADSET 0x1108
+#define SDP_SERVICE_CLASS_CORDLESS_TELEPHONY 0x1109
+#define SDP_SERVICE_CLASS_AUDIO_SOURCE 0x110A
+#define SDP_SERVICE_CLASS_AUDIO_SINK 0x110B
+#define SDP_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET 0x110C
+#define SDP_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION 0x110D
+#define SDP_SERVICE_CLASS_AV_REMOTE_CONTROL 0x110E
+#define SDP_SERVICE_CLASS_VIDEO_CONFERENCING 0x110F
+#define SDP_SERVICE_CLASS_INTERCOM 0x1110
+#define SDP_SERVICE_CLASS_FAX 0x1111
+#define SDP_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY 0x1112
+#define SDP_SERVICE_CLASS_WAP 0x1113
+#define SDP_SERVICE_CLASS_WAP_CLIENT 0x1114
+#define SDP_SERVICE_CLASS_PANU 0x1115
+#define SDP_SERVICE_CLASS_NAP 0x1116
+#define SDP_SERVICE_CLASS_GN 0x1117
+#define SDP_SERVICE_CLASS_DIRECT_PRINTING 0x1118
+#define SDP_SERVICE_CLASS_REFERENCE_PRINTING 0x1119
+#define SDP_SERVICE_CLASS_IMAGING 0x111A
+#define SDP_SERVICE_CLASS_IMAGING_RESPONDER 0x111B
+#define SDP_SERVICE_CLASS_IMAGING_AUTOMATIC_ARCHIVE 0x111C
+#define SDP_SERVICE_CLASS_IMAGING_REFERENCED_OBJECTS 0x111D
+#define SDP_SERVICE_CLASS_HANDSFREE 0x111E
+#define SDP_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY 0x111F
+#define SDP_SERVICE_CLASS_DIRECT_PRINTING_REFERENCE_OBJECTS 0x1120
+#define SDP_SERVICE_CLASS_REFLECTED_UI 0x1121
+#define SDP_SERVICE_CLASS_BASIC_PRINTING 0x1122
+#define SDP_SERVICE_CLASS_PRINTING_STATUS 0x1123
+#define SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE 0x1124
+#define SDP_SERVICE_CLASS_HARDCOPY_CABLE_REPLACEMENT 0x1125
+#define SDP_SERVICE_CLASS_HCR_PRINT 0x1126
+#define SDP_SERVICE_CLASS_HCR_SCAN 0x1127
+#define SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS 0x1128
+#define SDP_SERVICE_CLASS_VIDEO_CONFERENCING_GW 0x1129
+#define SDP_SERVICE_CLASS_UDI_MT 0x112A
+#define SDP_SERVICE_CLASS_UDI_TA 0x112B
+#define SDP_SERVICE_CLASS_AUDIO_VIDEO 0x112C
+#define SDP_SERVICE_CLASS_SIM_ACCESS 0x112D
+#define SDP_SERVICE_CLASS_PHONEBOOK_ACCESS_PCE 0x112E
+#define SDP_SERVICE_CLASS_PHONEBOOK_ACCESS_PSE 0x112F
+#define SDP_SERVICE_CLASS_PHONEBOOK_ACCESS 0x1130
+#define SDP_SERVICE_CLASS_PNP_INFORMATION 0x1200
+#define SDP_SERVICE_CLASS_GENERIC_NETWORKING 0x1201
+#define SDP_SERVICE_CLASS_GENERIC_FILE_TRANSFER 0x1202
+#define SDP_SERVICE_CLASS_GENERIC_AUDIO 0x1203
+#define SDP_SERVICE_CLASS_GENERIC_TELEPHONY 0x1204
+#define SDP_SERVICE_CLASS_UPNP 0x1205
+#define SDP_SERVICE_CLASS_UPNP_IP 0x1206
+#define SDP_SERVICE_CLASS_ESDP_UPNP_IP_PAN 0x1300
+#define SDP_SERVICE_CLASS_ESDP_UPNP_IP_LAP 0x1301
+#define SDP_SERVICE_CLASS_ESDP_UPNP_L2CAP 0x1302
+#define SDP_SERVICE_CLASS_VIDEO_SOURCE 0x1303
+#define SDP_SERVICE_CLASS_VIDEO_SINK 0x1304
+#define SDP_SERVICE_CLASS_VIDEO_DISTRIBUTION 0x1305
+
+/*
+ * Universal attribute definitions (page 366) and
+ * https://www.bluetooth.org/assigned-numbers/service_discovery.php
+ */
+
+#define SDP_ATTR_RANGE(lo, hi) \
+ (uint32_t)(((uint16_t)(lo) << 16) | ((uint16_t)(hi)))
+
+#define SDP_ATTR_SERVICE_RECORD_HANDLE 0x0000
+#define SDP_ATTR_SERVICE_CLASS_ID_LIST 0x0001
+#define SDP_ATTR_SERVICE_RECORD_STATE 0x0002
+#define SDP_ATTR_SERVICE_ID 0x0003
+#define SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST 0x0004
+#define SDP_ATTR_BROWSE_GROUP_LIST 0x0005
+#define SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST 0x0006
+#define SDP_ATTR_SERVICE_INFO_TIME_TO_LIVE 0x0007
+#define SDP_ATTR_SERVICE_AVAILABILITY 0x0008
+#define SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST 0x0009
+#define SDP_ATTR_DOCUMENTATION_URL 0x000A
+#define SDP_ATTR_CLIENT_EXECUTABLE_URL 0x000B
+#define SDP_ATTR_ICON_URL 0x000C
+#define SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS 0x000D
+#define SDP_ATTR_GROUP_ID 0x0200
+#define SDP_ATTR_IP_SUBNET 0x0200
+#define SDP_ATTR_VERSION_NUMBER_LIST 0x0200
+#define SDP_ATTR_SERVICE_DATABASE_STATE 0x0201
+#define SDP_ATTR_SERVICE_VERSION 0x0300
+#define SDP_ATTR_EXTERNAL_NETWORK 0x0301
+#define SDP_ATTR_NETWORK 0x0301
+#define SDP_ATTR_SUPPORTED_DATA_STORES_LIST 0x0301
+#define SDP_ATTR_FAX_CLASS1_SUPPORT 0x0302
+#define SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL 0x0302
+#define SDP_ATTR_FAX_CLASS20_SUPPORT 0x0303
+#define SDP_ATTR_SUPPORTED_FORMATS_LIST 0x0303
+#define SDP_ATTR_FAX_CLASS2_SUPPORT 0x0304
+#define SDP_ATTR_AUDIO_FEEDBACK_SUPPORT 0x0305
+#define SDP_ATTR_NETWORK_ADDRESS 0x0306
+#define SDP_ATTR_WAP_GATEWAY 0x0307
+#define SDP_ATTR_HOME_PAGE_URL 0x0308
+#define SDP_ATTR_WAP_STACK_TYPE 0x0309
+#define SDP_ATTR_SECURITY_DESCRIPTION 0x030A
+#define SDP_ATTR_NET_ACCESS_TYPE 0x030B
+#define SDP_ATTR_MAX_NET_ACCESS_RATE 0x030C
+#define SDP_ATTR_IPV4_SUBNET 0x030D
+#define SDP_ATTR_IPV6_SUBNET 0x030E
+#define SDP_ATTR_SUPPORTED_CAPABALITIES 0x0310
+#define SDP_ATTR_SUPPORTED_FEATURES 0x0311
+#define SDP_ATTR_SUPPORTED_FUNCTIONS 0x0312
+#define SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY 0x0313
+#define SDP_ATTR_SUPPORTED_REPOSITORIES 0x0314
+
+/*
+ * The offset must be added to the attribute ID base (contained in the
+ * LANGUAGE_BASE_ATTRIBUTE_ID_LIST attribute) in order to compute the
+ * attribute ID for these attributes.
+ */
+
+#define SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID 0x0100
+#define SDP_ATTR_SERVICE_NAME_OFFSET 0x0000
+#define SDP_ATTR_SERVICE_DESCRIPTION_OFFSET 0x0001
+#define SDP_ATTR_PROVIDER_NAME_OFFSET 0x0002
+
+/*
+ * Protocol data unit (PDU) format (page 352)
+ */
+
+#define SDP_PDU_ERROR_RESPONSE 0x01
+#define SDP_PDU_SERVICE_SEARCH_REQUEST 0x02
+#define SDP_PDU_SERVICE_SEARCH_RESPONSE 0x03
+#define SDP_PDU_SERVICE_ATTRIBUTE_REQUEST 0x04
+#define SDP_PDU_SERVICE_ATTRIBUTE_RESPONSE 0x05
+#define SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST 0x06
+#define SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_RESPONSE 0x07
+
+struct sdp_pdu {
+ uint8_t pid; /* PDU ID - SDP_PDU_xxx */
+ uint16_t tid; /* transaction ID */
+ uint16_t len; /* parameters length (in bytes) */
+} __attribute__ ((packed));
+typedef struct sdp_pdu sdp_pdu_t;
+typedef struct sdp_pdu * sdp_pdu_p;
+
+/*
+ * Error codes for SDP_PDU_ERROR_RESPONSE
+ */
+
+#define SDP_ERROR_CODE_INVALID_SDP_VERSION 0x0001
+#define SDP_ERROR_CODE_INVALID_SERVICE_RECORD_HANDLE 0x0002
+#define SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX 0x0003
+#define SDP_ERROR_CODE_INVALID_PDU_SIZE 0x0004
+#define SDP_ERROR_CODE_INVALID_CONTINUATION_STATE 0x0005
+#define SDP_ERROR_CODE_INSUFFICIENT_RESOURCES 0x0006
+
+/*
+ * SDP int128/uint128 parameter
+ */
+
+struct int128 {
+ int8_t b[16];
+};
+typedef struct int128 int128_t;
+typedef struct int128 uint128_t;
+
+/*
+ * SDP attribute
+ */
+
+struct sdp_attr {
+ uint16_t flags;
+#define SDP_ATTR_OK (0 << 0)
+#define SDP_ATTR_INVALID (1 << 0)
+#define SDP_ATTR_TRUNCATED (1 << 1)
+ uint16_t attr; /* SDP_ATTR_xxx */
+ uint32_t vlen; /* length of the value[] in bytes */
+ uint8_t *value; /* base pointer */
+};
+typedef struct sdp_attr sdp_attr_t;
+typedef struct sdp_attr * sdp_attr_p;
+
+/******************************************************************************
+ * User interface
+ *****************************************************************************/
+
+/* Inline versions of get/put byte/short/long. Pointer is advanced */
+#define SDP_GET8(b, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ (b) = *t_cp; \
+ (cp) ++; \
+}
+
+#define SDP_GET16(s, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ (s) = ((uint16_t)t_cp[0] << 8) \
+ | ((uint16_t)t_cp[1]) \
+ ; \
+ (cp) += 2; \
+}
+
+#define SDP_GET32(l, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ (l) = ((uint32_t)t_cp[0] << 24) \
+ | ((uint32_t)t_cp[1] << 16) \
+ | ((uint32_t)t_cp[2] << 8) \
+ | ((uint32_t)t_cp[3]) \
+ ; \
+ (cp) += 4; \
+}
+
+#define SDP_GET64(l, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ (l) = ((uint64_t)t_cp[0] << 56) \
+ | ((uint64_t)t_cp[1] << 48) \
+ | ((uint64_t)t_cp[2] << 40) \
+ | ((uint64_t)t_cp[3] << 32) \
+ | ((uint64_t)t_cp[4] << 24) \
+ | ((uint64_t)t_cp[5] << 16) \
+ | ((uint64_t)t_cp[6] << 8) \
+ | ((uint64_t)t_cp[7]) \
+ ; \
+ (cp) += 8; \
+}
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define SDP_GET128(l, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ (l)->b[15] = *t_cp++; \
+ (l)->b[14] = *t_cp++; \
+ (l)->b[13] = *t_cp++; \
+ (l)->b[12] = *t_cp++; \
+ (l)->b[11] = *t_cp++; \
+ (l)->b[10] = *t_cp++; \
+ (l)->b[9] = *t_cp++; \
+ (l)->b[8] = *t_cp++; \
+ (l)->b[7] = *t_cp++; \
+ (l)->b[6] = *t_cp++; \
+ (l)->b[5] = *t_cp++; \
+ (l)->b[4] = *t_cp++; \
+ (l)->b[3] = *t_cp++; \
+ (l)->b[2] = *t_cp++; \
+ (l)->b[1] = *t_cp++; \
+ (l)->b[0] = *t_cp++; \
+ (cp) += 16; \
+}
+
+#define SDP_GET_UUID128(l, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ (l)->b[0] = *t_cp++; \
+ (l)->b[1] = *t_cp++; \
+ (l)->b[2] = *t_cp++; \
+ (l)->b[3] = *t_cp++; \
+ (l)->b[4] = *t_cp++; \
+ (l)->b[5] = *t_cp++; \
+ (l)->b[6] = *t_cp++; \
+ (l)->b[7] = *t_cp++; \
+ (l)->b[8] = *t_cp++; \
+ (l)->b[9] = *t_cp++; \
+ (l)->b[10] = *t_cp++; \
+ (l)->b[11] = *t_cp++; \
+ (l)->b[12] = *t_cp++; \
+ (l)->b[13] = *t_cp++; \
+ (l)->b[14] = *t_cp++; \
+ (l)->b[15] = *t_cp++; \
+ (cp) += 16; \
+}
+#elif BYTE_ORDER == BIG_ENDIAN
+#define SDP_GET128(l, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ (l)->b[0] = *t_cp++; \
+ (l)->b[1] = *t_cp++; \
+ (l)->b[2] = *t_cp++; \
+ (l)->b[3] = *t_cp++; \
+ (l)->b[4] = *t_cp++; \
+ (l)->b[5] = *t_cp++; \
+ (l)->b[6] = *t_cp++; \
+ (l)->b[7] = *t_cp++; \
+ (l)->b[8] = *t_cp++; \
+ (l)->b[9] = *t_cp++; \
+ (l)->b[10] = *t_cp++; \
+ (l)->b[11] = *t_cp++; \
+ (l)->b[12] = *t_cp++; \
+ (l)->b[13] = *t_cp++; \
+ (l)->b[14] = *t_cp++; \
+ (l)->b[15] = *t_cp++; \
+ (cp) += 16; \
+}
+
+#define SDP_GET_UUID128(l, cp) SDP_GET128(l, cp)
+#else
+#error "Unsupported BYTE_ORDER"
+#endif /* BYTE_ORDER */
+
+#define SDP_PUT8(b, cp) { \
+ register uint8_t t_b = (uint8_t)(b); \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ *t_cp = t_b; \
+ (cp) ++; \
+}
+
+#define SDP_PUT16(s, cp) { \
+ register uint16_t t_s = (uint16_t)(s); \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ *t_cp++ = t_s >> 8; \
+ *t_cp = t_s; \
+ (cp) += 2; \
+}
+
+#define SDP_PUT32(l, cp) { \
+ register uint32_t t_l = (uint32_t)(l); \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ *t_cp++ = t_l >> 24; \
+ *t_cp++ = t_l >> 16; \
+ *t_cp++ = t_l >> 8; \
+ *t_cp = t_l; \
+ (cp) += 4; \
+}
+
+#define SDP_PUT64(l, cp) { \
+ register uint64_t t_l = (uint64_t)(l); \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ *t_cp++ = t_l >> 56; \
+ *t_cp++ = t_l >> 48; \
+ *t_cp++ = t_l >> 40; \
+ *t_cp++ = t_l >> 32; \
+ *t_cp++ = t_l >> 24; \
+ *t_cp++ = t_l >> 16; \
+ *t_cp++ = t_l >> 8; \
+ *t_cp = t_l; \
+ (cp) += 8; \
+}
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define SDP_PUT128(l, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ *t_cp++ = (l)->b[15]; \
+ *t_cp++ = (l)->b[14]; \
+ *t_cp++ = (l)->b[13]; \
+ *t_cp++ = (l)->b[12]; \
+ *t_cp++ = (l)->b[11]; \
+ *t_cp++ = (l)->b[10]; \
+ *t_cp++ = (l)->b[9]; \
+ *t_cp++ = (l)->b[8]; \
+ *t_cp++ = (l)->b[7]; \
+ *t_cp++ = (l)->b[6]; \
+ *t_cp++ = (l)->b[5]; \
+ *t_cp++ = (l)->b[4]; \
+ *t_cp++ = (l)->b[3]; \
+ *t_cp++ = (l)->b[2]; \
+ *t_cp++ = (l)->b[1]; \
+ *t_cp = (l)->b[0]; \
+ (cp) += 16; \
+}
+
+#define SDP_PUT_UUID128(l, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ *t_cp++ = (l)->b[0]; \
+ *t_cp++ = (l)->b[1]; \
+ *t_cp++ = (l)->b[2]; \
+ *t_cp++ = (l)->b[3]; \
+ *t_cp++ = (l)->b[4]; \
+ *t_cp++ = (l)->b[5]; \
+ *t_cp++ = (l)->b[6]; \
+ *t_cp++ = (l)->b[7]; \
+ *t_cp++ = (l)->b[8]; \
+ *t_cp++ = (l)->b[9]; \
+ *t_cp++ = (l)->b[10]; \
+ *t_cp++ = (l)->b[11]; \
+ *t_cp++ = (l)->b[12]; \
+ *t_cp++ = (l)->b[13]; \
+ *t_cp++ = (l)->b[14]; \
+ *t_cp = (l)->b[15]; \
+ (cp) += 16; \
+}
+#elif BYTE_ORDER == BIG_ENDIAN
+#define SDP_PUT128(l, cp) { \
+ register uint8_t *t_cp = (uint8_t *)(cp); \
+ *t_cp++ = (l)->b[0]; \
+ *t_cp++ = (l)->b[1]; \
+ *t_cp++ = (l)->b[2]; \
+ *t_cp++ = (l)->b[3]; \
+ *t_cp++ = (l)->b[4]; \
+ *t_cp++ = (l)->b[5]; \
+ *t_cp++ = (l)->b[6]; \
+ *t_cp++ = (l)->b[7]; \
+ *t_cp++ = (l)->b[8]; \
+ *t_cp++ = (l)->b[9]; \
+ *t_cp++ = (l)->b[10]; \
+ *t_cp++ = (l)->b[11]; \
+ *t_cp++ = (l)->b[12]; \
+ *t_cp++ = (l)->b[13]; \
+ *t_cp++ = (l)->b[14]; \
+ *t_cp = (l)->b[15]; \
+ (cp) += 16; \
+}
+
+#define SDP_PUT_UUID128(l, cp) SDP_PUT128(l, cp)
+#else
+#error "Unsupported BYTE_ORDER"
+#endif /* BYTE_ORDER */
+
+void * sdp_open (bdaddr_t const *l, bdaddr_t const *r);
+void * sdp_open_local (char const *control);
+int32_t sdp_close (void *xs);
+int32_t sdp_error (void *xs);
+
+int32_t sdp_search (void *xs,
+ uint32_t plen, uint16_t const *pp,
+ uint32_t alen, uint32_t const *ap,
+ uint32_t vlen, sdp_attr_t *vp);
+
+char const * sdp_attr2desc (uint16_t attr);
+char const * sdp_uuid2desc (uint16_t uuid);
+void sdp_print (uint32_t level, uint8_t const *start,
+ uint8_t const *end);
+
+/******************************************************************************
+ * sdpd interface and Bluetooth profiles data
+ *****************************************************************************/
+
+#define SDP_LOCAL_PATH "/var/run/sdp"
+#define SDP_LOCAL_MTU 4096
+
+/*
+ * These are NOT defined in spec and only accepted on control sockets.
+ * The response to these request always will be SDP_PDU_ERROR_RESPONSE.
+ * The first 2 bytes (after PDU header) is an error code (in network
+ * byte order). The rest of the data (pdu->len - 2) is a response data
+ * and depend on the request.
+ *
+ * SDP_PDU_SERVICE_REGISTER_REQUEST
+ * pdu_header_t hdr;
+ * u_int16_t uuid; service class UUID (network byte order)
+ * bdaddr_t bdaddr; local BD_ADDR (or ANY)
+ * profile data[pdu->len - sizeof(uuid) - sizeof(bdaddr)]
+ *
+ * in successful reponse additional data will contain 4 bytes record handle
+ *
+ *
+ * SDP_PDU_SERVICE_UNREGISTER_REQUEST
+ * pdu_header_t hdr;
+ * u_int32_t record_handle; (network byte order)
+ *
+ * no additional data in response.
+ *
+ *
+ * SDP_PDU_SERVICE_CHANGE_REQUEST
+ * pdu_header_t hdr;
+ * u_int32_t record_handle; (network byte order)
+ * profile data[pdu->len - sizeof(record_handle)]
+ *
+ * no additional data in response.
+ */
+
+#define SDP_PDU_SERVICE_REGISTER_REQUEST 0x81
+#define SDP_PDU_SERVICE_UNREGISTER_REQUEST 0x82
+#define SDP_PDU_SERVICE_CHANGE_REQUEST 0x83
+
+struct sdp_dun_profile
+{
+ uint8_t server_channel;
+ uint8_t audio_feedback_support;
+ uint8_t reserved[2];
+};
+typedef struct sdp_dun_profile sdp_dun_profile_t;
+typedef struct sdp_dun_profile * sdp_dun_profile_p;
+
+struct sdp_ftrn_profile
+{
+ uint8_t server_channel;
+ uint8_t reserved[3];
+};
+typedef struct sdp_ftrn_profile sdp_ftrn_profile_t;
+typedef struct sdp_ftrn_profile * sdp_ftrn_profile_p;
+
+/* Keep this in sync with sdp_opush_profile */
+struct sdp_irmc_profile
+{
+ uint8_t server_channel;
+ uint8_t supported_formats_size;
+ uint8_t supported_formats[30];
+};
+typedef struct sdp_irmc_profile sdp_irmc_profile_t;
+typedef struct sdp_irmc_profile * sdp_irmc_profile_p;
+
+struct sdp_irmc_command_profile
+{
+ uint8_t server_channel;
+ uint8_t reserved[3];
+};
+typedef struct sdp_irmc_command_profile sdp_irmc_command_profile_t;
+typedef struct sdp_irmc_command_profile * sdp_irmc_command_profile_p;
+
+struct sdp_lan_profile
+{
+ uint8_t server_channel;
+ uint8_t load_factor;
+ uint8_t reserved;
+ uint8_t ip_subnet_radius;
+ uint32_t ip_subnet;
+};
+typedef struct sdp_lan_profile sdp_lan_profile_t;
+typedef struct sdp_lan_profile * sdp_lan_profile_p;
+
+/* Keep this in sync with sdp_irmc_profile */
+struct sdp_opush_profile
+{
+ uint8_t server_channel;
+ uint8_t supported_formats_size;
+ uint8_t supported_formats[30];
+};
+typedef struct sdp_opush_profile sdp_opush_profile_t;
+typedef struct sdp_opush_profile * sdp_opush_profile_p;
+
+struct sdp_sp_profile
+{
+ uint8_t server_channel;
+ uint8_t reserved[3];
+};
+typedef struct sdp_sp_profile sdp_sp_profile_t;
+typedef struct sdp_sp_profile * sdp_sp_profile_p;
+
+struct sdp_nap_profile
+{
+ uint16_t security_description; /* HBO: NAP/GN */
+ uint16_t net_access_type; /* HBO: NAP */
+ uint32_t max_net_access_rate; /* HBO: NAP */
+};
+typedef struct sdp_nap_profile sdp_nap_profile_t;
+typedef struct sdp_nap_profile * sdp_nap_profile_p;
+
+/* Reuse struct sdp_nap_profile for GN */
+typedef struct sdp_nap_profile sdp_gn_profile_t;
+typedef struct sdp_nap_profile * sdp_gn_profile_p;
+
+/* Reuse struct sdp_nap_profile for PANU */
+typedef struct sdp_nap_profile sdp_panu_profile_t;
+typedef struct sdp_nap_profile * sdp_panu_profile_p;
+
+int32_t sdp_register_service (void *xss, uint16_t uuid,
+ bdaddr_p const bdaddr, uint8_t const *data,
+ uint32_t datalen, uint32_t *handle);
+int32_t sdp_unregister_service (void *xss, uint32_t handle);
+int32_t sdp_change_service (void *xss, uint32_t handle,
+ uint8_t const *data, uint32_t datalen);
+
+__END_DECLS
+
+#endif /* ndef _SDP_H_ */
+
diff --git a/lib/libsdp/search.c b/lib/libsdp/search.c
new file mode 100644
index 0000000..868fbe5
--- /dev/null
+++ b/lib/libsdp/search.c
@@ -0,0 +1,421 @@
+/*
+ * 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/04 22:12:13 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sdp-int.h>
+#include <sdp.h>
+
+int32_t
+sdp_search(void *xss,
+ uint32_t plen, uint16_t const *pp,
+ uint32_t alen, uint32_t const *ap,
+ uint32_t vlen, sdp_attr_t *vp)
+{
+ struct sdp_xpdu {
+ sdp_pdu_t pdu;
+ uint16_t len;
+ } __attribute__ ((packed)) xpdu;
+
+ sdp_session_p ss = (sdp_session_p) xss;
+ uint8_t *req = NULL, *rsp = NULL, *rsp_tmp = NULL;
+ int32_t t, len;
+ uint16_t lo, hi;
+
+ if (ss == NULL)
+ return (-1);
+
+ if (ss->req == NULL || ss->rsp == NULL ||
+ plen == 0 || pp == NULL || alen == 0 || ap == NULL) {
+ ss->error = EINVAL;
+ return (-1);
+ }
+
+ req = ss->req;
+
+ /* Calculate ServiceSearchPattern length */
+ plen = plen * (sizeof(pp[0]) + 1);
+
+ /* Calculate AttributeIDList length */
+ for (len = 0, t = 0; t < alen; t ++) {
+ lo = (uint16_t) (ap[t] >> 16);
+ hi = (uint16_t) (ap[t]);
+
+ if (lo > hi) {
+ ss->error = EINVAL;
+ return (-1);
+ }
+
+ if (lo != hi)
+ len += (sizeof(ap[t]) + 1);
+ else
+ len += (sizeof(lo) + 1);
+ }
+ alen = len;
+
+ /* Calculate length of the request */
+ len = plen + sizeof(uint8_t) + sizeof(uint16_t) +
+ /* ServiceSearchPattern */
+ sizeof(uint16_t) +
+ /* MaximumAttributeByteCount */
+ alen + sizeof(uint8_t) + sizeof(uint16_t);
+ /* AttributeIDList */
+
+ if (ss->req_e - req < len) {
+ ss->error = ENOBUFS;
+ return (-1);
+ }
+
+ /* Put ServiceSearchPattern */
+ SDP_PUT8(SDP_DATA_SEQ16, req);
+ SDP_PUT16(plen, req);
+ for (; plen > 0; pp ++, plen -= (sizeof(pp[0]) + 1)) {
+ SDP_PUT8(SDP_DATA_UUID16, req);
+ SDP_PUT16(*pp, req);
+ }
+
+ /* Put MaximumAttributeByteCount */
+ SDP_PUT16(0xffff, req);
+
+ /* Put AttributeIDList */
+ SDP_PUT8(SDP_DATA_SEQ16, req);
+ SDP_PUT16(alen, req);
+ for (; alen > 0; ap ++) {
+ lo = (uint16_t) (*ap >> 16);
+ hi = (uint16_t) (*ap);
+
+ if (lo != hi) {
+ /* Put attribute range */
+ SDP_PUT8(SDP_DATA_UINT32, req);
+ SDP_PUT32(*ap, req);
+ alen -= (sizeof(ap[0]) + 1);
+ } else {
+ /* Put attribute */
+ SDP_PUT8(SDP_DATA_UINT16, req);
+ SDP_PUT16(lo, req);
+ alen -= (sizeof(lo) + 1);
+ }
+ }
+
+ /* Submit ServiceSearchAttributeRequest and wait for response */
+ ss->cslen = 0;
+ rsp = ss->rsp;
+
+ do {
+ struct iovec iov[2];
+ uint8_t *req_cs = req;
+
+ /* Add continuation state (if any) */
+ if (ss->req_e - req_cs < ss->cslen + 1) {
+ ss->error = ENOBUFS;
+ return (-1);
+ }
+
+ SDP_PUT8(ss->cslen, req_cs);
+ if (ss->cslen > 0) {
+ memcpy(req_cs, ss->cs, ss->cslen);
+ req_cs += ss->cslen;
+ }
+
+ /* Prepare SDP PDU header */
+ xpdu.pdu.pid = SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST;
+ xpdu.pdu.tid = htons(ss->tid);
+ xpdu.pdu.len = htons(req_cs - ss->req);
+
+ /* Submit request */
+ iov[0].iov_base = (void *) &xpdu;
+ iov[0].iov_len = sizeof(xpdu.pdu);
+ iov[1].iov_base = (void *) ss->req;
+ iov[1].iov_len = req_cs - ss->req;
+
+ do {
+ len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ ss->error = errno;
+ return (-1);
+ }
+
+ /* Read response */
+ iov[0].iov_base = (void *) &xpdu;
+ iov[0].iov_len = sizeof(xpdu);
+ iov[1].iov_base = (void *) rsp;
+ iov[1].iov_len = ss->imtu;
+
+ do {
+ len = readv(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ ss->error = errno;
+ return (-1);
+ }
+ if (len < sizeof(xpdu)) {
+ ss->error = ENOMSG;
+ return (-1);
+ }
+
+ xpdu.pdu.tid = ntohs(xpdu.pdu.tid);
+ xpdu.pdu.len = ntohs(xpdu.pdu.len);
+ xpdu.len = ntohs(xpdu.len);
+
+ if (xpdu.pdu.pid == SDP_PDU_ERROR_RESPONSE ||
+ xpdu.pdu.tid != ss->tid ||
+ xpdu.pdu.len > len ||
+ xpdu.len > xpdu.pdu.len) {
+ ss->error = EIO;
+ return (-1);
+ }
+
+ rsp += xpdu.len;
+ ss->tid ++;
+
+ /* Save continuation state (if any) */
+ ss->cslen = rsp[0];
+ if (ss->cslen > 0) {
+ if (ss->cslen > sizeof(ss->cs)) {
+ ss->error = ENOBUFS;
+ return (-1);
+ }
+
+ memcpy(ss->cs, rsp + 1, ss->cslen);
+
+ /*
+ * Ensure that we always have ss->imtu bytes
+ * available in the ss->rsp buffer
+ */
+
+ if (ss->rsp_e - rsp <= ss->imtu) {
+ uint32_t size, offset;
+
+ size = ss->rsp_e - ss->rsp + ss->imtu;
+ offset = rsp - ss->rsp;
+
+ rsp_tmp = realloc(ss->rsp, size);
+ if (rsp_tmp == NULL) {
+ ss->error = ENOMEM;
+ return (-1);
+ }
+
+ ss->rsp = rsp_tmp;
+ ss->rsp_e = ss->rsp + size;
+ rsp = ss->rsp + offset;
+ }
+ }
+ } while (ss->cslen > 0);
+
+ /*
+ * If we got here then we have completed SDP transaction and now
+ * we must populate attribute values into vp array. At this point
+ * ss->rsp points to the beginning of the response and rsp points
+ * to the end of the response.
+ *
+ * From Bluetooth v1.1 spec page 364
+ *
+ * The AttributeLists is a data element sequence where each element
+ * in turn is a data element sequence representing an attribute list.
+ * Each attribute list contains attribute IDs and attribute values
+ * from one service record. The first element in each attribute list
+ * contains the attribute ID of the first attribute to be returned for
+ * that service record. The second element in each attribute list
+ * contains the corresponding attribute value. Successive pairs of
+ * elements in each attribute list contain additional attribute ID
+ * and value pairs. Only attributes that have non-null values within
+ * the service record and whose attribute IDs were specified in the
+ * SDP_ServiceSearchAttributeRequest are contained in the AttributeLists
+ * Neither an attribute ID nor attribute value is placed in
+ * AttributeLists for attributes in the service record that have no
+ * value. Within each attribute list, the attributes are listed in
+ * ascending order of attribute ID value.
+ */
+
+ if (vp == NULL)
+ goto done;
+
+ rsp_tmp = ss->rsp;
+
+ /* Skip the first SEQ */
+ SDP_GET8(t, rsp_tmp);
+ switch (t) {
+ case SDP_DATA_SEQ8:
+ SDP_GET8(len, rsp_tmp);
+ break;
+
+ case SDP_DATA_SEQ16:
+ SDP_GET16(len, rsp_tmp);
+ break;
+
+ case SDP_DATA_SEQ32:
+ SDP_GET32(len, rsp_tmp);
+ break;
+
+ default:
+ ss->error = ENOATTR;
+ return (-1);
+ /* NOT REACHED */
+ }
+
+ for (; rsp_tmp < rsp && vlen > 0; ) {
+ /* Get set of attributes for the next record */
+ SDP_GET8(t, rsp_tmp);
+ switch (t) {
+ case SDP_DATA_SEQ8:
+ SDP_GET8(len, rsp_tmp);
+ break;
+
+ case SDP_DATA_SEQ16:
+ SDP_GET16(len, rsp_tmp);
+ break;
+
+ case SDP_DATA_SEQ32:
+ SDP_GET32(len, rsp_tmp);
+ break;
+
+ default:
+ ss->error = ENOATTR;
+ return (-1);
+ /* NOT REACHED */
+ }
+
+ /* Now rsp_tmp points to list of (attr,value) pairs */
+ for (; len > 0 && vlen > 0; vp ++, vlen --) {
+ /* Attribute */
+ SDP_GET8(t, rsp_tmp);
+ if (t != SDP_DATA_UINT16) {
+ ss->error = ENOATTR;
+ return (-1);
+ }
+ SDP_GET16(vp->attr, rsp_tmp);
+
+ /* Attribute value */
+ switch (rsp_tmp[0]) {
+ case SDP_DATA_NIL:
+ alen = 0;
+ break;
+
+ case SDP_DATA_UINT8:
+ case SDP_DATA_INT8:
+ case SDP_DATA_BOOL:
+ alen = sizeof(uint8_t);
+ break;
+
+ case SDP_DATA_UINT16:
+ case SDP_DATA_INT16:
+ case SDP_DATA_UUID16:
+ alen = sizeof(uint16_t);
+ break;
+
+ case SDP_DATA_UINT32:
+ case SDP_DATA_INT32:
+ case SDP_DATA_UUID32:
+ alen = sizeof(uint32_t);
+ break;
+
+ case SDP_DATA_UINT64:
+ case SDP_DATA_INT64:
+ alen = sizeof(uint64_t);
+ break;
+
+ case SDP_DATA_UINT128:
+ case SDP_DATA_INT128:
+ case SDP_DATA_UUID128:
+ alen = sizeof(uint128_t);
+ break;
+
+ case SDP_DATA_STR8:
+ case SDP_DATA_URL8:
+ case SDP_DATA_SEQ8:
+ case SDP_DATA_ALT8:
+ alen = rsp_tmp[1] + sizeof(uint8_t);
+ break;
+
+ case SDP_DATA_STR16:
+ case SDP_DATA_URL16:
+ case SDP_DATA_SEQ16:
+ case SDP_DATA_ALT16:
+ alen = ((uint16_t)rsp_tmp[1] << 8)
+ | ((uint16_t)rsp_tmp[2]);
+ alen += sizeof(uint16_t);
+ break;
+
+ case SDP_DATA_STR32:
+ case SDP_DATA_URL32:
+ case SDP_DATA_SEQ32:
+ case SDP_DATA_ALT32:
+ alen = ((uint32_t)rsp_tmp[1] << 24)
+ | ((uint32_t)rsp_tmp[2] << 16)
+ | ((uint32_t)rsp_tmp[3] << 8)
+ | ((uint32_t)rsp_tmp[4]);
+ alen += sizeof(uint32_t);
+ break;
+
+ default:
+ ss->error = ENOATTR;
+ return (-1);
+ /* NOT REACHED */
+ }
+
+ alen += sizeof(uint8_t);
+
+ if (vp->value != NULL) {
+ if (alen <= vp->vlen) {
+ vp->flags = SDP_ATTR_OK;
+ vp->vlen = alen;
+ } else
+ vp->flags = SDP_ATTR_TRUNCATED;
+
+ memcpy(vp->value, rsp_tmp, vp->vlen);
+ } else
+ vp->flags = SDP_ATTR_INVALID;
+
+ len -= (
+ sizeof(uint8_t) + sizeof(uint16_t) +
+ alen
+ );
+
+ rsp_tmp += alen;
+ }
+ }
+done:
+ ss->error = 0;
+
+ return (0);
+}
+
diff --git a/lib/libsdp/service.c b/lib/libsdp/service.c
new file mode 100644
index 0000000..2667966
--- /dev/null
+++ b/lib/libsdp/service.c
@@ -0,0 +1,237 @@
+/*
+ * service.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: service.c,v 1.1 2004/01/13 19:32:36 max Exp $
+ * $FreeBSD$
+ */
+
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <bluetooth.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sdp-int.h>
+#include <sdp.h>
+
+static int32_t sdp_receive_error_pdu(sdp_session_p ss);
+
+int32_t
+sdp_register_service(void *xss, uint16_t uuid, bdaddr_p const bdaddr,
+ uint8_t const *data, uint32_t datalen, uint32_t *handle)
+{
+ sdp_session_p ss = (sdp_session_p) xss;
+ struct iovec iov[4];
+ sdp_pdu_t pdu;
+ int32_t len;
+
+ if (ss == NULL)
+ return (-1);
+ if (bdaddr == NULL || data == NULL ||
+ datalen == 0 || !(ss->flags & SDP_SESSION_LOCAL)) {
+ ss->error = EINVAL;
+ return (-1);
+ }
+ if (sizeof(pdu)+sizeof(uuid)+sizeof(*bdaddr)+datalen > SDP_LOCAL_MTU) {
+ ss->error = EMSGSIZE;
+ return (-1);
+ }
+
+ pdu.pid = SDP_PDU_SERVICE_REGISTER_REQUEST;
+ pdu.tid = htons(++ss->tid);
+ pdu.len = htons(sizeof(uuid) + sizeof(*bdaddr) + datalen);
+
+ uuid = htons(uuid);
+
+ iov[0].iov_base = (void *) &pdu;
+ iov[0].iov_len = sizeof(pdu);
+
+ iov[1].iov_base = (void *) &uuid;
+ iov[1].iov_len = sizeof(uuid);
+
+ iov[2].iov_base = (void *) bdaddr;
+ iov[2].iov_len = sizeof(*bdaddr);
+
+ iov[3].iov_base = (void *) data;
+ iov[3].iov_len = datalen;
+
+ do {
+ len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ ss->error = errno;
+ return (-1);
+ }
+
+ len = sdp_receive_error_pdu(ss);
+ if (len < 0)
+ return (-1);
+ if (len != sizeof(pdu) + sizeof(uint16_t) + sizeof(uint32_t)) {
+ ss->error = EIO;
+ return (-1);
+ }
+
+ if (handle != NULL) {
+ *handle = (uint32_t) ss->rsp[--len];
+ *handle |= (uint32_t) ss->rsp[--len] << 8;
+ *handle |= (uint32_t) ss->rsp[--len] << 16;
+ *handle |= (uint32_t) ss->rsp[--len] << 24;
+ }
+
+ return (0);
+}
+
+int32_t
+sdp_unregister_service(void *xss, uint32_t handle)
+{
+ sdp_session_p ss = (sdp_session_p) xss;
+ struct iovec iov[2];
+ sdp_pdu_t pdu;
+ int32_t len;
+
+ if (ss == NULL)
+ return (-1);
+ if (!(ss->flags & SDP_SESSION_LOCAL)) {
+ ss->error = EINVAL;
+ return (-1);
+ }
+ if (sizeof(pdu) + sizeof(handle) > SDP_LOCAL_MTU) {
+ ss->error = EMSGSIZE;
+ return (-1);
+ }
+
+ pdu.pid = SDP_PDU_SERVICE_UNREGISTER_REQUEST;
+ pdu.tid = htons(++ss->tid);
+ pdu.len = htons(sizeof(handle));
+
+ handle = htonl(handle);
+
+ iov[0].iov_base = (void *) &pdu;
+ iov[0].iov_len = sizeof(pdu);
+
+ iov[1].iov_base = (void *) &handle;
+ iov[1].iov_len = sizeof(handle);
+
+ do {
+ len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ ss->error = errno;
+ return (-1);
+ }
+
+ return ((sdp_receive_error_pdu(ss) < 0)? -1 : 0);
+}
+
+int32_t
+sdp_change_service(void *xss, uint32_t handle,
+ uint8_t const *data, uint32_t datalen)
+{
+ sdp_session_p ss = (sdp_session_p) xss;
+ struct iovec iov[3];
+ sdp_pdu_t pdu;
+ int32_t len;
+
+ if (ss == NULL)
+ return (-1);
+ if (data == NULL || datalen == 0 || !(ss->flags & SDP_SESSION_LOCAL)) {
+ ss->error = EINVAL;
+ return (-1);
+ }
+ if (sizeof(pdu) + sizeof(handle) + datalen > SDP_LOCAL_MTU) {
+ ss->error = EMSGSIZE;
+ return (-1);
+ }
+
+ pdu.pid = SDP_PDU_SERVICE_CHANGE_REQUEST;
+ pdu.tid = htons(++ss->tid);
+ pdu.len = htons(sizeof(handle) + datalen);
+
+ handle = htons(handle);
+
+ iov[0].iov_base = (void *) &pdu;
+ iov[0].iov_len = sizeof(pdu);
+
+ iov[1].iov_base = (void *) &handle;
+ iov[1].iov_len = sizeof(handle);
+
+ iov[2].iov_base = (void *) data;
+ iov[2].iov_len = datalen;
+
+ do {
+ len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0]));
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ ss->error = errno;
+ return (-1);
+ }
+
+ return ((sdp_receive_error_pdu(ss) < 0)? -1 : 0);
+}
+
+static int32_t
+sdp_receive_error_pdu(sdp_session_p ss)
+{
+ sdp_pdu_p pdu;
+ int32_t len;
+ uint16_t error;
+
+ do {
+ len = read(ss->s, ss->rsp, ss->rsp_e - ss->rsp);
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ ss->error = errno;
+ return (-1);
+ }
+
+ pdu = (sdp_pdu_p) ss->rsp;
+ pdu->tid = ntohs(pdu->tid);
+ pdu->len = ntohs(pdu->len);
+
+ if (pdu->pid != SDP_PDU_ERROR_RESPONSE || pdu->tid != ss->tid ||
+ pdu->len < 2 || pdu->len != len - sizeof(*pdu)) {
+ ss->error = EIO;
+ return (-1);
+ }
+
+ error = (uint16_t) ss->rsp[sizeof(pdu)] << 8;
+ error |= (uint16_t) ss->rsp[sizeof(pdu) + 1];
+
+ if (error != 0) {
+ ss->error = EIO;
+ return (-1);
+ }
+
+ return (len);
+}
+
diff --git a/lib/libsdp/session.c b/lib/libsdp/session.c
new file mode 100644
index 0000000..a31f327
--- /dev/null
+++ b/lib/libsdp/session.c
@@ -0,0 +1,177 @@
+/*
+ * session.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: session.c,v 1.2 2003/09/04 22:12:13 max Exp $
+ * $FreeBSD$
+ */
+
+#include <bluetooth.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sdp-int.h>
+#include <sdp.h>
+
+void *
+sdp_open(bdaddr_t const *l, bdaddr_t const *r)
+{
+ sdp_session_p ss = NULL;
+ struct sockaddr_l2cap sa;
+ socklen_t size;
+
+ if ((ss = calloc(1, sizeof(*ss))) == NULL)
+ goto fail;
+
+ if (l == NULL || r == NULL) {
+ ss->error = EINVAL;
+ goto fail;
+ }
+
+ ss->s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
+ if (ss->s < 0) {
+ ss->error = errno;
+ goto fail;
+ }
+
+ sa.l2cap_len = sizeof(sa);
+ sa.l2cap_family = AF_BLUETOOTH;
+ sa.l2cap_psm = 0;
+ memcpy(&sa.l2cap_bdaddr, l, sizeof(sa.l2cap_bdaddr));
+ if (bind(ss->s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ ss->error = errno;
+ goto fail;
+ }
+
+ sa.l2cap_psm = htole16(NG_L2CAP_PSM_SDP);
+ memcpy(&sa.l2cap_bdaddr, r, sizeof(sa.l2cap_bdaddr));
+ if (connect(ss->s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ ss->error = errno;
+ goto fail;
+ }
+
+ size = sizeof(ss->omtu);
+ if (getsockopt(ss->s, SOL_L2CAP, SO_L2CAP_OMTU, &ss->omtu, &size) < 0) {
+ ss->error = errno;
+ goto fail;
+ }
+ if ((ss->req = malloc(ss->omtu)) == NULL) {
+ ss->error = ENOMEM;
+ goto fail;
+ }
+ ss->req_e = ss->req + ss->omtu;
+
+ size = sizeof(ss->imtu);
+ if (getsockopt(ss->s, SOL_L2CAP, SO_L2CAP_IMTU, &ss->imtu, &size) < 0) {
+ ss->error = errno;
+ goto fail;
+ }
+ if ((ss->rsp = malloc(ss->imtu)) == NULL) {
+ ss->error = ENOMEM;
+ goto fail;
+ }
+ ss->rsp_e = ss->rsp + ss->imtu;
+ ss->error = 0;
+fail:
+ return ((void *) ss);
+}
+
+void *
+sdp_open_local(char const *control)
+{
+ sdp_session_p ss = NULL;
+ struct sockaddr_un sa;
+
+ if ((ss = calloc(1, sizeof(*ss))) == NULL)
+ goto fail;
+
+ ss->s = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (ss->s < 0) {
+ ss->error = errno;
+ goto fail;
+ }
+
+ if (control == NULL)
+ control = SDP_LOCAL_PATH;
+
+ sa.sun_len = sizeof(sa);
+ sa.sun_family = AF_UNIX;
+ strlcpy(sa.sun_path, control, sizeof(sa.sun_path));
+
+ if (connect(ss->s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ ss->error = errno;
+ goto fail;
+ }
+
+ ss->flags |= SDP_SESSION_LOCAL;
+ ss->imtu = ss->omtu = SDP_LOCAL_MTU;
+
+ if ((ss->req = malloc(ss->omtu)) == NULL) {
+ ss->error = ENOMEM;
+ goto fail;
+ }
+ ss->req_e = ss->req + ss->omtu;
+
+ if ((ss->rsp = malloc(ss->imtu)) == NULL) {
+ ss->error = ENOMEM;
+ goto fail;
+ }
+ ss->rsp_e = ss->rsp + ss->imtu;
+ ss->error = 0;
+fail:
+ return ((void *) ss);
+}
+
+int32_t
+sdp_close(void *xss)
+{
+ sdp_session_p ss = (sdp_session_p) xss;
+
+ if (ss != NULL) {
+ if (ss->s >= 0)
+ close(ss->s);
+
+ if (ss->req != NULL)
+ free(ss->req);
+ if (ss->rsp != NULL)
+ free(ss->rsp);
+
+ memset(ss, 0, sizeof(*ss));
+ free(ss);
+ }
+
+ return (0);
+}
+
+int32_t
+sdp_error(void *xss)
+{
+ sdp_session_p ss = (sdp_session_p) xss;
+
+ return ((ss != NULL)? ss->error : EINVAL);
+}
diff --git a/lib/libsdp/util.c b/lib/libsdp/util.c
new file mode 100644
index 0000000..b996bd2
--- /dev/null
+++ b/lib/libsdp/util.c
@@ -0,0 +1,457 @@
+/*
+ * util.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: util.c,v 1.5 2003/09/08 02:29:35 max Exp $
+ * $FreeBSD$
+ */
+
+#include <netinet/in.h>
+#include <bluetooth.h>
+#include <stdio.h>
+#include <sdp.h>
+
+/*
+ * SDP attribute description
+ */
+
+struct sdp_attr_desc {
+ uint32_t attr;
+ char const *desc;
+};
+typedef struct sdp_attr_desc sdp_attr_desc_t;
+typedef struct sdp_attr_desc * sdp_attr_desc_p;
+
+static sdp_attr_desc_t sdp_uuids_desc[] = {
+{ SDP_UUID_PROTOCOL_SDP, "SDP", },
+{ SDP_UUID_PROTOCOL_UDP, "UDP", },
+{ SDP_UUID_PROTOCOL_RFCOMM, "RFCOMM", },
+{ SDP_UUID_PROTOCOL_TCP, "TCP", },
+{ SDP_UUID_PROTOCOL_TCS_BIN, "TCS BIN", },
+{ SDP_UUID_PROTOCOL_TCS_AT, "TCS AT", },
+{ SDP_UUID_PROTOCOL_OBEX, "OBEX", },
+{ SDP_UUID_PROTOCOL_IP, "IP", },
+{ SDP_UUID_PROTOCOL_FTP, "FTP", },
+{ SDP_UUID_PROTOCOL_HTTP, "HTTP", },
+{ SDP_UUID_PROTOCOL_WSP, "WSP", },
+{ SDP_UUID_PROTOCOL_BNEP, "BNEP", },
+{ SDP_UUID_PROTOCOL_UPNP, "UPNP", },
+{ SDP_UUID_PROTOCOL_HIDP, "HIDP", },
+{ SDP_UUID_PROTOCOL_HARDCOPY_CONTROL_CHANNEL, "Hardcopy Control Channel", },
+{ SDP_UUID_PROTOCOL_HARDCOPY_DATA_CHANNEL, "Hardcopy Data Channel", },
+{ SDP_UUID_PROTOCOL_HARDCOPY_NOTIFICATION, "Hardcopy Notification", },
+{ SDP_UUID_PROTOCOL_AVCTP, "AVCTP", },
+{ SDP_UUID_PROTOCOL_AVDTP, "AVDTP", },
+{ SDP_UUID_PROTOCOL_CMPT, "CMPT", },
+{ SDP_UUID_PROTOCOL_UDI_C_PLANE, "UDI C-Plane", },
+{ SDP_UUID_PROTOCOL_L2CAP, "L2CAP", },
+/* Service Class IDs/Bluetooth Profile IDs */
+{ SDP_SERVICE_CLASS_SERVICE_DISCOVERY_SERVER, "Service Discovery Server", },
+{ SDP_SERVICE_CLASS_BROWSE_GROUP_DESCRIPTOR, "Browse Group Descriptor", },
+{ SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP, "Public Browse Group", },
+{ SDP_SERVICE_CLASS_SERIAL_PORT, "Serial Port", },
+{ SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP, "LAN Access Using PPP", },
+{ SDP_SERVICE_CLASS_DIALUP_NETWORKING, "Dial-Up Networking", },
+{ SDP_SERVICE_CLASS_IR_MC_SYNC, "IrMC Sync", },
+{ SDP_SERVICE_CLASS_OBEX_OBJECT_PUSH, "OBEX Object Push", },
+{ SDP_SERVICE_CLASS_OBEX_FILE_TRANSFER, "OBEX File Transfer", },
+{ SDP_SERVICE_CLASS_IR_MC_SYNC_COMMAND, "IrMC Sync Command", },
+{ SDP_SERVICE_CLASS_HEADSET, "Headset", },
+{ SDP_SERVICE_CLASS_CORDLESS_TELEPHONY, "Cordless Telephony", },
+{ SDP_SERVICE_CLASS_AUDIO_SOURCE, "Audio Source", },
+{ SDP_SERVICE_CLASS_AUDIO_SINK, "Audio Sink", },
+{ SDP_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET, "A/V Remote Control Target", },
+{ SDP_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION, "Advanced Audio Distribution", },
+{ SDP_SERVICE_CLASS_AV_REMOTE_CONTROL, "A/V Remote Control", },
+{ SDP_SERVICE_CLASS_VIDEO_CONFERENCING, "Video Conferencing", },
+{ SDP_SERVICE_CLASS_INTERCOM, "Intercom", },
+{ SDP_SERVICE_CLASS_FAX, "Fax", },
+{ SDP_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY, "Headset Audio Gateway", },
+{ SDP_SERVICE_CLASS_WAP, "WAP", },
+{ SDP_SERVICE_CLASS_WAP_CLIENT, "WAP Client", },
+{ SDP_SERVICE_CLASS_PANU, "PANU", },
+{ SDP_SERVICE_CLASS_NAP, "Network Access Point", },
+{ SDP_SERVICE_CLASS_GN, "GN", },
+{ SDP_SERVICE_CLASS_DIRECT_PRINTING, "Direct Printing", },
+{ SDP_SERVICE_CLASS_REFERENCE_PRINTING, "Reference Printing", },
+{ SDP_SERVICE_CLASS_IMAGING, "Imaging", },
+{ SDP_SERVICE_CLASS_IMAGING_RESPONDER, "Imaging Responder", },
+{ SDP_SERVICE_CLASS_IMAGING_AUTOMATIC_ARCHIVE, "Imaging Automatic Archive", },
+{ SDP_SERVICE_CLASS_IMAGING_REFERENCED_OBJECTS, "Imaging Referenced Objects", },
+{ SDP_SERVICE_CLASS_HANDSFREE, "Handsfree", },
+{ SDP_SERVICE_CLASS_HANDSFREE_AUDIO_GATEWAY, "Handsfree Audio Gateway", },
+{ SDP_SERVICE_CLASS_DIRECT_PRINTING_REFERENCE_OBJECTS, "Direct Printing Reference Objects", },
+{ SDP_SERVICE_CLASS_REFLECTED_UI, "Reflected UI", },
+{ SDP_SERVICE_CLASS_BASIC_PRINTING, "Basic Printing", },
+{ SDP_SERVICE_CLASS_PRINTING_STATUS, "Printing Status", },
+{ SDP_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE, "Human Interface Device", },
+{ SDP_SERVICE_CLASS_HARDCOPY_CABLE_REPLACEMENT, "Hardcopy Cable Replacement", },
+{ SDP_SERVICE_CLASS_HCR_PRINT, "HCR Print", },
+{ SDP_SERVICE_CLASS_HCR_SCAN, "HCR Scan", },
+{ SDP_SERVICE_CLASS_COMMON_ISDN_ACCESS, "Common ISDN Access", },
+{ SDP_SERVICE_CLASS_VIDEO_CONFERENCING_GW, "Video Conferencing Gateway", },
+{ SDP_SERVICE_CLASS_UDI_MT, "UDI MT", },
+{ SDP_SERVICE_CLASS_UDI_TA, "UDI TA", },
+{ SDP_SERVICE_CLASS_AUDIO_VIDEO, "Audio/Video", },
+{ SDP_SERVICE_CLASS_SIM_ACCESS, "SIM Access", },
+{ SDP_SERVICE_CLASS_PHONEBOOK_ACCESS_PCE, "Phonebook Access - PCE", },
+{ SDP_SERVICE_CLASS_PHONEBOOK_ACCESS_PSE, "Phonebook Access - PSE", },
+{ SDP_SERVICE_CLASS_PHONEBOOK_ACCESS, "Phonebook Access", },
+{ SDP_SERVICE_CLASS_PNP_INFORMATION, "PNP Information", },
+{ SDP_SERVICE_CLASS_GENERIC_NETWORKING, "Generic Networking", },
+{ SDP_SERVICE_CLASS_GENERIC_FILE_TRANSFER, "Generic File Transfer", },
+{ SDP_SERVICE_CLASS_GENERIC_AUDIO, "Generic Audio", },
+{ SDP_SERVICE_CLASS_GENERIC_TELEPHONY, "Generic Telephony", },
+{ SDP_SERVICE_CLASS_UPNP, "UPNP", },
+{ SDP_SERVICE_CLASS_UPNP_IP, "UPNP IP", },
+{ SDP_SERVICE_CLASS_ESDP_UPNP_IP_PAN, "ESDP UPNP IP PAN", },
+{ SDP_SERVICE_CLASS_ESDP_UPNP_IP_LAP, "ESDP UPNP IP LAP", },
+{ SDP_SERVICE_CLASS_ESDP_UPNP_L2CAP, "ESDP UPNP L2CAP", },
+{ SDP_SERVICE_CLASS_VIDEO_SOURCE, "Video Source", },
+{ SDP_SERVICE_CLASS_VIDEO_SINK, "Video Sink", },
+{ SDP_SERVICE_CLASS_VIDEO_DISTRIBUTION, "Video Distribution", },
+{ 0xffff, NULL, }
+};
+
+static sdp_attr_desc_t sdp_attrs_desc[] = {
+{ SDP_ATTR_SERVICE_RECORD_HANDLE,
+ "Record handle",
+ },
+{ SDP_ATTR_SERVICE_CLASS_ID_LIST,
+ "Service Class ID list",
+ },
+{ SDP_ATTR_SERVICE_RECORD_STATE,
+ "Service Record State",
+ },
+{ SDP_ATTR_SERVICE_ID,
+ "Service ID",
+ },
+{ SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
+ "Protocol Descriptor List",
+ },
+{ SDP_ATTR_BROWSE_GROUP_LIST,
+ "Browse Group List",
+ },
+{ SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,
+ "Language Base Attribute ID List",
+ },
+{ SDP_ATTR_SERVICE_INFO_TIME_TO_LIVE,
+ "Service Info Time-To-Live",
+ },
+{ SDP_ATTR_SERVICE_AVAILABILITY,
+ "Service Availability",
+ },
+{ SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
+ "Bluetooh Profile Descriptor List",
+ },
+{ SDP_ATTR_DOCUMENTATION_URL,
+ "Documentation URL",
+ },
+{ SDP_ATTR_CLIENT_EXECUTABLE_URL,
+ "Client Executable URL",
+ },
+{ SDP_ATTR_ICON_URL,
+ "Icon URL",
+ },
+{ SDP_ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS,
+ "Additional Protocol Descriptor Lists" },
+{ SDP_ATTR_GROUP_ID,
+/*SDP_ATTR_IP_SUBNET,
+ SDP_ATTR_VERSION_NUMBER_LIST*/
+ "Group ID/IP Subnet/Version Number List",
+ },
+{ SDP_ATTR_SERVICE_DATABASE_STATE,
+ "Service Database State",
+ },
+{ SDP_ATTR_SERVICE_VERSION,
+ "Service Version",
+ },
+{ SDP_ATTR_EXTERNAL_NETWORK,
+/*SDP_ATTR_NETWORK,
+ SDP_ATTR_SUPPORTED_DATA_STORES_LIST*/
+ "External Network/Network/Supported Data Stores List",
+ },
+{ SDP_ATTR_FAX_CLASS1_SUPPORT,
+/*SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL*/
+ "Fax Class1 Support/Remote Audio Volume Control",
+ },
+{ SDP_ATTR_FAX_CLASS20_SUPPORT,
+/*SDP_ATTR_SUPPORTED_FORMATS_LIST*/
+ "Fax Class20 Support/Supported Formats List",
+ },
+{ SDP_ATTR_FAX_CLASS2_SUPPORT,
+ "Fax Class2 Support",
+ },
+{ SDP_ATTR_AUDIO_FEEDBACK_SUPPORT,
+ "Audio Feedback Support",
+ },
+{ SDP_ATTR_NETWORK_ADDRESS,
+ "Network Address",
+ },
+{ SDP_ATTR_WAP_GATEWAY,
+ "WAP Gateway",
+ },
+{ SDP_ATTR_HOME_PAGE_URL,
+ "Home Page URL",
+ },
+{ SDP_ATTR_WAP_STACK_TYPE,
+ "WAP Stack Type",
+ },
+{ SDP_ATTR_SECURITY_DESCRIPTION,
+ "Security Description",
+ },
+{ SDP_ATTR_NET_ACCESS_TYPE,
+ "Net Access Type",
+ },
+{ SDP_ATTR_MAX_NET_ACCESS_RATE,
+ "Max Net Access Rate",
+ },
+{ SDP_ATTR_IPV4_SUBNET,
+ "IPv4 Subnet",
+ },
+{ SDP_ATTR_IPV6_SUBNET,
+ "IPv6 Subnet",
+ },
+{ SDP_ATTR_SUPPORTED_CAPABALITIES,
+ "Supported Capabalities",
+ },
+{ SDP_ATTR_SUPPORTED_FEATURES,
+ "Supported Features",
+ },
+{ SDP_ATTR_SUPPORTED_FUNCTIONS,
+ "Supported Functions",
+ },
+{ SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY,
+ "Total Imaging Data Capacity",
+ },
+{ SDP_ATTR_SUPPORTED_REPOSITORIES,
+ "Supported Repositories",
+ },
+{ 0xffff, NULL, }
+};
+
+char const *
+sdp_attr2desc(uint16_t attr)
+{
+ register sdp_attr_desc_p a = sdp_attrs_desc;
+
+ for (; a->desc != NULL; a++)
+ if (attr == a->attr)
+ break;
+
+ return ((a->desc != NULL)? a->desc : "Unknown");
+}
+
+char const *
+sdp_uuid2desc(uint16_t uuid)
+{
+ register sdp_attr_desc_p a = sdp_uuids_desc;
+
+ for (; a->desc != NULL; a++)
+ if (uuid == a->attr)
+ break;
+
+ return ((a->desc != NULL)? a->desc : "Unknown");
+}
+
+void
+sdp_print(uint32_t level, uint8_t const *start, uint8_t const *end)
+{
+ union {
+ int8_t int8;
+ int16_t int16;
+ int32_t int32;
+ int64_t int64;
+ int128_t int128;
+ uint8_t uint8;
+ uint16_t uint16;
+ uint32_t uint32;
+ uint64_t uint64;
+ } value;
+ uint8_t type;
+ uint32_t i;
+
+ if (start == NULL || end == NULL)
+ return;
+
+ while (start < end) {
+ for (i = 0; i < level; i++)
+ printf("\t");
+
+ SDP_GET8(type, start);
+
+ switch (type) {
+ case SDP_DATA_NIL:
+ printf("nil\n");
+ break;
+
+ case SDP_DATA_UINT8:
+ SDP_GET8(value.uint8, start);
+ printf("uint8 %u\n", value.uint8);
+ break;
+ case SDP_DATA_UINT16:
+ SDP_GET16(value.uint16, start);
+ printf("uint16 %u\n", value.uint16);
+ break;
+ case SDP_DATA_UINT32:
+ SDP_GET32(value.uint32, start);
+ printf("uint32 %u\n", value.uint32);
+ break;
+ case SDP_DATA_UINT64:
+ SDP_GET64(value.uint64, start);
+ printf("uint64 %ju\n", value.uint64);
+ break;
+
+ case SDP_DATA_UINT128:
+ case SDP_DATA_INT128:
+ SDP_GET128(&value.int128, start);
+ printf("u/int128 %#8.8x%8.8x%8.8x%8.8x\n",
+ *(uint32_t *)&value.int128.b[0],
+ *(uint32_t *)&value.int128.b[4],
+ *(uint32_t *)&value.int128.b[8],
+ *(uint32_t *)&value.int128.b[12]);
+ break;
+
+ case SDP_DATA_UUID128:
+ SDP_GET_UUID128(&value.int128, start);
+ printf("uuid128 %#8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.8x\n",
+ ntohl(*(uint32_t *)&value.int128.b[0]),
+ ntohs(*(uint16_t *)&value.int128.b[4]),
+ ntohs(*(uint16_t *)&value.int128.b[6]),
+ ntohs(*(uint16_t *)&value.int128.b[8]),
+ ntohs(*(uint16_t *)&value.int128.b[10]),
+ ntohl(*(uint32_t *)&value.int128.b[12]));
+ break;
+
+ case SDP_DATA_INT8:
+ SDP_GET8(value.int8, start);
+ printf("int8 %d\n", value.int8);
+ break;
+ case SDP_DATA_INT16:
+ SDP_GET16(value.int16, start);
+ printf("int16 %d\n", value.int16);
+ break;
+ case SDP_DATA_INT32:
+ SDP_GET32(value.int32, start);
+ printf("int32 %d\n", value.int32);
+ break;
+ case SDP_DATA_INT64:
+ SDP_GET64(value.int64, start);
+ printf("int64 %ju\n", value.int64);
+ break;
+
+ case SDP_DATA_UUID16:
+ SDP_GET16(value.uint16, start);
+ printf("uuid16 %#4.4x - %s\n", value.uint16,
+ sdp_uuid2desc(value.uint16));
+ break;
+ case SDP_DATA_UUID32:
+ SDP_GET32(value.uint32, start);
+ printf("uuid32 %#8.8x\n", value.uint32);
+ break;
+
+ case SDP_DATA_STR8:
+ SDP_GET8(value.uint8, start);
+ printf("str8 %*.*s\n", value.uint8, value.uint8, start);
+ start += value.uint8;
+ break;
+ case SDP_DATA_STR16:
+ SDP_GET16(value.uint16, start);
+ printf("str16 %*.*s\n", value.uint16, value.uint16, start);
+ start += value.uint16;
+ break;
+ case SDP_DATA_STR32:
+ SDP_GET32(value.uint32, start);
+ printf("str32 %*.*s\n", value.uint32, value.uint32, start);
+ start += value.uint32;
+ break;
+
+ case SDP_DATA_BOOL:
+ SDP_GET8(value.uint8, start);
+ printf("bool %d\n", value.uint8);
+ break;
+
+ case SDP_DATA_SEQ8:
+ SDP_GET8(value.uint8, start);
+ printf("seq8 %d\n", value.uint8);
+ sdp_print(level + 1, start, start + value.uint8);
+ start += value.uint8;
+ break;
+ case SDP_DATA_SEQ16:
+ SDP_GET16(value.uint16, start);
+ printf("seq16 %d\n", value.uint16);
+ sdp_print(level + 1, start, start + value.uint16);
+ start += value.uint16;
+ break;
+ case SDP_DATA_SEQ32:
+ SDP_GET32(value.uint32, start);
+ printf("seq32 %d\n", value.uint32);
+ sdp_print(level + 1, start, start + value.uint32);
+ start += value.uint32;
+ break;
+
+ case SDP_DATA_ALT8:
+ SDP_GET8(value.uint8, start);
+ printf("alt8 %d\n", value.uint8);
+ sdp_print(level + 1, start, start + value.uint8);
+ start += value.uint8;
+ break;
+ case SDP_DATA_ALT16:
+ SDP_GET16(value.uint16, start);
+ printf("alt16 %d\n", value.uint16);
+ sdp_print(level + 1, start, start + value.uint16);
+ start += value.uint16;
+ break;
+ case SDP_DATA_ALT32:
+ SDP_GET32(value.uint32, start);
+ printf("alt32 %d\n", value.uint32);
+ sdp_print(level + 1, start, start + value.uint32);
+ start += value.uint32;
+ break;
+
+ case SDP_DATA_URL8:
+ SDP_GET8(value.uint8, start);
+ printf("url8 %*.*s\n", value.uint8, value.uint8, start);
+ start += value.uint8;
+ break;
+ case SDP_DATA_URL16:
+ SDP_GET16(value.uint16, start);
+ printf("url16 %*.*s\n", value.uint16, value.uint16, start);
+ start += value.uint16;
+ break;
+ case SDP_DATA_URL32:
+ SDP_GET32(value.uint32, start);
+ printf("url32 %*.*s\n", value.uint32, value.uint32, start);
+ start += value.uint32;
+ break;
+
+ default:
+ printf("unknown data type: %#02x\n", *start ++);
+ break;
+ }
+ }
+}
+
OpenPOWER on IntegriCloud