All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH -v3 01/19] headset: remove deprecated D-Bus methods
@ 2012-07-04 12:51 Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 02/19] sink: remove deprecated D-Bus method Gustavo Padovan
                   ` (12 more replies)
  0 siblings, 13 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

---
 audio/headset.c     |  151 ---------------------------------------------------
 doc/audio-api.txt   |   28 ----------
 test/test-telephony |   12 ----
 3 files changed, 191 deletions(-)

diff --git a/audio/headset.c b/audio/headset.c
index b9c6265..1014c59 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -1673,26 +1673,6 @@ static DBusMessage *hs_stop(DBusConnection *conn, DBusMessage *msg,
 	return reply;
 }
 
-static DBusMessage *hs_is_playing(DBusConnection *conn, DBusMessage *msg,
-					void *data)
-{
-	struct audio_device *device = data;
-	struct headset *hs = device->headset;
-	DBusMessage *reply;
-	dbus_bool_t playing;
-
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
-		return NULL;
-
-	playing = (hs->state == HEADSET_STATE_PLAYING);
-
-	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &playing,
-					DBUS_TYPE_INVALID);
-
-	return reply;
-}
-
 static DBusMessage *hs_disconnect(DBusConnection *conn, DBusMessage *msg,
 					void *data)
 {
@@ -1816,95 +1796,6 @@ static DBusMessage *hs_cancel_call(DBusConnection *conn,
 	return reply;
 }
 
-static DBusMessage *hs_play(DBusConnection *conn, DBusMessage *msg,
-				void *data)
-{
-	struct audio_device *device = data;
-	struct headset *hs = device->headset;
-	int err;
-
-	if (sco_hci) {
-		error("Refusing Headset.Play() because SCO HCI routing "
-				"is enabled");
-		return btd_error_not_available(msg);
-	}
-
-	switch (hs->state) {
-	case HEADSET_STATE_DISCONNECTED:
-	case HEADSET_STATE_CONNECTING:
-		return btd_error_not_connected(msg);
-	case HEADSET_STATE_PLAY_IN_PROGRESS:
-		if (hs->pending && hs->pending->msg == NULL) {
-			hs->pending->msg = dbus_message_ref(msg);
-			return NULL;
-		}
-		return btd_error_busy(msg);
-	case HEADSET_STATE_PLAYING:
-		return btd_error_already_connected(msg);
-	case HEADSET_STATE_CONNECTED:
-	default:
-		break;
-	}
-
-	err = sco_connect(device, NULL, NULL, NULL);
-	if (err < 0)
-		return btd_error_failed(msg, strerror(-err));
-
-	hs->pending->msg = dbus_message_ref(msg);
-
-	return NULL;
-}
-
-static DBusMessage *hs_get_speaker_gain(DBusConnection *conn,
-					DBusMessage *msg,
-					void *data)
-{
-	struct audio_device *device = data;
-	struct headset *hs = device->headset;
-	struct headset_slc *slc = hs->slc;
-	DBusMessage *reply;
-	dbus_uint16_t gain;
-
-	if (hs->state < HEADSET_STATE_CONNECTED)
-		return btd_error_not_available(msg);
-
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
-		return NULL;
-
-	gain = (dbus_uint16_t) slc->sp_gain;
-
-	dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
-					DBUS_TYPE_INVALID);
-
-	return reply;
-}
-
-static DBusMessage *hs_get_mic_gain(DBusConnection *conn,
-					DBusMessage *msg,
-					void *data)
-{
-	struct audio_device *device = data;
-	struct headset *hs = device->headset;
-	struct headset_slc *slc = hs->slc;
-	DBusMessage *reply;
-	dbus_uint16_t gain;
-
-	if (hs->state < HEADSET_STATE_CONNECTED || slc == NULL)
-		return btd_error_not_available(msg);
-
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
-		return NULL;
-
-	gain = (dbus_uint16_t) slc->mic_gain;
-
-	dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
-					DBUS_TYPE_INVALID);
-
-	return reply;
-}
-
 static DBusMessage *hs_set_gain(DBusConnection *conn,
 				DBusMessage *msg,
 				void *data, uint16_t gain,
@@ -1937,32 +1828,6 @@ static DBusMessage *hs_set_gain(DBusConnection *conn,
 	return reply;
 }
 
-static DBusMessage *hs_set_speaker_gain(DBusConnection *conn,
-					DBusMessage *msg,
-					void *data)
-{
-	uint16_t gain;
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &gain,
-				DBUS_TYPE_INVALID))
-		return NULL;
-
-	return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_SPEAKER);
-}
-
-static DBusMessage *hs_set_mic_gain(DBusConnection *conn,
-					DBusMessage *msg,
-					void *data)
-{
-	uint16_t gain;
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &gain,
-				DBUS_TYPE_INVALID))
-		return NULL;
-
-	return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_MICROPHONE);
-}
-
 static DBusMessage *hs_get_properties(DBusConnection *conn,
 					DBusMessage *msg, void *data)
 {
@@ -2065,23 +1930,7 @@ static const GDBusMethodTable headset_methods[] = {
 			hs_is_connected) },
 	{ GDBUS_METHOD("IndicateCall", NULL, NULL, hs_ring) },
 	{ GDBUS_METHOD("CancelCall", NULL, NULL, hs_cancel_call) },
-	{ GDBUS_DEPRECATED_ASYNC_METHOD("Play", NULL, NULL, hs_play) },
 	{ GDBUS_METHOD("Stop", NULL, NULL, hs_stop) },
-	{ GDBUS_DEPRECATED_METHOD("IsPlaying",
-					NULL, GDBUS_ARGS({ "playing", "b" }),
-					hs_is_playing) },
-	{ GDBUS_DEPRECATED_METHOD("GetSpeakerGain",
-					NULL, GDBUS_ARGS({ "gain", "q" }),
-					hs_get_speaker_gain) },
-	{ GDBUS_DEPRECATED_METHOD("GetMicrophoneGain",
-					NULL, GDBUS_ARGS({ "gain", "q" }),
-					hs_get_mic_gain) },
-	{ GDBUS_DEPRECATED_METHOD("SetSpeakerGain",
-					GDBUS_ARGS({ "gain", "q" }), NULL,
-					hs_set_speaker_gain) },
-	{ GDBUS_DEPRECATED_METHOD("SetMicrophoneGain",
-					GDBUS_ARGS({ "gain", "q" }), NULL,
-					hs_set_mic_gain) },
 	{ GDBUS_METHOD("GetProperties",
 			NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
 			hs_get_properties) },
diff --git a/doc/audio-api.txt b/doc/audio-api.txt
index 9b1737d..2419531 100644
--- a/doc/audio-api.txt
+++ b/doc/audio-api.txt
@@ -66,11 +66,6 @@ Methods		void Connect()
 			Disconnect from the HSP/HFP service on the remote
 			device.
 
-		boolean IsConnected() {deprecated}
-
-			Returns TRUE if there is a active connection to the
-			HSP/HFP connection on the remote device.
-
 		void IndicateCall()
 
 			Indicate an incoming call on the headset
@@ -89,29 +84,6 @@ Methods		void Connect()
 
 			Close the audio connection.
 
-		boolean IsPlaying() {deprecated}
-
-			Returns true if an audio connection to the headset
-			is active.
-
-		uint16 GetSpeakerGain() {deprecated}
-
-			Returns the current speaker gain if available,
-			otherwise returns the error NotAvailable.
-
-		uint16 GetMicrophoneGain() {deprecated}
-
-			Returns the current microphone gain if available,
-			otherwise returns the error NotAvailable.
-
-		void SetSpeakerGain(uint16 gain) {deprecated}
-
-			Changes the current speaker gain if possible.
-
-		void SetMicrophoneGain(uint16 gain) {deprecated}
-
-			Changes the current speaker gain if possible.
-
 		dict GetProperties()
 
 			Returns all properties for the interface. See the
diff --git a/test/test-telephony b/test/test-telephony
index bd7d3b2..57ac7f0 100755
--- a/test/test-telephony
+++ b/test/test-telephony
@@ -44,7 +44,6 @@ if len(args) < 1:
 	subscriber <number>
 	speakergain <bdaddr> [level]
 	microphonegain <bdaddr> [level]
-	play <bdaddr>
 	stop <bdaddr>
 	""" % sys.argv[0])
 	sys.exit(1)
@@ -99,17 +98,6 @@ if args[0] == "microphonegain":
 
 	sys.exit(0)
 
-if args[0] == "play":
-	if len(args) < 2:
-		print("Need device address parameter")
-		sys.exit(1)
-	device = adapter.FindDevice(args[1])
-	headset = dbus.Interface(bus.get_object("org.bluez", device),
-					"org.bluez.Headset")
-	headset.Play()
-
-	sys.exit(0)
-
 if args[0] == "stop":
 	if len(args) < 2:
 		print("Need device address parameter")
-- 
1.7.10.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH -v3 02/19] sink: remove deprecated D-Bus method
  2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 03/19] serial: remove SerialProxy interface Gustavo Padovan
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

---
 audio/sink.c      |   24 ------------------------
 doc/audio-api.txt |    5 -----
 2 files changed, 29 deletions(-)

diff --git a/audio/sink.c b/audio/sink.c
index 8ba4e2a..64e38f4 100644
--- a/audio/sink.c
+++ b/audio/sink.c
@@ -492,27 +492,6 @@ static DBusMessage *sink_disconnect(DBusConnection *conn,
 	return NULL;
 }
 
-static DBusMessage *sink_is_connected(DBusConnection *conn,
-					DBusMessage *msg,
-					void *data)
-{
-	struct audio_device *device = data;
-	struct sink *sink = device->sink;
-	DBusMessage *reply;
-	dbus_bool_t connected;
-
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
-		return NULL;
-
-	connected = (sink->stream_state >= AVDTP_STATE_CONFIGURED);
-
-	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
-					DBUS_TYPE_INVALID);
-
-	return reply;
-}
-
 static DBusMessage *sink_get_properties(DBusConnection *conn,
 					DBusMessage *msg, void *data)
 {
@@ -556,9 +535,6 @@ static DBusMessage *sink_get_properties(DBusConnection *conn,
 static const GDBusMethodTable sink_methods[] = {
 	{ GDBUS_ASYNC_METHOD("Connect", NULL, NULL, sink_connect) },
 	{ GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, sink_disconnect) },
-	{ GDBUS_DEPRECATED_METHOD("IsConnected",
-			NULL, GDBUS_ARGS({ "connected", "b" }),
-			sink_is_connected) },
 	{ GDBUS_METHOD("GetProperties",
 				NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
 				sink_get_properties) },
diff --git a/doc/audio-api.txt b/doc/audio-api.txt
index 2419531..ca430fc 100644
--- a/doc/audio-api.txt
+++ b/doc/audio-api.txt
@@ -193,11 +193,6 @@ Methods		void Connect()
 
 			Disconnect from the remote device.
 
-		boolean IsConnected() {deprecated}
-
-			Returns TRUE if a stream is setup to a A2DP sink on
-			the remote device.
-
 		dict GetProperties()
 
 			Returns all properties for the interface. See the
-- 
1.7.10.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH -v3 03/19] serial: remove SerialProxy interface
  2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 02/19] sink: remove deprecated D-Bus method Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 04/19] serial: remove unneeded headers include Gustavo Padovan
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

---
 Makefile.am        |    1 -
 doc/serial-api.txt |  106 -----
 serial/manager.c   |   26 --
 serial/proxy.c     | 1269 ----------------------------------------------------
 serial/proxy.h     |   25 --
 5 files changed, 1427 deletions(-)
 delete mode 100644 serial/proxy.c
 delete mode 100644 serial/proxy.h

diff --git a/Makefile.am b/Makefile.am
index 5009ca8..25d1026 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -190,7 +190,6 @@ if SERIALPLUGIN
 builtin_modules += serial
 builtin_sources += serial/main.c \
 			serial/manager.h serial/manager.c \
-			serial/proxy.h serial/proxy.c \
 			serial/port.h serial/port.c
 endif
 
diff --git a/doc/serial-api.txt b/doc/serial-api.txt
index 0bdbdcd..42afe3d 100644
--- a/doc/serial-api.txt
+++ b/doc/serial-api.txt
@@ -55,109 +55,3 @@ Methods		fd ConnectFD(string pattern) [experimental]
 
 			Possible errors: org.bluez.Error.InvalidArguments
 					 org.bluez.Error.DoesNotExist
-
-Serial Proxy Manager hierarchy [experimental]
-=============================================
-
-Service		org.bluez
-Interface	org.bluez.SerialProxyManager
-Object path	[variable prefix]/{hci0,hci1,...}
-
-Methods		array{string} ListProxies()
-
-			Returns an array of the object path strings of
-			all the proxies created for the adapter.
-
-		string CreateProxy(string pattern, string address)
-
-			Possible patterns: UUID 128 bit as string
-					   Profile short names, e.g: spp, dun
-					   RFCOMM channel as string, 1-30
-
-			Address is the path to the TTY or Unix socket to be used.
-			Only one proxy per address (TTY or Unix socket)
-			is allowed.
-
-			The object path of created proxy is returned.
-			On success this will emit a ProxyCreated signal.
-
-			Possible Errors: org.bluez.Error.InvalidArguments
-					 org.bluez.Error.AlreadyExists
-					 org.bluez.Error.Failed
-
-		void RemoveProxy(string path)
-
-			This removes the proxy object at the given path.
-			On success this will emit a ProxyRemoved signal.
-
-			Possible Errors: org.bluez.Error.DoesNotExist
-					 org.bluez.Error.NotAuthorized
-
-Signals		ProxyCreated(string path)
-
-			This signal indicates a proxy was created.
-			Parameter is object path of created proxy.
-
-		ProxyRemoved(string path)
-
-			This signal indicates a proxy was removed.
-			Parameter is object path of removed proxy.
-
-Serial Proxy hierarchy [experimental]
-=====================================
-
-Service		org.bluez
-Interface	org.bluez.SerialProxy
-Object path	[variable prefix]/{hci0,hci1,...}/{proxy0,proxy1,...}
-
-Methods		void Enable()
-
-			Starts to listen to the TTY or Unix socket, allocates
-			a RFCOMM channel and add record to the server.
-
-			Possible errors: org.bluez.Error.Failed
-
-		void Disable()
-
-			Stops to listen to the TTY or Unix socket, shutdown
-			the RFCOMM channel allocated for the proxy, and remove
-			record from the server.
-
-			Possible errors: org.bluez.Error.Failed
-
-		dict GetInfo()
-
-			Returns all properties for the proxy. See the
-			properties section for available properties.
-
-		void SetSerialParameters(string rate, uint8 data, uint8 stop,
-			string parity)
-
-			Configures serial communication setting baud rate,
-			data bits, stop bits and parity.
-
-			Doesn't allow change TTY settings if it is open.
-
-			Possible errors: org.bluez.Error.InvalidArguments
-					 org.bluez.Error.NotAuthorized
-
-Properties	string uuid [readonly]
-
-			128-bit UUID that represents the available remote service.
-
-		string address [readonly]
-
-			Address is the path to the TTY or Unix socket name used,
-			set when the proxy was created.
-
-		uint8 channel [readonly]
-
-			RFCOMM channel.
-
-		boolean enabled [readonly]
-
-			Indicates if the proxy is currently enabled.
-
-		boolean connected [readonly]
-
-			Indicates if the proxy is currently connected.
diff --git a/serial/manager.c b/serial/manager.c
index 438ba6c..a84ce03 100644
--- a/serial/manager.c
+++ b/serial/manager.c
@@ -58,7 +58,6 @@
 
 #include "error.h"
 #include "port.h"
-#include "proxy.h"
 #include "storage.h"
 #include "manager.h"
 #include "sdpd.h"
@@ -131,35 +130,10 @@ static struct btd_device_driver serial_port_driver = {
 	.remove	= port_remove,
 };
 
-static int proxy_probe(struct btd_adapter *adapter)
-{
-	const char *path = adapter_get_path(adapter);
-
-	DBG("path %s", path);
-
-	return proxy_register(connection, adapter);
-}
-
-static void proxy_remove(struct btd_adapter *adapter)
-{
-	const char *path = adapter_get_path(adapter);
-
-	DBG("path %s", path);
-
-	proxy_unregister(adapter);
-}
-
-static struct btd_adapter_driver serial_proxy_driver = {
-	.name	= "serial-proxy",
-	.probe	= proxy_probe,
-	.remove	= proxy_remove,
-};
-
 int serial_manager_init(DBusConnection *conn)
 {
 	connection = dbus_connection_ref(conn);
 
-	btd_register_adapter_driver(&serial_proxy_driver);
 	btd_register_device_driver(&serial_port_driver);
 
 	return 0;
diff --git a/serial/proxy.c b/serial/proxy.c
deleted file mode 100644
index dd38317..0000000
--- a/serial/proxy.c
+++ /dev/null
@@ -1,1269 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-#include <bluetooth/rfcomm.h>
-
-#include <glib.h>
-#include <gdbus.h>
-
-#include "../src/dbus-common.h"
-#include "../src/adapter.h"
-
-#include "log.h"
-
-#include "error.h"
-#include "sdpd.h"
-#include "glib-helper.h"
-#include "btio.h"
-#include "proxy.h"
-
-#define SERIAL_PROXY_INTERFACE	"org.bluez.SerialProxy"
-#define SERIAL_MANAGER_INTERFACE "org.bluez.SerialProxyManager"
-#define BUF_SIZE		1024
-
-typedef enum {
-	TTY_PROXY,
-	UNIX_SOCKET_PROXY,
-	TCP_SOCKET_PROXY,
-	UNKNOWN_PROXY_TYPE = 0xFF
-} proxy_type_t;
-
-struct serial_adapter {
-	struct btd_adapter	*btd_adapter;	/* Adapter pointer */
-	DBusConnection		*conn;		/* Adapter connection */
-	GSList			*proxies;	/* Proxies list */
-};
-
-struct serial_proxy {
-	bdaddr_t	src;		/* Local address */
-	bdaddr_t	dst;		/* Remote address */
-	char		*path;		/* Proxy path */
-	char		*uuid128;	/* UUID 128 */
-	char		*address;	/* TTY or Unix socket name */
-	char		*owner;		/* Application bus name */
-	guint		watch;		/* Application watch */
-	short int	port;		/* TCP port */
-	proxy_type_t	type;		/* TTY or Unix socket */
-	struct termios  sys_ti;		/* Default TTY setting */
-	struct termios  proxy_ti;	/* Proxy TTY settings */
-	uint8_t		channel;	/* RFCOMM channel */
-	uint32_t	record_id;	/* Service record id */
-	GIOChannel	*io;		/* Server listen */
-	GIOChannel	*rfcomm;	/* Remote RFCOMM channel*/
-	GIOChannel	*local;		/* Local channel: TTY or Unix socket */
-	struct serial_adapter *adapter;	/* Adapter pointer */
-};
-
-static GSList *adapters = NULL;
-static int sk_counter = 0;
-
-static void disable_proxy(struct serial_proxy *prx)
-{
-	if (prx->rfcomm) {
-		g_io_channel_shutdown(prx->rfcomm, TRUE, NULL);
-		g_io_channel_unref(prx->rfcomm);
-		prx->rfcomm = NULL;
-	}
-
-	if (prx->local) {
-		g_io_channel_shutdown(prx->local, TRUE, NULL);
-		g_io_channel_unref(prx->local);
-		prx->local = NULL;
-	}
-
-	remove_record_from_server(prx->record_id);
-	prx->record_id = 0;
-
-	g_io_channel_unref(prx->io);
-	prx->io = NULL;
-}
-
-static void proxy_free(struct serial_proxy *prx)
-{
-	g_free(prx->owner);
-	g_free(prx->path);
-	g_free(prx->address);
-	g_free(prx->uuid128);
-	g_free(prx);
-}
-
-static sdp_record_t *proxy_record_new(const char *uuid128, uint8_t channel)
-{
-	sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id;
-	uuid_t uuid, root_uuid, l2cap, rfcomm;
-	sdp_profile_desc_t profile;
-	sdp_record_t *record;
-	sdp_data_t *ch;
-
-	record = sdp_record_alloc();
-	if (!record)
-		return NULL;
-
-	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-	root = sdp_list_append(NULL, &root_uuid);
-	sdp_set_browse_groups(record, root);
-	sdp_list_free(root, NULL);
-
-	bt_string2uuid(&uuid, uuid128);
-	sdp_uuid128_to_uuid(&uuid);
-	svclass_id = sdp_list_append(NULL, &uuid);
-	sdp_set_service_classes(record, svclass_id);
-	sdp_list_free(svclass_id, NULL);
-
-	sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
-	profile.version = 0x0100;
-	profiles = sdp_list_append(NULL, &profile);
-	sdp_set_profile_descs(record, profiles);
-	sdp_list_free(profiles, NULL);
-
-	sdp_uuid16_create(&l2cap, L2CAP_UUID);
-	proto[0] = sdp_list_append(NULL, &l2cap);
-	apseq = sdp_list_append(NULL, proto[0]);
-
-	sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
-	proto[1] = sdp_list_append(NULL, &rfcomm);
-	ch = sdp_data_alloc(SDP_UINT8, &channel);
-	proto[1] = sdp_list_append(proto[1], ch);
-	apseq = sdp_list_append(apseq, proto[1]);
-
-	aproto = sdp_list_append(NULL, apseq);
-	sdp_set_access_protos(record, aproto);
-
-	sdp_add_lang_attr(record);
-
-	sdp_set_info_attr(record, "Serial Proxy", NULL, "Serial Proxy");
-
-	sdp_data_free(ch);
-	sdp_list_free(proto[0], NULL);
-	sdp_list_free(proto[1], NULL);
-	sdp_list_free(apseq, NULL);
-	sdp_list_free(aproto, NULL);
-
-	return record;
-}
-
-static int channel_write(GIOChannel *chan, char *buf, size_t size)
-{
-	size_t wbytes;
-	ssize_t written;
-	int fd;
-
-	fd = g_io_channel_unix_get_fd(chan);
-
-	wbytes = 0;
-	while (wbytes < size) {
-		written = write(fd, buf + wbytes, size - wbytes);
-		if (written < 0)
-			return -errno;
-
-		wbytes += written;
-	}
-
-	return 0;
-}
-
-static gboolean forward_data(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
-	char buf[BUF_SIZE];
-	struct serial_proxy *prx = data;
-	GIOChannel *dest;
-	ssize_t rbytes;
-	int fd, err;
-
-	if (cond & G_IO_NVAL)
-		return FALSE;
-
-	dest = (chan == prx->rfcomm) ? prx->local : prx->rfcomm;
-
-	fd = g_io_channel_unix_get_fd(chan);
-
-	if (cond & (G_IO_HUP | G_IO_ERR)) {
-		/* Try forward remaining data */
-		do {
-			rbytes = read(fd, buf, sizeof(buf));
-			if (rbytes <= 0)
-				break;
-
-			err = channel_write(dest, buf, rbytes);
-		} while (err == 0);
-
-		g_io_channel_shutdown(prx->local, TRUE, NULL);
-		g_io_channel_unref(prx->local);
-		prx->local = NULL;
-
-		g_io_channel_shutdown(prx->rfcomm, TRUE, NULL);
-		g_io_channel_unref(prx->rfcomm);
-		prx->rfcomm = NULL;
-
-		return FALSE;
-	}
-
-	rbytes = read(fd, buf, sizeof(buf));
-	if (rbytes < 0)
-		return FALSE;
-
-	err = channel_write(dest, buf, rbytes);
-	if (err != 0)
-		return FALSE;
-
-	return TRUE;
-}
-
-static inline int unix_socket_connect(const char *address)
-{
-	struct sockaddr_un addr;
-	int err, sk;
-
-	memset(&addr, 0, sizeof(addr));
-	addr.sun_family = PF_UNIX;
-
-	if (strncmp("x00", address, 3) == 0) {
-		/*
-		 * Abstract namespace: first byte NULL, x00
-		 * must be removed from the original address.
-		 */
-		strncpy(addr.sun_path + 1, address + 3,
-						sizeof(addr.sun_path) - 2);
-	} else {
-		/* Filesystem address */
-		strncpy(addr.sun_path, address, sizeof(addr.sun_path) - 1);
-	}
-
-	/* Unix socket */
-	sk = socket(AF_UNIX, SOCK_STREAM, 0);
-	if (sk < 0) {
-		err = -errno;
-		error("Unix socket(%s) create failed: %s(%d)",
-				address, strerror(-err), -err);
-		return err;
-	}
-
-	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		err = -errno;
-		error("Unix socket(%s) connect failed: %s(%d)",
-				address, strerror(-err), -err);
-		close(sk);
-		return err;
-	}
-
-	return sk;
-}
-
-static int tcp_socket_connect(const char *address)
-{
-	struct sockaddr_in addr;
-	int err, sk, port;
-
-	memset(&addr, 0, sizeof(addr));
-
-	if (strncmp(address, "localhost", 9) != 0) {
-		error("Address should have the form localhost:port.");
-		return -1;
-	}
-	port = atoi(strchr(address, ':') + 1);
-	if (port <= 0) {
-		error("Invalid port '%d'.", port);
-		return -1;
-	}
-	addr.sin_family = AF_INET;
-	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
-	addr.sin_port = htons(port);
-
-	sk = socket(PF_INET, SOCK_STREAM, 0);
-	if (sk < 0) {
-		err = -errno;
-		error("TCP socket(%s) create failed %s(%d)", address,
-							strerror(-err), -err);
-		return err;
-	}
-	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		err = -errno;
-		error("TCP socket(%s) connect failed: %s(%d)",
-						address, strerror(-err), -err);
-		close(sk);
-		return err;
-	}
-	return sk;
-}
-
-static inline int tty_open(const char *tty, struct termios *ti)
-{
-	int err, sk;
-
-	sk = open(tty, O_RDWR | O_NOCTTY);
-	if (sk < 0) {
-		err = -errno;
-		error("Can't open TTY %s: %s(%d)", tty, strerror(-err), -err);
-		return err;
-	}
-
-	if (ti && tcsetattr(sk, TCSANOW, ti) < 0) {
-		err = -errno;
-		error("Can't change serial settings: %s(%d)",
-				strerror(-err), -err);
-		close(sk);
-		return err;
-	}
-
-	return sk;
-}
-
-static void connect_event_cb(GIOChannel *chan, GError *conn_err, gpointer data)
-{
-	struct serial_proxy *prx = data;
-	int sk;
-
-	if (conn_err) {
-		error("%s", conn_err->message);
-		goto drop;
-	}
-
-	/* Connect local */
-	switch (prx->type) {
-	case UNIX_SOCKET_PROXY:
-		sk = unix_socket_connect(prx->address);
-		break;
-	case TTY_PROXY:
-		sk = tty_open(prx->address, &prx->proxy_ti);
-		break;
-	case TCP_SOCKET_PROXY:
-		sk = tcp_socket_connect(prx->address);
-		break;
-	default:
-		sk = -1;
-	}
-
-	if (sk < 0)
-		goto drop;
-
-	prx->local = g_io_channel_unix_new(sk);
-
-	g_io_add_watch(prx->rfcomm,
-			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-			forward_data, prx);
-
-	g_io_add_watch(prx->local,
-			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-			forward_data, prx);
-
-	return;
-
-drop:
-	g_io_channel_shutdown(prx->rfcomm, TRUE, NULL);
-	g_io_channel_unref(prx->rfcomm);
-	prx->rfcomm = NULL;
-}
-
-static void auth_cb(DBusError *derr, void *user_data)
-{
-	struct serial_proxy *prx = user_data;
-	GError *err = NULL;
-
-	if (derr) {
-		error("Access denied: %s", derr->message);
-		goto reject;
-	}
-
-	if (!bt_io_accept(prx->rfcomm, connect_event_cb, prx, NULL,
-							&err)) {
-		error("bt_io_accept: %s", err->message);
-		g_error_free(err);
-		goto reject;
-	}
-
-	return;
-
-reject:
-	g_io_channel_shutdown(prx->rfcomm, TRUE, NULL);
-	g_io_channel_unref(prx->rfcomm);
-	prx->rfcomm = NULL;
-}
-
-static void confirm_event_cb(GIOChannel *chan, gpointer user_data)
-{
-	struct serial_proxy *prx = user_data;
-	int perr;
-	char address[18];
-	GError *err = NULL;
-
-	bt_io_get(chan, BT_IO_RFCOMM, &err,
-			BT_IO_OPT_DEST_BDADDR, &prx->dst,
-			BT_IO_OPT_DEST, address,
-			BT_IO_OPT_INVALID);
-	if (err) {
-		error("%s", err->message);
-		g_error_free(err);
-		goto drop;
-	}
-
-	if (prx->rfcomm) {
-		error("Refusing connect from %s: Proxy already in use",
-				address);
-		goto drop;
-	}
-
-	DBG("Serial Proxy: incoming connect from %s", address);
-
-	prx->rfcomm = g_io_channel_ref(chan);
-
-	perr = btd_request_authorization(&prx->src, &prx->dst,
-					prx->uuid128, auth_cb, prx);
-	if (perr < 0) {
-		error("Refusing connect from %s: %s (%d)", address,
-				strerror(-perr), -perr);
-		g_io_channel_unref(prx->rfcomm);
-		prx->rfcomm = NULL;
-		goto drop;
-	}
-
-	return;
-
-drop:
-	g_io_channel_shutdown(chan, TRUE, NULL);
-}
-
-static int enable_proxy(struct serial_proxy *prx)
-{
-	sdp_record_t *record;
-	GError *gerr = NULL;
-	int err;
-
-	if (prx->io)
-		return -EALREADY;
-
-	/* Listen */
-	prx->io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_event_cb, prx,
-				NULL, &gerr,
-				BT_IO_OPT_SOURCE_BDADDR, &prx->src,
-				BT_IO_OPT_INVALID);
-	if (!prx->io)
-		goto failed;
-
-	bt_io_get(prx->io, BT_IO_RFCOMM, &gerr,
-			BT_IO_OPT_CHANNEL, &prx->channel,
-			BT_IO_OPT_INVALID);
-	if (gerr) {
-		g_io_channel_unref(prx->io);
-		prx->io = NULL;
-		goto failed;
-	}
-
-	DBG("Allocated channel %d", prx->channel);
-
-	g_io_channel_set_close_on_unref(prx->io, TRUE);
-
-	record = proxy_record_new(prx->uuid128, prx->channel);
-	if (!record) {
-		g_io_channel_unref(prx->io);
-		return -ENOMEM;
-	}
-
-	err = add_record_to_server(&prx->src, record);
-	if (err < 0) {
-		sdp_record_free(record);
-		g_io_channel_unref(prx->io);
-		return err;
-	}
-
-	prx->record_id = record->handle;
-
-	return 0;
-
-failed:
-	error("%s", gerr->message);
-	g_error_free(gerr);
-	return -EIO;
-
-}
-static DBusMessage *proxy_enable(DBusConnection *conn,
-				DBusMessage *msg, void *data)
-{
-	struct serial_proxy *prx = data;
-	int err;
-
-	err = enable_proxy(prx);
-	if (err < 0)
-		return btd_error_failed(msg, strerror(-err));
-
-	return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *proxy_disable(DBusConnection *conn,
-				DBusMessage *msg, void *data)
-{
-	struct serial_proxy *prx = data;
-
-	if (!prx->io)
-		return btd_error_failed(msg, "Not enabled");
-
-	/* Remove the watches and unregister the record */
-	disable_proxy(prx);
-
-	return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *proxy_get_info(DBusConnection *conn,
-				DBusMessage *msg, void *data)
-{
-	struct serial_proxy *prx = data;
-	DBusMessage *reply;
-	DBusMessageIter iter, dict;
-	dbus_bool_t boolean;
-
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
-		return NULL;
-
-	dbus_message_iter_init_append(reply, &iter);
-
-	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-	dict_append_entry(&dict, "uuid", DBUS_TYPE_STRING, &prx->uuid128);
-
-	dict_append_entry(&dict, "address", DBUS_TYPE_STRING, &prx->address);
-
-	if (prx->channel)
-		dict_append_entry(&dict, "channel",
-					DBUS_TYPE_BYTE, &prx->channel);
-
-	boolean = (prx->io ? TRUE : FALSE);
-	dict_append_entry(&dict, "enabled", DBUS_TYPE_BOOLEAN, &boolean);
-
-	boolean = (prx->rfcomm ? TRUE : FALSE);
-	dict_append_entry(&dict, "connected", DBUS_TYPE_BOOLEAN, &boolean);
-
-	/* If connected: append the remote address */
-	if (boolean) {
-		char bda[18];
-		const char *pstr = bda;
-
-		ba2str(&prx->dst, bda);
-		dict_append_entry(&dict, "address", DBUS_TYPE_STRING, &pstr);
-	}
-
-	dbus_message_iter_close_container(&iter, &dict);
-
-	return reply;
-}
-
-static struct {
-	const char	*str;
-	speed_t		speed;
-} supported_speed[]  = {
-	{"50",		B50	},
-	{"300",		B300	},
-	{"600",		B600	},
-	{"1200",	B1200	},
-	{"1800",	B1800	},
-	{"2400",	B2400	},
-	{"4800",	B4800	},
-	{"9600",	B9600	},
-	{"19200",	B19200	},
-	{"38400",	B38400	},
-	{"57600",	B57600	},
-	{"115200",	B115200	},
-	{ NULL,		B0	}
-};
-
-static speed_t str2speed(const char *str, speed_t *speed)
-{
-	int i;
-
-	for (i = 0; supported_speed[i].str; i++) {
-		if (strcmp(supported_speed[i].str, str) != 0)
-			continue;
-
-		if (speed)
-			*speed = supported_speed[i].speed;
-
-		return supported_speed[i].speed;
-	}
-
-	return B0;
-}
-
-static int set_parity(const char *str, tcflag_t *ctrl)
-{
-	if (strcasecmp("even", str) == 0) {
-		*ctrl |= PARENB;
-		*ctrl &= ~PARODD;
-	} else if (strcasecmp("odd", str) == 0) {
-		*ctrl |= PARENB;
-		*ctrl |= PARODD;
-	} else if (strcasecmp("mark", str) == 0)
-		*ctrl |= PARENB;
-	else if ((strcasecmp("none", str) == 0) ||
-			(strcasecmp("space", str) == 0))
-		*ctrl &= ~PARENB;
-	else
-		return -1;
-
-	return 0;
-}
-
-static int set_databits(uint8_t databits, tcflag_t *ctrl)
-{
-	if (databits < 5 || databits > 8)
-		return -EINVAL;
-
-	*ctrl &= ~CSIZE;
-	switch (databits) {
-	case 5:
-		*ctrl |= CS5;
-		break;
-	case 6:
-		*ctrl |= CS6;
-		break;
-	case 7:
-		*ctrl |= CS7;
-		break;
-	case 8:
-		*ctrl |= CS8;
-		break;
-	}
-
-	return 0;
-}
-
-static int set_stopbits(uint8_t stopbits, tcflag_t *ctrl)
-{
-	/* 1.5 will not be allowed */
-	switch (stopbits) {
-	case 1:
-		*ctrl &= ~CSTOPB;
-		return 0;
-	case 2:
-		*ctrl |= CSTOPB;
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
-static DBusMessage *proxy_set_serial_params(DBusConnection *conn,
-						DBusMessage *msg, void *data)
-{
-	struct serial_proxy *prx = data;
-	const char *ratestr, *paritystr;
-	uint8_t databits, stopbits;
-	tcflag_t ctrl;		/* Control mode flags */
-	speed_t speed = B0;	/* In/Out speed */
-
-	/* Don't allow change TTY settings if it is open */
-	if (prx->local)
-		return btd_error_not_authorized(msg);
-
-	if (!dbus_message_get_args(msg, NULL,
-				DBUS_TYPE_STRING, &ratestr,
-				DBUS_TYPE_BYTE, &databits,
-				DBUS_TYPE_BYTE, &stopbits,
-				DBUS_TYPE_STRING, &paritystr,
-				DBUS_TYPE_INVALID))
-		return NULL;
-
-	if (str2speed(ratestr, &speed)  == B0)
-		return btd_error_invalid_args(msg);
-
-	ctrl = prx->proxy_ti.c_cflag;
-	if (set_databits(databits, &ctrl) < 0)
-		return btd_error_invalid_args(msg);
-
-	if (set_stopbits(stopbits, &ctrl) < 0)
-		return btd_error_invalid_args(msg);
-
-	if (set_parity(paritystr, &ctrl) < 0)
-		return btd_error_invalid_args(msg);
-
-	prx->proxy_ti.c_cflag = ctrl;
-	prx->proxy_ti.c_cflag |= (CLOCAL | CREAD);
-	cfsetispeed(&prx->proxy_ti, speed);
-	cfsetospeed(&prx->proxy_ti, speed);
-
-	return dbus_message_new_method_return(msg);
-}
-
-static const GDBusMethodTable proxy_methods[] = {
-	{ GDBUS_METHOD("Enable", NULL, NULL, proxy_enable) },
-	{ GDBUS_METHOD("Disable", NULL, NULL, proxy_disable) },
-	{ GDBUS_METHOD("GetInfo",
-			NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
-			proxy_get_info) },
-	{ GDBUS_METHOD("SetSerialParameters",
-			GDBUS_ARGS({ "rate", "s" }, { "data", "y" },
-					{ "stop", "y" }, { "parity", "s" }),
-			NULL, proxy_set_serial_params) },
-	{ },
-};
-
-static void proxy_path_unregister(gpointer data)
-{
-	struct serial_proxy *prx = data;
-	int sk;
-
-	DBG("Unregistered proxy: %s", prx->address);
-
-	if (prx->type != TTY_PROXY)
-		goto done;
-
-	/* Restore the initial TTY configuration */
-	sk = open(prx->address, O_RDWR | O_NOCTTY);
-	if (sk >= 0) {
-		tcsetattr(sk, TCSAFLUSH, &prx->sys_ti);
-		close(sk);
-	}
-done:
-
-	proxy_free(prx);
-}
-
-static int register_proxy_object(struct serial_proxy *prx)
-{
-	struct serial_adapter *adapter = prx->adapter;
-	char path[MAX_PATH_LENGTH + 1];
-
-	snprintf(path, MAX_PATH_LENGTH, "%s/proxy%d",
-			adapter_get_path(adapter->btd_adapter), sk_counter++);
-
-	if (!g_dbus_register_interface(adapter->conn, path,
-					SERIAL_PROXY_INTERFACE,
-					proxy_methods, NULL, NULL,
-					prx, proxy_path_unregister)) {
-		error("D-Bus failed to register %s path", path);
-		return -1;
-	}
-
-	prx->path = g_strdup(path);
-	adapter->proxies = g_slist_append(adapter->proxies, prx);
-
-	DBG("Registered proxy: %s", path);
-
-	return 0;
-}
-
-static int proxy_tty_register(struct serial_adapter *adapter,
-				const char *uuid128, const char *address,
-				struct termios *ti,
-				struct serial_proxy **proxy)
-{
-	struct termios sys_ti;
-	struct serial_proxy *prx;
-	int sk, ret;
-
-	sk = open(address, O_RDONLY | O_NOCTTY);
-	if (sk < 0) {
-		error("Can't open TTY: %s(%d)", strerror(errno), errno);
-		return -EINVAL;
-	}
-
-	prx = g_new0(struct serial_proxy, 1);
-	prx->address = g_strdup(address);
-	prx->uuid128 = g_strdup(uuid128);
-	prx->type = TTY_PROXY;
-	adapter_get_address(adapter->btd_adapter, &prx->src);
-	prx->adapter = adapter;
-
-	/* Current TTY settings */
-	memset(&sys_ti, 0, sizeof(sys_ti));
-	tcgetattr(sk, &sys_ti);
-	memcpy(&prx->sys_ti, &sys_ti, sizeof(sys_ti));
-	close(sk);
-
-	if (!ti) {
-		/* Use current settings */
-		memcpy(&prx->proxy_ti, &sys_ti, sizeof(sys_ti));
-	} else {
-		/* New TTY settings: user provided */
-		memcpy(&prx->proxy_ti, ti, sizeof(*ti));
-	}
-
-	ret = register_proxy_object(prx);
-	if (ret < 0) {
-		proxy_free(prx);
-		return ret;
-	}
-
-	*proxy = prx;
-
-	return ret;
-}
-
-static int proxy_socket_register(struct serial_adapter *adapter,
-				const char *uuid128, const char *address,
-				struct serial_proxy **proxy)
-{
-	struct serial_proxy *prx;
-	int ret;
-
-	prx = g_new0(struct serial_proxy, 1);
-	prx->address = g_strdup(address);
-	prx->uuid128 = g_strdup(uuid128);
-	prx->type = UNIX_SOCKET_PROXY;
-	adapter_get_address(adapter->btd_adapter, &prx->src);
-	prx->adapter = adapter;
-
-	ret = register_proxy_object(prx);
-	if (ret < 0) {
-		proxy_free(prx);
-		return ret;
-	}
-
-	*proxy = prx;
-
-	return ret;
-}
-
-static int proxy_tcp_register(struct serial_adapter *adapter,
-				const char *uuid128, const char *address,
-				struct serial_proxy **proxy)
-{
-	struct serial_proxy *prx;
-	int ret;
-
-	prx = g_new0(struct serial_proxy, 1);
-	prx->address = g_strdup(address);
-	prx->uuid128 = g_strdup(uuid128);
-	prx->type = TCP_SOCKET_PROXY;
-	adapter_get_address(adapter->btd_adapter, &prx->src);
-	prx->adapter = adapter;
-
-	ret = register_proxy_object(prx);
-	if (ret < 0) {
-		proxy_free(prx);
-		return ret;
-	}
-
-	*proxy = prx;
-
-	return ret;
-}
-
-static proxy_type_t addr2type(const char *address)
-{
-	struct stat st;
-
-	if (stat(address, &st) < 0) {
-		/*
-		 * Unix socket: if the sun_path starts with null byte
-		 * it refers to abstract namespace. 'x00' will be used
-		 * to represent the null byte.
-		 */
-		if (strncmp("localhost:", address, 10) == 0)
-			return TCP_SOCKET_PROXY;
-		if (strncmp("x00", address, 3) != 0)
-			return UNKNOWN_PROXY_TYPE;
-		else
-			return UNIX_SOCKET_PROXY;
-	} else {
-		/* Filesystem: char device or unix socket */
-		if (S_ISCHR(st.st_mode) && strncmp("/dev/", address, 4) == 0)
-			return TTY_PROXY;
-		else if (S_ISSOCK(st.st_mode))
-			return UNIX_SOCKET_PROXY;
-		else
-			return UNKNOWN_PROXY_TYPE;
-	}
-}
-
-static int proxy_addrcmp(gconstpointer proxy, gconstpointer addr)
-{
-	const struct serial_proxy *prx = proxy;
-	const char *address = addr;
-
-	return strcmp(prx->address, address);
-}
-
-static int proxy_pathcmp(gconstpointer proxy, gconstpointer p)
-{
-	const struct serial_proxy *prx = proxy;
-	const char *path = p;
-
-	return strcmp(prx->path, path);
-}
-
-static int register_proxy(struct serial_adapter *adapter,
-				const char *uuid_str, const char *address,
-				struct serial_proxy **proxy)
-{
-	proxy_type_t type;
-	int err;
-
-	type = addr2type(address);
-	if (type == UNKNOWN_PROXY_TYPE)
-		return -EINVAL;
-
-	/* Only one proxy per address(TTY or unix socket) is allowed */
-	if (g_slist_find_custom(adapter->proxies, address, proxy_addrcmp))
-		return -EALREADY;
-
-	switch (type) {
-	case UNIX_SOCKET_PROXY:
-		err = proxy_socket_register(adapter, uuid_str, address, proxy);
-		break;
-	case TTY_PROXY:
-		err = proxy_tty_register(adapter, uuid_str, address, NULL,
-					proxy);
-		break;
-	case TCP_SOCKET_PROXY:
-		err = proxy_tcp_register(adapter, uuid_str, address, proxy);
-		break;
-	default:
-		err = -EINVAL;
-	}
-
-	if (err < 0)
-		return err;
-
-	g_dbus_emit_signal(adapter->conn,
-				adapter_get_path(adapter->btd_adapter),
-				SERIAL_MANAGER_INTERFACE, "ProxyCreated",
-				DBUS_TYPE_STRING, &(*proxy)->path,
-				DBUS_TYPE_INVALID);
-
-	return 0;
-}
-
-static void unregister_proxy(struct serial_proxy *proxy)
-{
-	struct serial_adapter *adapter = proxy->adapter;
-	char *path = g_strdup(proxy->path);
-
-	if (proxy->watch > 0)
-		g_dbus_remove_watch(adapter->conn, proxy->watch);
-
-	g_dbus_emit_signal(adapter->conn,
-			adapter_get_path(adapter->btd_adapter),
-			SERIAL_MANAGER_INTERFACE, "ProxyRemoved",
-			DBUS_TYPE_STRING, &path,
-			DBUS_TYPE_INVALID);
-
-	adapter->proxies = g_slist_remove(adapter->proxies, proxy);
-
-	g_dbus_unregister_interface(adapter->conn, path,
-					SERIAL_PROXY_INTERFACE);
-
-	g_free(path);
-}
-
-static void watch_proxy(DBusConnection *connection, void *user_data)
-{
-	struct serial_proxy *proxy = user_data;
-
-	proxy->watch = 0;
-	unregister_proxy(proxy);
-}
-
-static DBusMessage *create_proxy(DBusConnection *conn,
-				DBusMessage *msg, void *data)
-{
-	struct serial_adapter *adapter = data;
-	struct serial_proxy *proxy;
-	const char *pattern, *address;
-	char *uuid_str;
-	int err;
-
-	if (!dbus_message_get_args(msg, NULL,
-				DBUS_TYPE_STRING, &pattern,
-				DBUS_TYPE_STRING, &address,
-				DBUS_TYPE_INVALID))
-		return NULL;
-
-	uuid_str = bt_name2string(pattern);
-	if (!uuid_str)
-		return btd_error_invalid_args(msg);
-
-	err = register_proxy(adapter, uuid_str, address, &proxy);
-	g_free(uuid_str);
-
-	if (err == -EINVAL)
-		return btd_error_invalid_args(msg);
-	else if (err == -EALREADY)
-		return btd_error_already_exists(msg);
-	else if (err < 0)
-		return btd_error_failed(msg, strerror(-err));
-
-	proxy->owner = g_strdup(dbus_message_get_sender(msg));
-	proxy->watch = g_dbus_add_disconnect_watch(conn, proxy->owner,
-						watch_proxy,
-						proxy, NULL);
-
-	return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &proxy->path,
-					DBUS_TYPE_INVALID);
-}
-
-static DBusMessage *list_proxies(DBusConnection *conn,
-				DBusMessage *msg, void *data)
-{
-	struct serial_adapter *adapter = data;
-	const GSList *l;
-	DBusMessage *reply;
-	DBusMessageIter iter, iter_array;
-
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
-		return NULL;
-
-	dbus_message_iter_init_append(reply, &iter);
-	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-			DBUS_TYPE_STRING_AS_STRING, &iter_array);
-
-	for (l = adapter->proxies; l; l = l->next) {
-		struct serial_proxy *prx = l->data;
-
-		dbus_message_iter_append_basic(&iter_array,
-				DBUS_TYPE_STRING, &prx->path);
-	}
-
-	dbus_message_iter_close_container(&iter, &iter_array);
-
-	return reply;
-}
-
-static DBusMessage *remove_proxy(DBusConnection *conn,
-				DBusMessage *msg, void *data)
-{
-	struct serial_adapter *adapter = data;
-	struct serial_proxy *prx;
-	const char *path, *sender;
-	GSList *l;
-
-	if (!dbus_message_get_args(msg, NULL,
-				DBUS_TYPE_STRING, &path,
-				DBUS_TYPE_INVALID))
-		return NULL;
-
-	l = g_slist_find_custom(adapter->proxies, path, proxy_pathcmp);
-	if (!l)
-		return btd_error_does_not_exist(msg);
-
-	prx = l->data;
-
-	sender = dbus_message_get_sender(msg);
-	if (g_strcmp0(prx->owner, sender) != 0)
-		return btd_error_not_authorized(msg);
-
-	unregister_proxy(prx);
-
-	return dbus_message_new_method_return(msg);
-}
-
-static void manager_path_unregister(void *data)
-{
-	struct serial_adapter *adapter = data;
-	GSList *l;
-
-	/* Remove proxy objects */
-	for (l = adapter->proxies; l; l = l->next) {
-		struct serial_proxy *prx = l->data;
-		char *path = g_strdup(prx->path);
-
-		g_dbus_unregister_interface(adapter->conn, path,
-					SERIAL_PROXY_INTERFACE);
-		g_free(path);
-	}
-
-	if (adapter->conn)
-		dbus_connection_unref(adapter->conn);
-
-	adapters = g_slist_remove(adapters, adapter);
-	g_slist_free(adapter->proxies);
-	btd_adapter_unref(adapter->btd_adapter);
-	g_free(adapter);
-}
-
-static const GDBusMethodTable manager_methods[] = {
-	{ GDBUS_METHOD("CreateProxy",
-			GDBUS_ARGS({ "pattern", "s" },
-					{ "address", "s" }),
-			GDBUS_ARGS({ "path", "s" }),
-			create_proxy) },
-	{ GDBUS_METHOD("ListProxies",
-			NULL, GDBUS_ARGS({ "paths", "as" }),
-			list_proxies) },
-	{ GDBUS_METHOD("RemoveProxy",
-			GDBUS_ARGS({ "path", "s" }), NULL,
-			remove_proxy) },
-	{ },
-};
-
-static const GDBusSignalTable manager_signals[] = {
-	{ GDBUS_SIGNAL("ProxyCreated", GDBUS_ARGS({ "path", "s" })) },
-	{ GDBUS_SIGNAL("ProxyRemoved", GDBUS_ARGS({ "path", "s" })) },
-	{ }
-};
-
-static struct serial_adapter *find_adapter(GSList *list,
-					struct btd_adapter *btd_adapter)
-{
-	for (; list; list = list->next) {
-		struct serial_adapter *adapter = list->data;
-
-		if (adapter->btd_adapter == btd_adapter)
-			return adapter;
-	}
-
-	return NULL;
-}
-
-static void serial_proxy_init(struct serial_adapter *adapter)
-{
-	GKeyFile *config;
-	GError *gerr = NULL;
-	const char *file = CONFIGDIR "/serial.conf";
-	char **group_list;
-	int i;
-
-	config = g_key_file_new();
-
-	if (!g_key_file_load_from_file(config, file, 0, &gerr)) {
-		error("Parsing %s failed: %s", file, gerr->message);
-		g_error_free(gerr);
-		g_key_file_free(config);
-		return;
-	}
-
-	group_list = g_key_file_get_groups(config, NULL);
-
-	for (i = 0; group_list[i] != NULL; i++) {
-		char *group_str = group_list[i], *uuid_str, *address;
-		int err;
-		struct serial_proxy *prx;
-
-		/* string length of "Proxy" is 5 */
-		if (strlen(group_str) < 5 || strncmp(group_str, "Proxy", 5))
-			continue;
-
-		uuid_str = g_key_file_get_string(config, group_str, "UUID",
-									&gerr);
-		if (gerr) {
-			DBG("%s: %s", file, gerr->message);
-			g_error_free(gerr);
-			g_key_file_free(config);
-			g_strfreev(group_list);
-			return;
-		}
-
-		address = g_key_file_get_string(config, group_str, "Address",
-									&gerr);
-		if (gerr) {
-			DBG("%s: %s", file, gerr->message);
-			g_error_free(gerr);
-			g_key_file_free(config);
-			g_free(uuid_str);
-			g_strfreev(group_list);
-			return;
-		}
-
-		err = register_proxy(adapter, uuid_str, address, &prx);
-		if (err == -EINVAL)
-			error("Invalid address.");
-		else if (err == -EALREADY)
-			DBG("Proxy already exists.");
-		else if (err < 0)
-			error("Proxy creation failed (%s)", strerror(-err));
-		else {
-			err = enable_proxy(prx);
-			if (err < 0)
-				error("Proxy enable failed (%s)",
-						strerror(-err));
-		}
-
-		g_free(uuid_str);
-		g_free(address);
-	}
-
-	g_strfreev(group_list);
-	g_key_file_free(config);
-}
-
-int proxy_register(DBusConnection *conn, struct btd_adapter *btd_adapter)
-{
-	struct serial_adapter *adapter;
-	const char *path;
-
-	adapter = find_adapter(adapters, btd_adapter);
-	if (adapter)
-		return -EINVAL;
-
-	adapter = g_new0(struct serial_adapter, 1);
-	adapter->conn = dbus_connection_ref(conn);
-	adapter->btd_adapter = btd_adapter_ref(btd_adapter);
-
-	path = adapter_get_path(btd_adapter);
-
-	if (!g_dbus_register_interface(conn, path,
-					SERIAL_MANAGER_INTERFACE,
-					manager_methods, manager_signals, NULL,
-					adapter, manager_path_unregister)) {
-		error("Failed to register %s interface to %s",
-				SERIAL_MANAGER_INTERFACE, path);
-		return -1;
-	}
-
-	adapters = g_slist_append(adapters, adapter);
-
-	DBG("Registered interface %s on path %s",
-		SERIAL_MANAGER_INTERFACE, path);
-
-	serial_proxy_init(adapter);
-
-	return 0;
-}
-
-void proxy_unregister(struct btd_adapter *btd_adapter)
-{
-	struct serial_adapter *adapter;
-
-	adapter = find_adapter(adapters, btd_adapter);
-	if (!adapter)
-		return;
-
-	g_dbus_unregister_interface(adapter->conn,
-			adapter_get_path(btd_adapter),
-			SERIAL_MANAGER_INTERFACE);
-}
diff --git a/serial/proxy.h b/serial/proxy.h
deleted file mode 100644
index 7871665..0000000
--- a/serial/proxy.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-int proxy_register(DBusConnection *conn, struct btd_adapter *btd_adapter);
-void proxy_unregister(struct btd_adapter *btd_adapter);
-- 
1.7.10.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH -v3 04/19] serial: remove unneeded headers include
  2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 02/19] sink: remove deprecated D-Bus method Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 03/19] serial: remove SerialProxy interface Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 05/19] input: remove unneeded header inclusions Gustavo Padovan
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

---
 serial/manager.c |   21 ---------------------
 serial/port.c    |    8 --------
 2 files changed, 29 deletions(-)

diff --git a/serial/manager.c b/serial/manager.c
index a84ce03..6f3fc1f 100644
--- a/serial/manager.c
+++ b/serial/manager.c
@@ -25,43 +25,22 @@
 #include <config.h>
 #endif
 
-#include <ctype.h>
-#include <dirent.h>
 #include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
-#include <bluetooth/rfcomm.h>
 #include <bluetooth/uuid.h>
 
-#include <glib.h>
 #include <gdbus.h>
 
-#include "../src/dbus-common.h"
 #include "adapter.h"
 #include "device.h"
 
 #include "log.h"
 
-#include "error.h"
 #include "port.h"
-#include "storage.h"
 #include "manager.h"
-#include "sdpd.h"
-#include "glib-helper.h"
 
 static DBusConnection *connection = NULL;
 
diff --git a/serial/port.c b/serial/port.c
index f90bb6a..2422cfe 100644
--- a/serial/port.c
+++ b/serial/port.c
@@ -26,15 +26,9 @@
 #endif
 
 #include <errno.h>
-#include <stdio.h>
-#include <stdint.h>
 #include <stdlib.h>
-#include <string.h>
-#include <termios.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <fcntl.h>
 
 #include <bluetooth/bluetooth.h>
@@ -45,8 +39,6 @@
 #include <glib.h>
 #include <gdbus.h>
 
-#include "../src/dbus-common.h"
-
 #include "log.h"
 #include "glib-helper.h"
 #include "sdp-client.h"
-- 
1.7.10.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH -v3 05/19] input: remove unneeded header inclusions
  2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
                   ` (2 preceding siblings ...)
  2012-07-04 12:51 ` [PATCH -v3 04/19] serial: remove unneeded headers include Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 06/19] serial: remove old way to connect to a serial port Gustavo Padovan
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

---
 input/device.c  |    5 -----
 input/fakehid.c |    4 ----
 input/manager.c |    3 ---
 3 files changed, 12 deletions(-)

diff --git a/input/device.c b/input/device.c
index c08ba18..f3ceabb 100644
--- a/input/device.c
+++ b/input/device.c
@@ -29,9 +29,6 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <unistd.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hidp.h>
@@ -39,8 +36,6 @@
 #include <bluetooth/sdp_lib.h>
 #include <bluetooth/uuid.h>
 
-#include <glib.h>
-#include <dbus/dbus.h>
 #include <gdbus.h>
 
 #include "log.h"
diff --git a/input/fakehid.c b/input/fakehid.c
index 3181538..3be1489 100644
--- a/input/fakehid.c
+++ b/input/fakehid.c
@@ -25,12 +25,8 @@
 #include <config.h>
 #endif
 
-#include <stdio.h>
-#include <errno.h>
 #include <fcntl.h>
 #include <unistd.h>
-#include <stdlib.h>
-#include <sys/types.h>
 
 #include <bluetooth/bluetooth.h>
 
diff --git a/input/manager.c b/input/manager.c
index 5cc552b..3572ea9 100644
--- a/input/manager.c
+++ b/input/manager.c
@@ -28,13 +28,10 @@
 #include <errno.h>
 
 #include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 #include <bluetooth/uuid.h>
 
-#include <gdbus.h>
-
 #include "log.h"
 #include "../src/adapter.h"
 #include "../src/device.h"
-- 
1.7.10.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH -v3 06/19] serial: remove old way to connect to a serial port
  2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
                   ` (3 preceding siblings ...)
  2012-07-04 12:51 ` [PATCH -v3 05/19] input: remove unneeded header inclusions Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 07/19] emulator: move it to the tools folder Gustavo Padovan
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

Only the fd-passing connect is available now.
---
 doc/serial-api.txt |   32 +--------
 serial/port.c      |  202 +++-------------------------------------------------
 2 files changed, 9 insertions(+), 225 deletions(-)

diff --git a/doc/serial-api.txt b/doc/serial-api.txt
index 42afe3d..9bb0054 100644
--- a/doc/serial-api.txt
+++ b/doc/serial-api.txt
@@ -11,22 +11,7 @@ Service		org.bluez
 Interface	org.bluez.Serial
 Object path	[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
 
-Methods		string Connect(string pattern)
-
-			Connects to a specific RFCOMM based service on a
-			remote device and then creates a RFCOMM TTY
-			device for it. The RFCOMM TTY device is returned.
-
-			Possible patterns: UUID 128 bit as string
-					   Profile short names, e.g: spp, dun
-					   RFCOMM channel as string, 1-30
-
-			Possible errors: org.bluez.Error.InvalidArguments
-					 org.bluez.Error.InProgress
-					 org.bluez.Error.ConnectionAttemptFailed
-					 org.bluez.Error.NotSupported
-
-Methods		fd ConnectFD(string pattern) [experimental]
+Methods		fd Connect(string pattern)
 
 			Connects to a specific RFCOMM based service on a
 			remote device and returns a file descriptor to talk
@@ -40,18 +25,3 @@ Methods		fd ConnectFD(string pattern) [experimental]
 					 org.bluez.Error.InProgress
 					 org.bluez.Error.ConnectionAttemptFailed
 					 org.bluez.Error.NotSupported
-
-
-		void Disconnect(string device)
-
-			Disconnect a RFCOMM TTY device that has been
-			created by Connect method.
-
-			To abort a connection attempt in case of errors or
-			timeouts in the client it is fine to call this method.
-
-			In that case one of patterns of the Connect method should
-			be supplied instead of the TTY device.
-
-			Possible errors: org.bluez.Error.InvalidArguments
-					 org.bluez.Error.DoesNotExist
diff --git a/serial/port.c b/serial/port.c
index 2422cfe..f2b7184 100644
--- a/serial/port.c
+++ b/serial/port.c
@@ -69,8 +69,6 @@ struct serial_port {
 	int16_t		id;		/* RFCOMM device id */
 	uint8_t		channel;	/* RFCOMM channel */
 	char		*uuid;		/* service identification */
-	char		*dev;		/* RFCOMM device name */
-	int		fd;		/* Opened file descriptor */
 	GIOChannel	*io;		/* BtIO channel */
 	guint		listener_id;
 	struct serial_device *device;
@@ -111,9 +109,6 @@ static struct serial_port *find_port(GSList *ports, const char *pattern)
 		if (endptr && *endptr == '\0' && port->channel == channel)
 			return port;
 
-		if (port->dev && !strcmp(port->dev, pattern))
-			return port;
-
 		if (!port->uuid)
 			continue;
 
@@ -130,12 +125,8 @@ static struct serial_port *find_port(GSList *ports, const char *pattern)
 	return NULL;
 }
 
-static int port_release(struct serial_port *port)
+static void port_release(struct serial_port *port)
 {
-	struct rfcomm_dev_req req;
-	int rfcomm_ctl;
-	int err = 0;
-
 	if (port->id < 0) {
 		if (port->io) {
 			g_io_channel_shutdown(port->io, TRUE, NULL);
@@ -145,41 +136,7 @@ static int port_release(struct serial_port *port)
 			bt_cancel_discovery(&port->device->src,
 						&port->device->dst);
 
-		return 0;
 	}
-
-	DBG("Serial port %s released", port->dev);
-
-	rfcomm_ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM);
-	if (rfcomm_ctl < 0)
-		return -errno;
-
-	if (port->fd >= 0) {
-		close(port->fd);
-		port->fd = -1;
-	}
-
-	memset(&req, 0, sizeof(req));
-	req.dev_id = port->id;
-
-	/*
-	 * We are hitting a kernel bug inside RFCOMM code when
-	 * RFCOMM_HANGUP_NOW bit is set on request's flags passed to
-	 * ioctl(RFCOMMRELEASEDEV)!
-	 */
-	req.flags = (1 << RFCOMM_HANGUP_NOW);
-
-	if (ioctl(rfcomm_ctl, RFCOMMRELEASEDEV, &req) < 0) {
-		err = -errno;
-		error("Can't release device %s: %s (%d)",
-				port->dev, strerror(-err), -err);
-	}
-
-	g_free(port->dev);
-	port->dev = NULL;
-	port->id = -1;
-	close(rfcomm_ctl);
-	return err;
 }
 
 static void serial_port_free(void *data)
@@ -231,74 +188,12 @@ void port_release_all(void)
 	g_slist_free_full(devices, serial_device_free);
 }
 
-static void open_notify(int fd, int err, struct serial_port *port)
-{
-	struct serial_device *device = port->device;
-	DBusMessage *reply;
-
-	if (err < 0) {
-		/* Max tries exceeded */
-		port_release(port);
-		reply = btd_error_failed(port->msg, strerror(-err));
-	} else {
-		port->fd = fd;
-		reply = g_dbus_create_reply(port->msg,
-				DBUS_TYPE_STRING, &port->dev,
-				DBUS_TYPE_INVALID);
-	}
-
-	/* Reply to the requestor */
-	g_dbus_send_message(device->conn, reply);
-}
-
-static gboolean open_continue(gpointer user_data)
-{
-	struct serial_port *port = user_data;
-	int fd;
-	static int ntries = MAX_OPEN_TRIES;
-
-	if (!port->listener_id)
-		return FALSE; /* Owner exited */
-
-	fd = open(port->dev, O_RDONLY | O_NOCTTY);
-	if (fd < 0) {
-		int err = -errno;
-		error("Could not open %s: %s (%d)",
-				port->dev, strerror(-err), -err);
-		if (!--ntries) {
-			/* Reporting error */
-			open_notify(fd, err, port);
-			ntries = MAX_OPEN_TRIES;
-			return FALSE;
-		}
-		return TRUE;
-	}
-
-	/* Connection succeeded */
-	open_notify(fd, 0, port);
-	return FALSE;
-}
-
-static int port_open(struct serial_port *port)
-{
-	int fd;
-
-	fd = open(port->dev, O_RDONLY | O_NOCTTY);
-	if (fd < 0) {
-		g_timeout_add(OPEN_WAIT, open_continue, port);
-		return -EINPROGRESS;
-	}
-
-	return fd;
-}
-
 static void rfcomm_connect_cb(GIOChannel *chan, GError *conn_err,
 							gpointer user_data)
 {
 	struct serial_port *port = user_data;
 	struct serial_device *device = port->device;
-	struct rfcomm_dev_req req;
-	int sk, fd;
+	int sk;
 	DBusMessage *reply;
 
 	/* Owner exited? */
@@ -308,60 +203,18 @@ static void rfcomm_connect_cb(GIOChannel *chan, GError *conn_err,
 	if (conn_err) {
 		error("%s", conn_err->message);
 		reply = btd_error_failed(port->msg, conn_err->message);
-		goto fail;
-	}
-
-	sk = g_io_channel_unix_get_fd(chan);
-
-	if (dbus_message_has_member(port->msg, "ConnectFD")) {
-		reply = g_dbus_create_reply(port->msg, DBUS_TYPE_UNIX_FD, &sk,
-							DBUS_TYPE_INVALID);
 		g_dbus_send_message(device->conn, reply);
-
-		close(sk);
-
-		g_dbus_remove_watch(device->conn, port->listener_id);
-		port->listener_id = 0;
-
-		return;
-	}
-
-	memset(&req, 0, sizeof(req));
-	req.dev_id = -1;
-	req.flags = (1 << RFCOMM_REUSE_DLC);
-	bacpy(&req.src, &device->src);
-	bacpy(&req.dst, &device->dst);
-	req.channel = port->channel;
-
-	g_io_channel_unref(port->io);
-	port->io = NULL;
-
-	port->id = ioctl(sk, RFCOMMCREATEDEV, &req);
-	if (port->id < 0) {
-		int err = -errno;
-		error("ioctl(RFCOMMCREATEDEV): %s (%d)", strerror(-err), -err);
-		reply = btd_error_failed(port->msg, strerror(-err));
-		g_io_channel_shutdown(chan, TRUE, NULL);
 		goto fail;
 	}
 
-	port->dev = g_strdup_printf("/dev/rfcomm%d", port->id);
-
-	DBG("Serial port %s created", port->dev);
-
-	g_io_channel_shutdown(chan, TRUE, NULL);
-
-	/* Addressing connect port */
-	fd = port_open(port);
-	if (fd < 0)
-		/* Open in progress: Wait the callback */
-		return;
+	sk = g_io_channel_unix_get_fd(chan);
+	reply = g_dbus_create_reply(port->msg, DBUS_TYPE_UNIX_FD, &sk,
+						DBUS_TYPE_INVALID);
+	g_dbus_send_message(device->conn, reply);
 
-	open_notify(fd, 0, port);
-	return;
+	close(sk);
 
 fail:
-	g_dbus_send_message(device->conn, reply);
 	g_dbus_remove_watch(device->conn, port->listener_id);
 	port->listener_id = 0;
 }
@@ -468,7 +321,6 @@ static struct serial_port *create_port(struct serial_device *device,
 	port->channel = channel;
 	port->device = device;
 	port->id = -1;
-	port->fd = -1;
 
 	device->ports = g_slist_append(device->ports, port);
 
@@ -521,47 +373,10 @@ static DBusMessage *port_connect(DBusConnection *conn,
 	return NULL;
 }
 
-static DBusMessage *port_disconnect(DBusConnection *conn,
-					DBusMessage *msg, void *user_data)
-{
-	struct serial_device *device = user_data;
-	struct serial_port *port;
-	const char *dev, *owner, *caller;
-
-	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &dev,
-						DBUS_TYPE_INVALID) == FALSE)
-		return NULL;
-
-	port = find_port(device->ports, dev);
-	if (!port)
-		return btd_error_does_not_exist(msg);
-
-	if (!port->listener_id)
-		return btd_error_not_connected(msg);
-
-	owner = dbus_message_get_sender(port->msg);
-	caller = dbus_message_get_sender(msg);
-	if (!g_str_equal(owner, caller))
-		return btd_error_not_authorized(msg);
-
-	port_release(port);
-
-	g_dbus_remove_watch(conn, port->listener_id);
-	port->listener_id = 0;
-
-	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-}
-
 static const GDBusMethodTable port_methods[] = {
 	{ GDBUS_ASYNC_METHOD("Connect",
-		GDBUS_ARGS({ "pattern", "s" }),	GDBUS_ARGS({ "tty", "s" }),
-		port_connect) },
-	{ GDBUS_ASYNC_METHOD("ConnectFD",
-		GDBUS_ARGS({ "pattern", "s" }), GDBUS_ARGS({ "fd", "s" }),
+		GDBUS_ARGS({ "pattern", "s" }),	GDBUS_ARGS({ "fd", "s" }),
 		port_connect) },
-	{ GDBUS_METHOD("Disconnect",
-		GDBUS_ARGS({ "device", "s" }), NULL,
-		port_disconnect) },
 	{ }
 };
 
@@ -615,7 +430,6 @@ int port_register(DBusConnection *conn, const char *path, bdaddr_t *src,
 	port->channel = channel;
 	port->device = device;
 	port->id = -1;
-	port->fd = -1;
 
 	device->ports = g_slist_append(device->ports, port);
 
-- 
1.7.10.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH -v3 07/19] emulator: move it to the tools folder
  2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
                   ` (4 preceding siblings ...)
  2012-07-04 12:51 ` [PATCH -v3 06/19] serial: remove old way to connect to a serial port Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 08/19] btmgmt: move to " Gustavo Padovan
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

---
 .gitignore              |    2 +-
 Makefile.tools          |   12 +-
 emulator/btdev.c        | 1076 -----------------------------------------------
 emulator/btdev.h        |   38 --
 emulator/main.c         |   73 ----
 emulator/server.c       |  288 -------------
 emulator/server.h       |   30 --
 emulator/vhci.c         |  133 ------
 emulator/vhci.h         |   35 --
 tools/emulator/btdev.c  | 1076 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/emulator/btdev.h  |   38 ++
 tools/emulator/main.c   |   73 ++++
 tools/emulator/server.c |  288 +++++++++++++
 tools/emulator/server.h |   30 ++
 tools/emulator/vhci.c   |  133 ++++++
 tools/emulator/vhci.h   |   35 ++
 16 files changed, 1680 insertions(+), 1680 deletions(-)
 delete mode 100644 emulator/btdev.c
 delete mode 100644 emulator/btdev.h
 delete mode 100644 emulator/main.c
 delete mode 100644 emulator/server.c
 delete mode 100644 emulator/server.h
 delete mode 100644 emulator/vhci.c
 delete mode 100644 emulator/vhci.h
 create mode 100644 tools/emulator/btdev.c
 create mode 100644 tools/emulator/btdev.h
 create mode 100644 tools/emulator/main.c
 create mode 100644 tools/emulator/server.c
 create mode 100644 tools/emulator/server.h
 create mode 100644 tools/emulator/vhci.c
 create mode 100644 tools/emulator/vhci.h

diff --git a/.gitignore b/.gitignore
index c7d079e..aaf52c3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -88,7 +88,7 @@ compat/pand
 unit/test-eir
 mgmt/btmgmt
 monitor/btmon
-emulator/btvirt
+tools/emulator/btvirt
 
 doc/*.bak
 doc/*.stamp
diff --git a/Makefile.tools b/Makefile.tools
index 1626a4b..e1be0fa 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -50,7 +50,7 @@ tools_ppporc_LDADD = lib/libbluetooth-private.la
 
 tools_hcieventmask_LDADD = lib/libbluetooth-private.la
 
-noinst_PROGRAMS += mgmt/btmgmt monitor/btmon emulator/btvirt
+noinst_PROGRAMS += mgmt/btmgmt monitor/btmon tools/emulator/btvirt
 
 mgmt_btmgmt_SOURCES = mgmt/main.c src/glib-helper.c
 mgmt_btmgmt_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@
@@ -63,11 +63,11 @@ monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
 					monitor/packet.h monitor/packet.c
 monitor_btmon_LDADD = lib/libbluetooth-private.la
 
-emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
-					monitor/mainloop.h monitor/mainloop.c \
-					emulator/server.h emulator/server.c \
-					emulator/vhci.h emulator/vhci.c \
-					emulator/btdev.h emulator/btdev.c
+emulator_btvirt_SOURCES = tools/emulator/main.c monitor/bt.h \
+			monitor/mainloop.h monitor/mainloop.c \
+			tools/emulator/server.h tools/emulator/server.c \
+			tools/emulator/vhci.h tools/emulator/vhci.c \
+			tools/emulator/btdev.h tools/emulator/btdev.c
 
 if READLINE
 bin_PROGRAMS += attrib/gatttool
diff --git a/emulator/btdev.c b/emulator/btdev.c
deleted file mode 100644
index 7d4517a..0000000
--- a/emulator/btdev.c
+++ /dev/null
@@ -1,1076 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011-2012  Intel Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "bt.h"
-#include "btdev.h"
-
-#define le16_to_cpu(val) (val)
-#define cpu_to_le16(val) (val)
-
-struct btdev {
-	struct btdev *conn;
-
-	btdev_send_func send_handler;
-	void *send_data;
-
-        uint16_t manufacturer;
-        uint8_t  version;
-	uint16_t revision;
-	uint8_t  commands[64];
-	uint8_t  features[8];
-	uint16_t acl_mtu;
-	uint16_t acl_max_pkt;
-	uint8_t  country_code;
-	uint8_t  bdaddr[6];
-	uint8_t  le_features[8];
-	uint8_t  le_states[8];
-
-	uint16_t default_link_policy;
-	uint8_t  event_mask[8];
-	uint8_t  event_filter;
-	uint8_t  name[248];
-	uint8_t  dev_class[3];
-	uint16_t voice_setting;
-	uint16_t conn_accept_timeout;
-	uint16_t page_timeout;
-	uint8_t  scan_enable;
-	uint8_t  auth_enable;
-	uint8_t  inquiry_mode;
-	uint8_t  afh_assess_mode;
-	uint8_t  ext_inquiry_fec;
-	uint8_t  ext_inquiry_rsp[240];
-	uint8_t  simple_pairing_mode;
-	uint8_t  le_supported;
-	uint8_t  le_simultaneous;
-	uint8_t  le_event_mask[8];
-};
-
-#define MAX_BTDEV_ENTRIES 16
-
-static struct btdev *btdev_list[MAX_BTDEV_ENTRIES] = { };
-
-static inline int add_btdev(struct btdev *btdev)
-{
-	int i, index = -1;
-
-	for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
-		if (btdev_list[i] == NULL) {
-			index = i;
-			btdev_list[index] = btdev;
-			break;
-		}
-	}
-
-	return index;
-}
-
-static inline int del_btdev(struct btdev *btdev)
-{
-	int i, index = -1;
-
-	for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
-		if (btdev_list[i] == btdev) {
-			index = i;
-			btdev_list[index] = NULL;
-			break;
-		}
-	}
-
-	return index;
-}
-
-static inline struct btdev *find_btdev_by_bdaddr(const uint8_t *bdaddr)
-{
-	int i;
-
-	for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
-		if (btdev_list[i] && !memcmp(btdev_list[i]->bdaddr, bdaddr, 6))
-			return btdev_list[i];
-	}
-
-	return NULL;
-}
-
-static void hexdump(const unsigned char *buf, uint16_t len)
-{
-	static const char hexdigits[] = "0123456789abcdef";
-	char str[68];
-	uint16_t i;
-
-	if (!len)
-		return;
-
-	for (i = 0; i < len; i++) {
-		str[((i % 16) * 3) + 0] = hexdigits[buf[i] >> 4];
-		str[((i % 16) * 3) + 1] = hexdigits[buf[i] & 0xf];
-		str[((i % 16) * 3) + 2] = ' ';
-		str[(i % 16) + 49] = isprint(buf[i]) ? buf[i] : '.';
-
-		if ((i + 1) % 16 == 0) {
-			str[47] = ' ';
-			str[48] = ' ';
-			str[65] = '\0';
-			printf("%-12c%s\n", ' ', str);
-			str[0] = ' ';
-		}
-	}
-
-	if (i % 16 > 0) {
-		uint16_t j;
-		for (j = (i % 16); j < 16; j++) {
-			str[(j * 3) + 0] = ' ';
-			str[(j * 3) + 1] = ' ';
-			str[(j * 3) + 2] = ' ';
-			str[j + 49] = ' ';
-		}
-		str[47] = ' ';
-		str[48] = ' ';
-		str[65] = '\0';
-		printf("%-12c%s\n", ' ', str);
-	}
-}
-
-static void get_bdaddr(uint16_t id, uint8_t *bdaddr)
-{
-	bdaddr[0] = id & 0xff;
-	bdaddr[1] = id >> 8;
-	bdaddr[2] = 0x00;
-	bdaddr[3] = 0x01;
-	bdaddr[4] = 0xaa;
-	bdaddr[5] = 0x00;
-}
-
-struct btdev *btdev_create(uint16_t id)
-{
-	struct btdev *btdev;
-
-	btdev = malloc(sizeof(*btdev));
-	if (!btdev)
-		return NULL;
-
-	memset(btdev, 0, sizeof(*btdev));
-
-	btdev->manufacturer = 63;
-	btdev->version = 0x06;
-	btdev->revision = 0x0000;
-
-	btdev->features[0] |= 0x04;	/* Encryption */
-	btdev->features[0] |= 0x20;	/* Role switch */
-	btdev->features[0] |= 0x80;	/* Sniff mode */
-	btdev->features[1] |= 0x08;	/* SCO link */
-	btdev->features[3] |= 0x40;	/* RSSI with inquiry results */
-	btdev->features[3] |= 0x80;	/* Extended SCO link */
-	btdev->features[4] |= 0x08;	/* AFH capable slave */
-	btdev->features[4] |= 0x10;	/* AFH classification slave */
-	btdev->features[4] |= 0x40;	/* LE Supported */
-	btdev->features[5] |= 0x02;	/* Sniff subrating */
-	btdev->features[5] |= 0x04;	/* Pause encryption */
-	btdev->features[5] |= 0x08;	/* AFH capable master */
-	btdev->features[5] |= 0x10;	/* AFH classification master */
-	btdev->features[6] |= 0x01;	/* Extended Inquiry Response */
-	btdev->features[6] |= 0x02;	/* Simultaneous LE and BR/EDR */
-	btdev->features[6] |= 0x08;	/* Secure Simple Pairing */
-	btdev->features[6] |= 0x10;	/* Encapsulated PDU */
-	btdev->features[6] |= 0x20;	/* Erroneous Data Reporting */
-	btdev->features[6] |= 0x40;	/* Non-flushable Packet Boundary Flag */
-	btdev->features[7] |= 0x01;	/* Link Supervision Timeout Event */
-	btdev->features[7] |= 0x02;	/* Inquiry TX Power Level */
-	btdev->features[7] |= 0x80;	/* Extended features */
-
-	btdev->acl_mtu = 192;
-	btdev->acl_max_pkt = 1;
-
-	btdev->country_code = 0x00;
-
-	get_bdaddr(id, btdev->bdaddr);
-
-	add_btdev(btdev);
-
-	return btdev;
-}
-
-void btdev_destroy(struct btdev *btdev)
-{
-	if (!btdev)
-		return;
-
-	del_btdev(btdev);
-
-	free(btdev);
-}
-
-void btdev_set_send_handler(struct btdev *btdev, btdev_send_func handler,
-							void *user_data)
-{
-	if (!btdev)
-		return;
-
-	btdev->send_handler = handler;
-	btdev->send_data = user_data;
-}
-
-static void send_packet(struct btdev *btdev, const void *data, uint16_t len)
-{
-	if (!btdev->send_handler)
-		return;
-
-	btdev->send_handler(data, len, btdev->send_data);
-}
-
-static void send_event(struct btdev *btdev, uint8_t event,
-						const void *data, uint8_t len)
-{
-	struct bt_hci_evt_hdr *hdr;
-	uint16_t pkt_len;
-	void *pkt_data;
-
-	pkt_len = 1 + sizeof(*hdr) + len;
-
-	pkt_data = malloc(pkt_len);
-	if (!pkt_data)
-		return;
-
-	((uint8_t *) pkt_data)[0] = BT_H4_EVT_PKT;
-
-	hdr = pkt_data + 1;
-	hdr->evt = event;
-	hdr->plen = len;
-
-	if (len > 0)
-		memcpy(pkt_data + 1 + sizeof(*hdr), data, len);
-
-	send_packet(btdev, pkt_data, pkt_len);
-
-	free(pkt_data);
-}
-
-static void cmd_complete(struct btdev *btdev, uint16_t opcode,
-						const void *data, uint8_t len)
-{
-	struct bt_hci_evt_hdr *hdr;
-	struct bt_hci_evt_cmd_complete *cc;
-	uint16_t pkt_len;
-	void *pkt_data;
-
-	pkt_len = 1 + sizeof(*hdr) + sizeof(*cc) + len;
-
-	pkt_data = malloc(pkt_len);
-	if (!pkt_data)
-		return;
-
-	((uint8_t *) pkt_data)[0] = BT_H4_EVT_PKT;
-
-	hdr = pkt_data + 1;
-	hdr->evt = BT_HCI_EVT_CMD_COMPLETE;
-	hdr->plen = sizeof(*cc) + len;
-
-	cc = pkt_data + 1 + sizeof(*hdr);
-	cc->ncmd = 0x01;
-	cc->opcode = cpu_to_le16(opcode);
-
-	if (len > 0)
-		memcpy(pkt_data + 1 + sizeof(*hdr) + sizeof(*cc), data, len);
-
-	send_packet(btdev, pkt_data, pkt_len);
-
-	free(pkt_data);
-}
-
-static void cmd_status(struct btdev *btdev, uint8_t status, uint16_t opcode)
-{
-	struct bt_hci_evt_cmd_status cs;
-
-	cs.status = status;
-	cs.ncmd = 0x01;
-	cs.opcode = cpu_to_le16(opcode);
-
-	send_event(btdev, BT_HCI_EVT_CMD_STATUS, &cs, sizeof(cs));
-}
-
-static void num_completed_packets(struct btdev *btdev)
-{
-	if (btdev->conn) {
-		struct bt_hci_evt_num_completed_packets ncp;
-
-		ncp.num_handles = 1;
-		ncp.handle = cpu_to_le16(42);
-		ncp.count = cpu_to_le16(1);
-
-		send_event(btdev, BT_HCI_EVT_NUM_COMPLETED_PACKETS,
-							&ncp, sizeof(ncp));
-	}
-}
-
-static void inquiry_complete(struct btdev *btdev, uint8_t status)
-{
-	struct bt_hci_evt_inquiry_complete ic;
-	int i;
-
-	for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
-		if (!btdev_list[i] || btdev_list[i] == btdev)
-			continue;
-
-		if (!(btdev_list[i]->scan_enable & 0x02))
-			continue;
-
-		if (btdev->inquiry_mode == 0x02 &&
-					btdev_list[i]->ext_inquiry_rsp[0]) {
-			struct bt_hci_evt_ext_inquiry_result ir;
-
-			ir.num_resp = 0x01;
-			memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
-			memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
-			ir.rssi = -60;
-			memcpy(ir.data, btdev_list[i]->ext_inquiry_rsp, 240);
-
-			send_event(btdev, BT_HCI_EVT_EXT_INQUIRY_RESULT,
-							&ir, sizeof(ir));
-			continue;
-		}
-
-		if (btdev->inquiry_mode > 0x00) {
-			struct bt_hci_evt_inquiry_result_with_rssi ir;
-
-			ir.num_resp = 0x01;
-			memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
-			memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
-			ir.rssi = -60;
-
-			send_event(btdev, BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI,
-							&ir, sizeof(ir));
-		} else {
-			struct bt_hci_evt_inquiry_result ir;
-
-			ir.num_resp = 0x01;
-			memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
-			memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
-
-			send_event(btdev, BT_HCI_EVT_INQUIRY_RESULT,
-							&ir, sizeof(ir));
-		}
-        }
-
-	ic.status = status;
-
-	send_event(btdev, BT_HCI_EVT_INQUIRY_COMPLETE, &ic, sizeof(ic));
-}
-
-static void conn_complete(struct btdev *btdev,
-					const uint8_t *bdaddr, uint8_t status)
-{
-	struct bt_hci_evt_conn_complete cc;
-
-	if (!status) {
-		struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
-
-		btdev->conn = remote;
-		remote->conn = btdev;
-
-		cc.status = status;
-		memcpy(cc.bdaddr, btdev->bdaddr, 6);
-		cc.encr_mode = 0x00;
-
-		cc.handle = cpu_to_le16(42);
-		cc.link_type = 0x01;
-
-		send_event(remote, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc));
-
-		cc.handle = cpu_to_le16(42);
-		cc.link_type = 0x01;
-	} else {
-		cc.handle = cpu_to_le16(0x0000);
-		cc.link_type = 0x01;
-	}
-
-	cc.status = status;
-	memcpy(cc.bdaddr, bdaddr, 6);
-	cc.encr_mode = 0x00;
-
-	send_event(btdev, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc));
-}
-
-static void conn_request(struct btdev *btdev, const uint8_t *bdaddr)
-{
-	struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
-
-	if (remote) {
-		if (remote->scan_enable & 0x01) {
-			struct bt_hci_evt_conn_request cr;
-
-			memcpy(cr.bdaddr, btdev->bdaddr, 6);
-			memcpy(cr.dev_class, btdev->dev_class, 3);
-			cr.link_type = 0x01;
-
-			send_event(remote, BT_HCI_EVT_CONN_REQUEST,
-							&cr, sizeof(cr));
-		} else
-			conn_complete(btdev, bdaddr, BT_HCI_ERR_PAGE_TIMEOUT);
-	} else
-		conn_complete(btdev, bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
-}
-
-static void disconnect_complete(struct btdev *btdev, uint16_t handle,
-							uint8_t reason)
-{
-	struct bt_hci_evt_disconnect_complete dc;
-	struct btdev *remote;
-
-	if (!btdev) {
-		dc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
-		dc.handle = cpu_to_le16(handle);
-		dc.reason = 0x00;
-
-		send_event(btdev, BT_HCI_EVT_DISCONNECT_COMPLETE,
-							&dc, sizeof(dc));
-		return;
-	}
-
-	dc.status = BT_HCI_ERR_SUCCESS;
-	dc.handle = cpu_to_le16(handle);
-	dc.reason = reason;
-
-	remote = btdev->conn;
-
-	btdev->conn = NULL;
-	remote->conn = NULL;
-
-	send_event(btdev, BT_HCI_EVT_DISCONNECT_COMPLETE, &dc, sizeof(dc));
-	send_event(remote, BT_HCI_EVT_DISCONNECT_COMPLETE, &dc, sizeof(dc));
-}
-
-static void name_request_complete(struct btdev *btdev,
-					const uint8_t *bdaddr, uint8_t status)
-{
-        struct bt_hci_evt_remote_name_req_complete nc;
-
-	nc.status = status;
-	memcpy(nc.bdaddr, bdaddr, 6);
-	memset(nc.name, 0, 248);
-
-	if (!status) {
-		struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
-
-		if (remote)
-			memcpy(nc.name, remote->name, 248);
-		else
-			nc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
-	}
-
-	send_event(btdev, BT_HCI_EVT_REMOTE_NAME_REQUEST_COMPLETE,
-							&nc, sizeof(nc));
-}
-
-static void remote_features_complete(struct btdev *btdev, uint16_t handle)
-{
-	struct bt_hci_evt_remote_features_complete rfc;
-
-	if (btdev->conn) {
-		rfc.status = BT_HCI_ERR_SUCCESS;
-		rfc.handle = cpu_to_le16(handle);
-		memcpy(rfc.features, btdev->conn->features, 8);
-	} else {
-		rfc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
-		rfc.handle = cpu_to_le16(handle);
-		memset(rfc.features, 0, 8);
-	}
-
-	send_event(btdev, BT_HCI_EVT_REMOTE_FEATURES_COMPLETE,
-							&rfc, sizeof(rfc));
-}
-
-static void remote_ext_features_complete(struct btdev *btdev, uint16_t handle,
-								uint8_t page)
-{
-	struct bt_hci_evt_remote_ext_features_complete refc;
-
-	if (btdev->conn && page < 0x02) {
-		refc.handle = cpu_to_le16(handle);
-		refc.page = page;
-		refc.max_page = 0x01;
-
-		switch (page) {
-		case 0x00:
-			refc.status = BT_HCI_ERR_SUCCESS;
-			memcpy(refc.features, btdev->conn->features, 8);
-			break;
-		case 0x01:
-			refc.status = BT_HCI_ERR_SUCCESS;
-			memset(refc.features, 0, 8);
-			break;
-		default:
-			refc.status = BT_HCI_ERR_INVALID_PARAMETERS;
-			memset(refc.features, 0, 8);
-			break;
-		}
-	} else {
-		refc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
-		refc.handle = cpu_to_le16(handle);
-		refc.page = page;
-		refc.max_page = 0x01;
-		memset(refc.features, 0, 8);
-	}
-
-	send_event(btdev, BT_HCI_EVT_REMOTE_EXT_FEATURES_COMPLETE,
-							&refc, sizeof(refc));
-}
-
-static void remote_version_complete(struct btdev *btdev, uint16_t handle)
-{
-	struct bt_hci_evt_remote_version_complete rvc;
-
-	if (btdev->conn) {
-		rvc.status = BT_HCI_ERR_SUCCESS;
-		rvc.handle = cpu_to_le16(handle);
-		rvc.lmp_ver = btdev->conn->version;
-		rvc.manufacturer = cpu_to_le16(btdev->conn->manufacturer);
-		rvc.lmp_subver = cpu_to_le16(btdev->conn->revision);
-	} else {
-		rvc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
-		rvc.handle = cpu_to_le16(handle);
-		rvc.lmp_ver = 0x00;
-		rvc.manufacturer = cpu_to_le16(0);
-		rvc.lmp_subver = cpu_to_le16(0);
-	}
-
-	send_event(btdev, BT_HCI_EVT_REMOTE_VERSION_COMPLETE,
-							&rvc, sizeof(rvc));
-}
-
-static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
-{
-	const struct bt_hci_cmd_hdr *hdr = data;
-	const struct bt_hci_cmd_create_conn *cc;
-	const struct bt_hci_cmd_disconnect *dc;
-	const struct bt_hci_cmd_create_conn_cancel *ccc;
-	const struct bt_hci_cmd_accept_conn_request *acr;
-	const struct bt_hci_cmd_reject_conn_request *rcr;
-	const struct bt_hci_cmd_remote_name_request *rnr;
-	const struct bt_hci_cmd_remote_name_request_cancel *rnrc;
-	const struct bt_hci_cmd_read_remote_features *rrf;
-	const struct bt_hci_cmd_read_remote_ext_features *rref;
-	const struct bt_hci_cmd_read_remote_version *rrv;
-	const struct bt_hci_cmd_write_default_link_policy *wdlp;
-	const struct bt_hci_cmd_set_event_mask *sem;
-	const struct bt_hci_cmd_set_event_filter *sef;
-	const struct bt_hci_cmd_write_local_name *wln;
-	const struct bt_hci_cmd_write_conn_accept_timeout *wcat;
-	const struct bt_hci_cmd_write_page_timeout *wpt;
-	const struct bt_hci_cmd_write_scan_enable *wse;
-	const struct bt_hci_cmd_write_auth_enable *wae;
-	const struct bt_hci_cmd_write_class_of_dev *wcod;
-	const struct bt_hci_cmd_write_voice_setting *wvs;
-	const struct bt_hci_cmd_write_inquiry_mode *wim;
-	const struct bt_hci_cmd_write_afh_assess_mode *waam;
-	const struct bt_hci_cmd_write_ext_inquiry_rsp *weir;
-	const struct bt_hci_cmd_write_simple_pairing_mode *wspm;
-	const struct bt_hci_cmd_write_le_host_supported *wlhs;
-	const struct bt_hci_cmd_le_set_event_mask *lsem;
-	struct bt_hci_rsp_read_default_link_policy rdlp;
-	struct bt_hci_rsp_read_stored_link_key rslk;
-	struct bt_hci_rsp_write_stored_link_key wslk;
-	struct bt_hci_rsp_delete_stored_link_key dslk;
-	struct bt_hci_rsp_read_local_name rln;
-	struct bt_hci_rsp_read_conn_accept_timeout rcat;
-	struct bt_hci_rsp_read_page_timeout rpt;
-	struct bt_hci_rsp_read_scan_enable rse;
-	struct bt_hci_rsp_read_auth_enable rae;
-	struct bt_hci_rsp_read_class_of_dev rcod;
-	struct bt_hci_rsp_read_voice_setting rvs;
-	struct bt_hci_rsp_read_inquiry_mode rim;
-	struct bt_hci_rsp_read_afh_assess_mode raam;
-	struct bt_hci_rsp_read_ext_inquiry_rsp reir;
-	struct bt_hci_rsp_read_simple_pairing_mode rspm;
-	struct bt_hci_rsp_read_inquiry_rsp_tx_power rirtp;
-	struct bt_hci_rsp_read_le_host_supported rlhs;
-	struct bt_hci_rsp_read_local_version rlv;
-	struct bt_hci_rsp_read_local_commands rlc;
-	struct bt_hci_rsp_read_local_features rlf;
-	struct bt_hci_rsp_read_local_ext_features rlef;
-	struct bt_hci_rsp_read_buffer_size rbs;
-	struct bt_hci_rsp_read_country_code rcc;
-	struct bt_hci_rsp_read_bd_addr rba;
-	struct bt_hci_rsp_read_data_block_size rdbs;
-	struct bt_hci_rsp_le_read_buffer_size lrbs;
-	struct bt_hci_rsp_le_read_local_features lrlf;
-	struct bt_hci_rsp_le_read_supported_states lrss;
-	uint16_t opcode;
-	uint8_t status, page;
-
-	if (len < sizeof(*hdr))
-		return;
-
-	opcode = le16_to_cpu(hdr->opcode);
-
-	switch (opcode) {
-	case BT_HCI_CMD_INQUIRY:
-		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
-		inquiry_complete(btdev, BT_HCI_ERR_SUCCESS);
-		break;
-
-	case BT_HCI_CMD_INQUIRY_CANCEL:
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_CREATE_CONN:
-		cc = data + sizeof(*hdr);
-		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
-		conn_request(btdev, cc->bdaddr);
-		break;
-
-	case BT_HCI_CMD_DISCONNECT:
-		dc = data + sizeof(*hdr);
-		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
-		disconnect_complete(btdev, le16_to_cpu(dc->handle), dc->reason);
-		break;
-
-	case BT_HCI_CMD_CREATE_CONN_CANCEL:
-		ccc = data + sizeof(*hdr);
-		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
-		conn_complete(btdev, ccc->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
-		break;
-
-	case BT_HCI_CMD_ACCEPT_CONN_REQUEST:
-		acr = data + sizeof(*hdr);
-		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
-		conn_complete(btdev, acr->bdaddr, BT_HCI_ERR_SUCCESS);
-		break;
-
-	case BT_HCI_CMD_REJECT_CONN_REQUEST:
-		rcr = data + sizeof(*hdr);
-		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
-		conn_complete(btdev, rcr->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
-		break;
-
-	case BT_HCI_CMD_REMOTE_NAME_REQUEST:
-		rnr = data + sizeof(*hdr);
-		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
-		name_request_complete(btdev, rnr->bdaddr, BT_HCI_ERR_SUCCESS);
-		break;
-
-	case BT_HCI_CMD_REMOTE_NAME_REQUEST_CANCEL:
-		rnrc = data + sizeof(*hdr);
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		name_request_complete(btdev, rnrc->bdaddr,
-						BT_HCI_ERR_UNKNOWN_CONN_ID);
-		break;
-
-	case BT_HCI_CMD_READ_REMOTE_FEATURES:
-		rrf = data + sizeof(*hdr);
-		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
-		remote_features_complete(btdev, le16_to_cpu(rrf->handle));
-		break;
-
-	case BT_HCI_CMD_READ_REMOTE_EXT_FEATURES:
-		rref = data + sizeof(*hdr);
-		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
-		remote_ext_features_complete(btdev, le16_to_cpu(rref->handle),
-								rref->page);
-		break;
-
-	case BT_HCI_CMD_READ_REMOTE_VERSION:
-		rrv = data + sizeof(*hdr);
-		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
-		remote_version_complete(btdev, le16_to_cpu(rrv->handle));
-		break;
-
-	case BT_HCI_CMD_READ_DEFAULT_LINK_POLICY:
-		rdlp.status = BT_HCI_ERR_SUCCESS;
-		rdlp.policy = cpu_to_le16(btdev->default_link_policy);
-		cmd_complete(btdev, opcode, &rdlp, sizeof(rdlp));
-		break;
-
-	case BT_HCI_CMD_WRITE_DEFAULT_LINK_POLICY:
-		wdlp = data + sizeof(*hdr);
-		btdev->default_link_policy = le16_to_cpu(wdlp->policy);
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_SET_EVENT_MASK:
-		sem = data + sizeof(*hdr);
-		memcpy(btdev->event_mask, sem->mask, 8);
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_RESET:
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_SET_EVENT_FILTER:
-		sef = data + sizeof(*hdr);
-		btdev->event_filter = sef->type;
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_READ_STORED_LINK_KEY:
-		rslk.status = BT_HCI_ERR_SUCCESS;
-		rslk.max_num_keys = cpu_to_le16(0);
-		rslk.num_keys = cpu_to_le16(0);
-		cmd_complete(btdev, opcode, &rslk, sizeof(rslk));
-		break;
-
-	case BT_HCI_CMD_WRITE_STORED_LINK_KEY:
-		wslk.status = BT_HCI_ERR_SUCCESS;
-		wslk.num_keys = 0;
-		cmd_complete(btdev, opcode, &wslk, sizeof(wslk));
-		break;
-
-	case BT_HCI_CMD_DELETE_STORED_LINK_KEY:
-		dslk.status = BT_HCI_ERR_SUCCESS;
-		dslk.num_keys = cpu_to_le16(0);
-		cmd_complete(btdev, opcode, &dslk, sizeof(dslk));
-		break;
-
-	case BT_HCI_CMD_WRITE_LOCAL_NAME:
-		wln = data + sizeof(*hdr);
-		memcpy(btdev->name, wln->name, 248);
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_READ_LOCAL_NAME:
-		rln.status = BT_HCI_ERR_SUCCESS;
-		memcpy(rln.name, btdev->name, 248);
-		cmd_complete(btdev, opcode, &rln, sizeof(rln));
-		break;
-
-	case BT_HCI_CMD_READ_CONN_ACCEPT_TIMEOUT:
-		rcat.status = BT_HCI_ERR_SUCCESS;
-		rcat.timeout = cpu_to_le16(btdev->conn_accept_timeout);
-		cmd_complete(btdev, opcode, &rcat, sizeof(rcat));
-		break;
-
-	case BT_HCI_CMD_WRITE_CONN_ACCEPT_TIMEOUT:
-		wcat = data + sizeof(*hdr);
-		btdev->conn_accept_timeout = le16_to_cpu(wcat->timeout);
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_READ_PAGE_TIMEOUT:
-		rpt.status = BT_HCI_ERR_SUCCESS;
-		rpt.timeout = cpu_to_le16(btdev->page_timeout);
-		cmd_complete(btdev, opcode, &rpt, sizeof(rpt));
-		break;
-
-	case BT_HCI_CMD_WRITE_PAGE_TIMEOUT:
-		wpt = data + sizeof(*hdr);
-		btdev->page_timeout = le16_to_cpu(wpt->timeout);
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_READ_SCAN_ENABLE:
-		rse.status = BT_HCI_ERR_SUCCESS;
-		rse.enable = btdev->scan_enable;
-		cmd_complete(btdev, opcode, &rse, sizeof(rse));
-		break;
-
-	case BT_HCI_CMD_WRITE_SCAN_ENABLE:
-		wse = data + sizeof(*hdr);
-		btdev->scan_enable = wse->enable;
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_READ_AUTH_ENABLE:
-		rae.status = BT_HCI_ERR_SUCCESS;
-		rae.enable = btdev->auth_enable;
-		cmd_complete(btdev, opcode, &rae, sizeof(rae));
-		break;
-
-	case BT_HCI_CMD_WRITE_AUTH_ENABLE:
-		wae = data + sizeof(*hdr);
-		btdev->auth_enable = wae->enable;
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_READ_CLASS_OF_DEV:
-		rcod.status = BT_HCI_ERR_SUCCESS;
-		memcpy(rcod.dev_class, btdev->dev_class, 3);
-		cmd_complete(btdev, opcode, &rcod, sizeof(rcod));
-		break;
-
-	case BT_HCI_CMD_WRITE_CLASS_OF_DEV:
-		wcod = data + sizeof(*hdr);
-		memcpy(btdev->dev_class, wcod->dev_class, 3);
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_READ_VOICE_SETTING:
-		rvs.status = BT_HCI_ERR_SUCCESS;
-		rvs.setting = cpu_to_le16(btdev->voice_setting);
-		cmd_complete(btdev, opcode, &rvs, sizeof(rvs));
-		break;
-
-	case BT_HCI_CMD_WRITE_VOICE_SETTING:
-		wvs = data + sizeof(*hdr);
-		btdev->voice_setting = le16_to_cpu(wvs->setting);
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_READ_INQUIRY_MODE:
-		rim.status = BT_HCI_ERR_SUCCESS;
-		rim.mode = btdev->inquiry_mode;
-		cmd_complete(btdev, opcode, &rim, sizeof(rim));
-		break;
-
-	case BT_HCI_CMD_WRITE_INQUIRY_MODE:
-		wim = data + sizeof(*hdr);
-		btdev->inquiry_mode = wim->mode;
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_READ_AFH_ASSESS_MODE:
-		raam.status = BT_HCI_ERR_SUCCESS;
-		raam.mode = btdev->afh_assess_mode;
-		cmd_complete(btdev, opcode, &raam, sizeof(raam));
-		break;
-
-	case BT_HCI_CMD_WRITE_AFH_ASSESS_MODE:
-		waam = data + sizeof(*hdr);
-		btdev->afh_assess_mode = waam->mode;
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_READ_EXT_INQUIRY_RSP:
-		reir.status = BT_HCI_ERR_SUCCESS;
-		reir.fec = btdev->ext_inquiry_fec;
-		memcpy(reir.data, btdev->ext_inquiry_rsp, 240);
-		cmd_complete(btdev, opcode, &reir, sizeof(reir));
-		break;
-
-	case BT_HCI_CMD_WRITE_EXT_INQUIRY_RSP:
-		weir = data + sizeof(*hdr);
-		btdev->ext_inquiry_fec = weir->fec;
-		memcpy(btdev->ext_inquiry_rsp, weir->data, 240);
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_READ_SIMPLE_PAIRING_MODE:
-		rspm.status = BT_HCI_ERR_SUCCESS;
-		rspm.mode = btdev->simple_pairing_mode;
-		cmd_complete(btdev, opcode, &rspm, sizeof(rspm));
-		break;
-
-	case BT_HCI_CMD_WRITE_SIMPLE_PAIRING_MODE:
-		wspm = data + sizeof(*hdr);
-		btdev->simple_pairing_mode = wspm->mode;
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_READ_INQUIRY_RSP_TX_POWER:
-		rirtp.status = BT_HCI_ERR_SUCCESS;
-		rirtp.level = 0;
-		cmd_complete(btdev, opcode, &rirtp, sizeof(rirtp));
-		break;
-
-	case BT_HCI_CMD_READ_LE_HOST_SUPPORTED:
-		rlhs.status = BT_HCI_ERR_SUCCESS;
-		rlhs.supported = btdev->le_supported;
-		rlhs.simultaneous = btdev->le_simultaneous;
-		cmd_complete(btdev, opcode, &rlhs, sizeof(rlhs));
-		break;
-
-	case BT_HCI_CMD_WRITE_LE_HOST_SUPPORTED:
-		wlhs = data + sizeof(*hdr);
-		btdev->le_supported = wlhs->supported;
-		btdev->le_simultaneous = wlhs->simultaneous;
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_READ_LOCAL_VERSION:
-		rlv.status = BT_HCI_ERR_SUCCESS;
-		rlv.hci_ver = btdev->version;
-		rlv.hci_rev = cpu_to_le16(btdev->revision);
-		rlv.lmp_ver = btdev->version;
-		rlv.manufacturer = cpu_to_le16(btdev->manufacturer);
-		rlv.lmp_subver = cpu_to_le16(btdev->revision);
-		cmd_complete(btdev, opcode, &rlv, sizeof(rlv));
-		break;
-
-	case BT_HCI_CMD_READ_LOCAL_COMMANDS:
-		rlc.status = BT_HCI_ERR_SUCCESS;
-		memcpy(rlc.commands, btdev->commands, 64);
-		cmd_complete(btdev, opcode, &rlc, sizeof(rlc));
-		break;
-
-	case BT_HCI_CMD_READ_LOCAL_FEATURES:
-		rlf.status = BT_HCI_ERR_SUCCESS;
-		memcpy(rlf.features, btdev->features, 8);
-		cmd_complete(btdev, opcode, &rlf, sizeof(rlf));
-		break;
-
-	case BT_HCI_CMD_READ_LOCAL_EXT_FEATURES:
-		page = ((const uint8_t *) data)[sizeof(*hdr)];
-		switch (page) {
-		case 0x00:
-			rlef.status = BT_HCI_ERR_SUCCESS;
-			rlef.page = 0x00;
-			rlef.max_page = 0x01;
-			memcpy(rlef.features, btdev->features, 8);
-			break;
-		case 0x01:
-			rlef.status = BT_HCI_ERR_SUCCESS;
-			rlef.page = 0x01;
-			rlef.max_page = 0x01;
-			memset(rlef.features, 0, 8);
-			if (btdev->simple_pairing_mode)
-				rlef.features[0] |= 0x01;
-			if (btdev->le_supported)
-				rlef.features[0] |= 0x02;
-			if (btdev->le_simultaneous)
-				rlef.features[0] |= 0x04;
-			break;
-		default:
-			rlef.status = BT_HCI_ERR_INVALID_PARAMETERS;
-			rlef.page = page;
-			rlef.max_page = 0x01;
-			memset(rlef.features, 0, 8);
-			break;
-		}
-		cmd_complete(btdev, opcode, &rlef, sizeof(rlef));
-		break;
-
-	case BT_HCI_CMD_READ_BUFFER_SIZE:
-		rbs.status = BT_HCI_ERR_SUCCESS;
-		rbs.acl_mtu = cpu_to_le16(btdev->acl_mtu);
-		rbs.sco_mtu = 0;
-		rbs.acl_max_pkt = cpu_to_le16(btdev->acl_max_pkt);
-		rbs.sco_max_pkt = cpu_to_le16(0);
-		cmd_complete(btdev, opcode, &rbs, sizeof(rbs));
-		break;
-
-	case BT_HCI_CMD_READ_COUNTRY_CODE:
-		rcc.status = BT_HCI_ERR_SUCCESS;
-		rcc.code = btdev->country_code;
-		cmd_complete(btdev, opcode, &rcc, sizeof(rcc));
-		break;
-
-	case BT_HCI_CMD_READ_BD_ADDR:
-		rba.status = BT_HCI_ERR_SUCCESS;
-		memcpy(rba.bdaddr, btdev->bdaddr, 6);
-		cmd_complete(btdev, opcode, &rba, sizeof(rba));
-		break;
-
-	case BT_HCI_CMD_READ_DATA_BLOCK_SIZE:
-		rdbs.status = BT_HCI_ERR_SUCCESS;
-		rdbs.max_acl_len = cpu_to_le16(btdev->acl_mtu);
-		rdbs.block_len = cpu_to_le16(btdev->acl_mtu);
-		rdbs.num_blocks = cpu_to_le16(btdev->acl_max_pkt);
-		cmd_complete(btdev, opcode, &rdbs, sizeof(rdbs));
-		break;
-
-	case BT_HCI_CMD_LE_SET_EVENT_MASK:
-		lsem = data + sizeof(*hdr);
-		memcpy(btdev->le_event_mask, lsem->mask, 8);
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_LE_READ_BUFFER_SIZE:
-		lrbs.status = BT_HCI_ERR_SUCCESS;
-		lrbs.le_mtu = cpu_to_le16(btdev->acl_mtu);
-		lrbs.le_max_pkt = btdev->acl_max_pkt;
-		cmd_complete(btdev, opcode, &lrbs, sizeof(lrbs));
-		break;
-
-	case BT_HCI_CMD_LE_READ_LOCAL_FEATURES:
-		lrlf.status = BT_HCI_ERR_SUCCESS;
-		memcpy(lrlf.features, btdev->le_features, 8);
-		cmd_complete(btdev, opcode, &lrlf, sizeof(lrlf));
-		break;
-
-	case BT_HCI_CMD_LE_SET_SCAN_PARAMETERS:
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_LE_SET_SCAN_ENABLE:
-		status = BT_HCI_ERR_SUCCESS;
-		cmd_complete(btdev, opcode, &status, sizeof(status));
-		break;
-
-	case BT_HCI_CMD_LE_READ_SUPPORTED_STATES:
-		lrss.status = BT_HCI_ERR_SUCCESS;
-		memcpy(lrss.states, btdev->le_states, 8);
-		cmd_complete(btdev, opcode, &lrss, sizeof(lrss));
-		break;
-
-	default:
-		printf("Unsupported command 0x%4.4x\n", opcode);
-		hexdump(data, len);
-		cmd_status(btdev, BT_HCI_ERR_UNKNOWN_COMMAND, opcode);
-		break;
-	}
-}
-
-void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len)
-{
-	uint8_t pkt_type;
-
-	if (!btdev)
-		return;
-
-	if (len < 1)
-		return;
-
-	pkt_type = ((const uint8_t *) data)[0];
-
-	switch (pkt_type) {
-	case BT_H4_CMD_PKT:
-		process_cmd(btdev, data + 1, len - 1);
-		break;
-	case BT_H4_ACL_PKT:
-		if (btdev->conn)
-			send_packet(btdev->conn, data, len);
-		num_completed_packets(btdev);
-		break;
-	default:
-		printf("Unsupported packet 0x%2.2x\n", pkt_type);
-		break;
-	}
-}
diff --git a/emulator/btdev.h b/emulator/btdev.h
deleted file mode 100644
index 7b211a2..0000000
--- a/emulator/btdev.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011-2012  Intel Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <stdint.h>
-
-typedef void (*btdev_send_func) (const void *data, uint16_t len,
-							void *user_data);
-
-struct btdev;
-
-struct btdev *btdev_create(uint16_t id);
-void btdev_destroy(struct btdev *btdev);
-
-void btdev_set_send_handler(struct btdev *btdev, btdev_send_func handler,
-							void *user_data);
-
-void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len);
diff --git a/emulator/main.c b/emulator/main.c
deleted file mode 100644
index 125460d..0000000
--- a/emulator/main.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011-2012  Intel Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-
-#include "mainloop.h"
-#include "server.h"
-#include "vhci.h"
-
-static void signal_callback(int signum, void *user_data)
-{
-	switch (signum) {
-	case SIGINT:
-	case SIGTERM:
-		mainloop_quit();
-		break;
-	}
-}
-
-int main(int argc, char *argv[])
-{
-	struct vhci *vhci;
-	struct server *server;
-	sigset_t mask;
-
-	mainloop_init();
-
-	sigemptyset(&mask);
-	sigaddset(&mask, SIGINT);
-	sigaddset(&mask, SIGTERM);
-
-	mainloop_set_signal(&mask, signal_callback, NULL, NULL);
-
-	vhci = vhci_open(VHCI_TYPE_BREDR, 0x23);
-	if (!vhci) {
-		fprintf(stderr, "Failed to open Virtual HCI device\n");
-		return 1;
-	}
-
-	server = server_open_unix("/tmp/bt-server-bredr", 0x42);
-	if (!server) {
-		fprintf(stderr, "Failed to open server channel\n");
-		vhci_close(vhci);
-		return 1;
-	}
-
-	return mainloop_run();
-}
diff --git a/emulator/server.c b/emulator/server.c
deleted file mode 100644
index 1ff9904..0000000
--- a/emulator/server.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011-2012  Intel Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-
-#include "mainloop.h"
-#include "btdev.h"
-#include "server.h"
-
-struct server {
-	uint16_t id;
-	int fd;
-};
-
-struct client {
-	int fd;
-	struct btdev *btdev;
-	uint8_t *pkt_data;
-	uint8_t pkt_type;
-	uint16_t pkt_expect;
-	uint16_t pkt_len;
-	uint16_t pkt_offset;
-};
-
-static void server_destroy(void *user_data)
-{
-	struct server *server = user_data;
-
-	close(server->fd);
-
-	free(server);
-}
-
-static void client_destroy(void *user_data)
-{
-	struct client *client = user_data;
-
-	btdev_destroy(client->btdev);
-
-	close(client->fd);
-
-	free(client);
-}
-
-static void client_write_callback(const void *data, uint16_t len,
-							void *user_data)
-{
-	struct client *client = user_data;
-	ssize_t written;
-
-	written = send(client->fd, data, len, MSG_DONTWAIT);
-	if (written < 0)
-		return;
-}
-
-static void client_read_callback(int fd, uint32_t events, void *user_data)
-{
-	struct client *client = user_data;
-	static uint8_t buf[4096];
-	uint8_t *ptr = buf;
-	ssize_t len;
-	uint16_t count;
-
-	if (events & (EPOLLERR | EPOLLHUP))
-		return;
-
-again:
-	len = recv(fd, buf + client->pkt_offset,
-			sizeof(buf) - client->pkt_offset, MSG_DONTWAIT);
-	if (len < 0) {
-		if (errno == EAGAIN)
-			goto again;
-		return;
-	}
-
-	count = client->pkt_offset + len;
-
-	while (count > 0) {
-		hci_command_hdr *cmd_hdr;
-
-		if (!client->pkt_data) {
-			client->pkt_type = ptr[0];
-
-			switch (client->pkt_type) {
-			case HCI_COMMAND_PKT:
-				if (count < HCI_COMMAND_HDR_SIZE + 1) {
-					client->pkt_offset += len;
-					return;
-				}
-				cmd_hdr = (hci_command_hdr *) (ptr + 1);
-				client->pkt_expect = HCI_COMMAND_HDR_SIZE +
-							cmd_hdr->plen + 1;
-				client->pkt_data = malloc(client->pkt_expect);
-				client->pkt_len = 0;
-				break;
-			default:
-				printf("packet error\n");
-				return;
-			}
-
-			client->pkt_offset = 0;
-		}
-
-		if (count >= client->pkt_expect) {
-			memcpy(client->pkt_data + client->pkt_len,
-						ptr, client->pkt_expect);
-			ptr += client->pkt_expect;
-			count -= client->pkt_expect;
-
-			btdev_receive_h4(client->btdev, client->pkt_data,
-					client->pkt_len + client->pkt_expect);
-
-			free(client->pkt_data);
-			client->pkt_data = NULL;
-		} else {
-			memcpy(client->pkt_data + client->pkt_len, ptr, count);
-			client->pkt_len += count;
-			client->pkt_expect -= count;
-			count = 0;
-		}
-	}
-}
-
-static int accept_client(int fd)
-{
-	struct sockaddr_un addr;
-	socklen_t len;
-	int nfd;
-
-	memset(&addr, 0, sizeof(addr));
-	len = sizeof(addr);
-
-	if (getsockname(fd, (struct sockaddr *) &addr, &len) < 0) {
-		perror("Failed to get socket name");
-		return -1;
-	}
-
-	printf("Request for %s\n", addr.sun_path);
-
-	nfd = accept(fd, (struct sockaddr *) &addr, &len);
-	if (nfd < 0) {
-		perror("Failed to accept client socket");
-		return -1;
-	}
-
-	return nfd;
-}
-
-static void server_accept_callback(int fd, uint32_t events, void *user_data)
-{
-	struct server *server = user_data;
-	struct client *client;
-
-	if (events & (EPOLLERR | EPOLLHUP))
-		return;
-
-	client = malloc(sizeof(*client));
-	if (!client)
-		return;
-
-	memset(client, 0, sizeof(*client));
-
-	client->fd = accept_client(server->fd);
-	if (client->fd < 0) {
-		free(client);
-		return;
-	}
-
-	client->btdev = btdev_create(server->id);
-	if (!client->btdev) {
-		close(client->fd);
-		free(client);
-		return;
-	}
-
-	btdev_set_send_handler(client->btdev, client_write_callback, client);
-
-	if (mainloop_add_fd(client->fd, EPOLLIN, client_read_callback,
-						client, client_destroy) < 0) {
-		btdev_destroy(client->btdev);
-		close(client->fd);
-		free(client);
-	}
-}
-
-static int open_server(const char *path)
-{
-	struct sockaddr_un addr;
-	int fd;
-
-	unlink(path);
-
-	fd = socket(PF_UNIX, SOCK_STREAM, 0);
-	if (fd < 0) {
-		perror("Failed to open server socket");
-		return -1;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_UNIX;
-	strcpy(addr.sun_path, path);
-
-	if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("Failed to bind server socket");
-		close(fd);
-		return -1;
-	}
-
-	if (listen(fd, 5) < 0) {
-		perror("Failed to listen server socket");
-		close(fd);
-		return -1;
-	}
-
-	return fd;
-}
-
-struct server *server_open_unix(const char *path, uint16_t id)
-{
-	struct server *server;
-
-	server = malloc(sizeof(*server));
-	if (!server)
-		return NULL;
-
-	memset(server, 0, sizeof(*server));
-	server->id = id;
-
-	server->fd = open_server(path);
-	if (server->fd < 0) {
-		free(server);
-		return NULL;
-	}
-
-	if (mainloop_add_fd(server->fd, EPOLLIN, server_accept_callback,
-						server, server_destroy) < 0) {
-		close(server->fd);
-		free(server);
-		return NULL;
-	}
-
-	return server;
-}
-
-void server_close(struct server *server)
-{
-	if (!server)
-		return;
-
-	mainloop_remove_fd(server->fd);
-}
diff --git a/emulator/server.h b/emulator/server.h
deleted file mode 100644
index 836db5f..0000000
--- a/emulator/server.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011-2012  Intel Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <stdint.h>
-
-struct server;
-
-struct server *server_open_unix(const char *path, uint16_t id);
-void server_close(struct server *server);
diff --git a/emulator/vhci.c b/emulator/vhci.c
deleted file mode 100644
index 940e562..0000000
--- a/emulator/vhci.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011-2012  Intel Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "mainloop.h"
-#include "btdev.h"
-#include "vhci.h"
-
-struct vhci {
-	enum vhci_type type;
-	int fd;
-	struct btdev *btdev;
-};
-
-static void vhci_destroy(void *user_data)
-{
-	struct vhci *vhci = user_data;
-
-	btdev_destroy(vhci->btdev);
-
-	close(vhci->fd);
-
-	free(vhci);
-}
-
-static void vhci_write_callback(const void *data, uint16_t len, void *user_data)
-{
-	struct vhci *vhci = user_data;
-	ssize_t written;
-
-	written = write(vhci->fd, data, len);
-	if (written < 0)
-		return;
-}
-
-static void vhci_read_callback(int fd, uint32_t events, void *user_data)
-{
-	struct vhci *vhci = user_data;
-	unsigned char buf[4096];
-	ssize_t len;
-
-	if (events & (EPOLLERR | EPOLLHUP))
-		return;
-
-	len = read(vhci->fd, buf, sizeof(buf));
-	if (len < 0)
-		return;
-
-	btdev_receive_h4(vhci->btdev, buf, len);
-}
-
-struct vhci *vhci_open(enum vhci_type type, uint16_t id)
-{
-	struct vhci *vhci;
-
-	switch (type) {
-	case VHCI_TYPE_BREDR:
-		break;
-	case VHCI_TYPE_AMP:
-		return NULL;
-	}
-
-	vhci = malloc(sizeof(*vhci));
-	if (!vhci)
-		return NULL;
-
-	memset(vhci, 0, sizeof(*vhci));
-	vhci->type = type;
-
-	vhci->fd = open("/dev/vhci", O_RDWR | O_NONBLOCK);
-	if (vhci->fd < 0) {
-		free(vhci);
-		return NULL;
-	}
-
-	vhci->btdev = btdev_create(id);
-	if (!vhci->btdev) {
-		close(vhci->fd);
-		free(vhci);
-		return NULL;
-	}
-
-	btdev_set_send_handler(vhci->btdev, vhci_write_callback, vhci);
-
-	if (mainloop_add_fd(vhci->fd, EPOLLIN, vhci_read_callback,
-						vhci, vhci_destroy) < 0) {
-		btdev_destroy(vhci->btdev);
-		close(vhci->fd);
-		free(vhci);
-		return NULL;
-	}
-
-	return vhci;
-}
-
-void vhci_close(struct vhci *vhci)
-{
-	if (!vhci)
-		return;
-
-	mainloop_remove_fd(vhci->fd);
-}
diff --git a/emulator/vhci.h b/emulator/vhci.h
deleted file mode 100644
index 4abb183..0000000
--- a/emulator/vhci.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011-2012  Intel Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <stdint.h>
-
-enum vhci_type {
-	VHCI_TYPE_BREDR	= 0,
-	VHCI_TYPE_AMP	= 1,
-};
-
-struct vhci;
-
-struct vhci *vhci_open(enum vhci_type type, uint16_t id);
-void vhci_close(struct vhci *vhci);
diff --git a/tools/emulator/btdev.c b/tools/emulator/btdev.c
new file mode 100644
index 0000000..7d4517a
--- /dev/null
+++ b/tools/emulator/btdev.c
@@ -0,0 +1,1076 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt.h"
+#include "btdev.h"
+
+#define le16_to_cpu(val) (val)
+#define cpu_to_le16(val) (val)
+
+struct btdev {
+	struct btdev *conn;
+
+	btdev_send_func send_handler;
+	void *send_data;
+
+        uint16_t manufacturer;
+        uint8_t  version;
+	uint16_t revision;
+	uint8_t  commands[64];
+	uint8_t  features[8];
+	uint16_t acl_mtu;
+	uint16_t acl_max_pkt;
+	uint8_t  country_code;
+	uint8_t  bdaddr[6];
+	uint8_t  le_features[8];
+	uint8_t  le_states[8];
+
+	uint16_t default_link_policy;
+	uint8_t  event_mask[8];
+	uint8_t  event_filter;
+	uint8_t  name[248];
+	uint8_t  dev_class[3];
+	uint16_t voice_setting;
+	uint16_t conn_accept_timeout;
+	uint16_t page_timeout;
+	uint8_t  scan_enable;
+	uint8_t  auth_enable;
+	uint8_t  inquiry_mode;
+	uint8_t  afh_assess_mode;
+	uint8_t  ext_inquiry_fec;
+	uint8_t  ext_inquiry_rsp[240];
+	uint8_t  simple_pairing_mode;
+	uint8_t  le_supported;
+	uint8_t  le_simultaneous;
+	uint8_t  le_event_mask[8];
+};
+
+#define MAX_BTDEV_ENTRIES 16
+
+static struct btdev *btdev_list[MAX_BTDEV_ENTRIES] = { };
+
+static inline int add_btdev(struct btdev *btdev)
+{
+	int i, index = -1;
+
+	for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
+		if (btdev_list[i] == NULL) {
+			index = i;
+			btdev_list[index] = btdev;
+			break;
+		}
+	}
+
+	return index;
+}
+
+static inline int del_btdev(struct btdev *btdev)
+{
+	int i, index = -1;
+
+	for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
+		if (btdev_list[i] == btdev) {
+			index = i;
+			btdev_list[index] = NULL;
+			break;
+		}
+	}
+
+	return index;
+}
+
+static inline struct btdev *find_btdev_by_bdaddr(const uint8_t *bdaddr)
+{
+	int i;
+
+	for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
+		if (btdev_list[i] && !memcmp(btdev_list[i]->bdaddr, bdaddr, 6))
+			return btdev_list[i];
+	}
+
+	return NULL;
+}
+
+static void hexdump(const unsigned char *buf, uint16_t len)
+{
+	static const char hexdigits[] = "0123456789abcdef";
+	char str[68];
+	uint16_t i;
+
+	if (!len)
+		return;
+
+	for (i = 0; i < len; i++) {
+		str[((i % 16) * 3) + 0] = hexdigits[buf[i] >> 4];
+		str[((i % 16) * 3) + 1] = hexdigits[buf[i] & 0xf];
+		str[((i % 16) * 3) + 2] = ' ';
+		str[(i % 16) + 49] = isprint(buf[i]) ? buf[i] : '.';
+
+		if ((i + 1) % 16 == 0) {
+			str[47] = ' ';
+			str[48] = ' ';
+			str[65] = '\0';
+			printf("%-12c%s\n", ' ', str);
+			str[0] = ' ';
+		}
+	}
+
+	if (i % 16 > 0) {
+		uint16_t j;
+		for (j = (i % 16); j < 16; j++) {
+			str[(j * 3) + 0] = ' ';
+			str[(j * 3) + 1] = ' ';
+			str[(j * 3) + 2] = ' ';
+			str[j + 49] = ' ';
+		}
+		str[47] = ' ';
+		str[48] = ' ';
+		str[65] = '\0';
+		printf("%-12c%s\n", ' ', str);
+	}
+}
+
+static void get_bdaddr(uint16_t id, uint8_t *bdaddr)
+{
+	bdaddr[0] = id & 0xff;
+	bdaddr[1] = id >> 8;
+	bdaddr[2] = 0x00;
+	bdaddr[3] = 0x01;
+	bdaddr[4] = 0xaa;
+	bdaddr[5] = 0x00;
+}
+
+struct btdev *btdev_create(uint16_t id)
+{
+	struct btdev *btdev;
+
+	btdev = malloc(sizeof(*btdev));
+	if (!btdev)
+		return NULL;
+
+	memset(btdev, 0, sizeof(*btdev));
+
+	btdev->manufacturer = 63;
+	btdev->version = 0x06;
+	btdev->revision = 0x0000;
+
+	btdev->features[0] |= 0x04;	/* Encryption */
+	btdev->features[0] |= 0x20;	/* Role switch */
+	btdev->features[0] |= 0x80;	/* Sniff mode */
+	btdev->features[1] |= 0x08;	/* SCO link */
+	btdev->features[3] |= 0x40;	/* RSSI with inquiry results */
+	btdev->features[3] |= 0x80;	/* Extended SCO link */
+	btdev->features[4] |= 0x08;	/* AFH capable slave */
+	btdev->features[4] |= 0x10;	/* AFH classification slave */
+	btdev->features[4] |= 0x40;	/* LE Supported */
+	btdev->features[5] |= 0x02;	/* Sniff subrating */
+	btdev->features[5] |= 0x04;	/* Pause encryption */
+	btdev->features[5] |= 0x08;	/* AFH capable master */
+	btdev->features[5] |= 0x10;	/* AFH classification master */
+	btdev->features[6] |= 0x01;	/* Extended Inquiry Response */
+	btdev->features[6] |= 0x02;	/* Simultaneous LE and BR/EDR */
+	btdev->features[6] |= 0x08;	/* Secure Simple Pairing */
+	btdev->features[6] |= 0x10;	/* Encapsulated PDU */
+	btdev->features[6] |= 0x20;	/* Erroneous Data Reporting */
+	btdev->features[6] |= 0x40;	/* Non-flushable Packet Boundary Flag */
+	btdev->features[7] |= 0x01;	/* Link Supervision Timeout Event */
+	btdev->features[7] |= 0x02;	/* Inquiry TX Power Level */
+	btdev->features[7] |= 0x80;	/* Extended features */
+
+	btdev->acl_mtu = 192;
+	btdev->acl_max_pkt = 1;
+
+	btdev->country_code = 0x00;
+
+	get_bdaddr(id, btdev->bdaddr);
+
+	add_btdev(btdev);
+
+	return btdev;
+}
+
+void btdev_destroy(struct btdev *btdev)
+{
+	if (!btdev)
+		return;
+
+	del_btdev(btdev);
+
+	free(btdev);
+}
+
+void btdev_set_send_handler(struct btdev *btdev, btdev_send_func handler,
+							void *user_data)
+{
+	if (!btdev)
+		return;
+
+	btdev->send_handler = handler;
+	btdev->send_data = user_data;
+}
+
+static void send_packet(struct btdev *btdev, const void *data, uint16_t len)
+{
+	if (!btdev->send_handler)
+		return;
+
+	btdev->send_handler(data, len, btdev->send_data);
+}
+
+static void send_event(struct btdev *btdev, uint8_t event,
+						const void *data, uint8_t len)
+{
+	struct bt_hci_evt_hdr *hdr;
+	uint16_t pkt_len;
+	void *pkt_data;
+
+	pkt_len = 1 + sizeof(*hdr) + len;
+
+	pkt_data = malloc(pkt_len);
+	if (!pkt_data)
+		return;
+
+	((uint8_t *) pkt_data)[0] = BT_H4_EVT_PKT;
+
+	hdr = pkt_data + 1;
+	hdr->evt = event;
+	hdr->plen = len;
+
+	if (len > 0)
+		memcpy(pkt_data + 1 + sizeof(*hdr), data, len);
+
+	send_packet(btdev, pkt_data, pkt_len);
+
+	free(pkt_data);
+}
+
+static void cmd_complete(struct btdev *btdev, uint16_t opcode,
+						const void *data, uint8_t len)
+{
+	struct bt_hci_evt_hdr *hdr;
+	struct bt_hci_evt_cmd_complete *cc;
+	uint16_t pkt_len;
+	void *pkt_data;
+
+	pkt_len = 1 + sizeof(*hdr) + sizeof(*cc) + len;
+
+	pkt_data = malloc(pkt_len);
+	if (!pkt_data)
+		return;
+
+	((uint8_t *) pkt_data)[0] = BT_H4_EVT_PKT;
+
+	hdr = pkt_data + 1;
+	hdr->evt = BT_HCI_EVT_CMD_COMPLETE;
+	hdr->plen = sizeof(*cc) + len;
+
+	cc = pkt_data + 1 + sizeof(*hdr);
+	cc->ncmd = 0x01;
+	cc->opcode = cpu_to_le16(opcode);
+
+	if (len > 0)
+		memcpy(pkt_data + 1 + sizeof(*hdr) + sizeof(*cc), data, len);
+
+	send_packet(btdev, pkt_data, pkt_len);
+
+	free(pkt_data);
+}
+
+static void cmd_status(struct btdev *btdev, uint8_t status, uint16_t opcode)
+{
+	struct bt_hci_evt_cmd_status cs;
+
+	cs.status = status;
+	cs.ncmd = 0x01;
+	cs.opcode = cpu_to_le16(opcode);
+
+	send_event(btdev, BT_HCI_EVT_CMD_STATUS, &cs, sizeof(cs));
+}
+
+static void num_completed_packets(struct btdev *btdev)
+{
+	if (btdev->conn) {
+		struct bt_hci_evt_num_completed_packets ncp;
+
+		ncp.num_handles = 1;
+		ncp.handle = cpu_to_le16(42);
+		ncp.count = cpu_to_le16(1);
+
+		send_event(btdev, BT_HCI_EVT_NUM_COMPLETED_PACKETS,
+							&ncp, sizeof(ncp));
+	}
+}
+
+static void inquiry_complete(struct btdev *btdev, uint8_t status)
+{
+	struct bt_hci_evt_inquiry_complete ic;
+	int i;
+
+	for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
+		if (!btdev_list[i] || btdev_list[i] == btdev)
+			continue;
+
+		if (!(btdev_list[i]->scan_enable & 0x02))
+			continue;
+
+		if (btdev->inquiry_mode == 0x02 &&
+					btdev_list[i]->ext_inquiry_rsp[0]) {
+			struct bt_hci_evt_ext_inquiry_result ir;
+
+			ir.num_resp = 0x01;
+			memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
+			memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
+			ir.rssi = -60;
+			memcpy(ir.data, btdev_list[i]->ext_inquiry_rsp, 240);
+
+			send_event(btdev, BT_HCI_EVT_EXT_INQUIRY_RESULT,
+							&ir, sizeof(ir));
+			continue;
+		}
+
+		if (btdev->inquiry_mode > 0x00) {
+			struct bt_hci_evt_inquiry_result_with_rssi ir;
+
+			ir.num_resp = 0x01;
+			memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
+			memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
+			ir.rssi = -60;
+
+			send_event(btdev, BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI,
+							&ir, sizeof(ir));
+		} else {
+			struct bt_hci_evt_inquiry_result ir;
+
+			ir.num_resp = 0x01;
+			memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
+			memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
+
+			send_event(btdev, BT_HCI_EVT_INQUIRY_RESULT,
+							&ir, sizeof(ir));
+		}
+        }
+
+	ic.status = status;
+
+	send_event(btdev, BT_HCI_EVT_INQUIRY_COMPLETE, &ic, sizeof(ic));
+}
+
+static void conn_complete(struct btdev *btdev,
+					const uint8_t *bdaddr, uint8_t status)
+{
+	struct bt_hci_evt_conn_complete cc;
+
+	if (!status) {
+		struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
+
+		btdev->conn = remote;
+		remote->conn = btdev;
+
+		cc.status = status;
+		memcpy(cc.bdaddr, btdev->bdaddr, 6);
+		cc.encr_mode = 0x00;
+
+		cc.handle = cpu_to_le16(42);
+		cc.link_type = 0x01;
+
+		send_event(remote, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc));
+
+		cc.handle = cpu_to_le16(42);
+		cc.link_type = 0x01;
+	} else {
+		cc.handle = cpu_to_le16(0x0000);
+		cc.link_type = 0x01;
+	}
+
+	cc.status = status;
+	memcpy(cc.bdaddr, bdaddr, 6);
+	cc.encr_mode = 0x00;
+
+	send_event(btdev, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc));
+}
+
+static void conn_request(struct btdev *btdev, const uint8_t *bdaddr)
+{
+	struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
+
+	if (remote) {
+		if (remote->scan_enable & 0x01) {
+			struct bt_hci_evt_conn_request cr;
+
+			memcpy(cr.bdaddr, btdev->bdaddr, 6);
+			memcpy(cr.dev_class, btdev->dev_class, 3);
+			cr.link_type = 0x01;
+
+			send_event(remote, BT_HCI_EVT_CONN_REQUEST,
+							&cr, sizeof(cr));
+		} else
+			conn_complete(btdev, bdaddr, BT_HCI_ERR_PAGE_TIMEOUT);
+	} else
+		conn_complete(btdev, bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
+}
+
+static void disconnect_complete(struct btdev *btdev, uint16_t handle,
+							uint8_t reason)
+{
+	struct bt_hci_evt_disconnect_complete dc;
+	struct btdev *remote;
+
+	if (!btdev) {
+		dc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+		dc.handle = cpu_to_le16(handle);
+		dc.reason = 0x00;
+
+		send_event(btdev, BT_HCI_EVT_DISCONNECT_COMPLETE,
+							&dc, sizeof(dc));
+		return;
+	}
+
+	dc.status = BT_HCI_ERR_SUCCESS;
+	dc.handle = cpu_to_le16(handle);
+	dc.reason = reason;
+
+	remote = btdev->conn;
+
+	btdev->conn = NULL;
+	remote->conn = NULL;
+
+	send_event(btdev, BT_HCI_EVT_DISCONNECT_COMPLETE, &dc, sizeof(dc));
+	send_event(remote, BT_HCI_EVT_DISCONNECT_COMPLETE, &dc, sizeof(dc));
+}
+
+static void name_request_complete(struct btdev *btdev,
+					const uint8_t *bdaddr, uint8_t status)
+{
+        struct bt_hci_evt_remote_name_req_complete nc;
+
+	nc.status = status;
+	memcpy(nc.bdaddr, bdaddr, 6);
+	memset(nc.name, 0, 248);
+
+	if (!status) {
+		struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
+
+		if (remote)
+			memcpy(nc.name, remote->name, 248);
+		else
+			nc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+	}
+
+	send_event(btdev, BT_HCI_EVT_REMOTE_NAME_REQUEST_COMPLETE,
+							&nc, sizeof(nc));
+}
+
+static void remote_features_complete(struct btdev *btdev, uint16_t handle)
+{
+	struct bt_hci_evt_remote_features_complete rfc;
+
+	if (btdev->conn) {
+		rfc.status = BT_HCI_ERR_SUCCESS;
+		rfc.handle = cpu_to_le16(handle);
+		memcpy(rfc.features, btdev->conn->features, 8);
+	} else {
+		rfc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+		rfc.handle = cpu_to_le16(handle);
+		memset(rfc.features, 0, 8);
+	}
+
+	send_event(btdev, BT_HCI_EVT_REMOTE_FEATURES_COMPLETE,
+							&rfc, sizeof(rfc));
+}
+
+static void remote_ext_features_complete(struct btdev *btdev, uint16_t handle,
+								uint8_t page)
+{
+	struct bt_hci_evt_remote_ext_features_complete refc;
+
+	if (btdev->conn && page < 0x02) {
+		refc.handle = cpu_to_le16(handle);
+		refc.page = page;
+		refc.max_page = 0x01;
+
+		switch (page) {
+		case 0x00:
+			refc.status = BT_HCI_ERR_SUCCESS;
+			memcpy(refc.features, btdev->conn->features, 8);
+			break;
+		case 0x01:
+			refc.status = BT_HCI_ERR_SUCCESS;
+			memset(refc.features, 0, 8);
+			break;
+		default:
+			refc.status = BT_HCI_ERR_INVALID_PARAMETERS;
+			memset(refc.features, 0, 8);
+			break;
+		}
+	} else {
+		refc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+		refc.handle = cpu_to_le16(handle);
+		refc.page = page;
+		refc.max_page = 0x01;
+		memset(refc.features, 0, 8);
+	}
+
+	send_event(btdev, BT_HCI_EVT_REMOTE_EXT_FEATURES_COMPLETE,
+							&refc, sizeof(refc));
+}
+
+static void remote_version_complete(struct btdev *btdev, uint16_t handle)
+{
+	struct bt_hci_evt_remote_version_complete rvc;
+
+	if (btdev->conn) {
+		rvc.status = BT_HCI_ERR_SUCCESS;
+		rvc.handle = cpu_to_le16(handle);
+		rvc.lmp_ver = btdev->conn->version;
+		rvc.manufacturer = cpu_to_le16(btdev->conn->manufacturer);
+		rvc.lmp_subver = cpu_to_le16(btdev->conn->revision);
+	} else {
+		rvc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+		rvc.handle = cpu_to_le16(handle);
+		rvc.lmp_ver = 0x00;
+		rvc.manufacturer = cpu_to_le16(0);
+		rvc.lmp_subver = cpu_to_le16(0);
+	}
+
+	send_event(btdev, BT_HCI_EVT_REMOTE_VERSION_COMPLETE,
+							&rvc, sizeof(rvc));
+}
+
+static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
+{
+	const struct bt_hci_cmd_hdr *hdr = data;
+	const struct bt_hci_cmd_create_conn *cc;
+	const struct bt_hci_cmd_disconnect *dc;
+	const struct bt_hci_cmd_create_conn_cancel *ccc;
+	const struct bt_hci_cmd_accept_conn_request *acr;
+	const struct bt_hci_cmd_reject_conn_request *rcr;
+	const struct bt_hci_cmd_remote_name_request *rnr;
+	const struct bt_hci_cmd_remote_name_request_cancel *rnrc;
+	const struct bt_hci_cmd_read_remote_features *rrf;
+	const struct bt_hci_cmd_read_remote_ext_features *rref;
+	const struct bt_hci_cmd_read_remote_version *rrv;
+	const struct bt_hci_cmd_write_default_link_policy *wdlp;
+	const struct bt_hci_cmd_set_event_mask *sem;
+	const struct bt_hci_cmd_set_event_filter *sef;
+	const struct bt_hci_cmd_write_local_name *wln;
+	const struct bt_hci_cmd_write_conn_accept_timeout *wcat;
+	const struct bt_hci_cmd_write_page_timeout *wpt;
+	const struct bt_hci_cmd_write_scan_enable *wse;
+	const struct bt_hci_cmd_write_auth_enable *wae;
+	const struct bt_hci_cmd_write_class_of_dev *wcod;
+	const struct bt_hci_cmd_write_voice_setting *wvs;
+	const struct bt_hci_cmd_write_inquiry_mode *wim;
+	const struct bt_hci_cmd_write_afh_assess_mode *waam;
+	const struct bt_hci_cmd_write_ext_inquiry_rsp *weir;
+	const struct bt_hci_cmd_write_simple_pairing_mode *wspm;
+	const struct bt_hci_cmd_write_le_host_supported *wlhs;
+	const struct bt_hci_cmd_le_set_event_mask *lsem;
+	struct bt_hci_rsp_read_default_link_policy rdlp;
+	struct bt_hci_rsp_read_stored_link_key rslk;
+	struct bt_hci_rsp_write_stored_link_key wslk;
+	struct bt_hci_rsp_delete_stored_link_key dslk;
+	struct bt_hci_rsp_read_local_name rln;
+	struct bt_hci_rsp_read_conn_accept_timeout rcat;
+	struct bt_hci_rsp_read_page_timeout rpt;
+	struct bt_hci_rsp_read_scan_enable rse;
+	struct bt_hci_rsp_read_auth_enable rae;
+	struct bt_hci_rsp_read_class_of_dev rcod;
+	struct bt_hci_rsp_read_voice_setting rvs;
+	struct bt_hci_rsp_read_inquiry_mode rim;
+	struct bt_hci_rsp_read_afh_assess_mode raam;
+	struct bt_hci_rsp_read_ext_inquiry_rsp reir;
+	struct bt_hci_rsp_read_simple_pairing_mode rspm;
+	struct bt_hci_rsp_read_inquiry_rsp_tx_power rirtp;
+	struct bt_hci_rsp_read_le_host_supported rlhs;
+	struct bt_hci_rsp_read_local_version rlv;
+	struct bt_hci_rsp_read_local_commands rlc;
+	struct bt_hci_rsp_read_local_features rlf;
+	struct bt_hci_rsp_read_local_ext_features rlef;
+	struct bt_hci_rsp_read_buffer_size rbs;
+	struct bt_hci_rsp_read_country_code rcc;
+	struct bt_hci_rsp_read_bd_addr rba;
+	struct bt_hci_rsp_read_data_block_size rdbs;
+	struct bt_hci_rsp_le_read_buffer_size lrbs;
+	struct bt_hci_rsp_le_read_local_features lrlf;
+	struct bt_hci_rsp_le_read_supported_states lrss;
+	uint16_t opcode;
+	uint8_t status, page;
+
+	if (len < sizeof(*hdr))
+		return;
+
+	opcode = le16_to_cpu(hdr->opcode);
+
+	switch (opcode) {
+	case BT_HCI_CMD_INQUIRY:
+		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+		inquiry_complete(btdev, BT_HCI_ERR_SUCCESS);
+		break;
+
+	case BT_HCI_CMD_INQUIRY_CANCEL:
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_CREATE_CONN:
+		cc = data + sizeof(*hdr);
+		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+		conn_request(btdev, cc->bdaddr);
+		break;
+
+	case BT_HCI_CMD_DISCONNECT:
+		dc = data + sizeof(*hdr);
+		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+		disconnect_complete(btdev, le16_to_cpu(dc->handle), dc->reason);
+		break;
+
+	case BT_HCI_CMD_CREATE_CONN_CANCEL:
+		ccc = data + sizeof(*hdr);
+		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+		conn_complete(btdev, ccc->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
+		break;
+
+	case BT_HCI_CMD_ACCEPT_CONN_REQUEST:
+		acr = data + sizeof(*hdr);
+		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+		conn_complete(btdev, acr->bdaddr, BT_HCI_ERR_SUCCESS);
+		break;
+
+	case BT_HCI_CMD_REJECT_CONN_REQUEST:
+		rcr = data + sizeof(*hdr);
+		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+		conn_complete(btdev, rcr->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
+		break;
+
+	case BT_HCI_CMD_REMOTE_NAME_REQUEST:
+		rnr = data + sizeof(*hdr);
+		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+		name_request_complete(btdev, rnr->bdaddr, BT_HCI_ERR_SUCCESS);
+		break;
+
+	case BT_HCI_CMD_REMOTE_NAME_REQUEST_CANCEL:
+		rnrc = data + sizeof(*hdr);
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		name_request_complete(btdev, rnrc->bdaddr,
+						BT_HCI_ERR_UNKNOWN_CONN_ID);
+		break;
+
+	case BT_HCI_CMD_READ_REMOTE_FEATURES:
+		rrf = data + sizeof(*hdr);
+		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+		remote_features_complete(btdev, le16_to_cpu(rrf->handle));
+		break;
+
+	case BT_HCI_CMD_READ_REMOTE_EXT_FEATURES:
+		rref = data + sizeof(*hdr);
+		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+		remote_ext_features_complete(btdev, le16_to_cpu(rref->handle),
+								rref->page);
+		break;
+
+	case BT_HCI_CMD_READ_REMOTE_VERSION:
+		rrv = data + sizeof(*hdr);
+		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+		remote_version_complete(btdev, le16_to_cpu(rrv->handle));
+		break;
+
+	case BT_HCI_CMD_READ_DEFAULT_LINK_POLICY:
+		rdlp.status = BT_HCI_ERR_SUCCESS;
+		rdlp.policy = cpu_to_le16(btdev->default_link_policy);
+		cmd_complete(btdev, opcode, &rdlp, sizeof(rdlp));
+		break;
+
+	case BT_HCI_CMD_WRITE_DEFAULT_LINK_POLICY:
+		wdlp = data + sizeof(*hdr);
+		btdev->default_link_policy = le16_to_cpu(wdlp->policy);
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_SET_EVENT_MASK:
+		sem = data + sizeof(*hdr);
+		memcpy(btdev->event_mask, sem->mask, 8);
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_RESET:
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_SET_EVENT_FILTER:
+		sef = data + sizeof(*hdr);
+		btdev->event_filter = sef->type;
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_READ_STORED_LINK_KEY:
+		rslk.status = BT_HCI_ERR_SUCCESS;
+		rslk.max_num_keys = cpu_to_le16(0);
+		rslk.num_keys = cpu_to_le16(0);
+		cmd_complete(btdev, opcode, &rslk, sizeof(rslk));
+		break;
+
+	case BT_HCI_CMD_WRITE_STORED_LINK_KEY:
+		wslk.status = BT_HCI_ERR_SUCCESS;
+		wslk.num_keys = 0;
+		cmd_complete(btdev, opcode, &wslk, sizeof(wslk));
+		break;
+
+	case BT_HCI_CMD_DELETE_STORED_LINK_KEY:
+		dslk.status = BT_HCI_ERR_SUCCESS;
+		dslk.num_keys = cpu_to_le16(0);
+		cmd_complete(btdev, opcode, &dslk, sizeof(dslk));
+		break;
+
+	case BT_HCI_CMD_WRITE_LOCAL_NAME:
+		wln = data + sizeof(*hdr);
+		memcpy(btdev->name, wln->name, 248);
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_READ_LOCAL_NAME:
+		rln.status = BT_HCI_ERR_SUCCESS;
+		memcpy(rln.name, btdev->name, 248);
+		cmd_complete(btdev, opcode, &rln, sizeof(rln));
+		break;
+
+	case BT_HCI_CMD_READ_CONN_ACCEPT_TIMEOUT:
+		rcat.status = BT_HCI_ERR_SUCCESS;
+		rcat.timeout = cpu_to_le16(btdev->conn_accept_timeout);
+		cmd_complete(btdev, opcode, &rcat, sizeof(rcat));
+		break;
+
+	case BT_HCI_CMD_WRITE_CONN_ACCEPT_TIMEOUT:
+		wcat = data + sizeof(*hdr);
+		btdev->conn_accept_timeout = le16_to_cpu(wcat->timeout);
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_READ_PAGE_TIMEOUT:
+		rpt.status = BT_HCI_ERR_SUCCESS;
+		rpt.timeout = cpu_to_le16(btdev->page_timeout);
+		cmd_complete(btdev, opcode, &rpt, sizeof(rpt));
+		break;
+
+	case BT_HCI_CMD_WRITE_PAGE_TIMEOUT:
+		wpt = data + sizeof(*hdr);
+		btdev->page_timeout = le16_to_cpu(wpt->timeout);
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_READ_SCAN_ENABLE:
+		rse.status = BT_HCI_ERR_SUCCESS;
+		rse.enable = btdev->scan_enable;
+		cmd_complete(btdev, opcode, &rse, sizeof(rse));
+		break;
+
+	case BT_HCI_CMD_WRITE_SCAN_ENABLE:
+		wse = data + sizeof(*hdr);
+		btdev->scan_enable = wse->enable;
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_READ_AUTH_ENABLE:
+		rae.status = BT_HCI_ERR_SUCCESS;
+		rae.enable = btdev->auth_enable;
+		cmd_complete(btdev, opcode, &rae, sizeof(rae));
+		break;
+
+	case BT_HCI_CMD_WRITE_AUTH_ENABLE:
+		wae = data + sizeof(*hdr);
+		btdev->auth_enable = wae->enable;
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_READ_CLASS_OF_DEV:
+		rcod.status = BT_HCI_ERR_SUCCESS;
+		memcpy(rcod.dev_class, btdev->dev_class, 3);
+		cmd_complete(btdev, opcode, &rcod, sizeof(rcod));
+		break;
+
+	case BT_HCI_CMD_WRITE_CLASS_OF_DEV:
+		wcod = data + sizeof(*hdr);
+		memcpy(btdev->dev_class, wcod->dev_class, 3);
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_READ_VOICE_SETTING:
+		rvs.status = BT_HCI_ERR_SUCCESS;
+		rvs.setting = cpu_to_le16(btdev->voice_setting);
+		cmd_complete(btdev, opcode, &rvs, sizeof(rvs));
+		break;
+
+	case BT_HCI_CMD_WRITE_VOICE_SETTING:
+		wvs = data + sizeof(*hdr);
+		btdev->voice_setting = le16_to_cpu(wvs->setting);
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_READ_INQUIRY_MODE:
+		rim.status = BT_HCI_ERR_SUCCESS;
+		rim.mode = btdev->inquiry_mode;
+		cmd_complete(btdev, opcode, &rim, sizeof(rim));
+		break;
+
+	case BT_HCI_CMD_WRITE_INQUIRY_MODE:
+		wim = data + sizeof(*hdr);
+		btdev->inquiry_mode = wim->mode;
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_READ_AFH_ASSESS_MODE:
+		raam.status = BT_HCI_ERR_SUCCESS;
+		raam.mode = btdev->afh_assess_mode;
+		cmd_complete(btdev, opcode, &raam, sizeof(raam));
+		break;
+
+	case BT_HCI_CMD_WRITE_AFH_ASSESS_MODE:
+		waam = data + sizeof(*hdr);
+		btdev->afh_assess_mode = waam->mode;
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_READ_EXT_INQUIRY_RSP:
+		reir.status = BT_HCI_ERR_SUCCESS;
+		reir.fec = btdev->ext_inquiry_fec;
+		memcpy(reir.data, btdev->ext_inquiry_rsp, 240);
+		cmd_complete(btdev, opcode, &reir, sizeof(reir));
+		break;
+
+	case BT_HCI_CMD_WRITE_EXT_INQUIRY_RSP:
+		weir = data + sizeof(*hdr);
+		btdev->ext_inquiry_fec = weir->fec;
+		memcpy(btdev->ext_inquiry_rsp, weir->data, 240);
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_READ_SIMPLE_PAIRING_MODE:
+		rspm.status = BT_HCI_ERR_SUCCESS;
+		rspm.mode = btdev->simple_pairing_mode;
+		cmd_complete(btdev, opcode, &rspm, sizeof(rspm));
+		break;
+
+	case BT_HCI_CMD_WRITE_SIMPLE_PAIRING_MODE:
+		wspm = data + sizeof(*hdr);
+		btdev->simple_pairing_mode = wspm->mode;
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_READ_INQUIRY_RSP_TX_POWER:
+		rirtp.status = BT_HCI_ERR_SUCCESS;
+		rirtp.level = 0;
+		cmd_complete(btdev, opcode, &rirtp, sizeof(rirtp));
+		break;
+
+	case BT_HCI_CMD_READ_LE_HOST_SUPPORTED:
+		rlhs.status = BT_HCI_ERR_SUCCESS;
+		rlhs.supported = btdev->le_supported;
+		rlhs.simultaneous = btdev->le_simultaneous;
+		cmd_complete(btdev, opcode, &rlhs, sizeof(rlhs));
+		break;
+
+	case BT_HCI_CMD_WRITE_LE_HOST_SUPPORTED:
+		wlhs = data + sizeof(*hdr);
+		btdev->le_supported = wlhs->supported;
+		btdev->le_simultaneous = wlhs->simultaneous;
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_READ_LOCAL_VERSION:
+		rlv.status = BT_HCI_ERR_SUCCESS;
+		rlv.hci_ver = btdev->version;
+		rlv.hci_rev = cpu_to_le16(btdev->revision);
+		rlv.lmp_ver = btdev->version;
+		rlv.manufacturer = cpu_to_le16(btdev->manufacturer);
+		rlv.lmp_subver = cpu_to_le16(btdev->revision);
+		cmd_complete(btdev, opcode, &rlv, sizeof(rlv));
+		break;
+
+	case BT_HCI_CMD_READ_LOCAL_COMMANDS:
+		rlc.status = BT_HCI_ERR_SUCCESS;
+		memcpy(rlc.commands, btdev->commands, 64);
+		cmd_complete(btdev, opcode, &rlc, sizeof(rlc));
+		break;
+
+	case BT_HCI_CMD_READ_LOCAL_FEATURES:
+		rlf.status = BT_HCI_ERR_SUCCESS;
+		memcpy(rlf.features, btdev->features, 8);
+		cmd_complete(btdev, opcode, &rlf, sizeof(rlf));
+		break;
+
+	case BT_HCI_CMD_READ_LOCAL_EXT_FEATURES:
+		page = ((const uint8_t *) data)[sizeof(*hdr)];
+		switch (page) {
+		case 0x00:
+			rlef.status = BT_HCI_ERR_SUCCESS;
+			rlef.page = 0x00;
+			rlef.max_page = 0x01;
+			memcpy(rlef.features, btdev->features, 8);
+			break;
+		case 0x01:
+			rlef.status = BT_HCI_ERR_SUCCESS;
+			rlef.page = 0x01;
+			rlef.max_page = 0x01;
+			memset(rlef.features, 0, 8);
+			if (btdev->simple_pairing_mode)
+				rlef.features[0] |= 0x01;
+			if (btdev->le_supported)
+				rlef.features[0] |= 0x02;
+			if (btdev->le_simultaneous)
+				rlef.features[0] |= 0x04;
+			break;
+		default:
+			rlef.status = BT_HCI_ERR_INVALID_PARAMETERS;
+			rlef.page = page;
+			rlef.max_page = 0x01;
+			memset(rlef.features, 0, 8);
+			break;
+		}
+		cmd_complete(btdev, opcode, &rlef, sizeof(rlef));
+		break;
+
+	case BT_HCI_CMD_READ_BUFFER_SIZE:
+		rbs.status = BT_HCI_ERR_SUCCESS;
+		rbs.acl_mtu = cpu_to_le16(btdev->acl_mtu);
+		rbs.sco_mtu = 0;
+		rbs.acl_max_pkt = cpu_to_le16(btdev->acl_max_pkt);
+		rbs.sco_max_pkt = cpu_to_le16(0);
+		cmd_complete(btdev, opcode, &rbs, sizeof(rbs));
+		break;
+
+	case BT_HCI_CMD_READ_COUNTRY_CODE:
+		rcc.status = BT_HCI_ERR_SUCCESS;
+		rcc.code = btdev->country_code;
+		cmd_complete(btdev, opcode, &rcc, sizeof(rcc));
+		break;
+
+	case BT_HCI_CMD_READ_BD_ADDR:
+		rba.status = BT_HCI_ERR_SUCCESS;
+		memcpy(rba.bdaddr, btdev->bdaddr, 6);
+		cmd_complete(btdev, opcode, &rba, sizeof(rba));
+		break;
+
+	case BT_HCI_CMD_READ_DATA_BLOCK_SIZE:
+		rdbs.status = BT_HCI_ERR_SUCCESS;
+		rdbs.max_acl_len = cpu_to_le16(btdev->acl_mtu);
+		rdbs.block_len = cpu_to_le16(btdev->acl_mtu);
+		rdbs.num_blocks = cpu_to_le16(btdev->acl_max_pkt);
+		cmd_complete(btdev, opcode, &rdbs, sizeof(rdbs));
+		break;
+
+	case BT_HCI_CMD_LE_SET_EVENT_MASK:
+		lsem = data + sizeof(*hdr);
+		memcpy(btdev->le_event_mask, lsem->mask, 8);
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_LE_READ_BUFFER_SIZE:
+		lrbs.status = BT_HCI_ERR_SUCCESS;
+		lrbs.le_mtu = cpu_to_le16(btdev->acl_mtu);
+		lrbs.le_max_pkt = btdev->acl_max_pkt;
+		cmd_complete(btdev, opcode, &lrbs, sizeof(lrbs));
+		break;
+
+	case BT_HCI_CMD_LE_READ_LOCAL_FEATURES:
+		lrlf.status = BT_HCI_ERR_SUCCESS;
+		memcpy(lrlf.features, btdev->le_features, 8);
+		cmd_complete(btdev, opcode, &lrlf, sizeof(lrlf));
+		break;
+
+	case BT_HCI_CMD_LE_SET_SCAN_PARAMETERS:
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_LE_SET_SCAN_ENABLE:
+		status = BT_HCI_ERR_SUCCESS;
+		cmd_complete(btdev, opcode, &status, sizeof(status));
+		break;
+
+	case BT_HCI_CMD_LE_READ_SUPPORTED_STATES:
+		lrss.status = BT_HCI_ERR_SUCCESS;
+		memcpy(lrss.states, btdev->le_states, 8);
+		cmd_complete(btdev, opcode, &lrss, sizeof(lrss));
+		break;
+
+	default:
+		printf("Unsupported command 0x%4.4x\n", opcode);
+		hexdump(data, len);
+		cmd_status(btdev, BT_HCI_ERR_UNKNOWN_COMMAND, opcode);
+		break;
+	}
+}
+
+void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len)
+{
+	uint8_t pkt_type;
+
+	if (!btdev)
+		return;
+
+	if (len < 1)
+		return;
+
+	pkt_type = ((const uint8_t *) data)[0];
+
+	switch (pkt_type) {
+	case BT_H4_CMD_PKT:
+		process_cmd(btdev, data + 1, len - 1);
+		break;
+	case BT_H4_ACL_PKT:
+		if (btdev->conn)
+			send_packet(btdev->conn, data, len);
+		num_completed_packets(btdev);
+		break;
+	default:
+		printf("Unsupported packet 0x%2.2x\n", pkt_type);
+		break;
+	}
+}
diff --git a/tools/emulator/btdev.h b/tools/emulator/btdev.h
new file mode 100644
index 0000000..7b211a2
--- /dev/null
+++ b/tools/emulator/btdev.h
@@ -0,0 +1,38 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+
+typedef void (*btdev_send_func) (const void *data, uint16_t len,
+							void *user_data);
+
+struct btdev;
+
+struct btdev *btdev_create(uint16_t id);
+void btdev_destroy(struct btdev *btdev);
+
+void btdev_set_send_handler(struct btdev *btdev, btdev_send_func handler,
+							void *user_data);
+
+void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len);
diff --git a/tools/emulator/main.c b/tools/emulator/main.c
new file mode 100644
index 0000000..125460d
--- /dev/null
+++ b/tools/emulator/main.c
@@ -0,0 +1,73 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include "mainloop.h"
+#include "server.h"
+#include "vhci.h"
+
+static void signal_callback(int signum, void *user_data)
+{
+	switch (signum) {
+	case SIGINT:
+	case SIGTERM:
+		mainloop_quit();
+		break;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	struct vhci *vhci;
+	struct server *server;
+	sigset_t mask;
+
+	mainloop_init();
+
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGINT);
+	sigaddset(&mask, SIGTERM);
+
+	mainloop_set_signal(&mask, signal_callback, NULL, NULL);
+
+	vhci = vhci_open(VHCI_TYPE_BREDR, 0x23);
+	if (!vhci) {
+		fprintf(stderr, "Failed to open Virtual HCI device\n");
+		return 1;
+	}
+
+	server = server_open_unix("/tmp/bt-server-bredr", 0x42);
+	if (!server) {
+		fprintf(stderr, "Failed to open server channel\n");
+		vhci_close(vhci);
+		return 1;
+	}
+
+	return mainloop_run();
+}
diff --git a/tools/emulator/server.c b/tools/emulator/server.c
new file mode 100644
index 0000000..1ff9904
--- /dev/null
+++ b/tools/emulator/server.c
@@ -0,0 +1,288 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+
+#include "mainloop.h"
+#include "btdev.h"
+#include "server.h"
+
+struct server {
+	uint16_t id;
+	int fd;
+};
+
+struct client {
+	int fd;
+	struct btdev *btdev;
+	uint8_t *pkt_data;
+	uint8_t pkt_type;
+	uint16_t pkt_expect;
+	uint16_t pkt_len;
+	uint16_t pkt_offset;
+};
+
+static void server_destroy(void *user_data)
+{
+	struct server *server = user_data;
+
+	close(server->fd);
+
+	free(server);
+}
+
+static void client_destroy(void *user_data)
+{
+	struct client *client = user_data;
+
+	btdev_destroy(client->btdev);
+
+	close(client->fd);
+
+	free(client);
+}
+
+static void client_write_callback(const void *data, uint16_t len,
+							void *user_data)
+{
+	struct client *client = user_data;
+	ssize_t written;
+
+	written = send(client->fd, data, len, MSG_DONTWAIT);
+	if (written < 0)
+		return;
+}
+
+static void client_read_callback(int fd, uint32_t events, void *user_data)
+{
+	struct client *client = user_data;
+	static uint8_t buf[4096];
+	uint8_t *ptr = buf;
+	ssize_t len;
+	uint16_t count;
+
+	if (events & (EPOLLERR | EPOLLHUP))
+		return;
+
+again:
+	len = recv(fd, buf + client->pkt_offset,
+			sizeof(buf) - client->pkt_offset, MSG_DONTWAIT);
+	if (len < 0) {
+		if (errno == EAGAIN)
+			goto again;
+		return;
+	}
+
+	count = client->pkt_offset + len;
+
+	while (count > 0) {
+		hci_command_hdr *cmd_hdr;
+
+		if (!client->pkt_data) {
+			client->pkt_type = ptr[0];
+
+			switch (client->pkt_type) {
+			case HCI_COMMAND_PKT:
+				if (count < HCI_COMMAND_HDR_SIZE + 1) {
+					client->pkt_offset += len;
+					return;
+				}
+				cmd_hdr = (hci_command_hdr *) (ptr + 1);
+				client->pkt_expect = HCI_COMMAND_HDR_SIZE +
+							cmd_hdr->plen + 1;
+				client->pkt_data = malloc(client->pkt_expect);
+				client->pkt_len = 0;
+				break;
+			default:
+				printf("packet error\n");
+				return;
+			}
+
+			client->pkt_offset = 0;
+		}
+
+		if (count >= client->pkt_expect) {
+			memcpy(client->pkt_data + client->pkt_len,
+						ptr, client->pkt_expect);
+			ptr += client->pkt_expect;
+			count -= client->pkt_expect;
+
+			btdev_receive_h4(client->btdev, client->pkt_data,
+					client->pkt_len + client->pkt_expect);
+
+			free(client->pkt_data);
+			client->pkt_data = NULL;
+		} else {
+			memcpy(client->pkt_data + client->pkt_len, ptr, count);
+			client->pkt_len += count;
+			client->pkt_expect -= count;
+			count = 0;
+		}
+	}
+}
+
+static int accept_client(int fd)
+{
+	struct sockaddr_un addr;
+	socklen_t len;
+	int nfd;
+
+	memset(&addr, 0, sizeof(addr));
+	len = sizeof(addr);
+
+	if (getsockname(fd, (struct sockaddr *) &addr, &len) < 0) {
+		perror("Failed to get socket name");
+		return -1;
+	}
+
+	printf("Request for %s\n", addr.sun_path);
+
+	nfd = accept(fd, (struct sockaddr *) &addr, &len);
+	if (nfd < 0) {
+		perror("Failed to accept client socket");
+		return -1;
+	}
+
+	return nfd;
+}
+
+static void server_accept_callback(int fd, uint32_t events, void *user_data)
+{
+	struct server *server = user_data;
+	struct client *client;
+
+	if (events & (EPOLLERR | EPOLLHUP))
+		return;
+
+	client = malloc(sizeof(*client));
+	if (!client)
+		return;
+
+	memset(client, 0, sizeof(*client));
+
+	client->fd = accept_client(server->fd);
+	if (client->fd < 0) {
+		free(client);
+		return;
+	}
+
+	client->btdev = btdev_create(server->id);
+	if (!client->btdev) {
+		close(client->fd);
+		free(client);
+		return;
+	}
+
+	btdev_set_send_handler(client->btdev, client_write_callback, client);
+
+	if (mainloop_add_fd(client->fd, EPOLLIN, client_read_callback,
+						client, client_destroy) < 0) {
+		btdev_destroy(client->btdev);
+		close(client->fd);
+		free(client);
+	}
+}
+
+static int open_server(const char *path)
+{
+	struct sockaddr_un addr;
+	int fd;
+
+	unlink(path);
+
+	fd = socket(PF_UNIX, SOCK_STREAM, 0);
+	if (fd < 0) {
+		perror("Failed to open server socket");
+		return -1;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	strcpy(addr.sun_path, path);
+
+	if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("Failed to bind server socket");
+		close(fd);
+		return -1;
+	}
+
+	if (listen(fd, 5) < 0) {
+		perror("Failed to listen server socket");
+		close(fd);
+		return -1;
+	}
+
+	return fd;
+}
+
+struct server *server_open_unix(const char *path, uint16_t id)
+{
+	struct server *server;
+
+	server = malloc(sizeof(*server));
+	if (!server)
+		return NULL;
+
+	memset(server, 0, sizeof(*server));
+	server->id = id;
+
+	server->fd = open_server(path);
+	if (server->fd < 0) {
+		free(server);
+		return NULL;
+	}
+
+	if (mainloop_add_fd(server->fd, EPOLLIN, server_accept_callback,
+						server, server_destroy) < 0) {
+		close(server->fd);
+		free(server);
+		return NULL;
+	}
+
+	return server;
+}
+
+void server_close(struct server *server)
+{
+	if (!server)
+		return;
+
+	mainloop_remove_fd(server->fd);
+}
diff --git a/tools/emulator/server.h b/tools/emulator/server.h
new file mode 100644
index 0000000..836db5f
--- /dev/null
+++ b/tools/emulator/server.h
@@ -0,0 +1,30 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+
+struct server;
+
+struct server *server_open_unix(const char *path, uint16_t id);
+void server_close(struct server *server);
diff --git a/tools/emulator/vhci.c b/tools/emulator/vhci.c
new file mode 100644
index 0000000..940e562
--- /dev/null
+++ b/tools/emulator/vhci.c
@@ -0,0 +1,133 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mainloop.h"
+#include "btdev.h"
+#include "vhci.h"
+
+struct vhci {
+	enum vhci_type type;
+	int fd;
+	struct btdev *btdev;
+};
+
+static void vhci_destroy(void *user_data)
+{
+	struct vhci *vhci = user_data;
+
+	btdev_destroy(vhci->btdev);
+
+	close(vhci->fd);
+
+	free(vhci);
+}
+
+static void vhci_write_callback(const void *data, uint16_t len, void *user_data)
+{
+	struct vhci *vhci = user_data;
+	ssize_t written;
+
+	written = write(vhci->fd, data, len);
+	if (written < 0)
+		return;
+}
+
+static void vhci_read_callback(int fd, uint32_t events, void *user_data)
+{
+	struct vhci *vhci = user_data;
+	unsigned char buf[4096];
+	ssize_t len;
+
+	if (events & (EPOLLERR | EPOLLHUP))
+		return;
+
+	len = read(vhci->fd, buf, sizeof(buf));
+	if (len < 0)
+		return;
+
+	btdev_receive_h4(vhci->btdev, buf, len);
+}
+
+struct vhci *vhci_open(enum vhci_type type, uint16_t id)
+{
+	struct vhci *vhci;
+
+	switch (type) {
+	case VHCI_TYPE_BREDR:
+		break;
+	case VHCI_TYPE_AMP:
+		return NULL;
+	}
+
+	vhci = malloc(sizeof(*vhci));
+	if (!vhci)
+		return NULL;
+
+	memset(vhci, 0, sizeof(*vhci));
+	vhci->type = type;
+
+	vhci->fd = open("/dev/vhci", O_RDWR | O_NONBLOCK);
+	if (vhci->fd < 0) {
+		free(vhci);
+		return NULL;
+	}
+
+	vhci->btdev = btdev_create(id);
+	if (!vhci->btdev) {
+		close(vhci->fd);
+		free(vhci);
+		return NULL;
+	}
+
+	btdev_set_send_handler(vhci->btdev, vhci_write_callback, vhci);
+
+	if (mainloop_add_fd(vhci->fd, EPOLLIN, vhci_read_callback,
+						vhci, vhci_destroy) < 0) {
+		btdev_destroy(vhci->btdev);
+		close(vhci->fd);
+		free(vhci);
+		return NULL;
+	}
+
+	return vhci;
+}
+
+void vhci_close(struct vhci *vhci)
+{
+	if (!vhci)
+		return;
+
+	mainloop_remove_fd(vhci->fd);
+}
diff --git a/tools/emulator/vhci.h b/tools/emulator/vhci.h
new file mode 100644
index 0000000..4abb183
--- /dev/null
+++ b/tools/emulator/vhci.h
@@ -0,0 +1,35 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+
+enum vhci_type {
+	VHCI_TYPE_BREDR	= 0,
+	VHCI_TYPE_AMP	= 1,
+};
+
+struct vhci;
+
+struct vhci *vhci_open(enum vhci_type type, uint16_t id);
+void vhci_close(struct vhci *vhci);
-- 
1.7.10.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH -v3 08/19] btmgmt: move to tools folder
  2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
                   ` (5 preceding siblings ...)
  2012-07-04 12:51 ` [PATCH -v3 07/19] emulator: move it to the tools folder Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 09/19] alert: move alert to profiles dir Gustavo Padovan
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

---
 .gitignore        |    2 +-
 Makefile.tools    |    8 +-
 mgmt/main.c       | 1933 -----------------------------------------------------
 tools/mgmt/main.c | 1933 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1938 insertions(+), 1938 deletions(-)
 delete mode 100644 mgmt/main.c
 create mode 100644 tools/mgmt/main.c

diff --git a/.gitignore b/.gitignore
index aaf52c3..63f6ae0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -86,7 +86,7 @@ compat/dund
 compat/hidd
 compat/pand
 unit/test-eir
-mgmt/btmgmt
+tools/mgmt/btmgmt
 monitor/btmon
 tools/emulator/btvirt
 
diff --git a/Makefile.tools b/Makefile.tools
index e1be0fa..e4cf238 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -50,10 +50,10 @@ tools_ppporc_LDADD = lib/libbluetooth-private.la
 
 tools_hcieventmask_LDADD = lib/libbluetooth-private.la
 
-noinst_PROGRAMS += mgmt/btmgmt monitor/btmon tools/emulator/btvirt
+noinst_PROGRAMS += tools/mgmt/btmgmt monitor/btmon tools/emulator/btvirt
 
-mgmt_btmgmt_SOURCES = mgmt/main.c src/glib-helper.c
-mgmt_btmgmt_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@
+tools_mgmt_btmgmt_SOURCES = tools/mgmt/main.c src/glib-helper.c
+tools_mgmt_btmgmt_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@
 
 monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
 					monitor/mainloop.h monitor/mainloop.c \
@@ -63,7 +63,7 @@ monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
 					monitor/packet.h monitor/packet.c
 monitor_btmon_LDADD = lib/libbluetooth-private.la
 
-emulator_btvirt_SOURCES = tools/emulator/main.c monitor/bt.h \
+tools_emulator_btvirt_SOURCES = tools/emulator/main.c monitor/bt.h \
 			monitor/mainloop.h monitor/mainloop.c \
 			tools/emulator/server.h tools/emulator/server.c \
 			tools/emulator/vhci.h tools/emulator/vhci.c \
diff --git a/mgmt/main.c b/mgmt/main.c
deleted file mode 100644
index b2d6c3c..0000000
--- a/mgmt/main.c
+++ /dev/null
@@ -1,1933 +0,0 @@
-/*
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  Intel Corporation. All rights reserved.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <poll.h>
-#include <getopt.h>
-#include <stdbool.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-#include <bluetooth/mgmt.h>
-
-#include <glib.h>
-#include "glib-helper.h"
-
-static bool monitor = false;
-static bool discovery = false;
-static bool resolve_names = true;
-
-typedef void (*cmd_cb)(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data);
-
-static struct pending_cmd {
-	uint16_t op;
-	uint16_t id;
-	cmd_cb cb;
-	void *user_data;
-	struct pending_cmd *next;
-} *pending = NULL;
-
-static int mgmt_send_cmd(int mgmt_sk, uint16_t op, uint16_t id, void *data,
-				size_t len, cmd_cb func, void *user_data)
-{
-	char buf[1024];
-	struct pending_cmd *cmd;
-	struct mgmt_hdr *hdr = (void *) buf;
-
-	if (len + MGMT_HDR_SIZE > sizeof(buf))
-		return -EINVAL;
-
-	cmd = calloc(1, sizeof(struct pending_cmd));
-	if (cmd == NULL)
-		return -errno;
-
-	cmd->op = op;
-	cmd->id = id;
-	cmd->cb = func;
-	cmd->user_data = user_data;
-
-	memset(buf, 0, sizeof(buf));
-	hdr->opcode = htobs(op);
-	hdr->index = htobs(id);
-	hdr->len = htobs(len);
-	memcpy(buf + MGMT_HDR_SIZE, data, len);
-
-	if (write(mgmt_sk, buf, MGMT_HDR_SIZE + len) < 0) {
-		fprintf(stderr, "Unable to write to socket: %s\n",
-							strerror(errno));
-		free(cmd);
-		return -1;
-	}
-
-	cmd->next = pending;
-	pending = cmd;
-
-	return 0;
-}
-
-static int mgmt_open(void)
-{
-	struct sockaddr_hci addr;
-	int sk;
-
-	sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
-	if (sk < 0) {
-		fprintf(stderr, "socket: %s\n", strerror(errno));
-		return sk;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.hci_family = AF_BLUETOOTH;
-	addr.hci_dev = HCI_DEV_NONE;
-	addr.hci_channel = HCI_CHANNEL_CONTROL;
-
-	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		fprintf(stderr, "bind: %s\n", strerror(errno));
-		close(sk);
-		return -1;
-	}
-
-	return sk;
-}
-
-static void mgmt_check_pending(int mgmt_sk, uint16_t op, uint16_t index,
-				uint16_t status, void *data, uint16_t len)
-{
-	struct pending_cmd *c, *prev;
-
-	for (c = pending, prev = NULL; c != NULL; prev = c, c = c->next) {
-		if (c->op != op)
-			continue;
-		if (c->id != index)
-			continue;
-
-		if (c == pending)
-			pending = c->next;
-		else
-			prev->next = c->next;
-
-		c->cb(mgmt_sk, op, index, status, data, len, c->user_data);
-
-		free(c);
-		break;
-	}
-}
-
-static int mgmt_cmd_complete(int mgmt_sk, uint16_t index,
-				struct mgmt_ev_cmd_complete *ev, uint16_t len)
-{
-	uint16_t op;
-
-	if (len < sizeof(*ev)) {
-		fprintf(stderr, "Too short (%u bytes) cmd complete event\n",
-									len);
-		return -EINVAL;
-	}
-
-	op = bt_get_le16(&ev->opcode);
-
-	len -= sizeof(*ev);
-
-	if (monitor)
-		printf("%s complete, opcode 0x%04x len %u\n", mgmt_opstr(op),
-								op, len);
-
-	mgmt_check_pending(mgmt_sk, op, index, ev->status, ev->data, len);
-
-	return 0;
-}
-
-static int mgmt_cmd_status(int mgmt_sk, uint16_t index,
-				struct mgmt_ev_cmd_status *ev, uint16_t len)
-{
-	uint16_t opcode;
-
-	if (len < sizeof(*ev)) {
-		fprintf(stderr, "Too short (%u bytes) cmd status event\n",
-									len);
-		return -EINVAL;
-	}
-
-	opcode = bt_get_le16(&ev->opcode);
-
-	if (monitor)
-		printf("cmd status, opcode 0x%04x status 0x%02x (%s)\n",
-				opcode, ev->status, mgmt_errstr(ev->status));
-
-	if (ev->status != 0)
-		mgmt_check_pending(mgmt_sk, opcode, index, ev->status,
-								NULL, 0);
-
-	return 0;
-}
-
-static int mgmt_controller_error(uint16_t index,
-					struct mgmt_ev_controller_error *ev,
-					uint16_t len)
-{
-	if (len < sizeof(*ev)) {
-		fprintf(stderr,
-			"Too short (%u bytes) controller error event\n", len);
-		return -EINVAL;
-	}
-
-	if (monitor)
-		printf("hci%u error 0x%02x\n", index, ev->error_code);
-
-	return 0;
-}
-
-static int mgmt_index_added(int mgmt_sk, uint16_t index)
-{
-	if (monitor)
-		printf("hci%u added\n", index);
-	return 0;
-}
-
-static int mgmt_index_removed(int mgmt_sk, uint16_t index)
-{
-	if (monitor)
-		printf("hci%u removed\n", index);
-	return 0;
-}
-
-static const char *settings_str[] = {
-				"powered",
-				"connectable",
-				"fast-connectable",
-				"discoverable",
-				"pairable",
-				"link-security",
-				"ssp",
-				"br/edr",
-				"hs",
-				"le" ,
-};
-
-static void print_settings(uint32_t settings)
-{
-	unsigned i;
-
-	for (i = 0; i < NELEM(settings_str); i++) {
-		if ((settings & (1 << i)) != 0)
-			printf("%s ", settings_str[i]);
-	}
-}
-
-static int mgmt_new_settings(int mgmt_sk, uint16_t index,
-					uint32_t *ev, uint16_t len)
-{
-	if (len < sizeof(*ev)) {
-		fprintf(stderr, "Too short new_settings event (%u)\n", len);
-		return -EINVAL;
-	}
-
-	if (monitor) {
-		printf("hci%u new_settings: ", index);
-		print_settings(bt_get_le32(ev));
-		printf("\n");
-	}
-
-	return 0;
-}
-
-static int mgmt_discovering(int mgmt_sk, uint16_t index,
-				struct mgmt_ev_discovering *ev, uint16_t len)
-{
-	if (len < sizeof(*ev)) {
-		fprintf(stderr, "Too short (%u bytes) discovering event\n",
-									len);
-		return -EINVAL;
-	}
-
-	if (ev->discovering == 0 && discovery)
-		exit(EXIT_SUCCESS);
-
-	if (monitor)
-		printf("hci%u type %u discovering %s\n", index,
-				ev->type, ev->discovering ? "on" : "off");
-
-	return 0;
-}
-
-static int mgmt_new_link_key(int mgmt_sk, uint16_t index,
-				struct mgmt_ev_new_link_key *ev, uint16_t len)
-{
-
-	if (len != sizeof(*ev)) {
-		fprintf(stderr, "Invalid new_link_key length (%u bytes)\n",
-									len);
-		return -EINVAL;
-	}
-
-	if (monitor) {
-		char addr[18];
-		ba2str(&ev->key.addr.bdaddr, addr);
-		printf("hci%u new_link_key %s type 0x%02x pin_len %d "
-				"store_hint %u\n", index, addr, ev->key.type,
-				ev->key.pin_len, ev->store_hint);
-	}
-
-	return 0;
-}
-
-static const char *typestr(uint8_t type)
-{
-	const char *str[] = { "BR/EDR", "LE Public", "LE Random" };
-
-	if (type <= BDADDR_LE_RANDOM)
-		return str[type];
-
-	return "(unknown)";
-}
-
-static int mgmt_connected(int mgmt_sk, uint16_t index,
-					struct mgmt_ev_device_connected *ev,
-					uint16_t len)
-{
-	uint16_t eir_len;
-
-	if (len < sizeof(*ev)) {
-		fprintf(stderr,
-			"Invalid connected event length (%u bytes)\n", len);
-		return -EINVAL;
-	}
-
-	eir_len = bt_get_le16(&ev->eir_len);
-	if (len != sizeof(*ev) + eir_len) {
-		fprintf(stderr, "Invalid connected event length "
-			"(%u bytes, eir_len %u bytes)\n", len, eir_len);
-		return -EINVAL;
-	}
-
-	if (monitor) {
-		char addr[18];
-		ba2str(&ev->addr.bdaddr, addr);
-		printf("hci%u %s type %s connected eir_len %u\n", index, addr,
-					typestr(ev->addr.type), eir_len);
-	}
-
-	return 0;
-}
-
-static int mgmt_disconnected(int mgmt_sk, uint16_t index,
-				struct mgmt_addr_info *ev, uint16_t len)
-{
-	if (len != sizeof(*ev)) {
-		fprintf(stderr,
-			"Invalid disconnected event length (%u bytes)\n", len);
-		return -EINVAL;
-	}
-
-	if (monitor) {
-		char addr[18];
-		ba2str(&ev->bdaddr, addr);
-		printf("hci%u %s type %s disconnected\n", index, addr,
-							typestr(ev->type));
-	}
-
-	return 0;
-}
-
-static int mgmt_conn_failed(int mgmt_sk, uint16_t index,
-				struct mgmt_ev_connect_failed *ev,
-				uint16_t len)
-{
-	if (len != sizeof(*ev)) {
-		fprintf(stderr,
-			"Invalid connect_failed event length (%u bytes)\n", len);
-		return -EINVAL;
-	}
-
-	if (monitor) {
-		char addr[18];
-		ba2str(&ev->addr.bdaddr, addr);
-		printf("hci%u %s type %s connect failed (status 0x%02x, %s)\n",
-				index, addr, typestr(ev->addr.type), ev->status,
-				mgmt_errstr(ev->status));
-	}
-
-	return 0;
-}
-
-static int mgmt_auth_failed(int mgmt_sk, uint16_t index,
-				struct mgmt_ev_auth_failed *ev,
-				uint16_t len)
-{
-	if (len != sizeof(*ev)) {
-		fprintf(stderr,
-			"Invalid auth_failed event length (%u bytes)\n", len);
-		return -EINVAL;
-	}
-
-	if (monitor) {
-		char addr[18];
-		ba2str(&ev->addr.bdaddr, addr);
-		printf("hci%u %s auth failed with status 0x%02x (%s)\n",
-			index, addr, ev->status, mgmt_errstr(ev->status));
-	}
-
-	return 0;
-}
-
-static int mgmt_name_changed(int mgmt_sk, uint16_t index,
-				struct mgmt_ev_local_name_changed *ev,
-				uint16_t len)
-{
-	if (len != sizeof(*ev)) {
-		fprintf(stderr,
-			"Invalid local_name_changed length (%u bytes)\n", len);
-		return -EINVAL;
-	}
-
-	if (monitor)
-		printf("hci%u name changed: %s\n", index, ev->name);
-
-	return 0;
-}
-
-static void confirm_name_rsp(int mgmt_sk, uint16_t op, uint16_t id,
-				uint8_t status, void *rsp, uint16_t len,
-				void *user_data)
-{
-	struct mgmt_rp_confirm_name *rp = rsp;
-	char addr[18];
-
-	if (len == 0 && status != 0) {
-		fprintf(stderr,
-			"hci%u confirm_name failed with status 0x%02x (%s)\n",
-					id, status, mgmt_errstr(status));
-		return;
-	}
-
-	if (len != sizeof(*rp)) {
-		fprintf(stderr,
-			"hci%u confirm_name rsp length %u instead of %zu\n",
-			id, len, sizeof(*rp));
-		return;
-	}
-
-	ba2str(&rp->addr.bdaddr, addr);
-
-	if (status != 0)
-		fprintf(stderr,
-			"hci%u confirm_name for %s failed: 0x%02x (%s)\n",
-			id, addr, status, mgmt_errstr(status));
-	else
-		printf("hci%u confirm_name succeeded for %s\n", id, addr);
-}
-
-static int mgmt_device_found(int mgmt_sk, uint16_t index,
-				struct mgmt_ev_device_found *ev, uint16_t len)
-{
-	uint32_t flags;
-	uint16_t eir_len;
-
-	if (len < sizeof(*ev)) {
-		fprintf(stderr,
-			"Too short device_found length (%u bytes)\n", len);
-		return -EINVAL;
-	}
-
-	flags = btohs(ev->flags);
-
-	eir_len = bt_get_le16(&ev->eir_len);
-	if (len != sizeof(*ev) + eir_len) {
-		fprintf(stderr, "dev_found: expected %zu bytes, got %u bytes",
-						sizeof(*ev) + eir_len, len);
-		return -EINVAL;
-	}
-
-	if (monitor || discovery) {
-		char addr[18];
-		ba2str(&ev->addr.bdaddr, addr);
-		printf("hci%u dev_found: %s type %s rssi %d "
-			"flags 0x%04x eir_len %u\n", index, addr,
-			typestr(ev->addr.type), ev->rssi, flags, eir_len);
-	}
-
-	if (discovery && (flags & MGMT_DEV_FOUND_CONFIRM_NAME)) {
-		struct mgmt_cp_confirm_name cp;
-
-		memset(&cp, 0, sizeof(cp));
-		memcpy(&cp.addr, &ev->addr, sizeof(cp.addr));
-		if (resolve_names)
-			cp.name_known = 0;
-		else
-			cp.name_known = 1;
-
-		mgmt_send_cmd(mgmt_sk, MGMT_OP_CONFIRM_NAME, index,
-					&cp, sizeof(cp), confirm_name_rsp,
-					NULL);
-	}
-
-	return 0;
-}
-
-static void pin_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	if (status != 0) {
-		fprintf(stderr,
-			"hci%u PIN Code reply failed with status 0x%02x (%s)",
-					id, status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	printf("hci%u PIN Reply successful\n", id);
-}
-
-static int mgmt_pin_reply(int mgmt_sk, uint16_t index,
-						struct mgmt_addr_info *addr,
-						const char *pin, size_t len)
-{
-	struct mgmt_cp_pin_code_reply cp;
-
-	memset(&cp, 0, sizeof(cp));
-	memcpy(&cp.addr, addr, sizeof(cp.addr));
-	cp.pin_len = len;
-	memcpy(cp.pin_code, pin, len);
-
-	return mgmt_send_cmd(mgmt_sk, MGMT_OP_PIN_CODE_REPLY, index,
-					&cp, sizeof(cp), pin_rsp, NULL);
-}
-
-static void pin_neg_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	if (status != 0) {
-		fprintf(stderr,
-			"hci%u PIN Neg reply failed with status 0x%02x (%s)",
-					id, status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	printf("hci%u PIN Negative Reply successful\n", id);
-}
-
-static int mgmt_pin_neg_reply(int mgmt_sk, uint16_t index,
-						struct mgmt_addr_info *addr)
-{
-	struct mgmt_cp_pin_code_neg_reply cp;
-
-	memset(&cp, 0, sizeof(cp));
-	memcpy(&cp.addr, addr, sizeof(cp.addr));
-
-	return mgmt_send_cmd(mgmt_sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
-					&cp, sizeof(cp), pin_neg_rsp, NULL);
-}
-
-static int mgmt_request_pin(int mgmt_sk, uint16_t index,
-				struct mgmt_ev_pin_code_request *ev,
-				uint16_t len)
-{
-	char pin[18];
-	size_t pin_len;
-
-	if (len != sizeof(*ev)) {
-		fprintf(stderr,
-			"Invalid pin_code request length (%u bytes)\n", len);
-		return -EINVAL;
-	}
-
-	if (monitor) {
-		char addr[18];
-		ba2str(&ev->addr.bdaddr, addr);
-		printf("hci%u %s request PIN\n", index, addr);
-	}
-
-	printf("PIN Request (press enter to reject) >> ");
-	fflush(stdout);
-
-	memset(pin, 0, sizeof(pin));
-
-	if (fgets(pin, sizeof(pin), stdin) == NULL || pin[0] == '\n')
-		return mgmt_pin_neg_reply(mgmt_sk, index, &ev->addr);
-
-	pin_len = strlen(pin);
-	if (pin[pin_len - 1] == '\n') {
-		pin[pin_len - 1] = '\0';
-		pin_len--;
-	}
-
-	return mgmt_pin_reply(mgmt_sk, index, &ev->addr, pin, pin_len);
-}
-
-static void confirm_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	if (status != 0) {
-		fprintf(stderr,
-			"hci%u User Confirm reply failed. status 0x%02x (%s)",
-					id, status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	printf("hci%u User Confirm Reply successful\n", id);
-}
-
-static int mgmt_confirm_reply(int mgmt_sk, uint16_t index, bdaddr_t *bdaddr)
-{
-	struct mgmt_cp_user_confirm_reply cp;
-
-	memset(&cp, 0, sizeof(cp));
-	bacpy(&cp.addr.bdaddr, bdaddr);
-
-	return mgmt_send_cmd(mgmt_sk, MGMT_OP_USER_CONFIRM_REPLY, index,
-					&cp, sizeof(cp), confirm_rsp, NULL);
-}
-
-static void confirm_neg_rsp(int mgmt_sk, uint16_t op, uint16_t id,
-				uint8_t status, void *rsp, uint16_t len,
-				void *user_data)
-{
-	if (status != 0) {
-		fprintf(stderr,
-			"hci%u Confirm Neg reply failed. status 0x%02x (%s)",
-					id, status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	printf("hci%u User Confirm Negative Reply successful\n", id);
-}
-
-static int mgmt_confirm_neg_reply(int mgmt_sk, uint16_t index,
-							bdaddr_t *bdaddr)
-{
-	struct mgmt_cp_user_confirm_reply cp;
-
-	memset(&cp, 0, sizeof(cp));
-	bacpy(&cp.addr.bdaddr, bdaddr);
-
-	return mgmt_send_cmd(mgmt_sk, MGMT_OP_USER_CONFIRM_NEG_REPLY, index,
-				&cp, sizeof(cp), confirm_neg_rsp, NULL);
-}
-
-
-static int mgmt_user_confirm(int mgmt_sk, uint16_t index,
-				struct mgmt_ev_user_confirm_request *ev,
-				uint16_t len)
-{
-	char rsp[5];
-	size_t rsp_len;
-	uint32_t val;
-	char addr[18];
-
-	if (len != sizeof(*ev)) {
-		fprintf(stderr,
-			"Invalid user_confirm request length (%u)\n", len);
-		return -EINVAL;
-	}
-
-	ba2str(&ev->addr.bdaddr, addr);
-	val = bt_get_le32(&ev->value);
-
-	if (monitor)
-		printf("hci%u %s User Confirm %06u hint %u\n", index, addr,
-							val, ev->confirm_hint);
-
-	if (ev->confirm_hint)
-		printf("Accept pairing with %s (yes/no) >> ", addr);
-	else
-		printf("Confirm value %06u for %s (yes/no) >> ", val, addr);
-
-	fflush(stdout);
-
-	memset(rsp, 0, sizeof(rsp));
-
-	if (fgets(rsp, sizeof(rsp), stdin) == NULL || rsp[0] == '\n')
-		return mgmt_confirm_neg_reply(mgmt_sk, index, &ev->addr.bdaddr);
-
-	rsp_len = strlen(rsp);
-	if (rsp[rsp_len - 1] == '\n') {
-		rsp[rsp_len - 1] = '\0';
-		rsp_len--;
-	}
-
-	if (rsp[0] == 'y' || rsp[0] == 'Y')
-		return mgmt_confirm_reply(mgmt_sk, index, &ev->addr.bdaddr);
-	else
-		return mgmt_confirm_neg_reply(mgmt_sk, index, &ev->addr.bdaddr);
-}
-
-static int mgmt_handle_event(int mgmt_sk, uint16_t ev, uint16_t index,
-						void *data, uint16_t len)
-{
-	if (monitor)
-		printf("event: %s\n", mgmt_evstr(ev));
-
-	switch (ev) {
-	case MGMT_EV_CMD_COMPLETE:
-		return mgmt_cmd_complete(mgmt_sk, index, data, len);
-	case MGMT_EV_CMD_STATUS:
-		return mgmt_cmd_status(mgmt_sk, index, data, len);
-	case MGMT_EV_CONTROLLER_ERROR:
-		return mgmt_controller_error(index, data, len);
-	case MGMT_EV_INDEX_ADDED:
-		return mgmt_index_added(mgmt_sk, index);
-	case MGMT_EV_INDEX_REMOVED:
-		return mgmt_index_removed(mgmt_sk, index);
-	case MGMT_EV_NEW_SETTINGS:
-		return mgmt_new_settings(mgmt_sk, index, data, len);
-	case MGMT_EV_DISCOVERING:
-		return mgmt_discovering(mgmt_sk, index, data, len);
-	case MGMT_EV_NEW_LINK_KEY:
-		return mgmt_new_link_key(mgmt_sk, index, data, len);
-	case MGMT_EV_DEVICE_CONNECTED:
-		return mgmt_connected(mgmt_sk, index, data, len);
-	case MGMT_EV_DEVICE_DISCONNECTED:
-		return mgmt_disconnected(mgmt_sk, index, data, len);
-	case MGMT_EV_CONNECT_FAILED:
-		return mgmt_conn_failed(mgmt_sk, index, data, len);
-	case MGMT_EV_AUTH_FAILED:
-		return mgmt_auth_failed(mgmt_sk, index, data, len);
-	case MGMT_EV_LOCAL_NAME_CHANGED:
-		return mgmt_name_changed(mgmt_sk, index, data, len);
-	case MGMT_EV_DEVICE_FOUND:
-		return mgmt_device_found(mgmt_sk, index, data, len);
-	case MGMT_EV_PIN_CODE_REQUEST:
-		return mgmt_request_pin(mgmt_sk, index, data, len);
-	case MGMT_EV_USER_CONFIRM_REQUEST:
-		return mgmt_user_confirm(mgmt_sk, index, data, len);
-	default:
-		if (monitor)
-			printf("Unhandled event 0x%04x (%s)\n", ev, mgmt_evstr(ev));
-		return 0;
-	}
-}
-
-static int mgmt_process_data(int mgmt_sk)
-{
-	char buf[1024];
-	struct mgmt_hdr *hdr = (void *) buf;
-	uint16_t len, ev, index;
-	ssize_t ret;
-
-	ret = read(mgmt_sk, buf, sizeof(buf));
-	if (ret < 0) {
-		fprintf(stderr, "read: %s\n", strerror(errno));
-		return ret;
-	}
-
-	if (ret < MGMT_HDR_SIZE) {
-		fprintf(stderr, "Too small mgmt packet (%zd bytes)\n", ret);
-		return 0;
-	}
-
-	ev = bt_get_le16(&hdr->opcode);
-	index = bt_get_le16(&hdr->index);
-	len = bt_get_le16(&hdr->len);
-
-	if (monitor)
-		printf("event 0x%04x len 0x%04x index 0x%04x\n", ev, len, index);
-
-	if (ret != MGMT_HDR_SIZE + len) {
-		fprintf(stderr, "Packet length mismatch. ret %zd len %u",
-								ret, len);
-		return 0;
-	}
-
-	mgmt_handle_event(mgmt_sk, ev, index, buf + MGMT_HDR_SIZE, len);
-
-	return 0;
-}
-
-static void cmd_monitor(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	printf("Monitoring mgmt events...\n");
-	monitor = true;
-}
-
-static void version_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	struct mgmt_rp_read_version *rp = rsp;
-
-	if (status != 0) {
-		fprintf(stderr, "Reading mgmt version failed with status"
-			" 0x%02x (%s)\n", status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	if (len < sizeof(*rp)) {
-		fprintf(stderr, "Too small version reply (%u bytes)\n", len);
-		exit(EXIT_FAILURE);
-	}
-
-	printf("MGMT Version %u, revision %u\n", rp->version,
-						bt_get_le16(&rp->revision));
-
-	exit(EXIT_SUCCESS);
-}
-
-static void cmd_version(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE,
-					NULL, 0, version_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send read_version cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void commands_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	struct mgmt_rp_read_commands *rp = rsp;
-	uint16_t num_commands, num_events, *opcode;
-	size_t expected_len;
-	int i;
-
-	if (status != 0) {
-		fprintf(stderr, "Reading supported commands failed with status"
-			" 0x%02x (%s)\n", status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	if (len < sizeof(*rp)) {
-		fprintf(stderr, "Too small commands reply (%u bytes)\n", len);
-		exit(EXIT_FAILURE);
-	}
-
-	num_commands = bt_get_le16(&rp->num_commands);
-	num_events = bt_get_le16(&rp->num_events);
-
-	expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) +
-						num_events * sizeof(uint16_t);
-
-	if (len < expected_len) {
-		fprintf(stderr, "Too small commands reply (%u != %zu)\n",
-							len, expected_len);
-		exit(EXIT_FAILURE);
-	}
-
-	opcode = rp->opcodes;
-
-	printf("%u commands:\n", num_commands);
-	for (i = 0; i < num_commands; i++) {
-		uint16_t op = bt_get_le16(opcode++);
-		printf("\t%s (0x%04x)\n", mgmt_opstr(op), op);
-	}
-
-	printf("%u events:\n", num_events);
-	for (i = 0; i < num_events; i++) {
-		uint16_t ev = bt_get_le16(opcode++);
-		printf("\t%s (0x%04x)\n", mgmt_evstr(ev), ev);
-	}
-
-	exit(EXIT_SUCCESS);
-}
-
-static void cmd_commands(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE,
-					NULL, 0, commands_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send read_commands cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void info_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	struct mgmt_rp_read_info *rp = rsp;
-	char addr[18];
-
-	if (status != 0) {
-		fprintf(stderr,
-			"Reading hci%u info failed with status 0x%02x (%s)\n",
-					id, status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	if (len < sizeof(*rp)) {
-		fprintf(stderr, "Too small info reply (%u bytes)\n", len);
-		exit(EXIT_FAILURE);
-	}
-
-	ba2str(&rp->bdaddr, addr);
-	printf("hci%u:\taddr %s version %u manufacturer %u"
-			" class 0x%02x%02x%02x\n",
-			id, addr, rp->version, bt_get_le16(&rp->manufacturer),
-			rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
-
-	printf("\tsupported settings: ");
-	print_settings(bt_get_le32(&rp->supported_settings));
-
-	printf("\n\tcurrent settings: ");
-	print_settings(bt_get_le32(&rp->current_settings));
-
-	printf("\n\tname %s\n", rp->name);
-	printf("\tshort name %s\n", rp->short_name);
-
-	if (pending == NULL)
-		exit(EXIT_SUCCESS);
-}
-
-static void index_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	struct mgmt_rp_read_index_list *rp = rsp;
-	uint16_t count;
-	unsigned int i;
-
-	if (status != 0) {
-		fprintf(stderr,
-			"Reading index list failed with status 0x%02x (%s)\n",
-						status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	if (len < sizeof(*rp)) {
-		fprintf(stderr, "Too small index list reply (%u bytes)\n",
-									len);
-		exit(EXIT_FAILURE);
-	}
-
-	count = bt_get_le16(&rp->num_controllers);
-
-	if (len < sizeof(*rp) + count * sizeof(uint16_t)) {
-		fprintf(stderr,
-			"Index count (%u) doesn't match reply length (%u)\n",
-								count, len);
-		exit(EXIT_FAILURE);
-	}
-
-	if (monitor)
-		printf("Index list with %u item%s\n",
-						count, count > 1 ? "s" : "");
-
-	if (count == 0)
-		exit(EXIT_SUCCESS);
-
-	if (monitor && count > 0)
-		printf("\t");
-
-	for (i = 0; i < count; i++) {
-		uint16_t index;
-
-		index = bt_get_le16(&rp->index[i]);
-
-		if (monitor)
-			printf("hci%u ", index);
-
-		if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INFO, index, NULL,
-					0, info_rsp, NULL) < 0) {
-			fprintf(stderr, "Unable to send read_info cmd\n");
-			exit(EXIT_FAILURE);
-		}
-	}
-
-	if (monitor && count > 0)
-		printf("\n");
-}
-
-static void cmd_info(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	if (index == MGMT_INDEX_NONE) {
-		if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INDEX_LIST,
-					MGMT_INDEX_NONE, NULL, 0,
-					index_rsp, NULL) < 0) {
-			fprintf(stderr, "Unable to send index_list cmd\n");
-			exit(EXIT_FAILURE);
-		}
-
-		return;
-	}
-
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INFO, index, NULL,
-						0, info_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send read_info cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void setting_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	uint32_t *rp = rsp;
-
-	if (status != 0) {
-		fprintf(stderr,
-			"%s for hci%u failed with status 0x%02x (%s)\n",
-			mgmt_opstr(op), id, status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	if (len < sizeof(*rp)) {
-		fprintf(stderr, "Too small %s response (%u bytes)\n",
-							mgmt_opstr(op), len);
-		exit(EXIT_FAILURE);
-	}
-
-	printf("hci%u %s complete, settings: ", id, mgmt_opstr(op));
-	print_settings(bt_get_le32(rp));
-	printf("\n");
-
-	exit(EXIT_SUCCESS);
-}
-
-static void cmd_setting(int mgmt_sk, uint16_t index, uint16_t op,
-							int argc, char **argv)
-{
-	uint8_t val;
-
-	if (argc < 2) {
-		printf("Specify \"on\" or \"off\"\n");
-		exit(EXIT_FAILURE);
-	}
-
-	if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
-		val = 1;
-	else if (strcasecmp(argv[1], "off") == 0)
-		val = 0;
-	else
-		val = atoi(argv[1]);
-
-	if (index == MGMT_INDEX_NONE)
-		index = 0;
-
-	if (mgmt_send_cmd(mgmt_sk, op, index, &val, sizeof(val),
-						setting_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send %s cmd\n", mgmt_opstr(op));
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void cmd_power(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	cmd_setting(mgmt_sk, index, MGMT_OP_SET_POWERED, argc, argv);
-}
-
-static void cmd_discov(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	struct mgmt_cp_set_discoverable cp;
-
-	if (argc < 2) {
-		printf("Usage: btmgmt %s <yes/no> [timeout]\n", argv[0]);
-		exit(EXIT_FAILURE);
-	}
-
-	memset(&cp, 0, sizeof(cp));
-
-	if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
-		cp.val = 1;
-	else if (strcasecmp(argv[1], "off") == 0)
-		cp.val = 0;
-	else
-		cp.val = atoi(argv[1]);
-
-	if (argc > 2)
-		cp.timeout = htobs(atoi(argv[2]));
-
-	if (index == MGMT_INDEX_NONE)
-		index = 0;
-
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DISCOVERABLE, index,
-				&cp, sizeof(cp), setting_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send set_discoverable cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void cmd_connectable(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	cmd_setting(mgmt_sk, index, MGMT_OP_SET_CONNECTABLE, argc, argv);
-}
-
-static void cmd_pairable(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	cmd_setting(mgmt_sk, index, MGMT_OP_SET_PAIRABLE, argc, argv);
-}
-
-static void cmd_linksec(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	cmd_setting(mgmt_sk, index, MGMT_OP_SET_LINK_SECURITY, argc, argv);
-}
-
-static void cmd_ssp(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	cmd_setting(mgmt_sk, index, MGMT_OP_SET_SSP, argc, argv);
-}
-
-static void cmd_hs(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	cmd_setting(mgmt_sk, index, MGMT_OP_SET_HS, argc, argv);
-}
-
-static void cmd_le(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	cmd_setting(mgmt_sk, index, MGMT_OP_SET_LE, argc, argv);
-}
-
-static void class_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	struct mgmt_ev_class_of_dev_changed *rp = rsp;
-
-	if (len == 0 && status != 0) {
-		fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
-				mgmt_opstr(op), status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	if (len != sizeof(*rp)) {
-		fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len);
-		exit(EXIT_FAILURE);
-	}
-
-	printf("%s succeeded. Class 0x%02x%02x%02x\n", mgmt_opstr(op),
-		rp->class_of_dev[2], rp->class_of_dev[1], rp->class_of_dev[0]);
-
-	exit(EXIT_SUCCESS);
-}
-
-static void cmd_class(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	uint8_t class[2];
-
-	if (argc < 3) {
-		printf("Usage: btmgmt %s <major> <minor>\n", argv[0]);
-		exit(EXIT_FAILURE);
-	}
-
-	class[0] = atoi(argv[1]);
-	class[1] = atoi(argv[2]);
-
-	if (index == MGMT_INDEX_NONE)
-		index = 0;
-
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DEV_CLASS, index,
-				class, sizeof(class), class_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send set_dev_class cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void disconnect_rsp(int mgmt_sk, uint16_t op, uint16_t id,
-				uint8_t status, void *rsp, uint16_t len,
-				void *user_data)
-{
-	struct mgmt_rp_disconnect *rp = rsp;
-	char addr[18];
-
-	if (len == 0 && status != 0) {
-		fprintf(stderr, "Disconnect failed with status 0x%02x (%s)\n",
-						status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	if (len != sizeof(*rp)) {
-		fprintf(stderr, "Invalid disconnect response length (%u)\n",
-									len);
-		exit(EXIT_FAILURE);
-	}
-
-	ba2str(&rp->addr.bdaddr, addr);
-
-	if (status == 0) {
-		printf("%s disconnected\n", addr);
-		exit(EXIT_SUCCESS);
-	} else {
-		fprintf(stderr,
-			"Disconnecting %s failed with status 0x%02x (%s)\n",
-				addr, status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void cmd_disconnect(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	struct mgmt_cp_disconnect cp;
-
-	if (argc < 2) {
-		printf("Usage: btmgmt %s <address>\n", argv[0]);
-		exit(EXIT_FAILURE);
-	}
-
-	str2ba(argv[1], &cp.addr.bdaddr);
-
-	if (index == MGMT_INDEX_NONE)
-		index = 0;
-
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_DISCONNECT, index,
-				&cp, sizeof(cp), disconnect_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send disconnect cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void con_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	struct mgmt_rp_get_connections *rp = rsp;
-	uint16_t count, i;
-
-	if (len < sizeof(*rp)) {
-		fprintf(stderr, "Too small (%u bytes) get_connections rsp\n",
-									len);
-		exit(EXIT_FAILURE);
-	}
-
-	count = bt_get_le16(&rp->conn_count);
-	if (len != sizeof(*rp) + count * sizeof(struct mgmt_addr_info)) {
-		fprintf(stderr, "Invalid get_connections length "
-					" (count=%u, len=%u)\n", count, len);
-		exit(EXIT_FAILURE);
-	}
-
-	for (i = 0; i < count; i++) {
-		char addr[18];
-
-		ba2str(&rp->addr[i].bdaddr, addr);
-
-		printf("%s type %s\n", addr, typestr(rp->addr[i].type));
-	}
-
-	exit(EXIT_SUCCESS);
-}
-
-static void cmd_con(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	if (index == MGMT_INDEX_NONE)
-		index = 0;
-
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_GET_CONNECTIONS, index, NULL, 0,
-							con_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send get_connections cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void find_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	if (status != 0) {
-		fprintf(stderr,
-			"Unable to start discovery. status 0x%02x (%s)\n",
-						status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	printf("Discovery started\n");
-	discovery = true;
-}
-
-static void find_usage(void)
-{
-	printf("Usage: btmgmt find [-l|-b]>\n");
-}
-
-static struct option find_options[] = {
-	{ "help",	0, 0, 'h' },
-	{ "le-only",	1, 0, 'l' },
-	{ "bredr-only",	1, 0, 'b' },
-	{ 0, 0, 0, 0 }
-};
-
-static void cmd_find(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	struct mgmt_cp_start_discovery cp;
-	uint8_t type;
-	int opt;
-
-	if (index == MGMT_INDEX_NONE)
-		index = 0;
-
-	type = 0;
-	hci_set_bit(BDADDR_BREDR, &type);
-	hci_set_bit(BDADDR_LE_PUBLIC, &type);
-	hci_set_bit(BDADDR_LE_RANDOM, &type);
-
-	while ((opt = getopt_long(argc, argv, "+lbh", find_options,
-								NULL)) != -1) {
-		switch (opt) {
-		case 'l':
-			hci_clear_bit(BDADDR_BREDR, &type);
-			hci_set_bit(BDADDR_LE_PUBLIC, &type);
-			hci_set_bit(BDADDR_LE_RANDOM, &type);
-			break;
-		case 'b':
-			hci_set_bit(BDADDR_BREDR, &type);
-			hci_clear_bit(BDADDR_LE_PUBLIC, &type);
-			hci_clear_bit(BDADDR_LE_RANDOM, &type);
-			break;
-		case 'h':
-		default:
-			find_usage();
-			exit(EXIT_SUCCESS);
-		}
-	}
-
-	argc -= optind;
-	argv += optind;
-	optind = 0;
-
-	memset(&cp, 0, sizeof(cp));
-	cp.type = type;
-
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_START_DISCOVERY, index,
-				&cp, sizeof(cp), find_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send start_discovery cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void name_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	if (status != 0) {
-		fprintf(stderr, "Unable to set local name. status 0x%02x (%s)",
-						status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	exit(EXIT_SUCCESS);
-}
-
-static void cmd_name(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	struct mgmt_cp_set_local_name cp;
-
-	if (argc < 2) {
-		printf("Usage: btmgmt %s <name> [shortname]\n", argv[0]);
-		exit(EXIT_FAILURE);
-	}
-
-	if (index == MGMT_INDEX_NONE)
-		index = 0;
-
-	memset(&cp, 0, sizeof(cp));
-	strncpy((char *) cp.name, argv[1], HCI_MAX_NAME_LENGTH);
-	if (argc > 2)
-		strncpy((char *) cp.short_name, argv[2],
-					MGMT_MAX_SHORT_NAME_LENGTH);
-
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_LOCAL_NAME, index,
-					&cp, sizeof(cp), name_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send set_name cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void pair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	struct mgmt_rp_pair_device *rp = rsp;
-	char addr[18];
-
-	if (len == 0 && status != 0) {
-		fprintf(stderr, "Pairing failed with status 0x%02x (%s)\n",
-						status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	if (len != sizeof(*rp)) {
-		fprintf(stderr, "Unexpected pair_rsp len %u\n", len);
-		exit(EXIT_FAILURE);
-	}
-
-	ba2str(&rp->addr.bdaddr, addr);
-
-	if (status != 0) {
-		fprintf(stderr,
-			"Pairing with %s (%s) failed. status 0x%02x (%s)\n",
-			addr, typestr(rp->addr.type), status,
-			mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	printf("Paired with %s\n", addr);
-
-	exit(EXIT_SUCCESS);
-}
-
-static void pair_usage(void)
-{
-	printf("Usage: btmgmt pair [-c cap] [-t type] <remote address>\n");
-}
-
-static struct option pair_options[] = {
-	{ "help",	0, 0, 'h' },
-	{ "capability",	1, 0, 'c' },
-	{ "type",	1, 0, 't' },
-	{ 0, 0, 0, 0 }
-};
-
-static void cmd_pair(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	struct mgmt_cp_pair_device cp;
-	uint8_t cap = 0x01;
-	uint8_t type = BDADDR_BREDR;
-	int opt;
-
-	while ((opt = getopt_long(argc, argv, "+c:t:h", pair_options,
-								NULL)) != -1) {
-		switch (opt) {
-		case 'c':
-			cap = strtol(optarg, NULL, 0);
-			break;
-		case 't':
-			type = strtol(optarg, NULL, 0);
-			break;
-		case 'h':
-		default:
-			pair_usage();
-			exit(EXIT_SUCCESS);
-		}
-	}
-
-	argc -= optind;
-	argv += optind;
-	optind = 0;
-
-	if (argc < 1) {
-		pair_usage();
-		exit(EXIT_FAILURE);
-	}
-
-	if (index == MGMT_INDEX_NONE)
-		index = 0;
-
-	memset(&cp, 0, sizeof(cp));
-	str2ba(argv[0], &cp.addr.bdaddr);
-	cp.addr.type = type;
-	cp.io_cap = cap;
-
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_PAIR_DEVICE, index, &cp, sizeof(cp),
-							pair_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send pair_device cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void unpair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	struct mgmt_rp_unpair_device *rp = rsp;
-	char addr[18];
-
-	if (len == 0 && status != 0) {
-		fprintf(stderr, "Unpair device failed. status 0x%02x (%s)\n",
-						status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	if (len != sizeof(*rp)) {
-		fprintf(stderr, "Unexpected unpair_device_rsp len %u\n", len);
-		exit(EXIT_FAILURE);
-	}
-
-	ba2str(&rp->addr.bdaddr, addr);
-
-	if (status != 0) {
-		fprintf(stderr,
-			"Unpairing %s failed. status 0x%02x (%s)\n",
-				addr, status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	printf("%s unpaired\n", addr);
-
-	exit(EXIT_SUCCESS);
-}
-
-static void cmd_unpair(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	struct mgmt_cp_unpair_device cp;
-
-	if (argc < 2) {
-		printf("Usage: btmgmt %s <remote address>\n", argv[0]);
-		exit(EXIT_FAILURE);
-	}
-
-	if (index == MGMT_INDEX_NONE)
-		index = 0;
-
-	memset(&cp, 0, sizeof(cp));
-	str2ba(argv[1], &cp.addr.bdaddr);
-	cp.disconnect = 1;
-
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_UNPAIR_DEVICE, index, &cp,
-					sizeof(cp), unpair_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send unpair_device cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void keys_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	if (status != 0) {
-		fprintf(stderr, "Load keys failed with status 0x%02x (%s)\n",
-						status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	printf("Keys successfully loaded\n");
-
-	exit(EXIT_SUCCESS);
-}
-
-static void cmd_keys(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	struct mgmt_cp_load_link_keys cp;
-
-	if (index == MGMT_INDEX_NONE)
-		index = 0;
-
-	memset(&cp, 0, sizeof(cp));
-
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_LOAD_LINK_KEYS, index,
-				&cp, sizeof(cp), keys_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send load_keys cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void block_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	struct mgmt_addr_info *rp = rsp;
-	char addr[18];
-
-	if (len == 0 && status != 0) {
-		fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
-				mgmt_opstr(op), status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	if (len != sizeof(*rp)) {
-		fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len);
-		exit(EXIT_FAILURE);
-	}
-
-	ba2str(&rp->bdaddr, addr);
-
-	if (status != 0) {
-		fprintf(stderr, "%s %s (%s) failed. status 0x%02x (%s)\n",
-				mgmt_opstr(op), addr, typestr(rp->type),
-				status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	printf("%s %s succeeded\n", mgmt_opstr(op), addr);
-
-	exit(EXIT_SUCCESS);
-}
-
-static void block_usage(void)
-{
-	printf("Usage: btmgmt block [-t type] <remote address>\n");
-}
-
-static struct option block_options[] = {
-	{ "help",	0, 0, 'h' },
-	{ "type",	1, 0, 't' },
-	{ 0, 0, 0, 0 }
-};
-
-static void cmd_block(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	struct mgmt_cp_block_device cp;
-	uint8_t type = BDADDR_BREDR;
-	int opt;
-
-	while ((opt = getopt_long(argc, argv, "+t:h", block_options,
-							NULL)) != -1) {
-		switch (opt) {
-		case 't':
-			type = strtol(optarg, NULL, 0);
-			break;
-		case 'h':
-		default:
-			block_usage();
-			exit(EXIT_SUCCESS);
-		}
-	}
-
-	argc -= optind;
-	argv += optind;
-	optind = 0;
-
-	if (argc < 1) {
-		block_usage();
-		exit(EXIT_FAILURE);
-	}
-
-	if (index == MGMT_INDEX_NONE)
-		index = 0;
-
-	memset(&cp, 0, sizeof(cp));
-	str2ba(argv[0], &cp.addr.bdaddr);
-	cp.addr.type = type;
-
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_BLOCK_DEVICE, index,
-				&cp, sizeof(cp), block_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send block_device cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void unblock_usage(void)
-{
-	printf("Usage: btmgmt unblock [-t type] <remote address>\n");
-}
-
-static void cmd_unblock(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	struct mgmt_cp_unblock_device cp;
-	uint8_t type = BDADDR_BREDR;
-	int opt;
-
-	while ((opt = getopt_long(argc, argv, "+t:h", block_options,
-							NULL)) != -1) {
-		switch (opt) {
-		case 't':
-			type = strtol(optarg, NULL, 0);
-			break;
-		case 'h':
-		default:
-			unblock_usage();
-			exit(EXIT_SUCCESS);
-		}
-	}
-
-	argc -= optind;
-	argv += optind;
-	optind = 0;
-
-	if (argc < 1) {
-		unblock_usage();
-		exit(EXIT_FAILURE);
-	}
-
-	if (index == MGMT_INDEX_NONE)
-		index = 0;
-
-	memset(&cp, 0, sizeof(cp));
-	str2ba(argv[0], &cp.addr.bdaddr);
-	cp.addr.type = type;
-
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_UNBLOCK_DEVICE, index,
-				&cp, sizeof(cp), block_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send unblock_device cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid)
-{
-	if (uuid->type == SDP_UUID16)
-		sdp_uuid16_to_uuid128(uuid128, uuid);
-	else if (uuid->type == SDP_UUID32)
-		sdp_uuid32_to_uuid128(uuid128, uuid);
-	else
-		memcpy(uuid128, uuid, sizeof(*uuid));
-}
-
-static void cmd_add_uuid(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	struct mgmt_cp_add_uuid cp;
-	uint128_t uint128;
-	uuid_t uuid, uuid128;
-
-	if (argc < 3) {
-		printf("UUID and service hint needed\n");
-		exit(EXIT_FAILURE);
-	}
-
-	if (index == MGMT_INDEX_NONE)
-		index = 0;
-
-	if (bt_string2uuid(&uuid, argv[1]) < 0) {
-		printf("Invalid UUID: %s\n", argv[1]);
-		exit(EXIT_FAILURE);
-	}
-
-	memset(&cp, 0, sizeof(cp));
-
-	uuid_to_uuid128(&uuid128, &uuid);
-	ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
-	htob128(&uint128, (uint128_t *) cp.uuid);
-
-	cp.svc_hint = atoi(argv[2]);
-
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_ADD_UUID, index,
-				&cp, sizeof(cp), class_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send add_uuid cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void cmd_remove_uuid(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	struct mgmt_cp_remove_uuid cp;
-	uint128_t uint128;
-	uuid_t uuid, uuid128;
-
-	if (argc < 2) {
-		printf("UUID needed\n");
-		exit(EXIT_FAILURE);
-	}
-
-	if (index == MGMT_INDEX_NONE)
-		index = 0;
-
-	if (bt_string2uuid(&uuid, argv[1]) < 0) {
-		printf("Invalid UUID: %s\n", argv[1]);
-		exit(EXIT_FAILURE);
-	}
-
-	memset(&cp, 0, sizeof(cp));
-
-	uuid_to_uuid128(&uuid128, &uuid);
-	ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
-	htob128(&uint128, (uint128_t *) cp.uuid);
-
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_REMOVE_UUID, index,
-				&cp, sizeof(cp), class_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send remove_uuid cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static void cmd_clr_uuids(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	char *uuid_any = "00000000-0000-0000-0000-000000000000";
-	char *rm_argv[] = { "rm-uuid", uuid_any, NULL };
-
-	cmd_remove_uuid(mgmt_sk, index, 2, rm_argv);
-}
-
-static void did_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-				void *rsp, uint16_t len, void *user_data)
-{
-	if (status != 0) {
-		fprintf(stderr, "Set Device ID failed with status 0x%02x (%s)\n",
-						status, mgmt_errstr(status));
-		exit(EXIT_FAILURE);
-	}
-
-	printf("Device ID successfully set\n");
-
-	exit(EXIT_SUCCESS);
-}
-
-static void did_usage(void)
-{
-	printf("Usage: btmgmt did <source>:<vendor>:<product>:<version>\n");
-	printf("       possible source values: bluetooth, usb\n");
-}
-
-static void cmd_did(int mgmt_sk, uint16_t index, int argc, char **argv)
-{
-	struct mgmt_cp_set_device_id cp;
-	uint16_t vendor, product, version , source;
-	int result;
-
-	if (argc < 2) {
-		did_usage();
-		exit(EXIT_FAILURE);
-	}
-
-	result = sscanf(argv[1], "bluetooth:%4hx:%4hx:%4hx", &vendor, &product,
-								&version);
-	if (result == 3) {
-		source = 0x0001;
-		goto done;
-	}
-
-	result = sscanf(argv[1], "usb:%4hx:%4hx:%4hx", &vendor, &product,
-								&version);
-	if (result == 3) {
-		source = 0x0002;
-		goto done;
-	}
-
-	did_usage();
-	exit(EXIT_FAILURE);
-
-done:
-	if (index == MGMT_INDEX_NONE)
-		index = 0;
-
-	cp.source = htobs(source);
-	cp.vendor = htobs(vendor);
-	cp.product = htobs(product);
-	cp.version = htobs(version);
-
-	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DEVICE_ID, index,
-				&cp, sizeof(cp), did_rsp, NULL) < 0) {
-		fprintf(stderr, "Unable to send set_dev_class cmd\n");
-		exit(EXIT_FAILURE);
-	}
-}
-
-static struct {
-	char *cmd;
-	void (*func)(int mgmt_sk, uint16_t index, int argc, char **argv);
-	char *doc;
-} command[] = {
-	{ "monitor",	cmd_monitor,	"Monitor events"		},
-	{ "version",	cmd_version,	"Get the MGMT Version"		},
-	{ "commands",	cmd_commands,	"List supported commands"	},
-	{ "info",	cmd_info,	"Show controller info"		},
-	{ "power",	cmd_power,	"Toggle powered state"		},
-	{ "discov",	cmd_discov,	"Toggle discoverable state"	},
-	{ "connectable",cmd_connectable,"Toggle connectable state"	},
-	{ "pairable",	cmd_pairable,	"Toggle pairable state"		},
-	{ "linksec",	cmd_linksec,	"Toggle link level security"	},
-	{ "ssp",	cmd_ssp,	"Toggle SSP mode"		},
-	{ "hs",		cmd_hs,		"Toggle HS Support"		},
-	{ "le",		cmd_le,		"Toggle LE Support"		},
-	{ "class",	cmd_class,	"Set device major/minor class"	},
-	{ "disconnect", cmd_disconnect, "Disconnect device"		},
-	{ "con",	cmd_con,	"List connections"		},
-	{ "find",	cmd_find,	"Discover nearby devices"	},
-	{ "name",	cmd_name,	"Set local name"		},
-	{ "pair",	cmd_pair,	"Pair with a remote device"	},
-	{ "unpair",	cmd_unpair,	"Unpair device"			},
-	{ "keys",	cmd_keys,	"Load Keys"			},
-	{ "block",	cmd_block,	"Block Device"			},
-	{ "unblock",	cmd_unblock,	"Unblock Device"		},
-	{ "add-uuid",	cmd_add_uuid,	"Add UUID"			},
-	{ "rm-uuid",	cmd_add_uuid,	"Remove UUID"			},
-	{ "clr-uuids",	cmd_clr_uuids,	"Clear UUIDs",			},
-	{ "did",	cmd_did,	"Set Device ID",		},
-	{ NULL, NULL, 0 }
-};
-
-static void usage(void)
-{
-	int i;
-
-	printf("btmgmt ver %s\n", VERSION);
-	printf("Usage:\n"
-		"\tbtmgmt [options] <command> [command parameters]\n");
-
-	printf("Options:\n"
-		"\t--index <id>\tSpecify adapter index\n"
-		"\t--verbose\tEnable extra logging\n"
-		"\t--help\tDisplay help\n");
-
-	printf("Commands:\n");
-	for (i = 0; command[i].cmd; i++)
-		printf("\t%-15s\t%s\n", command[i].cmd, command[i].doc);
-
-	printf("\n"
-		"For more information on the usage of each command use:\n"
-		"\tbtmgmt <command> --help\n" );
-}
-
-static struct option main_options[] = {
-	{ "index",	1, 0, 'i' },
-	{ "verbose",	0, 0, 'v' },
-	{ "help",	0, 0, 'h' },
-	{ 0, 0, 0, 0 }
-};
-
-int main(int argc, char *argv[])
-{
-	int opt, i, mgmt_sk;
-	uint16_t index = MGMT_INDEX_NONE;
-	struct pollfd pollfd;
-
-	while ((opt = getopt_long(argc, argv, "+hvi:",
-						main_options, NULL)) != -1) {
-		switch (opt) {
-		case 'i':
-			if (strlen(optarg) > 3 &&
-					strncasecmp(optarg, "hci", 3) == 0)
-				index = atoi(&optarg[4]);
-			else
-				index = atoi(optarg);
-			break;
-		case 'v':
-			monitor = true;
-			break;
-		case 'h':
-		default:
-			usage();
-			return 0;
-		}
-	}
-
-	argc -= optind;
-	argv += optind;
-	optind = 0;
-
-	if (argc < 1) {
-		usage();
-		return 0;
-	}
-
-	mgmt_sk = mgmt_open();
-	if (mgmt_sk < 0) {
-		fprintf(stderr, "Unable to open mgmt socket\n");
-		return -1;
-	}
-
-	for (i = 0; command[i].cmd; i++) {
-		if (strcmp(command[i].cmd, argv[0]) != 0)
-			continue;
-
-		command[i].func(mgmt_sk, index, argc, argv);
-		break;
-	}
-
-	if (command[i].cmd == NULL) {
-		fprintf(stderr, "Unknown command: %s\n", argv[0]);
-		close(mgmt_sk);
-		return -1;
-	}
-
-	pollfd.fd = mgmt_sk;
-	pollfd.events = POLLIN;
-	pollfd.revents = 0;
-
-	while (poll(&pollfd, 1, -1) >= 0) {
-		if (pollfd.revents & (POLLHUP | POLLERR | POLLNVAL))
-			break;
-
-		if (pollfd.revents & POLLIN)
-			mgmt_process_data(mgmt_sk);
-
-		pollfd.revents = 0;
-	}
-
-	close(mgmt_sk);
-
-	return 0;
-}
diff --git a/tools/mgmt/main.c b/tools/mgmt/main.c
new file mode 100644
index 0000000..b2d6c3c
--- /dev/null
+++ b/tools/mgmt/main.c
@@ -0,0 +1,1933 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <poll.h>
+#include <getopt.h>
+#include <stdbool.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+#include <bluetooth/mgmt.h>
+
+#include <glib.h>
+#include "glib-helper.h"
+
+static bool monitor = false;
+static bool discovery = false;
+static bool resolve_names = true;
+
+typedef void (*cmd_cb)(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data);
+
+static struct pending_cmd {
+	uint16_t op;
+	uint16_t id;
+	cmd_cb cb;
+	void *user_data;
+	struct pending_cmd *next;
+} *pending = NULL;
+
+static int mgmt_send_cmd(int mgmt_sk, uint16_t op, uint16_t id, void *data,
+				size_t len, cmd_cb func, void *user_data)
+{
+	char buf[1024];
+	struct pending_cmd *cmd;
+	struct mgmt_hdr *hdr = (void *) buf;
+
+	if (len + MGMT_HDR_SIZE > sizeof(buf))
+		return -EINVAL;
+
+	cmd = calloc(1, sizeof(struct pending_cmd));
+	if (cmd == NULL)
+		return -errno;
+
+	cmd->op = op;
+	cmd->id = id;
+	cmd->cb = func;
+	cmd->user_data = user_data;
+
+	memset(buf, 0, sizeof(buf));
+	hdr->opcode = htobs(op);
+	hdr->index = htobs(id);
+	hdr->len = htobs(len);
+	memcpy(buf + MGMT_HDR_SIZE, data, len);
+
+	if (write(mgmt_sk, buf, MGMT_HDR_SIZE + len) < 0) {
+		fprintf(stderr, "Unable to write to socket: %s\n",
+							strerror(errno));
+		free(cmd);
+		return -1;
+	}
+
+	cmd->next = pending;
+	pending = cmd;
+
+	return 0;
+}
+
+static int mgmt_open(void)
+{
+	struct sockaddr_hci addr;
+	int sk;
+
+	sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+	if (sk < 0) {
+		fprintf(stderr, "socket: %s\n", strerror(errno));
+		return sk;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.hci_family = AF_BLUETOOTH;
+	addr.hci_dev = HCI_DEV_NONE;
+	addr.hci_channel = HCI_CHANNEL_CONTROL;
+
+	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		fprintf(stderr, "bind: %s\n", strerror(errno));
+		close(sk);
+		return -1;
+	}
+
+	return sk;
+}
+
+static void mgmt_check_pending(int mgmt_sk, uint16_t op, uint16_t index,
+				uint16_t status, void *data, uint16_t len)
+{
+	struct pending_cmd *c, *prev;
+
+	for (c = pending, prev = NULL; c != NULL; prev = c, c = c->next) {
+		if (c->op != op)
+			continue;
+		if (c->id != index)
+			continue;
+
+		if (c == pending)
+			pending = c->next;
+		else
+			prev->next = c->next;
+
+		c->cb(mgmt_sk, op, index, status, data, len, c->user_data);
+
+		free(c);
+		break;
+	}
+}
+
+static int mgmt_cmd_complete(int mgmt_sk, uint16_t index,
+				struct mgmt_ev_cmd_complete *ev, uint16_t len)
+{
+	uint16_t op;
+
+	if (len < sizeof(*ev)) {
+		fprintf(stderr, "Too short (%u bytes) cmd complete event\n",
+									len);
+		return -EINVAL;
+	}
+
+	op = bt_get_le16(&ev->opcode);
+
+	len -= sizeof(*ev);
+
+	if (monitor)
+		printf("%s complete, opcode 0x%04x len %u\n", mgmt_opstr(op),
+								op, len);
+
+	mgmt_check_pending(mgmt_sk, op, index, ev->status, ev->data, len);
+
+	return 0;
+}
+
+static int mgmt_cmd_status(int mgmt_sk, uint16_t index,
+				struct mgmt_ev_cmd_status *ev, uint16_t len)
+{
+	uint16_t opcode;
+
+	if (len < sizeof(*ev)) {
+		fprintf(stderr, "Too short (%u bytes) cmd status event\n",
+									len);
+		return -EINVAL;
+	}
+
+	opcode = bt_get_le16(&ev->opcode);
+
+	if (monitor)
+		printf("cmd status, opcode 0x%04x status 0x%02x (%s)\n",
+				opcode, ev->status, mgmt_errstr(ev->status));
+
+	if (ev->status != 0)
+		mgmt_check_pending(mgmt_sk, opcode, index, ev->status,
+								NULL, 0);
+
+	return 0;
+}
+
+static int mgmt_controller_error(uint16_t index,
+					struct mgmt_ev_controller_error *ev,
+					uint16_t len)
+{
+	if (len < sizeof(*ev)) {
+		fprintf(stderr,
+			"Too short (%u bytes) controller error event\n", len);
+		return -EINVAL;
+	}
+
+	if (monitor)
+		printf("hci%u error 0x%02x\n", index, ev->error_code);
+
+	return 0;
+}
+
+static int mgmt_index_added(int mgmt_sk, uint16_t index)
+{
+	if (monitor)
+		printf("hci%u added\n", index);
+	return 0;
+}
+
+static int mgmt_index_removed(int mgmt_sk, uint16_t index)
+{
+	if (monitor)
+		printf("hci%u removed\n", index);
+	return 0;
+}
+
+static const char *settings_str[] = {
+				"powered",
+				"connectable",
+				"fast-connectable",
+				"discoverable",
+				"pairable",
+				"link-security",
+				"ssp",
+				"br/edr",
+				"hs",
+				"le" ,
+};
+
+static void print_settings(uint32_t settings)
+{
+	unsigned i;
+
+	for (i = 0; i < NELEM(settings_str); i++) {
+		if ((settings & (1 << i)) != 0)
+			printf("%s ", settings_str[i]);
+	}
+}
+
+static int mgmt_new_settings(int mgmt_sk, uint16_t index,
+					uint32_t *ev, uint16_t len)
+{
+	if (len < sizeof(*ev)) {
+		fprintf(stderr, "Too short new_settings event (%u)\n", len);
+		return -EINVAL;
+	}
+
+	if (monitor) {
+		printf("hci%u new_settings: ", index);
+		print_settings(bt_get_le32(ev));
+		printf("\n");
+	}
+
+	return 0;
+}
+
+static int mgmt_discovering(int mgmt_sk, uint16_t index,
+				struct mgmt_ev_discovering *ev, uint16_t len)
+{
+	if (len < sizeof(*ev)) {
+		fprintf(stderr, "Too short (%u bytes) discovering event\n",
+									len);
+		return -EINVAL;
+	}
+
+	if (ev->discovering == 0 && discovery)
+		exit(EXIT_SUCCESS);
+
+	if (monitor)
+		printf("hci%u type %u discovering %s\n", index,
+				ev->type, ev->discovering ? "on" : "off");
+
+	return 0;
+}
+
+static int mgmt_new_link_key(int mgmt_sk, uint16_t index,
+				struct mgmt_ev_new_link_key *ev, uint16_t len)
+{
+
+	if (len != sizeof(*ev)) {
+		fprintf(stderr, "Invalid new_link_key length (%u bytes)\n",
+									len);
+		return -EINVAL;
+	}
+
+	if (monitor) {
+		char addr[18];
+		ba2str(&ev->key.addr.bdaddr, addr);
+		printf("hci%u new_link_key %s type 0x%02x pin_len %d "
+				"store_hint %u\n", index, addr, ev->key.type,
+				ev->key.pin_len, ev->store_hint);
+	}
+
+	return 0;
+}
+
+static const char *typestr(uint8_t type)
+{
+	const char *str[] = { "BR/EDR", "LE Public", "LE Random" };
+
+	if (type <= BDADDR_LE_RANDOM)
+		return str[type];
+
+	return "(unknown)";
+}
+
+static int mgmt_connected(int mgmt_sk, uint16_t index,
+					struct mgmt_ev_device_connected *ev,
+					uint16_t len)
+{
+	uint16_t eir_len;
+
+	if (len < sizeof(*ev)) {
+		fprintf(stderr,
+			"Invalid connected event length (%u bytes)\n", len);
+		return -EINVAL;
+	}
+
+	eir_len = bt_get_le16(&ev->eir_len);
+	if (len != sizeof(*ev) + eir_len) {
+		fprintf(stderr, "Invalid connected event length "
+			"(%u bytes, eir_len %u bytes)\n", len, eir_len);
+		return -EINVAL;
+	}
+
+	if (monitor) {
+		char addr[18];
+		ba2str(&ev->addr.bdaddr, addr);
+		printf("hci%u %s type %s connected eir_len %u\n", index, addr,
+					typestr(ev->addr.type), eir_len);
+	}
+
+	return 0;
+}
+
+static int mgmt_disconnected(int mgmt_sk, uint16_t index,
+				struct mgmt_addr_info *ev, uint16_t len)
+{
+	if (len != sizeof(*ev)) {
+		fprintf(stderr,
+			"Invalid disconnected event length (%u bytes)\n", len);
+		return -EINVAL;
+	}
+
+	if (monitor) {
+		char addr[18];
+		ba2str(&ev->bdaddr, addr);
+		printf("hci%u %s type %s disconnected\n", index, addr,
+							typestr(ev->type));
+	}
+
+	return 0;
+}
+
+static int mgmt_conn_failed(int mgmt_sk, uint16_t index,
+				struct mgmt_ev_connect_failed *ev,
+				uint16_t len)
+{
+	if (len != sizeof(*ev)) {
+		fprintf(stderr,
+			"Invalid connect_failed event length (%u bytes)\n", len);
+		return -EINVAL;
+	}
+
+	if (monitor) {
+		char addr[18];
+		ba2str(&ev->addr.bdaddr, addr);
+		printf("hci%u %s type %s connect failed (status 0x%02x, %s)\n",
+				index, addr, typestr(ev->addr.type), ev->status,
+				mgmt_errstr(ev->status));
+	}
+
+	return 0;
+}
+
+static int mgmt_auth_failed(int mgmt_sk, uint16_t index,
+				struct mgmt_ev_auth_failed *ev,
+				uint16_t len)
+{
+	if (len != sizeof(*ev)) {
+		fprintf(stderr,
+			"Invalid auth_failed event length (%u bytes)\n", len);
+		return -EINVAL;
+	}
+
+	if (monitor) {
+		char addr[18];
+		ba2str(&ev->addr.bdaddr, addr);
+		printf("hci%u %s auth failed with status 0x%02x (%s)\n",
+			index, addr, ev->status, mgmt_errstr(ev->status));
+	}
+
+	return 0;
+}
+
+static int mgmt_name_changed(int mgmt_sk, uint16_t index,
+				struct mgmt_ev_local_name_changed *ev,
+				uint16_t len)
+{
+	if (len != sizeof(*ev)) {
+		fprintf(stderr,
+			"Invalid local_name_changed length (%u bytes)\n", len);
+		return -EINVAL;
+	}
+
+	if (monitor)
+		printf("hci%u name changed: %s\n", index, ev->name);
+
+	return 0;
+}
+
+static void confirm_name_rsp(int mgmt_sk, uint16_t op, uint16_t id,
+				uint8_t status, void *rsp, uint16_t len,
+				void *user_data)
+{
+	struct mgmt_rp_confirm_name *rp = rsp;
+	char addr[18];
+
+	if (len == 0 && status != 0) {
+		fprintf(stderr,
+			"hci%u confirm_name failed with status 0x%02x (%s)\n",
+					id, status, mgmt_errstr(status));
+		return;
+	}
+
+	if (len != sizeof(*rp)) {
+		fprintf(stderr,
+			"hci%u confirm_name rsp length %u instead of %zu\n",
+			id, len, sizeof(*rp));
+		return;
+	}
+
+	ba2str(&rp->addr.bdaddr, addr);
+
+	if (status != 0)
+		fprintf(stderr,
+			"hci%u confirm_name for %s failed: 0x%02x (%s)\n",
+			id, addr, status, mgmt_errstr(status));
+	else
+		printf("hci%u confirm_name succeeded for %s\n", id, addr);
+}
+
+static int mgmt_device_found(int mgmt_sk, uint16_t index,
+				struct mgmt_ev_device_found *ev, uint16_t len)
+{
+	uint32_t flags;
+	uint16_t eir_len;
+
+	if (len < sizeof(*ev)) {
+		fprintf(stderr,
+			"Too short device_found length (%u bytes)\n", len);
+		return -EINVAL;
+	}
+
+	flags = btohs(ev->flags);
+
+	eir_len = bt_get_le16(&ev->eir_len);
+	if (len != sizeof(*ev) + eir_len) {
+		fprintf(stderr, "dev_found: expected %zu bytes, got %u bytes",
+						sizeof(*ev) + eir_len, len);
+		return -EINVAL;
+	}
+
+	if (monitor || discovery) {
+		char addr[18];
+		ba2str(&ev->addr.bdaddr, addr);
+		printf("hci%u dev_found: %s type %s rssi %d "
+			"flags 0x%04x eir_len %u\n", index, addr,
+			typestr(ev->addr.type), ev->rssi, flags, eir_len);
+	}
+
+	if (discovery && (flags & MGMT_DEV_FOUND_CONFIRM_NAME)) {
+		struct mgmt_cp_confirm_name cp;
+
+		memset(&cp, 0, sizeof(cp));
+		memcpy(&cp.addr, &ev->addr, sizeof(cp.addr));
+		if (resolve_names)
+			cp.name_known = 0;
+		else
+			cp.name_known = 1;
+
+		mgmt_send_cmd(mgmt_sk, MGMT_OP_CONFIRM_NAME, index,
+					&cp, sizeof(cp), confirm_name_rsp,
+					NULL);
+	}
+
+	return 0;
+}
+
+static void pin_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	if (status != 0) {
+		fprintf(stderr,
+			"hci%u PIN Code reply failed with status 0x%02x (%s)",
+					id, status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	printf("hci%u PIN Reply successful\n", id);
+}
+
+static int mgmt_pin_reply(int mgmt_sk, uint16_t index,
+						struct mgmt_addr_info *addr,
+						const char *pin, size_t len)
+{
+	struct mgmt_cp_pin_code_reply cp;
+
+	memset(&cp, 0, sizeof(cp));
+	memcpy(&cp.addr, addr, sizeof(cp.addr));
+	cp.pin_len = len;
+	memcpy(cp.pin_code, pin, len);
+
+	return mgmt_send_cmd(mgmt_sk, MGMT_OP_PIN_CODE_REPLY, index,
+					&cp, sizeof(cp), pin_rsp, NULL);
+}
+
+static void pin_neg_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	if (status != 0) {
+		fprintf(stderr,
+			"hci%u PIN Neg reply failed with status 0x%02x (%s)",
+					id, status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	printf("hci%u PIN Negative Reply successful\n", id);
+}
+
+static int mgmt_pin_neg_reply(int mgmt_sk, uint16_t index,
+						struct mgmt_addr_info *addr)
+{
+	struct mgmt_cp_pin_code_neg_reply cp;
+
+	memset(&cp, 0, sizeof(cp));
+	memcpy(&cp.addr, addr, sizeof(cp.addr));
+
+	return mgmt_send_cmd(mgmt_sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
+					&cp, sizeof(cp), pin_neg_rsp, NULL);
+}
+
+static int mgmt_request_pin(int mgmt_sk, uint16_t index,
+				struct mgmt_ev_pin_code_request *ev,
+				uint16_t len)
+{
+	char pin[18];
+	size_t pin_len;
+
+	if (len != sizeof(*ev)) {
+		fprintf(stderr,
+			"Invalid pin_code request length (%u bytes)\n", len);
+		return -EINVAL;
+	}
+
+	if (monitor) {
+		char addr[18];
+		ba2str(&ev->addr.bdaddr, addr);
+		printf("hci%u %s request PIN\n", index, addr);
+	}
+
+	printf("PIN Request (press enter to reject) >> ");
+	fflush(stdout);
+
+	memset(pin, 0, sizeof(pin));
+
+	if (fgets(pin, sizeof(pin), stdin) == NULL || pin[0] == '\n')
+		return mgmt_pin_neg_reply(mgmt_sk, index, &ev->addr);
+
+	pin_len = strlen(pin);
+	if (pin[pin_len - 1] == '\n') {
+		pin[pin_len - 1] = '\0';
+		pin_len--;
+	}
+
+	return mgmt_pin_reply(mgmt_sk, index, &ev->addr, pin, pin_len);
+}
+
+static void confirm_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	if (status != 0) {
+		fprintf(stderr,
+			"hci%u User Confirm reply failed. status 0x%02x (%s)",
+					id, status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	printf("hci%u User Confirm Reply successful\n", id);
+}
+
+static int mgmt_confirm_reply(int mgmt_sk, uint16_t index, bdaddr_t *bdaddr)
+{
+	struct mgmt_cp_user_confirm_reply cp;
+
+	memset(&cp, 0, sizeof(cp));
+	bacpy(&cp.addr.bdaddr, bdaddr);
+
+	return mgmt_send_cmd(mgmt_sk, MGMT_OP_USER_CONFIRM_REPLY, index,
+					&cp, sizeof(cp), confirm_rsp, NULL);
+}
+
+static void confirm_neg_rsp(int mgmt_sk, uint16_t op, uint16_t id,
+				uint8_t status, void *rsp, uint16_t len,
+				void *user_data)
+{
+	if (status != 0) {
+		fprintf(stderr,
+			"hci%u Confirm Neg reply failed. status 0x%02x (%s)",
+					id, status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	printf("hci%u User Confirm Negative Reply successful\n", id);
+}
+
+static int mgmt_confirm_neg_reply(int mgmt_sk, uint16_t index,
+							bdaddr_t *bdaddr)
+{
+	struct mgmt_cp_user_confirm_reply cp;
+
+	memset(&cp, 0, sizeof(cp));
+	bacpy(&cp.addr.bdaddr, bdaddr);
+
+	return mgmt_send_cmd(mgmt_sk, MGMT_OP_USER_CONFIRM_NEG_REPLY, index,
+				&cp, sizeof(cp), confirm_neg_rsp, NULL);
+}
+
+
+static int mgmt_user_confirm(int mgmt_sk, uint16_t index,
+				struct mgmt_ev_user_confirm_request *ev,
+				uint16_t len)
+{
+	char rsp[5];
+	size_t rsp_len;
+	uint32_t val;
+	char addr[18];
+
+	if (len != sizeof(*ev)) {
+		fprintf(stderr,
+			"Invalid user_confirm request length (%u)\n", len);
+		return -EINVAL;
+	}
+
+	ba2str(&ev->addr.bdaddr, addr);
+	val = bt_get_le32(&ev->value);
+
+	if (monitor)
+		printf("hci%u %s User Confirm %06u hint %u\n", index, addr,
+							val, ev->confirm_hint);
+
+	if (ev->confirm_hint)
+		printf("Accept pairing with %s (yes/no) >> ", addr);
+	else
+		printf("Confirm value %06u for %s (yes/no) >> ", val, addr);
+
+	fflush(stdout);
+
+	memset(rsp, 0, sizeof(rsp));
+
+	if (fgets(rsp, sizeof(rsp), stdin) == NULL || rsp[0] == '\n')
+		return mgmt_confirm_neg_reply(mgmt_sk, index, &ev->addr.bdaddr);
+
+	rsp_len = strlen(rsp);
+	if (rsp[rsp_len - 1] == '\n') {
+		rsp[rsp_len - 1] = '\0';
+		rsp_len--;
+	}
+
+	if (rsp[0] == 'y' || rsp[0] == 'Y')
+		return mgmt_confirm_reply(mgmt_sk, index, &ev->addr.bdaddr);
+	else
+		return mgmt_confirm_neg_reply(mgmt_sk, index, &ev->addr.bdaddr);
+}
+
+static int mgmt_handle_event(int mgmt_sk, uint16_t ev, uint16_t index,
+						void *data, uint16_t len)
+{
+	if (monitor)
+		printf("event: %s\n", mgmt_evstr(ev));
+
+	switch (ev) {
+	case MGMT_EV_CMD_COMPLETE:
+		return mgmt_cmd_complete(mgmt_sk, index, data, len);
+	case MGMT_EV_CMD_STATUS:
+		return mgmt_cmd_status(mgmt_sk, index, data, len);
+	case MGMT_EV_CONTROLLER_ERROR:
+		return mgmt_controller_error(index, data, len);
+	case MGMT_EV_INDEX_ADDED:
+		return mgmt_index_added(mgmt_sk, index);
+	case MGMT_EV_INDEX_REMOVED:
+		return mgmt_index_removed(mgmt_sk, index);
+	case MGMT_EV_NEW_SETTINGS:
+		return mgmt_new_settings(mgmt_sk, index, data, len);
+	case MGMT_EV_DISCOVERING:
+		return mgmt_discovering(mgmt_sk, index, data, len);
+	case MGMT_EV_NEW_LINK_KEY:
+		return mgmt_new_link_key(mgmt_sk, index, data, len);
+	case MGMT_EV_DEVICE_CONNECTED:
+		return mgmt_connected(mgmt_sk, index, data, len);
+	case MGMT_EV_DEVICE_DISCONNECTED:
+		return mgmt_disconnected(mgmt_sk, index, data, len);
+	case MGMT_EV_CONNECT_FAILED:
+		return mgmt_conn_failed(mgmt_sk, index, data, len);
+	case MGMT_EV_AUTH_FAILED:
+		return mgmt_auth_failed(mgmt_sk, index, data, len);
+	case MGMT_EV_LOCAL_NAME_CHANGED:
+		return mgmt_name_changed(mgmt_sk, index, data, len);
+	case MGMT_EV_DEVICE_FOUND:
+		return mgmt_device_found(mgmt_sk, index, data, len);
+	case MGMT_EV_PIN_CODE_REQUEST:
+		return mgmt_request_pin(mgmt_sk, index, data, len);
+	case MGMT_EV_USER_CONFIRM_REQUEST:
+		return mgmt_user_confirm(mgmt_sk, index, data, len);
+	default:
+		if (monitor)
+			printf("Unhandled event 0x%04x (%s)\n", ev, mgmt_evstr(ev));
+		return 0;
+	}
+}
+
+static int mgmt_process_data(int mgmt_sk)
+{
+	char buf[1024];
+	struct mgmt_hdr *hdr = (void *) buf;
+	uint16_t len, ev, index;
+	ssize_t ret;
+
+	ret = read(mgmt_sk, buf, sizeof(buf));
+	if (ret < 0) {
+		fprintf(stderr, "read: %s\n", strerror(errno));
+		return ret;
+	}
+
+	if (ret < MGMT_HDR_SIZE) {
+		fprintf(stderr, "Too small mgmt packet (%zd bytes)\n", ret);
+		return 0;
+	}
+
+	ev = bt_get_le16(&hdr->opcode);
+	index = bt_get_le16(&hdr->index);
+	len = bt_get_le16(&hdr->len);
+
+	if (monitor)
+		printf("event 0x%04x len 0x%04x index 0x%04x\n", ev, len, index);
+
+	if (ret != MGMT_HDR_SIZE + len) {
+		fprintf(stderr, "Packet length mismatch. ret %zd len %u",
+								ret, len);
+		return 0;
+	}
+
+	mgmt_handle_event(mgmt_sk, ev, index, buf + MGMT_HDR_SIZE, len);
+
+	return 0;
+}
+
+static void cmd_monitor(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	printf("Monitoring mgmt events...\n");
+	monitor = true;
+}
+
+static void version_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	struct mgmt_rp_read_version *rp = rsp;
+
+	if (status != 0) {
+		fprintf(stderr, "Reading mgmt version failed with status"
+			" 0x%02x (%s)\n", status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	if (len < sizeof(*rp)) {
+		fprintf(stderr, "Too small version reply (%u bytes)\n", len);
+		exit(EXIT_FAILURE);
+	}
+
+	printf("MGMT Version %u, revision %u\n", rp->version,
+						bt_get_le16(&rp->revision));
+
+	exit(EXIT_SUCCESS);
+}
+
+static void cmd_version(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE,
+					NULL, 0, version_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send read_version cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void commands_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	struct mgmt_rp_read_commands *rp = rsp;
+	uint16_t num_commands, num_events, *opcode;
+	size_t expected_len;
+	int i;
+
+	if (status != 0) {
+		fprintf(stderr, "Reading supported commands failed with status"
+			" 0x%02x (%s)\n", status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	if (len < sizeof(*rp)) {
+		fprintf(stderr, "Too small commands reply (%u bytes)\n", len);
+		exit(EXIT_FAILURE);
+	}
+
+	num_commands = bt_get_le16(&rp->num_commands);
+	num_events = bt_get_le16(&rp->num_events);
+
+	expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) +
+						num_events * sizeof(uint16_t);
+
+	if (len < expected_len) {
+		fprintf(stderr, "Too small commands reply (%u != %zu)\n",
+							len, expected_len);
+		exit(EXIT_FAILURE);
+	}
+
+	opcode = rp->opcodes;
+
+	printf("%u commands:\n", num_commands);
+	for (i = 0; i < num_commands; i++) {
+		uint16_t op = bt_get_le16(opcode++);
+		printf("\t%s (0x%04x)\n", mgmt_opstr(op), op);
+	}
+
+	printf("%u events:\n", num_events);
+	for (i = 0; i < num_events; i++) {
+		uint16_t ev = bt_get_le16(opcode++);
+		printf("\t%s (0x%04x)\n", mgmt_evstr(ev), ev);
+	}
+
+	exit(EXIT_SUCCESS);
+}
+
+static void cmd_commands(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE,
+					NULL, 0, commands_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send read_commands cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void info_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	struct mgmt_rp_read_info *rp = rsp;
+	char addr[18];
+
+	if (status != 0) {
+		fprintf(stderr,
+			"Reading hci%u info failed with status 0x%02x (%s)\n",
+					id, status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	if (len < sizeof(*rp)) {
+		fprintf(stderr, "Too small info reply (%u bytes)\n", len);
+		exit(EXIT_FAILURE);
+	}
+
+	ba2str(&rp->bdaddr, addr);
+	printf("hci%u:\taddr %s version %u manufacturer %u"
+			" class 0x%02x%02x%02x\n",
+			id, addr, rp->version, bt_get_le16(&rp->manufacturer),
+			rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
+
+	printf("\tsupported settings: ");
+	print_settings(bt_get_le32(&rp->supported_settings));
+
+	printf("\n\tcurrent settings: ");
+	print_settings(bt_get_le32(&rp->current_settings));
+
+	printf("\n\tname %s\n", rp->name);
+	printf("\tshort name %s\n", rp->short_name);
+
+	if (pending == NULL)
+		exit(EXIT_SUCCESS);
+}
+
+static void index_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	struct mgmt_rp_read_index_list *rp = rsp;
+	uint16_t count;
+	unsigned int i;
+
+	if (status != 0) {
+		fprintf(stderr,
+			"Reading index list failed with status 0x%02x (%s)\n",
+						status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	if (len < sizeof(*rp)) {
+		fprintf(stderr, "Too small index list reply (%u bytes)\n",
+									len);
+		exit(EXIT_FAILURE);
+	}
+
+	count = bt_get_le16(&rp->num_controllers);
+
+	if (len < sizeof(*rp) + count * sizeof(uint16_t)) {
+		fprintf(stderr,
+			"Index count (%u) doesn't match reply length (%u)\n",
+								count, len);
+		exit(EXIT_FAILURE);
+	}
+
+	if (monitor)
+		printf("Index list with %u item%s\n",
+						count, count > 1 ? "s" : "");
+
+	if (count == 0)
+		exit(EXIT_SUCCESS);
+
+	if (monitor && count > 0)
+		printf("\t");
+
+	for (i = 0; i < count; i++) {
+		uint16_t index;
+
+		index = bt_get_le16(&rp->index[i]);
+
+		if (monitor)
+			printf("hci%u ", index);
+
+		if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INFO, index, NULL,
+					0, info_rsp, NULL) < 0) {
+			fprintf(stderr, "Unable to send read_info cmd\n");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (monitor && count > 0)
+		printf("\n");
+}
+
+static void cmd_info(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	if (index == MGMT_INDEX_NONE) {
+		if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INDEX_LIST,
+					MGMT_INDEX_NONE, NULL, 0,
+					index_rsp, NULL) < 0) {
+			fprintf(stderr, "Unable to send index_list cmd\n");
+			exit(EXIT_FAILURE);
+		}
+
+		return;
+	}
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INFO, index, NULL,
+						0, info_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send read_info cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void setting_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	uint32_t *rp = rsp;
+
+	if (status != 0) {
+		fprintf(stderr,
+			"%s for hci%u failed with status 0x%02x (%s)\n",
+			mgmt_opstr(op), id, status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	if (len < sizeof(*rp)) {
+		fprintf(stderr, "Too small %s response (%u bytes)\n",
+							mgmt_opstr(op), len);
+		exit(EXIT_FAILURE);
+	}
+
+	printf("hci%u %s complete, settings: ", id, mgmt_opstr(op));
+	print_settings(bt_get_le32(rp));
+	printf("\n");
+
+	exit(EXIT_SUCCESS);
+}
+
+static void cmd_setting(int mgmt_sk, uint16_t index, uint16_t op,
+							int argc, char **argv)
+{
+	uint8_t val;
+
+	if (argc < 2) {
+		printf("Specify \"on\" or \"off\"\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
+		val = 1;
+	else if (strcasecmp(argv[1], "off") == 0)
+		val = 0;
+	else
+		val = atoi(argv[1]);
+
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	if (mgmt_send_cmd(mgmt_sk, op, index, &val, sizeof(val),
+						setting_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send %s cmd\n", mgmt_opstr(op));
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void cmd_power(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	cmd_setting(mgmt_sk, index, MGMT_OP_SET_POWERED, argc, argv);
+}
+
+static void cmd_discov(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	struct mgmt_cp_set_discoverable cp;
+
+	if (argc < 2) {
+		printf("Usage: btmgmt %s <yes/no> [timeout]\n", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	memset(&cp, 0, sizeof(cp));
+
+	if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
+		cp.val = 1;
+	else if (strcasecmp(argv[1], "off") == 0)
+		cp.val = 0;
+	else
+		cp.val = atoi(argv[1]);
+
+	if (argc > 2)
+		cp.timeout = htobs(atoi(argv[2]));
+
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DISCOVERABLE, index,
+				&cp, sizeof(cp), setting_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send set_discoverable cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void cmd_connectable(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	cmd_setting(mgmt_sk, index, MGMT_OP_SET_CONNECTABLE, argc, argv);
+}
+
+static void cmd_pairable(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	cmd_setting(mgmt_sk, index, MGMT_OP_SET_PAIRABLE, argc, argv);
+}
+
+static void cmd_linksec(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	cmd_setting(mgmt_sk, index, MGMT_OP_SET_LINK_SECURITY, argc, argv);
+}
+
+static void cmd_ssp(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	cmd_setting(mgmt_sk, index, MGMT_OP_SET_SSP, argc, argv);
+}
+
+static void cmd_hs(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	cmd_setting(mgmt_sk, index, MGMT_OP_SET_HS, argc, argv);
+}
+
+static void cmd_le(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	cmd_setting(mgmt_sk, index, MGMT_OP_SET_LE, argc, argv);
+}
+
+static void class_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	struct mgmt_ev_class_of_dev_changed *rp = rsp;
+
+	if (len == 0 && status != 0) {
+		fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
+				mgmt_opstr(op), status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	if (len != sizeof(*rp)) {
+		fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len);
+		exit(EXIT_FAILURE);
+	}
+
+	printf("%s succeeded. Class 0x%02x%02x%02x\n", mgmt_opstr(op),
+		rp->class_of_dev[2], rp->class_of_dev[1], rp->class_of_dev[0]);
+
+	exit(EXIT_SUCCESS);
+}
+
+static void cmd_class(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	uint8_t class[2];
+
+	if (argc < 3) {
+		printf("Usage: btmgmt %s <major> <minor>\n", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	class[0] = atoi(argv[1]);
+	class[1] = atoi(argv[2]);
+
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DEV_CLASS, index,
+				class, sizeof(class), class_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send set_dev_class cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void disconnect_rsp(int mgmt_sk, uint16_t op, uint16_t id,
+				uint8_t status, void *rsp, uint16_t len,
+				void *user_data)
+{
+	struct mgmt_rp_disconnect *rp = rsp;
+	char addr[18];
+
+	if (len == 0 && status != 0) {
+		fprintf(stderr, "Disconnect failed with status 0x%02x (%s)\n",
+						status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	if (len != sizeof(*rp)) {
+		fprintf(stderr, "Invalid disconnect response length (%u)\n",
+									len);
+		exit(EXIT_FAILURE);
+	}
+
+	ba2str(&rp->addr.bdaddr, addr);
+
+	if (status == 0) {
+		printf("%s disconnected\n", addr);
+		exit(EXIT_SUCCESS);
+	} else {
+		fprintf(stderr,
+			"Disconnecting %s failed with status 0x%02x (%s)\n",
+				addr, status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void cmd_disconnect(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	struct mgmt_cp_disconnect cp;
+
+	if (argc < 2) {
+		printf("Usage: btmgmt %s <address>\n", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	str2ba(argv[1], &cp.addr.bdaddr);
+
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_DISCONNECT, index,
+				&cp, sizeof(cp), disconnect_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send disconnect cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void con_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	struct mgmt_rp_get_connections *rp = rsp;
+	uint16_t count, i;
+
+	if (len < sizeof(*rp)) {
+		fprintf(stderr, "Too small (%u bytes) get_connections rsp\n",
+									len);
+		exit(EXIT_FAILURE);
+	}
+
+	count = bt_get_le16(&rp->conn_count);
+	if (len != sizeof(*rp) + count * sizeof(struct mgmt_addr_info)) {
+		fprintf(stderr, "Invalid get_connections length "
+					" (count=%u, len=%u)\n", count, len);
+		exit(EXIT_FAILURE);
+	}
+
+	for (i = 0; i < count; i++) {
+		char addr[18];
+
+		ba2str(&rp->addr[i].bdaddr, addr);
+
+		printf("%s type %s\n", addr, typestr(rp->addr[i].type));
+	}
+
+	exit(EXIT_SUCCESS);
+}
+
+static void cmd_con(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_GET_CONNECTIONS, index, NULL, 0,
+							con_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send get_connections cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void find_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	if (status != 0) {
+		fprintf(stderr,
+			"Unable to start discovery. status 0x%02x (%s)\n",
+						status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	printf("Discovery started\n");
+	discovery = true;
+}
+
+static void find_usage(void)
+{
+	printf("Usage: btmgmt find [-l|-b]>\n");
+}
+
+static struct option find_options[] = {
+	{ "help",	0, 0, 'h' },
+	{ "le-only",	1, 0, 'l' },
+	{ "bredr-only",	1, 0, 'b' },
+	{ 0, 0, 0, 0 }
+};
+
+static void cmd_find(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	struct mgmt_cp_start_discovery cp;
+	uint8_t type;
+	int opt;
+
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	type = 0;
+	hci_set_bit(BDADDR_BREDR, &type);
+	hci_set_bit(BDADDR_LE_PUBLIC, &type);
+	hci_set_bit(BDADDR_LE_RANDOM, &type);
+
+	while ((opt = getopt_long(argc, argv, "+lbh", find_options,
+								NULL)) != -1) {
+		switch (opt) {
+		case 'l':
+			hci_clear_bit(BDADDR_BREDR, &type);
+			hci_set_bit(BDADDR_LE_PUBLIC, &type);
+			hci_set_bit(BDADDR_LE_RANDOM, &type);
+			break;
+		case 'b':
+			hci_set_bit(BDADDR_BREDR, &type);
+			hci_clear_bit(BDADDR_LE_PUBLIC, &type);
+			hci_clear_bit(BDADDR_LE_RANDOM, &type);
+			break;
+		case 'h':
+		default:
+			find_usage();
+			exit(EXIT_SUCCESS);
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+	optind = 0;
+
+	memset(&cp, 0, sizeof(cp));
+	cp.type = type;
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_START_DISCOVERY, index,
+				&cp, sizeof(cp), find_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send start_discovery cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void name_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	if (status != 0) {
+		fprintf(stderr, "Unable to set local name. status 0x%02x (%s)",
+						status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
+
+static void cmd_name(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	struct mgmt_cp_set_local_name cp;
+
+	if (argc < 2) {
+		printf("Usage: btmgmt %s <name> [shortname]\n", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	memset(&cp, 0, sizeof(cp));
+	strncpy((char *) cp.name, argv[1], HCI_MAX_NAME_LENGTH);
+	if (argc > 2)
+		strncpy((char *) cp.short_name, argv[2],
+					MGMT_MAX_SHORT_NAME_LENGTH);
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_LOCAL_NAME, index,
+					&cp, sizeof(cp), name_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send set_name cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void pair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	struct mgmt_rp_pair_device *rp = rsp;
+	char addr[18];
+
+	if (len == 0 && status != 0) {
+		fprintf(stderr, "Pairing failed with status 0x%02x (%s)\n",
+						status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	if (len != sizeof(*rp)) {
+		fprintf(stderr, "Unexpected pair_rsp len %u\n", len);
+		exit(EXIT_FAILURE);
+	}
+
+	ba2str(&rp->addr.bdaddr, addr);
+
+	if (status != 0) {
+		fprintf(stderr,
+			"Pairing with %s (%s) failed. status 0x%02x (%s)\n",
+			addr, typestr(rp->addr.type), status,
+			mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	printf("Paired with %s\n", addr);
+
+	exit(EXIT_SUCCESS);
+}
+
+static void pair_usage(void)
+{
+	printf("Usage: btmgmt pair [-c cap] [-t type] <remote address>\n");
+}
+
+static struct option pair_options[] = {
+	{ "help",	0, 0, 'h' },
+	{ "capability",	1, 0, 'c' },
+	{ "type",	1, 0, 't' },
+	{ 0, 0, 0, 0 }
+};
+
+static void cmd_pair(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	struct mgmt_cp_pair_device cp;
+	uint8_t cap = 0x01;
+	uint8_t type = BDADDR_BREDR;
+	int opt;
+
+	while ((opt = getopt_long(argc, argv, "+c:t:h", pair_options,
+								NULL)) != -1) {
+		switch (opt) {
+		case 'c':
+			cap = strtol(optarg, NULL, 0);
+			break;
+		case 't':
+			type = strtol(optarg, NULL, 0);
+			break;
+		case 'h':
+		default:
+			pair_usage();
+			exit(EXIT_SUCCESS);
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+	optind = 0;
+
+	if (argc < 1) {
+		pair_usage();
+		exit(EXIT_FAILURE);
+	}
+
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	memset(&cp, 0, sizeof(cp));
+	str2ba(argv[0], &cp.addr.bdaddr);
+	cp.addr.type = type;
+	cp.io_cap = cap;
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_PAIR_DEVICE, index, &cp, sizeof(cp),
+							pair_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send pair_device cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void unpair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	struct mgmt_rp_unpair_device *rp = rsp;
+	char addr[18];
+
+	if (len == 0 && status != 0) {
+		fprintf(stderr, "Unpair device failed. status 0x%02x (%s)\n",
+						status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	if (len != sizeof(*rp)) {
+		fprintf(stderr, "Unexpected unpair_device_rsp len %u\n", len);
+		exit(EXIT_FAILURE);
+	}
+
+	ba2str(&rp->addr.bdaddr, addr);
+
+	if (status != 0) {
+		fprintf(stderr,
+			"Unpairing %s failed. status 0x%02x (%s)\n",
+				addr, status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	printf("%s unpaired\n", addr);
+
+	exit(EXIT_SUCCESS);
+}
+
+static void cmd_unpair(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	struct mgmt_cp_unpair_device cp;
+
+	if (argc < 2) {
+		printf("Usage: btmgmt %s <remote address>\n", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	memset(&cp, 0, sizeof(cp));
+	str2ba(argv[1], &cp.addr.bdaddr);
+	cp.disconnect = 1;
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_UNPAIR_DEVICE, index, &cp,
+					sizeof(cp), unpair_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send unpair_device cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void keys_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	if (status != 0) {
+		fprintf(stderr, "Load keys failed with status 0x%02x (%s)\n",
+						status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	printf("Keys successfully loaded\n");
+
+	exit(EXIT_SUCCESS);
+}
+
+static void cmd_keys(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	struct mgmt_cp_load_link_keys cp;
+
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	memset(&cp, 0, sizeof(cp));
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_LOAD_LINK_KEYS, index,
+				&cp, sizeof(cp), keys_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send load_keys cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void block_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	struct mgmt_addr_info *rp = rsp;
+	char addr[18];
+
+	if (len == 0 && status != 0) {
+		fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
+				mgmt_opstr(op), status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	if (len != sizeof(*rp)) {
+		fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len);
+		exit(EXIT_FAILURE);
+	}
+
+	ba2str(&rp->bdaddr, addr);
+
+	if (status != 0) {
+		fprintf(stderr, "%s %s (%s) failed. status 0x%02x (%s)\n",
+				mgmt_opstr(op), addr, typestr(rp->type),
+				status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	printf("%s %s succeeded\n", mgmt_opstr(op), addr);
+
+	exit(EXIT_SUCCESS);
+}
+
+static void block_usage(void)
+{
+	printf("Usage: btmgmt block [-t type] <remote address>\n");
+}
+
+static struct option block_options[] = {
+	{ "help",	0, 0, 'h' },
+	{ "type",	1, 0, 't' },
+	{ 0, 0, 0, 0 }
+};
+
+static void cmd_block(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	struct mgmt_cp_block_device cp;
+	uint8_t type = BDADDR_BREDR;
+	int opt;
+
+	while ((opt = getopt_long(argc, argv, "+t:h", block_options,
+							NULL)) != -1) {
+		switch (opt) {
+		case 't':
+			type = strtol(optarg, NULL, 0);
+			break;
+		case 'h':
+		default:
+			block_usage();
+			exit(EXIT_SUCCESS);
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+	optind = 0;
+
+	if (argc < 1) {
+		block_usage();
+		exit(EXIT_FAILURE);
+	}
+
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	memset(&cp, 0, sizeof(cp));
+	str2ba(argv[0], &cp.addr.bdaddr);
+	cp.addr.type = type;
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_BLOCK_DEVICE, index,
+				&cp, sizeof(cp), block_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send block_device cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void unblock_usage(void)
+{
+	printf("Usage: btmgmt unblock [-t type] <remote address>\n");
+}
+
+static void cmd_unblock(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	struct mgmt_cp_unblock_device cp;
+	uint8_t type = BDADDR_BREDR;
+	int opt;
+
+	while ((opt = getopt_long(argc, argv, "+t:h", block_options,
+							NULL)) != -1) {
+		switch (opt) {
+		case 't':
+			type = strtol(optarg, NULL, 0);
+			break;
+		case 'h':
+		default:
+			unblock_usage();
+			exit(EXIT_SUCCESS);
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+	optind = 0;
+
+	if (argc < 1) {
+		unblock_usage();
+		exit(EXIT_FAILURE);
+	}
+
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	memset(&cp, 0, sizeof(cp));
+	str2ba(argv[0], &cp.addr.bdaddr);
+	cp.addr.type = type;
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_UNBLOCK_DEVICE, index,
+				&cp, sizeof(cp), block_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send unblock_device cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid)
+{
+	if (uuid->type == SDP_UUID16)
+		sdp_uuid16_to_uuid128(uuid128, uuid);
+	else if (uuid->type == SDP_UUID32)
+		sdp_uuid32_to_uuid128(uuid128, uuid);
+	else
+		memcpy(uuid128, uuid, sizeof(*uuid));
+}
+
+static void cmd_add_uuid(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	struct mgmt_cp_add_uuid cp;
+	uint128_t uint128;
+	uuid_t uuid, uuid128;
+
+	if (argc < 3) {
+		printf("UUID and service hint needed\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	if (bt_string2uuid(&uuid, argv[1]) < 0) {
+		printf("Invalid UUID: %s\n", argv[1]);
+		exit(EXIT_FAILURE);
+	}
+
+	memset(&cp, 0, sizeof(cp));
+
+	uuid_to_uuid128(&uuid128, &uuid);
+	ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
+	htob128(&uint128, (uint128_t *) cp.uuid);
+
+	cp.svc_hint = atoi(argv[2]);
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_ADD_UUID, index,
+				&cp, sizeof(cp), class_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send add_uuid cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void cmd_remove_uuid(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	struct mgmt_cp_remove_uuid cp;
+	uint128_t uint128;
+	uuid_t uuid, uuid128;
+
+	if (argc < 2) {
+		printf("UUID needed\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	if (bt_string2uuid(&uuid, argv[1]) < 0) {
+		printf("Invalid UUID: %s\n", argv[1]);
+		exit(EXIT_FAILURE);
+	}
+
+	memset(&cp, 0, sizeof(cp));
+
+	uuid_to_uuid128(&uuid128, &uuid);
+	ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
+	htob128(&uint128, (uint128_t *) cp.uuid);
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_REMOVE_UUID, index,
+				&cp, sizeof(cp), class_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send remove_uuid cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void cmd_clr_uuids(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	char *uuid_any = "00000000-0000-0000-0000-000000000000";
+	char *rm_argv[] = { "rm-uuid", uuid_any, NULL };
+
+	cmd_remove_uuid(mgmt_sk, index, 2, rm_argv);
+}
+
+static void did_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+				void *rsp, uint16_t len, void *user_data)
+{
+	if (status != 0) {
+		fprintf(stderr, "Set Device ID failed with status 0x%02x (%s)\n",
+						status, mgmt_errstr(status));
+		exit(EXIT_FAILURE);
+	}
+
+	printf("Device ID successfully set\n");
+
+	exit(EXIT_SUCCESS);
+}
+
+static void did_usage(void)
+{
+	printf("Usage: btmgmt did <source>:<vendor>:<product>:<version>\n");
+	printf("       possible source values: bluetooth, usb\n");
+}
+
+static void cmd_did(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+	struct mgmt_cp_set_device_id cp;
+	uint16_t vendor, product, version , source;
+	int result;
+
+	if (argc < 2) {
+		did_usage();
+		exit(EXIT_FAILURE);
+	}
+
+	result = sscanf(argv[1], "bluetooth:%4hx:%4hx:%4hx", &vendor, &product,
+								&version);
+	if (result == 3) {
+		source = 0x0001;
+		goto done;
+	}
+
+	result = sscanf(argv[1], "usb:%4hx:%4hx:%4hx", &vendor, &product,
+								&version);
+	if (result == 3) {
+		source = 0x0002;
+		goto done;
+	}
+
+	did_usage();
+	exit(EXIT_FAILURE);
+
+done:
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	cp.source = htobs(source);
+	cp.vendor = htobs(vendor);
+	cp.product = htobs(product);
+	cp.version = htobs(version);
+
+	if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DEVICE_ID, index,
+				&cp, sizeof(cp), did_rsp, NULL) < 0) {
+		fprintf(stderr, "Unable to send set_dev_class cmd\n");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static struct {
+	char *cmd;
+	void (*func)(int mgmt_sk, uint16_t index, int argc, char **argv);
+	char *doc;
+} command[] = {
+	{ "monitor",	cmd_monitor,	"Monitor events"		},
+	{ "version",	cmd_version,	"Get the MGMT Version"		},
+	{ "commands",	cmd_commands,	"List supported commands"	},
+	{ "info",	cmd_info,	"Show controller info"		},
+	{ "power",	cmd_power,	"Toggle powered state"		},
+	{ "discov",	cmd_discov,	"Toggle discoverable state"	},
+	{ "connectable",cmd_connectable,"Toggle connectable state"	},
+	{ "pairable",	cmd_pairable,	"Toggle pairable state"		},
+	{ "linksec",	cmd_linksec,	"Toggle link level security"	},
+	{ "ssp",	cmd_ssp,	"Toggle SSP mode"		},
+	{ "hs",		cmd_hs,		"Toggle HS Support"		},
+	{ "le",		cmd_le,		"Toggle LE Support"		},
+	{ "class",	cmd_class,	"Set device major/minor class"	},
+	{ "disconnect", cmd_disconnect, "Disconnect device"		},
+	{ "con",	cmd_con,	"List connections"		},
+	{ "find",	cmd_find,	"Discover nearby devices"	},
+	{ "name",	cmd_name,	"Set local name"		},
+	{ "pair",	cmd_pair,	"Pair with a remote device"	},
+	{ "unpair",	cmd_unpair,	"Unpair device"			},
+	{ "keys",	cmd_keys,	"Load Keys"			},
+	{ "block",	cmd_block,	"Block Device"			},
+	{ "unblock",	cmd_unblock,	"Unblock Device"		},
+	{ "add-uuid",	cmd_add_uuid,	"Add UUID"			},
+	{ "rm-uuid",	cmd_add_uuid,	"Remove UUID"			},
+	{ "clr-uuids",	cmd_clr_uuids,	"Clear UUIDs",			},
+	{ "did",	cmd_did,	"Set Device ID",		},
+	{ NULL, NULL, 0 }
+};
+
+static void usage(void)
+{
+	int i;
+
+	printf("btmgmt ver %s\n", VERSION);
+	printf("Usage:\n"
+		"\tbtmgmt [options] <command> [command parameters]\n");
+
+	printf("Options:\n"
+		"\t--index <id>\tSpecify adapter index\n"
+		"\t--verbose\tEnable extra logging\n"
+		"\t--help\tDisplay help\n");
+
+	printf("Commands:\n");
+	for (i = 0; command[i].cmd; i++)
+		printf("\t%-15s\t%s\n", command[i].cmd, command[i].doc);
+
+	printf("\n"
+		"For more information on the usage of each command use:\n"
+		"\tbtmgmt <command> --help\n" );
+}
+
+static struct option main_options[] = {
+	{ "index",	1, 0, 'i' },
+	{ "verbose",	0, 0, 'v' },
+	{ "help",	0, 0, 'h' },
+	{ 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+	int opt, i, mgmt_sk;
+	uint16_t index = MGMT_INDEX_NONE;
+	struct pollfd pollfd;
+
+	while ((opt = getopt_long(argc, argv, "+hvi:",
+						main_options, NULL)) != -1) {
+		switch (opt) {
+		case 'i':
+			if (strlen(optarg) > 3 &&
+					strncasecmp(optarg, "hci", 3) == 0)
+				index = atoi(&optarg[4]);
+			else
+				index = atoi(optarg);
+			break;
+		case 'v':
+			monitor = true;
+			break;
+		case 'h':
+		default:
+			usage();
+			return 0;
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+	optind = 0;
+
+	if (argc < 1) {
+		usage();
+		return 0;
+	}
+
+	mgmt_sk = mgmt_open();
+	if (mgmt_sk < 0) {
+		fprintf(stderr, "Unable to open mgmt socket\n");
+		return -1;
+	}
+
+	for (i = 0; command[i].cmd; i++) {
+		if (strcmp(command[i].cmd, argv[0]) != 0)
+			continue;
+
+		command[i].func(mgmt_sk, index, argc, argv);
+		break;
+	}
+
+	if (command[i].cmd == NULL) {
+		fprintf(stderr, "Unknown command: %s\n", argv[0]);
+		close(mgmt_sk);
+		return -1;
+	}
+
+	pollfd.fd = mgmt_sk;
+	pollfd.events = POLLIN;
+	pollfd.revents = 0;
+
+	while (poll(&pollfd, 1, -1) >= 0) {
+		if (pollfd.revents & (POLLHUP | POLLERR | POLLNVAL))
+			break;
+
+		if (pollfd.revents & POLLIN)
+			mgmt_process_data(mgmt_sk);
+
+		pollfd.revents = 0;
+	}
+
+	close(mgmt_sk);
+
+	return 0;
+}
-- 
1.7.10.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH -v3 09/19] alert: move alert to profiles dir
  2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
                   ` (6 preceding siblings ...)
  2012-07-04 12:51 ` [PATCH -v3 08/19] btmgmt: move to " Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 10/19] deviceinfo: move to profiles folder Gustavo Padovan
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

---
 Makefile.am             |    3 ++-
 alert/main.c            |   58 -----------------------------------------------
 alert/server.c          |   38 -------------------------------
 alert/server.h          |   26 ---------------------
 profiles/alert/main.c   |   58 +++++++++++++++++++++++++++++++++++++++++++++++
 profiles/alert/server.c |   38 +++++++++++++++++++++++++++++++
 profiles/alert/server.h |   26 +++++++++++++++++++++
 7 files changed, 124 insertions(+), 123 deletions(-)
 delete mode 100644 alert/main.c
 delete mode 100644 alert/server.c
 delete mode 100644 alert/server.h
 create mode 100644 profiles/alert/main.c
 create mode 100644 profiles/alert/server.c
 create mode 100644 profiles/alert/server.h

diff --git a/Makefile.am b/Makefile.am
index 25d1026..e4874ac 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -221,7 +221,8 @@ builtin_modules += thermometer alert time gatt_example proximity \
 builtin_sources += thermometer/main.c \
 			thermometer/manager.h thermometer/manager.c \
 			thermometer/thermometer.h thermometer/thermometer.c \
-			alert/main.c alert/server.h alert/server.c \
+			profiles/alert/main.c profiles/alert/server.h \
+			profiles/alert/server.c \
 			time/main.c time/server.h time/server.c \
 			plugins/gatt-example.c \
 			proximity/main.c proximity/manager.h proximity/manager.c \
diff --git a/alert/main.c b/alert/main.c
deleted file mode 100644
index ec4ab6d..0000000
--- a/alert/main.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  Nokia Corporation
- *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdint.h>
-#include <glib.h>
-#include <errno.h>
-
-#include "plugin.h"
-#include "hcid.h"
-#include "log.h"
-#include "server.h"
-
-static int alert_init(void)
-{
-	if (!main_opts.gatt_enabled) {
-		DBG("GATT is disabled");
-		return -ENOTSUP;
-	}
-
-	return alert_server_init();
-}
-
-static void alert_exit(void)
-{
-	if (!main_opts.gatt_enabled)
-		return;
-
-	alert_server_exit();
-}
-
-BLUETOOTH_PLUGIN_DEFINE(alert, VERSION,
-			BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
-			alert_init, alert_exit)
diff --git a/alert/server.c b/alert/server.c
deleted file mode 100644
index d91b156..0000000
--- a/alert/server.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  Nokia Corporation
- *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "server.h"
-
-int alert_server_init(void)
-{
-	return 0;
-}
-
-void alert_server_exit(void)
-{
-}
diff --git a/alert/server.h b/alert/server.h
deleted file mode 100644
index e59bdb1..0000000
--- a/alert/server.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  Nokia Corporation
- *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-int alert_server_init(void);
-void alert_server_exit(void);
diff --git a/profiles/alert/main.c b/profiles/alert/main.c
new file mode 100644
index 0000000..ec4ab6d
--- /dev/null
+++ b/profiles/alert/main.c
@@ -0,0 +1,58 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <glib.h>
+#include <errno.h>
+
+#include "plugin.h"
+#include "hcid.h"
+#include "log.h"
+#include "server.h"
+
+static int alert_init(void)
+{
+	if (!main_opts.gatt_enabled) {
+		DBG("GATT is disabled");
+		return -ENOTSUP;
+	}
+
+	return alert_server_init();
+}
+
+static void alert_exit(void)
+{
+	if (!main_opts.gatt_enabled)
+		return;
+
+	alert_server_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(alert, VERSION,
+			BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+			alert_init, alert_exit)
diff --git a/profiles/alert/server.c b/profiles/alert/server.c
new file mode 100644
index 0000000..d91b156
--- /dev/null
+++ b/profiles/alert/server.c
@@ -0,0 +1,38 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "server.h"
+
+int alert_server_init(void)
+{
+	return 0;
+}
+
+void alert_server_exit(void)
+{
+}
diff --git a/profiles/alert/server.h b/profiles/alert/server.h
new file mode 100644
index 0000000..e59bdb1
--- /dev/null
+++ b/profiles/alert/server.h
@@ -0,0 +1,26 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int alert_server_init(void);
+void alert_server_exit(void);
-- 
1.7.10.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH -v3 10/19] deviceinfo: move to profiles folder
  2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
                   ` (7 preceding siblings ...)
  2012-07-04 12:51 ` [PATCH -v3 09/19] alert: move alert to profiles dir Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 12/19] thermometer: move to the " Gustavo Padovan
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

---
 Makefile.am                      |   11 ++-
 deviceinfo/deviceinfo.c          |  195 --------------------------------------
 deviceinfo/deviceinfo.h          |   24 -----
 deviceinfo/main.c                |   52 ----------
 deviceinfo/manager.c             |   80 ----------------
 deviceinfo/manager.h             |   24 -----
 profiles/deviceinfo/deviceinfo.c |  195 ++++++++++++++++++++++++++++++++++++++
 profiles/deviceinfo/deviceinfo.h |   24 +++++
 profiles/deviceinfo/main.c       |   52 ++++++++++
 profiles/deviceinfo/manager.c    |   80 ++++++++++++++++
 profiles/deviceinfo/manager.h    |   24 +++++
 11 files changed, 381 insertions(+), 380 deletions(-)
 delete mode 100644 deviceinfo/deviceinfo.c
 delete mode 100644 deviceinfo/deviceinfo.h
 delete mode 100644 deviceinfo/main.c
 delete mode 100644 deviceinfo/manager.c
 delete mode 100644 deviceinfo/manager.h
 create mode 100644 profiles/deviceinfo/deviceinfo.c
 create mode 100644 profiles/deviceinfo/deviceinfo.h
 create mode 100644 profiles/deviceinfo/main.c
 create mode 100644 profiles/deviceinfo/manager.c
 create mode 100644 profiles/deviceinfo/manager.h

diff --git a/Makefile.am b/Makefile.am
index e4874ac..d1bc65f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -216,8 +216,7 @@ builtin_sources += health/hdp_main.c health/hdp_types.h \
 endif
 
 if GATTMODULES
-builtin_modules += thermometer alert time gatt_example proximity \
-			deviceinfo
+builtin_modules += thermometer alert time gatt_example proximity deviceinfo
 builtin_sources += thermometer/main.c \
 			thermometer/manager.h thermometer/manager.c \
 			thermometer/thermometer.h thermometer/thermometer.c \
@@ -230,9 +229,11 @@ builtin_sources += thermometer/main.c \
 			proximity/reporter.h proximity/reporter.c \
 			proximity/linkloss.h proximity/linkloss.c \
 			proximity/immalert.h proximity/immalert.c \
-			deviceinfo/main.c \
-			deviceinfo/manager.h deviceinfo/manager.c \
-			deviceinfo/deviceinfo.h deviceinfo/deviceinfo.c
+			profiles/deviceinfo/main.c \
+			profiles/deviceinfo/manager.h \
+			profiles/deviceinfo/manager.c \
+			profiles/deviceinfo/deviceinfo.h \
+			profiles/deviceinfo/deviceinfo.c
 endif
 
 
diff --git a/deviceinfo/deviceinfo.c b/deviceinfo/deviceinfo.c
deleted file mode 100644
index 4548553..0000000
--- a/deviceinfo/deviceinfo.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2012 Texas Instruments, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-#include <bluetooth/uuid.h>
-
-#include "adapter.h"
-#include "device.h"
-#include "gattrib.h"
-#include "attio.h"
-#include "att.h"
-#include "gattrib.h"
-#include "gatt.h"
-#include "log.h"
-#include "deviceinfo.h"
-
-#define PNP_ID_SIZE	7
-
-struct deviceinfo {
-	struct btd_device	*dev;		/* Device reference */
-	GAttrib			*attrib;	/* GATT connection */
-	guint			attioid;	/* Att watcher id */
-	struct att_range	*svc_range;	/* DeviceInfo range */
-	GSList			*chars;		/* Characteristics */
-};
-
-static GSList *servers = NULL;
-
-struct characteristic {
-	struct gatt_char	attr;	/* Characteristic */
-	struct deviceinfo	*d;	/* deviceinfo where the char belongs */
-};
-
-static void deviceinfo_free(gpointer user_data)
-{
-	struct deviceinfo *d = user_data;
-
-	if (d->attioid > 0)
-		btd_device_remove_attio_callback(d->dev, d->attioid);
-
-	if (d->attrib != NULL)
-		g_attrib_unref(d->attrib);
-
-	g_slist_free_full(d->chars, g_free);
-
-	btd_device_unref(d->dev);
-	g_free(d->svc_range);
-	g_free(d);
-}
-
-static gint cmp_device(gconstpointer a, gconstpointer b)
-{
-	const struct deviceinfo *d = a;
-	const struct btd_device *dev = b;
-
-	if (dev == d->dev)
-		return 0;
-
-	return -1;
-}
-
-static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len,
-							gpointer user_data)
-{
-	struct characteristic *ch = user_data;
-	uint8_t value[PNP_ID_SIZE];
-	ssize_t vlen;
-
-	if (status != 0) {
-		error("Error reading PNP_ID value: %s", att_ecode2str(status));
-		return;
-	}
-
-	vlen = dec_read_resp(pdu, len, value, sizeof(value));
-	if (vlen < 0) {
-		error("Error reading PNP_ID: Protocol error");
-		return;
-	}
-
-	if (vlen < 7) {
-		error("Error reading PNP_ID: Invalid pdu length received");
-		return;
-	}
-
-	device_set_pnpid(ch->d->dev, value[0], att_get_u16(&value[1]),
-				att_get_u16(&value[3]), att_get_u16(&value[5]));
-}
-
-static void process_deviceinfo_char(struct characteristic *ch)
-{
-	if (g_strcmp0(ch->attr.uuid, PNPID_UUID) == 0)
-		gatt_read_char(ch->d->attrib, ch->attr.value_handle, 0,
-							read_pnpid_cb, ch);
-}
-
-static void configure_deviceinfo_cb(GSList *characteristics, guint8 status,
-							gpointer user_data)
-{
-	struct deviceinfo *d = user_data;
-	GSList *l;
-
-	if (status != 0) {
-		error("Discover deviceinfo characteristics: %s",
-							att_ecode2str(status));
-		return;
-	}
-
-	for (l = characteristics; l; l = l->next) {
-		struct gatt_char *c = l->data;
-		struct characteristic *ch;
-
-		ch = g_new0(struct characteristic, 1);
-		ch->attr.handle = c->handle;
-		ch->attr.properties = c->properties;
-		ch->attr.value_handle = c->value_handle;
-		memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
-		ch->d = d;
-
-		d->chars = g_slist_append(d->chars, ch);
-
-		process_deviceinfo_char(ch);
-	}
-}
-static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
-{
-	struct deviceinfo *d = user_data;
-
-	d->attrib = g_attrib_ref(attrib);
-
-	gatt_discover_char(d->attrib, d->svc_range->start, d->svc_range->end,
-					NULL, configure_deviceinfo_cb, d);
-}
-
-static void attio_disconnected_cb(gpointer user_data)
-{
-	struct deviceinfo *d = user_data;
-
-	g_attrib_unref(d->attrib);
-	d->attrib = NULL;
-}
-
-int deviceinfo_register(struct btd_device *device, struct gatt_primary *prim)
-{
-	struct deviceinfo *d;
-
-	d = g_new0(struct deviceinfo, 1);
-	d->dev = btd_device_ref(device);
-	d->svc_range = g_new0(struct att_range, 1);
-	d->svc_range->start = prim->range.start;
-	d->svc_range->end = prim->range.end;
-
-	servers = g_slist_prepend(servers, d);
-
-	d->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
-						attio_disconnected_cb, d);
-	return 0;
-}
-
-void deviceinfo_unregister(struct btd_device *device)
-{
-	struct deviceinfo *d;
-	GSList *l;
-
-	l = g_slist_find_custom(servers, device, cmp_device);
-	if (l == NULL)
-		return;
-
-	d = l->data;
-	servers = g_slist_remove(servers, d);
-
-	deviceinfo_free(d);
-}
diff --git a/deviceinfo/deviceinfo.h b/deviceinfo/deviceinfo.h
deleted file mode 100644
index 7a804a5..0000000
--- a/deviceinfo/deviceinfo.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2012 Texas Instruments, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-int deviceinfo_register(struct btd_device *device, struct gatt_primary *prim);
-void deviceinfo_unregister(struct btd_device *device);
diff --git a/deviceinfo/main.c b/deviceinfo/main.c
deleted file mode 100644
index 82ecc82..0000000
--- a/deviceinfo/main.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2012 Texas Instruments, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-#include <errno.h>
-#include <stdint.h>
-
-#include "plugin.h"
-#include "manager.h"
-#include "hcid.h"
-#include "log.h"
-
-static int deviceinfo_init(void)
-{
-	if (!main_opts.gatt_enabled) {
-		error("DIS cannot start: GATT is disabled");
-		return -ENOTSUP;
-	}
-
-	return deviceinfo_manager_init();
-}
-
-static void deviceinfo_exit(void)
-{
-	deviceinfo_manager_exit();
-}
-
-BLUETOOTH_PLUGIN_DEFINE(deviceinfo, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
-					deviceinfo_init, deviceinfo_exit)
diff --git a/deviceinfo/manager.c b/deviceinfo/manager.c
deleted file mode 100644
index 1d59918..0000000
--- a/deviceinfo/manager.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2012 Texas Instruments, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <glib.h>
-#include <errno.h>
-#include <bluetooth/uuid.h>
-
-#include "adapter.h"
-#include "device.h"
-#include "att.h"
-#include "gattrib.h"
-#include "gatt.h"
-#include "deviceinfo.h"
-#include "manager.h"
-
-static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
-{
-	const struct gatt_primary *prim = a;
-	const char *uuid = b;
-
-	return g_strcmp0(prim->uuid, uuid);
-}
-
-static int deviceinfo_driver_probe(struct btd_device *device, GSList *uuids)
-{
-	struct gatt_primary *prim;
-	GSList *primaries, *l;
-
-	primaries = btd_device_get_primaries(device);
-
-	l = g_slist_find_custom(primaries, DEVICE_INFORMATION_UUID,
-							primary_uuid_cmp);
-	if (l == NULL)
-		return -EINVAL;
-
-	prim = l->data;
-
-	return deviceinfo_register(device, prim);
-}
-
-static void deviceinfo_driver_remove(struct btd_device *device)
-{
-	deviceinfo_unregister(device);
-}
-
-static struct btd_device_driver deviceinfo_device_driver = {
-	.name	= "deviceinfo-driver",
-	.uuids	= BTD_UUIDS(DEVICE_INFORMATION_UUID),
-	.probe	= deviceinfo_driver_probe,
-	.remove	= deviceinfo_driver_remove
-};
-
-int deviceinfo_manager_init(void)
-{
-	return btd_register_device_driver(&deviceinfo_device_driver);
-}
-
-void deviceinfo_manager_exit(void)
-{
-	btd_unregister_device_driver(&deviceinfo_device_driver);
-}
diff --git a/deviceinfo/manager.h b/deviceinfo/manager.h
deleted file mode 100644
index 0f742ca..0000000
--- a/deviceinfo/manager.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2012 Texas Instruments, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-int deviceinfo_manager_init(void);
-void deviceinfo_manager_exit(void);
diff --git a/profiles/deviceinfo/deviceinfo.c b/profiles/deviceinfo/deviceinfo.c
new file mode 100644
index 0000000..4548553
--- /dev/null
+++ b/profiles/deviceinfo/deviceinfo.c
@@ -0,0 +1,195 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "gattrib.h"
+#include "attio.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "log.h"
+#include "deviceinfo.h"
+
+#define PNP_ID_SIZE	7
+
+struct deviceinfo {
+	struct btd_device	*dev;		/* Device reference */
+	GAttrib			*attrib;	/* GATT connection */
+	guint			attioid;	/* Att watcher id */
+	struct att_range	*svc_range;	/* DeviceInfo range */
+	GSList			*chars;		/* Characteristics */
+};
+
+static GSList *servers = NULL;
+
+struct characteristic {
+	struct gatt_char	attr;	/* Characteristic */
+	struct deviceinfo	*d;	/* deviceinfo where the char belongs */
+};
+
+static void deviceinfo_free(gpointer user_data)
+{
+	struct deviceinfo *d = user_data;
+
+	if (d->attioid > 0)
+		btd_device_remove_attio_callback(d->dev, d->attioid);
+
+	if (d->attrib != NULL)
+		g_attrib_unref(d->attrib);
+
+	g_slist_free_full(d->chars, g_free);
+
+	btd_device_unref(d->dev);
+	g_free(d->svc_range);
+	g_free(d);
+}
+
+static gint cmp_device(gconstpointer a, gconstpointer b)
+{
+	const struct deviceinfo *d = a;
+	const struct btd_device *dev = b;
+
+	if (dev == d->dev)
+		return 0;
+
+	return -1;
+}
+
+static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	struct characteristic *ch = user_data;
+	uint8_t value[PNP_ID_SIZE];
+	ssize_t vlen;
+
+	if (status != 0) {
+		error("Error reading PNP_ID value: %s", att_ecode2str(status));
+		return;
+	}
+
+	vlen = dec_read_resp(pdu, len, value, sizeof(value));
+	if (vlen < 0) {
+		error("Error reading PNP_ID: Protocol error");
+		return;
+	}
+
+	if (vlen < 7) {
+		error("Error reading PNP_ID: Invalid pdu length received");
+		return;
+	}
+
+	device_set_pnpid(ch->d->dev, value[0], att_get_u16(&value[1]),
+				att_get_u16(&value[3]), att_get_u16(&value[5]));
+}
+
+static void process_deviceinfo_char(struct characteristic *ch)
+{
+	if (g_strcmp0(ch->attr.uuid, PNPID_UUID) == 0)
+		gatt_read_char(ch->d->attrib, ch->attr.value_handle, 0,
+							read_pnpid_cb, ch);
+}
+
+static void configure_deviceinfo_cb(GSList *characteristics, guint8 status,
+							gpointer user_data)
+{
+	struct deviceinfo *d = user_data;
+	GSList *l;
+
+	if (status != 0) {
+		error("Discover deviceinfo characteristics: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	for (l = characteristics; l; l = l->next) {
+		struct gatt_char *c = l->data;
+		struct characteristic *ch;
+
+		ch = g_new0(struct characteristic, 1);
+		ch->attr.handle = c->handle;
+		ch->attr.properties = c->properties;
+		ch->attr.value_handle = c->value_handle;
+		memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
+		ch->d = d;
+
+		d->chars = g_slist_append(d->chars, ch);
+
+		process_deviceinfo_char(ch);
+	}
+}
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+	struct deviceinfo *d = user_data;
+
+	d->attrib = g_attrib_ref(attrib);
+
+	gatt_discover_char(d->attrib, d->svc_range->start, d->svc_range->end,
+					NULL, configure_deviceinfo_cb, d);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+	struct deviceinfo *d = user_data;
+
+	g_attrib_unref(d->attrib);
+	d->attrib = NULL;
+}
+
+int deviceinfo_register(struct btd_device *device, struct gatt_primary *prim)
+{
+	struct deviceinfo *d;
+
+	d = g_new0(struct deviceinfo, 1);
+	d->dev = btd_device_ref(device);
+	d->svc_range = g_new0(struct att_range, 1);
+	d->svc_range->start = prim->range.start;
+	d->svc_range->end = prim->range.end;
+
+	servers = g_slist_prepend(servers, d);
+
+	d->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
+						attio_disconnected_cb, d);
+	return 0;
+}
+
+void deviceinfo_unregister(struct btd_device *device)
+{
+	struct deviceinfo *d;
+	GSList *l;
+
+	l = g_slist_find_custom(servers, device, cmp_device);
+	if (l == NULL)
+		return;
+
+	d = l->data;
+	servers = g_slist_remove(servers, d);
+
+	deviceinfo_free(d);
+}
diff --git a/profiles/deviceinfo/deviceinfo.h b/profiles/deviceinfo/deviceinfo.h
new file mode 100644
index 0000000..7a804a5
--- /dev/null
+++ b/profiles/deviceinfo/deviceinfo.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int deviceinfo_register(struct btd_device *device, struct gatt_primary *prim);
+void deviceinfo_unregister(struct btd_device *device);
diff --git a/profiles/deviceinfo/main.c b/profiles/deviceinfo/main.c
new file mode 100644
index 0000000..82ecc82
--- /dev/null
+++ b/profiles/deviceinfo/main.c
@@ -0,0 +1,52 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include "plugin.h"
+#include "manager.h"
+#include "hcid.h"
+#include "log.h"
+
+static int deviceinfo_init(void)
+{
+	if (!main_opts.gatt_enabled) {
+		error("DIS cannot start: GATT is disabled");
+		return -ENOTSUP;
+	}
+
+	return deviceinfo_manager_init();
+}
+
+static void deviceinfo_exit(void)
+{
+	deviceinfo_manager_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(deviceinfo, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+					deviceinfo_init, deviceinfo_exit)
diff --git a/profiles/deviceinfo/manager.c b/profiles/deviceinfo/manager.c
new file mode 100644
index 0000000..1d59918
--- /dev/null
+++ b/profiles/deviceinfo/manager.c
@@ -0,0 +1,80 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <glib.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "deviceinfo.h"
+#include "manager.h"
+
+static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
+{
+	const struct gatt_primary *prim = a;
+	const char *uuid = b;
+
+	return g_strcmp0(prim->uuid, uuid);
+}
+
+static int deviceinfo_driver_probe(struct btd_device *device, GSList *uuids)
+{
+	struct gatt_primary *prim;
+	GSList *primaries, *l;
+
+	primaries = btd_device_get_primaries(device);
+
+	l = g_slist_find_custom(primaries, DEVICE_INFORMATION_UUID,
+							primary_uuid_cmp);
+	if (l == NULL)
+		return -EINVAL;
+
+	prim = l->data;
+
+	return deviceinfo_register(device, prim);
+}
+
+static void deviceinfo_driver_remove(struct btd_device *device)
+{
+	deviceinfo_unregister(device);
+}
+
+static struct btd_device_driver deviceinfo_device_driver = {
+	.name	= "deviceinfo-driver",
+	.uuids	= BTD_UUIDS(DEVICE_INFORMATION_UUID),
+	.probe	= deviceinfo_driver_probe,
+	.remove	= deviceinfo_driver_remove
+};
+
+int deviceinfo_manager_init(void)
+{
+	return btd_register_device_driver(&deviceinfo_device_driver);
+}
+
+void deviceinfo_manager_exit(void)
+{
+	btd_unregister_device_driver(&deviceinfo_device_driver);
+}
diff --git a/profiles/deviceinfo/manager.h b/profiles/deviceinfo/manager.h
new file mode 100644
index 0000000..0f742ca
--- /dev/null
+++ b/profiles/deviceinfo/manager.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int deviceinfo_manager_init(void);
+void deviceinfo_manager_exit(void);
-- 
1.7.10.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH -v3 12/19] thermometer: move to the profiles folder
  2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
                   ` (8 preceding siblings ...)
  2012-07-04 12:51 ` [PATCH -v3 10/19] deviceinfo: move to profiles folder Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 13/19] time: " Gustavo Padovan
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

---
 Makefile.am                        |    8 +-
 profiles/thermometer/main.c        |   70 ++
 profiles/thermometer/manager.c     |   92 +++
 profiles/thermometer/manager.h     |   24 +
 profiles/thermometer/thermometer.c | 1274 ++++++++++++++++++++++++++++++++++++
 profiles/thermometer/thermometer.h |   25 +
 thermometer/main.c                 |   70 --
 thermometer/manager.c              |   92 ---
 thermometer/manager.h              |   24 -
 thermometer/thermometer.c          | 1274 ------------------------------------
 thermometer/thermometer.h          |   25 -
 11 files changed, 1490 insertions(+), 1488 deletions(-)
 create mode 100644 profiles/thermometer/main.c
 create mode 100644 profiles/thermometer/manager.c
 create mode 100644 profiles/thermometer/manager.h
 create mode 100644 profiles/thermometer/thermometer.c
 create mode 100644 profiles/thermometer/thermometer.h
 delete mode 100644 thermometer/main.c
 delete mode 100644 thermometer/manager.c
 delete mode 100644 thermometer/manager.h
 delete mode 100644 thermometer/thermometer.c
 delete mode 100644 thermometer/thermometer.h

diff --git a/Makefile.am b/Makefile.am
index 6592c5c..b816e20 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -217,9 +217,11 @@ endif
 
 if GATTMODULES
 builtin_modules += thermometer alert time gatt_example proximity deviceinfo
-builtin_sources += thermometer/main.c \
-			thermometer/manager.h thermometer/manager.c \
-			thermometer/thermometer.h thermometer/thermometer.c \
+builtin_sources += profiles/thermometer/main.c \
+			profiles/thermometer/manager.h \
+			profiles/thermometer/manager.c \
+			profiles/thermometer/thermometer.h \
+		       	profiles/thermometer/thermometer.c \
 			profiles/alert/main.c profiles/alert/server.h \
 			profiles/alert/server.c \
 			time/main.c time/server.h time/server.c \
diff --git a/profiles/thermometer/main.c b/profiles/thermometer/main.c
new file mode 100644
index 0000000..4447b52
--- /dev/null
+++ b/profiles/thermometer/main.c
@@ -0,0 +1,70 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <glib.h>
+#include <errno.h>
+#include <gdbus.h>
+
+#include "plugin.h"
+#include "manager.h"
+#include "hcid.h"
+#include "log.h"
+
+static DBusConnection *connection = NULL;
+
+static int thermometer_init(void)
+{
+	if (!main_opts.gatt_enabled) {
+		DBG("GATT is disabled");
+		return -ENOTSUP;
+	}
+
+	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+	if (connection == NULL)
+		return -EIO;
+
+	if (thermometer_manager_init(connection) < 0) {
+		dbus_connection_unref(connection);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void thermometer_exit(void)
+{
+	if (!main_opts.gatt_enabled)
+		return;
+
+	thermometer_manager_exit();
+
+	dbus_connection_unref(connection);
+	connection = NULL;
+}
+
+BLUETOOTH_PLUGIN_DEFINE(thermometer, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+					thermometer_init, thermometer_exit)
diff --git a/profiles/thermometer/manager.c b/profiles/thermometer/manager.c
new file mode 100644
index 0000000..3d5452b
--- /dev/null
+++ b/profiles/thermometer/manager.c
@@ -0,0 +1,92 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <gdbus.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "thermometer.h"
+#include "manager.h"
+
+static DBusConnection *connection = NULL;
+
+static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
+{
+	const struct gatt_primary *prim = a;
+	const char *uuid = b;
+
+	return g_strcmp0(prim->uuid, uuid);
+}
+
+static int thermometer_driver_probe(struct btd_device *device, GSList *uuids)
+{
+	struct gatt_primary *tattr;
+	GSList *primaries, *l;
+
+	primaries = btd_device_get_primaries(device);
+
+	l = g_slist_find_custom(primaries, HEALTH_THERMOMETER_UUID,
+							primary_uuid_cmp);
+	if (l == NULL)
+		return -EINVAL;
+
+	tattr = l->data;
+
+	return thermometer_register(connection, device, tattr);
+}
+
+static void thermometer_driver_remove(struct btd_device *device)
+{
+	thermometer_unregister(device);
+}
+
+static struct btd_device_driver thermometer_device_driver = {
+	.name	= "thermometer-device-driver",
+	.uuids	= BTD_UUIDS(HEALTH_THERMOMETER_UUID),
+	.probe	= thermometer_driver_probe,
+	.remove	= thermometer_driver_remove
+};
+
+int thermometer_manager_init(DBusConnection *conn)
+{
+	int ret;
+
+	ret = btd_register_device_driver(&thermometer_device_driver);
+	if (ret < 0)
+                return ret;
+
+	connection = dbus_connection_ref(conn);
+	return 0;
+}
+
+void thermometer_manager_exit(void)
+{
+	btd_unregister_device_driver(&thermometer_device_driver);
+
+	dbus_connection_unref(connection);
+	connection = NULL;
+}
diff --git a/profiles/thermometer/manager.h b/profiles/thermometer/manager.h
new file mode 100644
index 0000000..ed928ad
--- /dev/null
+++ b/profiles/thermometer/manager.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int thermometer_manager_init(DBusConnection *conn);
+void thermometer_manager_exit(void);
diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
new file mode 100644
index 0000000..087662e
--- /dev/null
+++ b/profiles/thermometer/thermometer.c
@@ -0,0 +1,1274 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gdbus.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+
+#include "dbus-common.h"
+#include "adapter.h"
+#include "device.h"
+#include "error.h"
+#include "log.h"
+#include "gattrib.h"
+#include "attio.h"
+#include "att.h"
+#include "gatt.h"
+#include "thermometer.h"
+
+#define THERMOMETER_INTERFACE "org.bluez.Thermometer"
+
+/* Temperature measurement flag fields */
+#define TEMP_UNITS		0x01
+#define TEMP_TIME_STAMP		0x02
+#define TEMP_TYPE		0x04
+
+#define FLOAT_MAX_MANTISSA	16777216 /* 2^24 */
+
+#define VALID_RANGE_DESC_SIZE	4
+#define TEMPERATURE_TYPE_SIZE	1
+#define MEASUREMENT_INTERVAL_SIZE	2
+
+struct thermometer {
+	DBusConnection		*conn;		/* The connection to the bus */
+	struct btd_device	*dev;		/* Device reference */
+	GAttrib			*attrib;	/* GATT connection */
+	struct att_range	*svc_range;	/* Thermometer range */
+	guint			attioid;	/* Att watcher id */
+	guint			attindid;	/* Att incications id */
+	guint			attnotid;	/* Att notifications id */
+	GSList			*chars;		/* Characteristics */
+	GSList			*fwatchers;     /* Final measurements */
+	GSList			*iwatchers;     /* Intermediate measurements */
+	gboolean		intermediate;
+	uint8_t			type;
+	uint16_t		interval;
+	uint16_t		max;
+	uint16_t		min;
+	gboolean		has_type;
+	gboolean		has_interval;
+};
+
+struct characteristic {
+	struct gatt_char		attr;	/* Characteristic */
+	GSList			*desc;	/* Descriptors */
+	struct thermometer	*t;	/* Thermometer where the char belongs */
+};
+
+struct descriptor {
+	struct characteristic	*ch;
+	uint16_t		handle;
+	bt_uuid_t		uuid;
+};
+
+struct watcher {
+	struct thermometer	*t;
+	guint			id;
+	char			*srv;
+	char			*path;
+};
+
+struct measurement {
+	int16_t		exp;
+	int32_t		mant;
+	uint64_t	time;
+	gboolean	suptime;
+	char		*unit;
+	char		*type;
+	char		*value;
+};
+
+struct tmp_interval_data {
+	struct thermometer	*thermometer;
+	uint16_t		interval;
+};
+
+static GSList *thermometers = NULL;
+
+const char *temp_type[] = {
+	"<reserved>",
+	"Armpit",
+	"Body",
+	"Ear",
+	"Finger",
+	"Intestines",
+	"Mouth",
+	"Rectum",
+	"Toe",
+	"Tympanum"
+};
+
+static const gchar *temptype2str(uint8_t value)
+{
+	 if (value > 0 && value < G_N_ELEMENTS(temp_type))
+		return temp_type[value];
+
+	error("Temperature type %d reserved for future use", value);
+	return NULL;
+}
+
+static void destroy_watcher(gpointer user_data)
+{
+	struct watcher *watcher = user_data;
+
+	g_free(watcher->path);
+	g_free(watcher->srv);
+	g_free(watcher);
+}
+
+static void remove_watcher(gpointer user_data)
+{
+	struct watcher *watcher = user_data;
+
+	g_dbus_remove_watch(watcher->t->conn, watcher->id);
+}
+
+static void destroy_char(gpointer user_data)
+{
+	struct characteristic *c = user_data;
+
+	g_slist_free_full(c->desc, g_free);
+	g_free(c);
+}
+
+static void destroy_thermometer(gpointer user_data)
+{
+	struct thermometer *t = user_data;
+
+	if (t->attioid > 0)
+		btd_device_remove_attio_callback(t->dev, t->attioid);
+
+	if (t->attindid > 0)
+		g_attrib_unregister(t->attrib, t->attindid);
+
+	if (t->attnotid > 0)
+		g_attrib_unregister(t->attrib, t->attnotid);
+
+	if (t->attrib != NULL)
+		g_attrib_unref(t->attrib);
+
+	if (t->chars != NULL)
+		g_slist_free_full(t->chars, destroy_char);
+
+	if (t->fwatchers != NULL)
+		g_slist_free_full(t->fwatchers, remove_watcher);
+
+	dbus_connection_unref(t->conn);
+	btd_device_unref(t->dev);
+	g_free(t->svc_range);
+	g_free(t);
+}
+
+static gint cmp_device(gconstpointer a, gconstpointer b)
+{
+	const struct thermometer *t = a;
+	const struct btd_device *dev = b;
+
+	if (dev == t->dev)
+		return 0;
+
+	return -1;
+}
+
+static gint cmp_watcher(gconstpointer a, gconstpointer b)
+{
+	const struct watcher *watcher = a;
+	const struct watcher *match = b;
+	int ret;
+
+	ret = g_strcmp0(watcher->srv, match->srv);
+	if (ret != 0)
+		return ret;
+
+	return g_strcmp0(watcher->path, match->path);
+}
+
+static gint cmp_char_uuid(gconstpointer a, gconstpointer b)
+{
+	const struct characteristic *ch = a;
+	const char *uuid = b;
+
+	return g_strcmp0(ch->attr.uuid, uuid);
+}
+
+static gint cmp_char_val_handle(gconstpointer a, gconstpointer b)
+{
+	const struct characteristic *ch = a;
+	const uint16_t *handle = b;
+
+	return ch->attr.value_handle - *handle;
+}
+
+static gint cmp_descriptor(gconstpointer a, gconstpointer b)
+{
+	const struct descriptor *desc = a;
+	const bt_uuid_t *uuid = b;
+
+	return bt_uuid_cmp(&desc->uuid, uuid);
+}
+
+static struct characteristic *get_characteristic(struct thermometer *t,
+							const char *uuid)
+{
+	GSList *l;
+
+	l = g_slist_find_custom(t->chars, uuid, cmp_char_uuid);
+	if (l == NULL)
+		return NULL;
+
+	return l->data;
+}
+
+static struct descriptor *get_descriptor(struct characteristic *ch,
+							const bt_uuid_t *uuid)
+{
+	GSList *l;
+
+	l = g_slist_find_custom(ch->desc, uuid, cmp_descriptor);
+	if (l == NULL)
+		return NULL;
+
+	return l->data;
+}
+
+static void change_property(struct thermometer *t, const char *name,
+							gpointer value) {
+	if (g_strcmp0(name, "Intermediate") == 0) {
+		gboolean *intermediate = value;
+		if (t->intermediate == *intermediate)
+			return;
+
+		t->intermediate = *intermediate;
+		emit_property_changed(t->conn, device_get_path(t->dev),
+					THERMOMETER_INTERFACE, name,
+					DBUS_TYPE_BOOLEAN, &t->intermediate);
+	} else if (g_strcmp0(name, "Interval") == 0) {
+		uint16_t *interval = value;
+		if (t->has_interval && t->interval == *interval)
+			return;
+
+		t->has_interval = TRUE;
+		t->interval = *interval;
+		emit_property_changed(t->conn, device_get_path(t->dev),
+					THERMOMETER_INTERFACE, name,
+					DBUS_TYPE_UINT16, &t->interval);
+	} else if (g_strcmp0(name, "Maximum") == 0) {
+		uint16_t *max = value;
+		if (t->max == *max)
+			return;
+
+		t->max = *max;
+		emit_property_changed(t->conn, device_get_path(t->dev),
+					THERMOMETER_INTERFACE, name,
+					DBUS_TYPE_UINT16, &t->max);
+	} else if (g_strcmp0(name, "Minimum") == 0) {
+		uint16_t *min = value;
+		if (t->min == *min)
+			return;
+
+		t->min = *min;
+		emit_property_changed(t->conn, device_get_path(t->dev),
+					THERMOMETER_INTERFACE, name,
+					DBUS_TYPE_UINT16, &t->min);
+	} else
+		DBG("%s is not a thermometer property", name);
+}
+
+static void valid_range_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	struct descriptor *desc = user_data;
+	uint8_t value[VALID_RANGE_DESC_SIZE];
+	uint16_t max, min;
+	ssize_t vlen;
+
+	if (status != 0) {
+		DBG("Valid Range descriptor read failed: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	vlen = dec_read_resp(pdu, len, value, sizeof(value));
+	if (vlen < 0) {
+		DBG("Protocol error\n");
+		return;
+	}
+
+	if (vlen < 4) {
+		DBG("Invalid range received");
+		return;
+	}
+
+	min = att_get_u16(&value[0]);
+	max = att_get_u16(&value[2]);
+
+	if (min == 0 || min > max) {
+		DBG("Invalid range");
+		return;
+	}
+
+	change_property(desc->ch->t, "Maximum", &max);
+	change_property(desc->ch->t, "Minimum", &min);
+}
+
+static void measurement_cb(guint8 status, const guint8 *pdu,
+						guint16 len, gpointer user_data)
+{
+	char *msg = user_data;
+
+	if (status != 0)
+		error("%s failed", msg);
+
+	g_free(msg);
+}
+
+static void process_thermometer_desc(struct descriptor *desc)
+{
+	struct characteristic *ch = desc->ch;
+	char uuidstr[MAX_LEN_UUID_STR];
+	bt_uuid_t btuuid;
+
+	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+
+	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
+		uint8_t atval[2];
+		uint16_t val;
+		char *msg;
+
+		if (g_strcmp0(ch->attr.uuid,
+					TEMPERATURE_MEASUREMENT_UUID) == 0) {
+			if (g_slist_length(ch->t->fwatchers) == 0)
+				return;
+
+			val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
+			msg = g_strdup("Enable Temperature Measurement "
+								"indication");
+		} else if (g_strcmp0(ch->attr.uuid,
+					INTERMEDIATE_TEMPERATURE_UUID) == 0) {
+			if (g_slist_length(ch->t->iwatchers) == 0)
+				return;
+
+			val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
+			msg = g_strdup("Enable Intermediate Temperature "
+								"notification");
+		} else if (g_strcmp0(ch->attr.uuid,
+					MEASUREMENT_INTERVAL_UUID) == 0) {
+			val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
+			msg = g_strdup("Enable Measurement Interval "
+								"indication");
+		} else
+			goto done;
+
+		att_put_u16(val, atval);
+		gatt_write_char(ch->t->attrib, desc->handle, atval, 2,
+							measurement_cb, msg);
+		return;
+	}
+
+	bt_uuid16_create(&btuuid, GATT_CHARAC_VALID_RANGE_UUID);
+
+	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0 && g_strcmp0(ch->attr.uuid,
+					MEASUREMENT_INTERVAL_UUID) == 0) {
+		gatt_read_char(ch->t->attrib, desc->handle, 0,
+						valid_range_desc_cb, desc);
+		return;
+	}
+
+done:
+	bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
+	DBG("Ignored descriptor %s in characteristic %s", uuidstr,
+								ch->attr.uuid);
+}
+
+static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	struct characteristic *ch = user_data;
+	struct att_data_list *list;
+	uint8_t format;
+	int i;
+
+	if (status != 0) {
+		error("Discover all characteristic descriptors failed [%s]: %s",
+					ch->attr.uuid, att_ecode2str(status));
+		return;
+	}
+
+	list = dec_find_info_resp(pdu, len, &format);
+	if (list == NULL)
+		return;
+
+	for (i = 0; i < list->num; i++) {
+		struct descriptor *desc;
+		uint8_t *value;
+
+		value = list->data[i];
+		desc = g_new0(struct descriptor, 1);
+		desc->handle = att_get_u16(value);
+		desc->ch = ch;
+
+		if (format == 0x01)
+			desc->uuid = att_get_uuid16(&value[2]);
+		else
+			desc->uuid = att_get_uuid128(&value[2]);
+
+		ch->desc = g_slist_append(ch->desc, desc);
+		process_thermometer_desc(desc);
+	}
+
+	att_data_list_free(list);
+}
+
+static void read_temp_type_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	struct characteristic *ch = user_data;
+	struct thermometer *t = ch->t;
+	uint8_t value[TEMPERATURE_TYPE_SIZE];
+	ssize_t vlen;
+
+	if (status != 0) {
+		DBG("Temperature Type value read failed: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	vlen = dec_read_resp(pdu, len, value, sizeof(value));
+	if (vlen < 0) {
+		DBG("Protocol error.");
+		return;
+	}
+
+	if (vlen != 1) {
+		DBG("Invalid length for Temperature type");
+		return;
+	}
+
+	t->has_type = TRUE;
+	t->type = value[0];
+}
+
+static void read_interval_cb(guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	struct characteristic *ch = user_data;
+	uint8_t value[MEASUREMENT_INTERVAL_SIZE];
+	uint16_t interval;
+	ssize_t vlen;
+
+	if (status != 0) {
+		DBG("Measurement Interval value read failed: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	vlen = dec_read_resp(pdu, len, value, sizeof(value));
+	if (vlen < 0) {
+		DBG("Protocol error\n");
+		return;
+	}
+
+	if (vlen < 2) {
+		DBG("Invalid Interval received");
+		return;
+	}
+
+	interval = att_get_u16(&value[0]);
+	change_property(ch->t, "Interval", &interval);
+}
+
+static void process_thermometer_char(struct characteristic *ch)
+{
+	if (g_strcmp0(ch->attr.uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0) {
+		gboolean intermediate = TRUE;
+		change_property(ch->t, "Intermediate", &intermediate);
+		return;
+	} else if (g_strcmp0(ch->attr.uuid, TEMPERATURE_TYPE_UUID) == 0)
+		gatt_read_char(ch->t->attrib, ch->attr.value_handle, 0,
+							read_temp_type_cb, ch);
+	else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
+		gatt_read_char(ch->t->attrib, ch->attr.value_handle, 0,
+							read_interval_cb, ch);
+}
+
+static void configure_thermometer_cb(GSList *characteristics, guint8 status,
+							gpointer user_data)
+{
+	struct thermometer *t = user_data;
+	GSList *l;
+
+	if (status != 0) {
+		error("Discover thermometer characteristics: %s",
+							att_ecode2str(status));
+		return;
+	}
+
+	for (l = characteristics; l; l = l->next) {
+		struct gatt_char *c = l->data;
+		struct characteristic *ch;
+		uint16_t start, end;
+
+		ch = g_new0(struct characteristic, 1);
+		ch->attr.handle = c->handle;
+		ch->attr.properties = c->properties;
+		ch->attr.value_handle = c->value_handle;
+		memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
+		ch->t = t;
+
+		t->chars = g_slist_append(t->chars, ch);
+
+		process_thermometer_char(ch);
+
+		start = c->value_handle + 1;
+
+		if (l->next != NULL) {
+			struct gatt_char *c = l->next->data;
+			if (start == c->handle)
+				continue;
+			end = c->handle - 1;
+		} else if (c->value_handle != t->svc_range->end)
+			end = t->svc_range->end;
+		else
+			continue;
+
+		gatt_find_info(t->attrib, start, end, discover_desc_cb, ch);
+	}
+}
+
+static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct thermometer *t = data;
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+	DBusMessage *reply;
+
+	reply = dbus_message_new_method_return(msg);
+	if (reply == NULL)
+		return NULL;
+
+	dbus_message_iter_init_append(reply, &iter);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	dict_append_entry(&dict, "Intermediate", DBUS_TYPE_BOOLEAN,
+							&t->intermediate);
+
+	if (t->has_interval) {
+		dict_append_entry(&dict, "Interval", DBUS_TYPE_UINT16,
+								&t->interval);
+		dict_append_entry(&dict, "Maximum", DBUS_TYPE_UINT16, &t->max);
+		dict_append_entry(&dict, "Minimum", DBUS_TYPE_UINT16, &t->min);
+	}
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	return reply;
+}
+
+static void write_interval_cb (guint8 status, const guint8 *pdu, guint16 len,
+							gpointer user_data)
+{
+	struct tmp_interval_data *data = user_data;
+
+	if (status != 0) {
+		error("Interval Write Request failed %s",
+							att_ecode2str(status));
+		goto done;
+	}
+
+	if (!dec_write_resp(pdu, len)) {
+		error("Interval Write Request: protocol error");
+		goto done;
+	}
+
+	change_property(data->thermometer, "Interval", &data->interval);
+
+done:
+	g_free(user_data);
+}
+
+static DBusMessage *write_attr_interval(struct thermometer *t, DBusMessage *msg,
+								uint16_t value)
+{
+	struct tmp_interval_data *data;
+	struct characteristic *ch;
+	uint8_t atval[2];
+
+	if (t->attrib == NULL)
+		return btd_error_not_connected(msg);
+
+	ch = get_characteristic(t, MEASUREMENT_INTERVAL_UUID);
+	if (ch == NULL)
+		return btd_error_not_available(msg);
+
+	if (value < t->min || value > t->max)
+		return btd_error_invalid_args(msg);
+
+	att_put_u16(value, &atval[0]);
+
+	data = g_new0(struct tmp_interval_data, 1);
+	data->thermometer = t;
+	data->interval = value;
+	gatt_write_char(t->attrib, ch->attr.value_handle, atval, 2,
+						write_interval_cb, data);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct thermometer *t = data;
+	const char *property;
+	DBusMessageIter iter;
+	DBusMessageIter sub;
+	uint16_t value;
+
+	if (!dbus_message_iter_init(msg, &iter))
+		return btd_error_invalid_args(msg);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+		return btd_error_invalid_args(msg);
+
+	dbus_message_iter_get_basic(&iter, &property);
+	if (g_strcmp0("Interval", property) != 0)
+		return btd_error_invalid_args(msg);
+
+	if (!t->has_interval)
+		return btd_error_not_available(msg);
+
+	dbus_message_iter_next(&iter);
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+		return btd_error_invalid_args(msg);
+
+	dbus_message_iter_recurse(&iter, &sub);
+
+	if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)
+		return btd_error_invalid_args(msg);
+
+	dbus_message_iter_get_basic(&sub, &value);
+
+	return write_attr_interval(t, msg, value);
+}
+
+static void enable_final_measurement(struct thermometer *t)
+{
+	struct characteristic *ch;
+	struct descriptor *desc;
+	bt_uuid_t btuuid;
+	uint8_t atval[2];
+	char *msg;
+
+	if (t->attrib == NULL)
+		return;
+
+	ch = get_characteristic(t, TEMPERATURE_MEASUREMENT_UUID);
+	if (ch == NULL) {
+		DBG("Temperature measurement characteristic not found");
+		return;
+	}
+
+	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+	desc = get_descriptor(ch, &btuuid);
+	if (desc == NULL) {
+		DBG("Client characteristic configuration descriptor not found");
+		return;
+	}
+
+	atval[0] = 0x02;
+	atval[1] = 0x00;
+	msg = g_strdup("Enable final measurement");
+	gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
+}
+
+static void enable_intermediate_measurement(struct thermometer *t)
+{
+	struct characteristic *ch;
+	struct descriptor *desc;
+	bt_uuid_t btuuid;
+	uint8_t atval[2];
+	char *msg;
+
+	if (t->attrib == NULL)
+		return;
+
+	ch = get_characteristic(t, INTERMEDIATE_TEMPERATURE_UUID);
+	if (ch == NULL) {
+		DBG("Intermediate measurement characteristic not found");
+		return;
+	}
+
+	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+	desc = get_descriptor(ch, &btuuid);
+	if (desc == NULL) {
+		DBG("Client characteristic configuration descriptor not found");
+		return;
+	}
+
+	atval[0] = 0x01;
+	atval[1] = 0x00;
+	msg = g_strdup("Enable intermediate measurement");
+	gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
+}
+
+static void disable_final_measurement(struct thermometer *t)
+{
+	struct characteristic *ch;
+	struct descriptor *desc;
+	bt_uuid_t btuuid;
+	uint8_t atval[2];
+	char *msg;
+
+	if (t->attrib == NULL)
+		return;
+
+	ch = get_characteristic(t, TEMPERATURE_MEASUREMENT_UUID);
+	if (ch == NULL) {
+		DBG("Temperature measurement characteristic not found");
+		return;
+	}
+
+	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+	desc = get_descriptor(ch, &btuuid);
+	if (desc == NULL) {
+		DBG("Client characteristic configuration descriptor not found");
+		return;
+	}
+
+	atval[0] = 0x00;
+	atval[1] = 0x00;
+	msg = g_strdup("Disable final measurement");
+	gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
+}
+
+static void disable_intermediate_measurement(struct thermometer *t)
+{
+	struct characteristic *ch;
+	struct descriptor *desc;
+	bt_uuid_t btuuid;
+	uint8_t atval[2];
+	char *msg;
+
+	if (t->attrib == NULL)
+		return;
+
+	ch = get_characteristic(t, INTERMEDIATE_TEMPERATURE_UUID);
+	if (ch == NULL) {
+		DBG("Intermediate measurement characteristic not found");
+		return;
+	}
+
+	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+	desc = get_descriptor(ch, &btuuid);
+	if (desc == NULL) {
+		DBG("Client characteristic configuration descriptor not found");
+		return;
+	}
+
+	atval[0] = 0x00;
+	atval[1] = 0x00;
+	msg = g_strdup("Disable intermediate measurement");
+	gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
+}
+
+static void remove_int_watcher(struct thermometer *t, struct watcher *w)
+{
+	if (!g_slist_find(t->iwatchers, w))
+		return;
+
+	t->iwatchers = g_slist_remove(t->iwatchers, w);
+
+	if (g_slist_length(t->iwatchers) == 0)
+		disable_intermediate_measurement(t);
+}
+
+static void watcher_exit(DBusConnection *conn, void *user_data)
+{
+	struct watcher *watcher = user_data;
+	struct thermometer *t = watcher->t;
+
+	DBG("Thermometer watcher %s disconnected", watcher->path);
+
+	remove_int_watcher(t, watcher);
+
+	t->fwatchers = g_slist_remove(t->fwatchers, watcher);
+	g_dbus_remove_watch(watcher->t->conn, watcher->id);
+
+	if (g_slist_length(t->fwatchers) == 0)
+		disable_final_measurement(t);
+}
+
+static struct watcher *find_watcher(GSList *list, const char *sender,
+							const char *path)
+{
+	struct watcher *match;
+	GSList *l;
+
+	match = g_new0(struct watcher, 1);
+	match->srv = g_strdup(sender);
+	match->path = g_strdup(path);
+
+	l = g_slist_find_custom(list, match, cmp_watcher);
+	destroy_watcher(match);
+
+	if (l != NULL)
+		return l->data;
+
+	return NULL;
+}
+
+static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	const char *sender = dbus_message_get_sender(msg);
+	struct thermometer *t = data;
+	struct watcher *watcher;
+	char *path;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	watcher = find_watcher(t->fwatchers, sender, path);
+	if (watcher != NULL)
+		return btd_error_already_exists(msg);
+
+	DBG("Thermometer watcher %s registered", path);
+
+	watcher = g_new0(struct watcher, 1);
+	watcher->srv = g_strdup(sender);
+	watcher->path = g_strdup(path);
+	watcher->t = t;
+	watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
+						watcher, destroy_watcher);
+
+	if (g_slist_length(t->fwatchers) == 0)
+		enable_final_measurement(t);
+
+	t->fwatchers = g_slist_prepend(t->fwatchers, watcher);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	const char *sender = dbus_message_get_sender(msg);
+	struct thermometer *t = data;
+	struct watcher *watcher;
+	char *path;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	watcher = find_watcher(t->fwatchers, sender, path);
+	if (watcher == NULL)
+		return btd_error_does_not_exist(msg);
+
+	DBG("Thermometer watcher %s unregistered", path);
+
+	remove_int_watcher(t, watcher);
+
+	t->fwatchers = g_slist_remove(t->fwatchers, watcher);
+	g_dbus_remove_watch(watcher->t->conn, watcher->id);
+
+	if (g_slist_length(t->fwatchers) == 0)
+		disable_final_measurement(t);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *enable_intermediate(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	const char *sender = dbus_message_get_sender(msg);
+	struct thermometer *t = data;
+	struct watcher *watcher;
+	char *path;
+
+	if (!t->intermediate)
+		return btd_error_not_supported(msg);
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	watcher = find_watcher(t->fwatchers, sender, path);
+	if (watcher == NULL)
+		return btd_error_does_not_exist(msg);
+
+	if (find_watcher(t->iwatchers, sender, path))
+		return btd_error_already_exists(msg);
+
+	DBG("Intermediate measurement watcher %s registered", path);
+
+	if (g_slist_length(t->iwatchers) == 0)
+		enable_intermediate_measurement(t);
+
+	t->iwatchers = g_slist_prepend(t->iwatchers, watcher);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *disable_intermediate(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	const char *sender = dbus_message_get_sender(msg);
+	struct thermometer *t = data;
+	struct watcher *watcher;
+	char *path;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	watcher = find_watcher(t->iwatchers, sender, path);
+	if (watcher == NULL)
+		return btd_error_does_not_exist(msg);
+
+	DBG("Intermediate measurement %s unregistered", path);
+
+	remove_int_watcher(t, watcher);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable thermometer_methods[] = {
+	{ GDBUS_METHOD("GetProperties",
+			NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+			get_properties) },
+	{ GDBUS_ASYNC_METHOD("SetProperty",
+			GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
+			set_property) },
+	{ GDBUS_METHOD("RegisterWatcher",
+			GDBUS_ARGS({ "agent", "o" }), NULL,
+			register_watcher) },
+	{ GDBUS_METHOD("UnregisterWatcher",
+			GDBUS_ARGS({ "agent", "o" }), NULL,
+			unregister_watcher) },
+	{ GDBUS_METHOD("EnableIntermediateMeasurement",
+			GDBUS_ARGS({ "agent", "o" }), NULL,
+			enable_intermediate) },
+	{ GDBUS_METHOD("DisableIntermediateMeasurement",
+			GDBUS_ARGS({ "agent", "o" }), NULL,
+			disable_intermediate) },
+	{ }
+};
+
+static const GDBusSignalTable thermometer_signals[] = {
+	{ GDBUS_SIGNAL("PropertyChanged",
+			GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+	{ }
+};
+
+static void update_watcher(gpointer data, gpointer user_data)
+{
+	struct watcher *w = data;
+	struct measurement *m = user_data;
+	DBusConnection *conn = w->t->conn;
+	DBusMessageIter iter;
+	DBusMessageIter dict;
+	DBusMessage *msg;
+
+	msg = dbus_message_new_method_call(w->srv, w->path,
+				"org.bluez.ThermometerWatcher",
+				"MeasurementReceived");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+	dict_append_entry(&dict, "Exponent", DBUS_TYPE_INT16, &m->exp);
+	dict_append_entry(&dict, "Mantissa", DBUS_TYPE_INT32, &m->mant);
+	dict_append_entry(&dict, "Unit", DBUS_TYPE_STRING, &m->unit);
+
+	if (m->suptime)
+		dict_append_entry(&dict, "Time", DBUS_TYPE_UINT64, &m->time);
+
+	dict_append_entry(&dict, "Type", DBUS_TYPE_STRING, &m->type);
+	dict_append_entry(&dict, "Measurement", DBUS_TYPE_STRING, &m->value);
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	dbus_message_set_no_reply(msg, TRUE);
+	g_dbus_send_message(conn, msg);
+}
+
+static void recv_measurement(struct thermometer *t, struct measurement *m)
+{
+	GSList *wlist;
+
+	if (g_strcmp0(m->value, "Intermediate") == 0)
+		wlist = t->iwatchers;
+	else
+		wlist = t->fwatchers;
+
+	g_slist_foreach(wlist, update_watcher, m);
+}
+
+static void proc_measurement(struct thermometer *t, const uint8_t *pdu,
+						uint16_t len, gboolean final)
+{
+	struct measurement m;
+	const char *type;
+	uint8_t flags;
+	uint32_t raw;
+
+	if (len < 4) {
+		DBG("Mandatory flags are not provided");
+		return;
+	}
+
+	flags = pdu[3];
+	if (flags & TEMP_UNITS)
+		m.unit = "Fahrenheit";
+	else
+		m.unit = "Celsius";
+
+	if (len < 8) {
+		DBG("Temperature measurement value is not provided");
+		return;
+	}
+
+	raw = att_get_u32(&pdu[4]);
+	m.mant = raw & 0x00FFFFFF;
+	m.exp = ((int32_t) raw) >> 24;
+
+	if (m.mant & 0x00800000) {
+		/* convert to C2 negative value */
+		m.mant = m.mant - FLOAT_MAX_MANTISSA;
+	}
+
+	if (flags & TEMP_TIME_STAMP) {
+		struct tm ts;
+		time_t time;
+
+		if (len < 15) {
+			DBG("Can't get time stamp value");
+			return;
+		}
+
+		ts.tm_year = att_get_u16(&pdu[8]) - 1900;
+		ts.tm_mon = pdu[10] - 1;
+		ts.tm_mday = pdu[11];
+		ts.tm_hour = pdu[12];
+		ts.tm_min = pdu[13];
+		ts.tm_sec = pdu[14];
+		ts.tm_isdst = -1;
+
+		time = mktime(&ts);
+		m.time = (uint64_t) time;
+		m.suptime = TRUE;
+	} else
+		m.suptime = FALSE;
+
+	if (flags & TEMP_TYPE) {
+		uint8_t index;
+
+		if (m.suptime && len >= 16)
+			index = 15;
+		else if (!m.suptime && len >= 9)
+			index = 9;
+		else {
+			DBG("Can't get temperature type");
+			return;
+		}
+
+		type = temptype2str(pdu[index]);
+	} else if (t->has_type)
+		type = temptype2str(t->type);
+	else
+		type = NULL;
+
+	m.type = type ? g_strdup(type) : NULL;
+	m.value = final ? "Final" : "Intermediate";
+
+	recv_measurement(t, &m);
+	g_free(m.type);
+}
+
+static void proc_measurement_interval(struct thermometer *t, const uint8_t *pdu,
+								uint16_t len)
+{
+	uint16_t interval;
+
+	if (len < 5) {
+		DBG("Measurement interval value is not provided");
+		return;
+	}
+
+	interval = att_get_u16(&pdu[3]);
+
+	change_property(t, "Interval", &interval);
+}
+
+static void ind_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+	struct thermometer *t = user_data;
+	const struct characteristic *ch;
+	uint8_t *opdu;
+	uint16_t handle, olen;
+	GSList *l;
+	int plen;
+
+	if (len < 3) {
+		DBG("Bad pdu received");
+		return;
+	}
+
+	handle = att_get_u16(&pdu[1]);
+	l = g_slist_find_custom(t->chars, &handle, cmp_char_val_handle);
+	if (l == NULL) {
+		DBG("Unexpected handle: 0x%04x", handle);
+		return;
+	}
+
+	ch = l->data;
+
+	if (g_strcmp0(ch->attr.uuid, TEMPERATURE_MEASUREMENT_UUID) == 0)
+		proc_measurement(t, pdu, len, TRUE);
+	else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
+		proc_measurement_interval(t, pdu, len);
+
+	opdu = g_attrib_get_buffer(t->attrib, &plen);
+	olen = enc_confirmation(opdu, plen);
+
+	if (olen > 0)
+		g_attrib_send(t->attrib, 0, opdu[0], opdu, olen, NULL, NULL,
+									NULL);
+}
+
+static void notif_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+	struct thermometer *t = user_data;
+	const struct characteristic *ch;
+	uint16_t handle;
+	GSList *l;
+
+	if (len < 3) {
+		DBG("Bad pdu received");
+		return;
+	}
+
+	handle = att_get_u16(&pdu[1]);
+	l = g_slist_find_custom(t->chars, &handle, cmp_char_val_handle);
+	if (l == NULL) {
+		DBG("Unexpected handle: 0x%04x", handle);
+		return;
+	}
+
+	ch = l->data;
+	if (g_strcmp0(ch->attr.uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0)
+		proc_measurement(t, pdu, len, FALSE);
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+	struct thermometer *t = user_data;
+
+	t->attrib = g_attrib_ref(attrib);
+
+	t->attindid = g_attrib_register(t->attrib, ATT_OP_HANDLE_IND,
+							ind_handler, t, NULL);
+	t->attnotid = g_attrib_register(t->attrib, ATT_OP_HANDLE_NOTIFY,
+							notif_handler, t, NULL);
+	gatt_discover_char(t->attrib, t->svc_range->start, t->svc_range->end,
+					NULL, configure_thermometer_cb, t);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+	struct thermometer *t = user_data;
+
+	DBG("GATT Disconnected");
+
+	if (t->attindid > 0) {
+		g_attrib_unregister(t->attrib, t->attindid);
+		t->attindid = 0;
+	}
+
+	if (t->attnotid > 0) {
+		g_attrib_unregister(t->attrib, t->attnotid);
+		t->attnotid = 0;
+	}
+
+	g_attrib_unref(t->attrib);
+	t->attrib = NULL;
+}
+
+int thermometer_register(DBusConnection *connection, struct btd_device *device,
+						struct gatt_primary *tattr)
+{
+	const gchar *path = device_get_path(device);
+	struct thermometer *t;
+
+	t = g_new0(struct thermometer, 1);
+	t->conn = dbus_connection_ref(connection);
+	t->dev = btd_device_ref(device);
+	t->svc_range = g_new0(struct att_range, 1);
+	t->svc_range->start = tattr->range.start;
+	t->svc_range->end = tattr->range.end;
+
+	if (!g_dbus_register_interface(t->conn, path, THERMOMETER_INTERFACE,
+				thermometer_methods, thermometer_signals,
+				NULL, t, destroy_thermometer)) {
+		error("D-Bus failed to register %s interface",
+							THERMOMETER_INTERFACE);
+		destroy_thermometer(t);
+		return -EIO;
+	}
+
+	thermometers = g_slist_prepend(thermometers, t);
+
+	t->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
+						attio_disconnected_cb, t);
+	return 0;
+}
+
+void thermometer_unregister(struct btd_device *device)
+{
+	struct thermometer *t;
+	GSList *l;
+
+	l = g_slist_find_custom(thermometers, device, cmp_device);
+	if (l == NULL)
+		return;
+
+	t = l->data;
+	thermometers = g_slist_remove(thermometers, t);
+	g_dbus_unregister_interface(t->conn, device_get_path(t->dev),
+							THERMOMETER_INTERFACE);
+}
diff --git a/profiles/thermometer/thermometer.h b/profiles/thermometer/thermometer.h
new file mode 100644
index 0000000..330503c
--- /dev/null
+++ b/profiles/thermometer/thermometer.h
@@ -0,0 +1,25 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int thermometer_register(DBusConnection *connection, struct btd_device *device,
+						struct gatt_primary *tattr);
+void thermometer_unregister(struct btd_device *device);
diff --git a/thermometer/main.c b/thermometer/main.c
deleted file mode 100644
index 4447b52..0000000
--- a/thermometer/main.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdint.h>
-#include <glib.h>
-#include <errno.h>
-#include <gdbus.h>
-
-#include "plugin.h"
-#include "manager.h"
-#include "hcid.h"
-#include "log.h"
-
-static DBusConnection *connection = NULL;
-
-static int thermometer_init(void)
-{
-	if (!main_opts.gatt_enabled) {
-		DBG("GATT is disabled");
-		return -ENOTSUP;
-	}
-
-	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-	if (connection == NULL)
-		return -EIO;
-
-	if (thermometer_manager_init(connection) < 0) {
-		dbus_connection_unref(connection);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static void thermometer_exit(void)
-{
-	if (!main_opts.gatt_enabled)
-		return;
-
-	thermometer_manager_exit();
-
-	dbus_connection_unref(connection);
-	connection = NULL;
-}
-
-BLUETOOTH_PLUGIN_DEFINE(thermometer, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
-					thermometer_init, thermometer_exit)
diff --git a/thermometer/manager.c b/thermometer/manager.c
deleted file mode 100644
index 3d5452b..0000000
--- a/thermometer/manager.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <gdbus.h>
-#include <errno.h>
-#include <bluetooth/uuid.h>
-
-#include "adapter.h"
-#include "device.h"
-#include "att.h"
-#include "gattrib.h"
-#include "gatt.h"
-#include "thermometer.h"
-#include "manager.h"
-
-static DBusConnection *connection = NULL;
-
-static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
-{
-	const struct gatt_primary *prim = a;
-	const char *uuid = b;
-
-	return g_strcmp0(prim->uuid, uuid);
-}
-
-static int thermometer_driver_probe(struct btd_device *device, GSList *uuids)
-{
-	struct gatt_primary *tattr;
-	GSList *primaries, *l;
-
-	primaries = btd_device_get_primaries(device);
-
-	l = g_slist_find_custom(primaries, HEALTH_THERMOMETER_UUID,
-							primary_uuid_cmp);
-	if (l == NULL)
-		return -EINVAL;
-
-	tattr = l->data;
-
-	return thermometer_register(connection, device, tattr);
-}
-
-static void thermometer_driver_remove(struct btd_device *device)
-{
-	thermometer_unregister(device);
-}
-
-static struct btd_device_driver thermometer_device_driver = {
-	.name	= "thermometer-device-driver",
-	.uuids	= BTD_UUIDS(HEALTH_THERMOMETER_UUID),
-	.probe	= thermometer_driver_probe,
-	.remove	= thermometer_driver_remove
-};
-
-int thermometer_manager_init(DBusConnection *conn)
-{
-	int ret;
-
-	ret = btd_register_device_driver(&thermometer_device_driver);
-	if (ret < 0)
-                return ret;
-
-	connection = dbus_connection_ref(conn);
-	return 0;
-}
-
-void thermometer_manager_exit(void)
-{
-	btd_unregister_device_driver(&thermometer_device_driver);
-
-	dbus_connection_unref(connection);
-	connection = NULL;
-}
diff --git a/thermometer/manager.h b/thermometer/manager.h
deleted file mode 100644
index ed928ad..0000000
--- a/thermometer/manager.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-int thermometer_manager_init(DBusConnection *conn);
-void thermometer_manager_exit(void);
diff --git a/thermometer/thermometer.c b/thermometer/thermometer.c
deleted file mode 100644
index 087662e..0000000
--- a/thermometer/thermometer.c
+++ /dev/null
@@ -1,1274 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <gdbus.h>
-#include <errno.h>
-#include <bluetooth/uuid.h>
-
-#include "dbus-common.h"
-#include "adapter.h"
-#include "device.h"
-#include "error.h"
-#include "log.h"
-#include "gattrib.h"
-#include "attio.h"
-#include "att.h"
-#include "gatt.h"
-#include "thermometer.h"
-
-#define THERMOMETER_INTERFACE "org.bluez.Thermometer"
-
-/* Temperature measurement flag fields */
-#define TEMP_UNITS		0x01
-#define TEMP_TIME_STAMP		0x02
-#define TEMP_TYPE		0x04
-
-#define FLOAT_MAX_MANTISSA	16777216 /* 2^24 */
-
-#define VALID_RANGE_DESC_SIZE	4
-#define TEMPERATURE_TYPE_SIZE	1
-#define MEASUREMENT_INTERVAL_SIZE	2
-
-struct thermometer {
-	DBusConnection		*conn;		/* The connection to the bus */
-	struct btd_device	*dev;		/* Device reference */
-	GAttrib			*attrib;	/* GATT connection */
-	struct att_range	*svc_range;	/* Thermometer range */
-	guint			attioid;	/* Att watcher id */
-	guint			attindid;	/* Att incications id */
-	guint			attnotid;	/* Att notifications id */
-	GSList			*chars;		/* Characteristics */
-	GSList			*fwatchers;     /* Final measurements */
-	GSList			*iwatchers;     /* Intermediate measurements */
-	gboolean		intermediate;
-	uint8_t			type;
-	uint16_t		interval;
-	uint16_t		max;
-	uint16_t		min;
-	gboolean		has_type;
-	gboolean		has_interval;
-};
-
-struct characteristic {
-	struct gatt_char		attr;	/* Characteristic */
-	GSList			*desc;	/* Descriptors */
-	struct thermometer	*t;	/* Thermometer where the char belongs */
-};
-
-struct descriptor {
-	struct characteristic	*ch;
-	uint16_t		handle;
-	bt_uuid_t		uuid;
-};
-
-struct watcher {
-	struct thermometer	*t;
-	guint			id;
-	char			*srv;
-	char			*path;
-};
-
-struct measurement {
-	int16_t		exp;
-	int32_t		mant;
-	uint64_t	time;
-	gboolean	suptime;
-	char		*unit;
-	char		*type;
-	char		*value;
-};
-
-struct tmp_interval_data {
-	struct thermometer	*thermometer;
-	uint16_t		interval;
-};
-
-static GSList *thermometers = NULL;
-
-const char *temp_type[] = {
-	"<reserved>",
-	"Armpit",
-	"Body",
-	"Ear",
-	"Finger",
-	"Intestines",
-	"Mouth",
-	"Rectum",
-	"Toe",
-	"Tympanum"
-};
-
-static const gchar *temptype2str(uint8_t value)
-{
-	 if (value > 0 && value < G_N_ELEMENTS(temp_type))
-		return temp_type[value];
-
-	error("Temperature type %d reserved for future use", value);
-	return NULL;
-}
-
-static void destroy_watcher(gpointer user_data)
-{
-	struct watcher *watcher = user_data;
-
-	g_free(watcher->path);
-	g_free(watcher->srv);
-	g_free(watcher);
-}
-
-static void remove_watcher(gpointer user_data)
-{
-	struct watcher *watcher = user_data;
-
-	g_dbus_remove_watch(watcher->t->conn, watcher->id);
-}
-
-static void destroy_char(gpointer user_data)
-{
-	struct characteristic *c = user_data;
-
-	g_slist_free_full(c->desc, g_free);
-	g_free(c);
-}
-
-static void destroy_thermometer(gpointer user_data)
-{
-	struct thermometer *t = user_data;
-
-	if (t->attioid > 0)
-		btd_device_remove_attio_callback(t->dev, t->attioid);
-
-	if (t->attindid > 0)
-		g_attrib_unregister(t->attrib, t->attindid);
-
-	if (t->attnotid > 0)
-		g_attrib_unregister(t->attrib, t->attnotid);
-
-	if (t->attrib != NULL)
-		g_attrib_unref(t->attrib);
-
-	if (t->chars != NULL)
-		g_slist_free_full(t->chars, destroy_char);
-
-	if (t->fwatchers != NULL)
-		g_slist_free_full(t->fwatchers, remove_watcher);
-
-	dbus_connection_unref(t->conn);
-	btd_device_unref(t->dev);
-	g_free(t->svc_range);
-	g_free(t);
-}
-
-static gint cmp_device(gconstpointer a, gconstpointer b)
-{
-	const struct thermometer *t = a;
-	const struct btd_device *dev = b;
-
-	if (dev == t->dev)
-		return 0;
-
-	return -1;
-}
-
-static gint cmp_watcher(gconstpointer a, gconstpointer b)
-{
-	const struct watcher *watcher = a;
-	const struct watcher *match = b;
-	int ret;
-
-	ret = g_strcmp0(watcher->srv, match->srv);
-	if (ret != 0)
-		return ret;
-
-	return g_strcmp0(watcher->path, match->path);
-}
-
-static gint cmp_char_uuid(gconstpointer a, gconstpointer b)
-{
-	const struct characteristic *ch = a;
-	const char *uuid = b;
-
-	return g_strcmp0(ch->attr.uuid, uuid);
-}
-
-static gint cmp_char_val_handle(gconstpointer a, gconstpointer b)
-{
-	const struct characteristic *ch = a;
-	const uint16_t *handle = b;
-
-	return ch->attr.value_handle - *handle;
-}
-
-static gint cmp_descriptor(gconstpointer a, gconstpointer b)
-{
-	const struct descriptor *desc = a;
-	const bt_uuid_t *uuid = b;
-
-	return bt_uuid_cmp(&desc->uuid, uuid);
-}
-
-static struct characteristic *get_characteristic(struct thermometer *t,
-							const char *uuid)
-{
-	GSList *l;
-
-	l = g_slist_find_custom(t->chars, uuid, cmp_char_uuid);
-	if (l == NULL)
-		return NULL;
-
-	return l->data;
-}
-
-static struct descriptor *get_descriptor(struct characteristic *ch,
-							const bt_uuid_t *uuid)
-{
-	GSList *l;
-
-	l = g_slist_find_custom(ch->desc, uuid, cmp_descriptor);
-	if (l == NULL)
-		return NULL;
-
-	return l->data;
-}
-
-static void change_property(struct thermometer *t, const char *name,
-							gpointer value) {
-	if (g_strcmp0(name, "Intermediate") == 0) {
-		gboolean *intermediate = value;
-		if (t->intermediate == *intermediate)
-			return;
-
-		t->intermediate = *intermediate;
-		emit_property_changed(t->conn, device_get_path(t->dev),
-					THERMOMETER_INTERFACE, name,
-					DBUS_TYPE_BOOLEAN, &t->intermediate);
-	} else if (g_strcmp0(name, "Interval") == 0) {
-		uint16_t *interval = value;
-		if (t->has_interval && t->interval == *interval)
-			return;
-
-		t->has_interval = TRUE;
-		t->interval = *interval;
-		emit_property_changed(t->conn, device_get_path(t->dev),
-					THERMOMETER_INTERFACE, name,
-					DBUS_TYPE_UINT16, &t->interval);
-	} else if (g_strcmp0(name, "Maximum") == 0) {
-		uint16_t *max = value;
-		if (t->max == *max)
-			return;
-
-		t->max = *max;
-		emit_property_changed(t->conn, device_get_path(t->dev),
-					THERMOMETER_INTERFACE, name,
-					DBUS_TYPE_UINT16, &t->max);
-	} else if (g_strcmp0(name, "Minimum") == 0) {
-		uint16_t *min = value;
-		if (t->min == *min)
-			return;
-
-		t->min = *min;
-		emit_property_changed(t->conn, device_get_path(t->dev),
-					THERMOMETER_INTERFACE, name,
-					DBUS_TYPE_UINT16, &t->min);
-	} else
-		DBG("%s is not a thermometer property", name);
-}
-
-static void valid_range_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
-							gpointer user_data)
-{
-	struct descriptor *desc = user_data;
-	uint8_t value[VALID_RANGE_DESC_SIZE];
-	uint16_t max, min;
-	ssize_t vlen;
-
-	if (status != 0) {
-		DBG("Valid Range descriptor read failed: %s",
-							att_ecode2str(status));
-		return;
-	}
-
-	vlen = dec_read_resp(pdu, len, value, sizeof(value));
-	if (vlen < 0) {
-		DBG("Protocol error\n");
-		return;
-	}
-
-	if (vlen < 4) {
-		DBG("Invalid range received");
-		return;
-	}
-
-	min = att_get_u16(&value[0]);
-	max = att_get_u16(&value[2]);
-
-	if (min == 0 || min > max) {
-		DBG("Invalid range");
-		return;
-	}
-
-	change_property(desc->ch->t, "Maximum", &max);
-	change_property(desc->ch->t, "Minimum", &min);
-}
-
-static void measurement_cb(guint8 status, const guint8 *pdu,
-						guint16 len, gpointer user_data)
-{
-	char *msg = user_data;
-
-	if (status != 0)
-		error("%s failed", msg);
-
-	g_free(msg);
-}
-
-static void process_thermometer_desc(struct descriptor *desc)
-{
-	struct characteristic *ch = desc->ch;
-	char uuidstr[MAX_LEN_UUID_STR];
-	bt_uuid_t btuuid;
-
-	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
-
-	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
-		uint8_t atval[2];
-		uint16_t val;
-		char *msg;
-
-		if (g_strcmp0(ch->attr.uuid,
-					TEMPERATURE_MEASUREMENT_UUID) == 0) {
-			if (g_slist_length(ch->t->fwatchers) == 0)
-				return;
-
-			val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
-			msg = g_strdup("Enable Temperature Measurement "
-								"indication");
-		} else if (g_strcmp0(ch->attr.uuid,
-					INTERMEDIATE_TEMPERATURE_UUID) == 0) {
-			if (g_slist_length(ch->t->iwatchers) == 0)
-				return;
-
-			val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
-			msg = g_strdup("Enable Intermediate Temperature "
-								"notification");
-		} else if (g_strcmp0(ch->attr.uuid,
-					MEASUREMENT_INTERVAL_UUID) == 0) {
-			val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
-			msg = g_strdup("Enable Measurement Interval "
-								"indication");
-		} else
-			goto done;
-
-		att_put_u16(val, atval);
-		gatt_write_char(ch->t->attrib, desc->handle, atval, 2,
-							measurement_cb, msg);
-		return;
-	}
-
-	bt_uuid16_create(&btuuid, GATT_CHARAC_VALID_RANGE_UUID);
-
-	if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0 && g_strcmp0(ch->attr.uuid,
-					MEASUREMENT_INTERVAL_UUID) == 0) {
-		gatt_read_char(ch->t->attrib, desc->handle, 0,
-						valid_range_desc_cb, desc);
-		return;
-	}
-
-done:
-	bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
-	DBG("Ignored descriptor %s in characteristic %s", uuidstr,
-								ch->attr.uuid);
-}
-
-static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
-							gpointer user_data)
-{
-	struct characteristic *ch = user_data;
-	struct att_data_list *list;
-	uint8_t format;
-	int i;
-
-	if (status != 0) {
-		error("Discover all characteristic descriptors failed [%s]: %s",
-					ch->attr.uuid, att_ecode2str(status));
-		return;
-	}
-
-	list = dec_find_info_resp(pdu, len, &format);
-	if (list == NULL)
-		return;
-
-	for (i = 0; i < list->num; i++) {
-		struct descriptor *desc;
-		uint8_t *value;
-
-		value = list->data[i];
-		desc = g_new0(struct descriptor, 1);
-		desc->handle = att_get_u16(value);
-		desc->ch = ch;
-
-		if (format == 0x01)
-			desc->uuid = att_get_uuid16(&value[2]);
-		else
-			desc->uuid = att_get_uuid128(&value[2]);
-
-		ch->desc = g_slist_append(ch->desc, desc);
-		process_thermometer_desc(desc);
-	}
-
-	att_data_list_free(list);
-}
-
-static void read_temp_type_cb(guint8 status, const guint8 *pdu, guint16 len,
-							gpointer user_data)
-{
-	struct characteristic *ch = user_data;
-	struct thermometer *t = ch->t;
-	uint8_t value[TEMPERATURE_TYPE_SIZE];
-	ssize_t vlen;
-
-	if (status != 0) {
-		DBG("Temperature Type value read failed: %s",
-							att_ecode2str(status));
-		return;
-	}
-
-	vlen = dec_read_resp(pdu, len, value, sizeof(value));
-	if (vlen < 0) {
-		DBG("Protocol error.");
-		return;
-	}
-
-	if (vlen != 1) {
-		DBG("Invalid length for Temperature type");
-		return;
-	}
-
-	t->has_type = TRUE;
-	t->type = value[0];
-}
-
-static void read_interval_cb(guint8 status, const guint8 *pdu, guint16 len,
-							gpointer user_data)
-{
-	struct characteristic *ch = user_data;
-	uint8_t value[MEASUREMENT_INTERVAL_SIZE];
-	uint16_t interval;
-	ssize_t vlen;
-
-	if (status != 0) {
-		DBG("Measurement Interval value read failed: %s",
-							att_ecode2str(status));
-		return;
-	}
-
-	vlen = dec_read_resp(pdu, len, value, sizeof(value));
-	if (vlen < 0) {
-		DBG("Protocol error\n");
-		return;
-	}
-
-	if (vlen < 2) {
-		DBG("Invalid Interval received");
-		return;
-	}
-
-	interval = att_get_u16(&value[0]);
-	change_property(ch->t, "Interval", &interval);
-}
-
-static void process_thermometer_char(struct characteristic *ch)
-{
-	if (g_strcmp0(ch->attr.uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0) {
-		gboolean intermediate = TRUE;
-		change_property(ch->t, "Intermediate", &intermediate);
-		return;
-	} else if (g_strcmp0(ch->attr.uuid, TEMPERATURE_TYPE_UUID) == 0)
-		gatt_read_char(ch->t->attrib, ch->attr.value_handle, 0,
-							read_temp_type_cb, ch);
-	else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
-		gatt_read_char(ch->t->attrib, ch->attr.value_handle, 0,
-							read_interval_cb, ch);
-}
-
-static void configure_thermometer_cb(GSList *characteristics, guint8 status,
-							gpointer user_data)
-{
-	struct thermometer *t = user_data;
-	GSList *l;
-
-	if (status != 0) {
-		error("Discover thermometer characteristics: %s",
-							att_ecode2str(status));
-		return;
-	}
-
-	for (l = characteristics; l; l = l->next) {
-		struct gatt_char *c = l->data;
-		struct characteristic *ch;
-		uint16_t start, end;
-
-		ch = g_new0(struct characteristic, 1);
-		ch->attr.handle = c->handle;
-		ch->attr.properties = c->properties;
-		ch->attr.value_handle = c->value_handle;
-		memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
-		ch->t = t;
-
-		t->chars = g_slist_append(t->chars, ch);
-
-		process_thermometer_char(ch);
-
-		start = c->value_handle + 1;
-
-		if (l->next != NULL) {
-			struct gatt_char *c = l->next->data;
-			if (start == c->handle)
-				continue;
-			end = c->handle - 1;
-		} else if (c->value_handle != t->svc_range->end)
-			end = t->svc_range->end;
-		else
-			continue;
-
-		gatt_find_info(t->attrib, start, end, discover_desc_cb, ch);
-	}
-}
-
-static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
-								void *data)
-{
-	struct thermometer *t = data;
-	DBusMessageIter iter;
-	DBusMessageIter dict;
-	DBusMessage *reply;
-
-	reply = dbus_message_new_method_return(msg);
-	if (reply == NULL)
-		return NULL;
-
-	dbus_message_iter_init_append(reply, &iter);
-
-	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-	dict_append_entry(&dict, "Intermediate", DBUS_TYPE_BOOLEAN,
-							&t->intermediate);
-
-	if (t->has_interval) {
-		dict_append_entry(&dict, "Interval", DBUS_TYPE_UINT16,
-								&t->interval);
-		dict_append_entry(&dict, "Maximum", DBUS_TYPE_UINT16, &t->max);
-		dict_append_entry(&dict, "Minimum", DBUS_TYPE_UINT16, &t->min);
-	}
-
-	dbus_message_iter_close_container(&iter, &dict);
-
-	return reply;
-}
-
-static void write_interval_cb (guint8 status, const guint8 *pdu, guint16 len,
-							gpointer user_data)
-{
-	struct tmp_interval_data *data = user_data;
-
-	if (status != 0) {
-		error("Interval Write Request failed %s",
-							att_ecode2str(status));
-		goto done;
-	}
-
-	if (!dec_write_resp(pdu, len)) {
-		error("Interval Write Request: protocol error");
-		goto done;
-	}
-
-	change_property(data->thermometer, "Interval", &data->interval);
-
-done:
-	g_free(user_data);
-}
-
-static DBusMessage *write_attr_interval(struct thermometer *t, DBusMessage *msg,
-								uint16_t value)
-{
-	struct tmp_interval_data *data;
-	struct characteristic *ch;
-	uint8_t atval[2];
-
-	if (t->attrib == NULL)
-		return btd_error_not_connected(msg);
-
-	ch = get_characteristic(t, MEASUREMENT_INTERVAL_UUID);
-	if (ch == NULL)
-		return btd_error_not_available(msg);
-
-	if (value < t->min || value > t->max)
-		return btd_error_invalid_args(msg);
-
-	att_put_u16(value, &atval[0]);
-
-	data = g_new0(struct tmp_interval_data, 1);
-	data->thermometer = t;
-	data->interval = value;
-	gatt_write_char(t->attrib, ch->attr.value_handle, atval, 2,
-						write_interval_cb, data);
-
-	return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
-								void *data)
-{
-	struct thermometer *t = data;
-	const char *property;
-	DBusMessageIter iter;
-	DBusMessageIter sub;
-	uint16_t value;
-
-	if (!dbus_message_iter_init(msg, &iter))
-		return btd_error_invalid_args(msg);
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-		return btd_error_invalid_args(msg);
-
-	dbus_message_iter_get_basic(&iter, &property);
-	if (g_strcmp0("Interval", property) != 0)
-		return btd_error_invalid_args(msg);
-
-	if (!t->has_interval)
-		return btd_error_not_available(msg);
-
-	dbus_message_iter_next(&iter);
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
-		return btd_error_invalid_args(msg);
-
-	dbus_message_iter_recurse(&iter, &sub);
-
-	if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)
-		return btd_error_invalid_args(msg);
-
-	dbus_message_iter_get_basic(&sub, &value);
-
-	return write_attr_interval(t, msg, value);
-}
-
-static void enable_final_measurement(struct thermometer *t)
-{
-	struct characteristic *ch;
-	struct descriptor *desc;
-	bt_uuid_t btuuid;
-	uint8_t atval[2];
-	char *msg;
-
-	if (t->attrib == NULL)
-		return;
-
-	ch = get_characteristic(t, TEMPERATURE_MEASUREMENT_UUID);
-	if (ch == NULL) {
-		DBG("Temperature measurement characteristic not found");
-		return;
-	}
-
-	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
-	desc = get_descriptor(ch, &btuuid);
-	if (desc == NULL) {
-		DBG("Client characteristic configuration descriptor not found");
-		return;
-	}
-
-	atval[0] = 0x02;
-	atval[1] = 0x00;
-	msg = g_strdup("Enable final measurement");
-	gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
-}
-
-static void enable_intermediate_measurement(struct thermometer *t)
-{
-	struct characteristic *ch;
-	struct descriptor *desc;
-	bt_uuid_t btuuid;
-	uint8_t atval[2];
-	char *msg;
-
-	if (t->attrib == NULL)
-		return;
-
-	ch = get_characteristic(t, INTERMEDIATE_TEMPERATURE_UUID);
-	if (ch == NULL) {
-		DBG("Intermediate measurement characteristic not found");
-		return;
-	}
-
-	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
-	desc = get_descriptor(ch, &btuuid);
-	if (desc == NULL) {
-		DBG("Client characteristic configuration descriptor not found");
-		return;
-	}
-
-	atval[0] = 0x01;
-	atval[1] = 0x00;
-	msg = g_strdup("Enable intermediate measurement");
-	gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
-}
-
-static void disable_final_measurement(struct thermometer *t)
-{
-	struct characteristic *ch;
-	struct descriptor *desc;
-	bt_uuid_t btuuid;
-	uint8_t atval[2];
-	char *msg;
-
-	if (t->attrib == NULL)
-		return;
-
-	ch = get_characteristic(t, TEMPERATURE_MEASUREMENT_UUID);
-	if (ch == NULL) {
-		DBG("Temperature measurement characteristic not found");
-		return;
-	}
-
-	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
-	desc = get_descriptor(ch, &btuuid);
-	if (desc == NULL) {
-		DBG("Client characteristic configuration descriptor not found");
-		return;
-	}
-
-	atval[0] = 0x00;
-	atval[1] = 0x00;
-	msg = g_strdup("Disable final measurement");
-	gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
-}
-
-static void disable_intermediate_measurement(struct thermometer *t)
-{
-	struct characteristic *ch;
-	struct descriptor *desc;
-	bt_uuid_t btuuid;
-	uint8_t atval[2];
-	char *msg;
-
-	if (t->attrib == NULL)
-		return;
-
-	ch = get_characteristic(t, INTERMEDIATE_TEMPERATURE_UUID);
-	if (ch == NULL) {
-		DBG("Intermediate measurement characteristic not found");
-		return;
-	}
-
-	bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
-	desc = get_descriptor(ch, &btuuid);
-	if (desc == NULL) {
-		DBG("Client characteristic configuration descriptor not found");
-		return;
-	}
-
-	atval[0] = 0x00;
-	atval[1] = 0x00;
-	msg = g_strdup("Disable intermediate measurement");
-	gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
-}
-
-static void remove_int_watcher(struct thermometer *t, struct watcher *w)
-{
-	if (!g_slist_find(t->iwatchers, w))
-		return;
-
-	t->iwatchers = g_slist_remove(t->iwatchers, w);
-
-	if (g_slist_length(t->iwatchers) == 0)
-		disable_intermediate_measurement(t);
-}
-
-static void watcher_exit(DBusConnection *conn, void *user_data)
-{
-	struct watcher *watcher = user_data;
-	struct thermometer *t = watcher->t;
-
-	DBG("Thermometer watcher %s disconnected", watcher->path);
-
-	remove_int_watcher(t, watcher);
-
-	t->fwatchers = g_slist_remove(t->fwatchers, watcher);
-	g_dbus_remove_watch(watcher->t->conn, watcher->id);
-
-	if (g_slist_length(t->fwatchers) == 0)
-		disable_final_measurement(t);
-}
-
-static struct watcher *find_watcher(GSList *list, const char *sender,
-							const char *path)
-{
-	struct watcher *match;
-	GSList *l;
-
-	match = g_new0(struct watcher, 1);
-	match->srv = g_strdup(sender);
-	match->path = g_strdup(path);
-
-	l = g_slist_find_custom(list, match, cmp_watcher);
-	destroy_watcher(match);
-
-	if (l != NULL)
-		return l->data;
-
-	return NULL;
-}
-
-static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
-								void *data)
-{
-	const char *sender = dbus_message_get_sender(msg);
-	struct thermometer *t = data;
-	struct watcher *watcher;
-	char *path;
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-							DBUS_TYPE_INVALID))
-		return btd_error_invalid_args(msg);
-
-	watcher = find_watcher(t->fwatchers, sender, path);
-	if (watcher != NULL)
-		return btd_error_already_exists(msg);
-
-	DBG("Thermometer watcher %s registered", path);
-
-	watcher = g_new0(struct watcher, 1);
-	watcher->srv = g_strdup(sender);
-	watcher->path = g_strdup(path);
-	watcher->t = t;
-	watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
-						watcher, destroy_watcher);
-
-	if (g_slist_length(t->fwatchers) == 0)
-		enable_final_measurement(t);
-
-	t->fwatchers = g_slist_prepend(t->fwatchers, watcher);
-
-	return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
-								void *data)
-{
-	const char *sender = dbus_message_get_sender(msg);
-	struct thermometer *t = data;
-	struct watcher *watcher;
-	char *path;
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-							DBUS_TYPE_INVALID))
-		return btd_error_invalid_args(msg);
-
-	watcher = find_watcher(t->fwatchers, sender, path);
-	if (watcher == NULL)
-		return btd_error_does_not_exist(msg);
-
-	DBG("Thermometer watcher %s unregistered", path);
-
-	remove_int_watcher(t, watcher);
-
-	t->fwatchers = g_slist_remove(t->fwatchers, watcher);
-	g_dbus_remove_watch(watcher->t->conn, watcher->id);
-
-	if (g_slist_length(t->fwatchers) == 0)
-		disable_final_measurement(t);
-
-	return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *enable_intermediate(DBusConnection *conn, DBusMessage *msg,
-								void *data)
-{
-	const char *sender = dbus_message_get_sender(msg);
-	struct thermometer *t = data;
-	struct watcher *watcher;
-	char *path;
-
-	if (!t->intermediate)
-		return btd_error_not_supported(msg);
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-							DBUS_TYPE_INVALID))
-		return btd_error_invalid_args(msg);
-
-	watcher = find_watcher(t->fwatchers, sender, path);
-	if (watcher == NULL)
-		return btd_error_does_not_exist(msg);
-
-	if (find_watcher(t->iwatchers, sender, path))
-		return btd_error_already_exists(msg);
-
-	DBG("Intermediate measurement watcher %s registered", path);
-
-	if (g_slist_length(t->iwatchers) == 0)
-		enable_intermediate_measurement(t);
-
-	t->iwatchers = g_slist_prepend(t->iwatchers, watcher);
-
-	return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *disable_intermediate(DBusConnection *conn, DBusMessage *msg,
-								void *data)
-{
-	const char *sender = dbus_message_get_sender(msg);
-	struct thermometer *t = data;
-	struct watcher *watcher;
-	char *path;
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-							DBUS_TYPE_INVALID))
-		return btd_error_invalid_args(msg);
-
-	watcher = find_watcher(t->iwatchers, sender, path);
-	if (watcher == NULL)
-		return btd_error_does_not_exist(msg);
-
-	DBG("Intermediate measurement %s unregistered", path);
-
-	remove_int_watcher(t, watcher);
-
-	return dbus_message_new_method_return(msg);
-}
-
-static const GDBusMethodTable thermometer_methods[] = {
-	{ GDBUS_METHOD("GetProperties",
-			NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
-			get_properties) },
-	{ GDBUS_ASYNC_METHOD("SetProperty",
-			GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
-			set_property) },
-	{ GDBUS_METHOD("RegisterWatcher",
-			GDBUS_ARGS({ "agent", "o" }), NULL,
-			register_watcher) },
-	{ GDBUS_METHOD("UnregisterWatcher",
-			GDBUS_ARGS({ "agent", "o" }), NULL,
-			unregister_watcher) },
-	{ GDBUS_METHOD("EnableIntermediateMeasurement",
-			GDBUS_ARGS({ "agent", "o" }), NULL,
-			enable_intermediate) },
-	{ GDBUS_METHOD("DisableIntermediateMeasurement",
-			GDBUS_ARGS({ "agent", "o" }), NULL,
-			disable_intermediate) },
-	{ }
-};
-
-static const GDBusSignalTable thermometer_signals[] = {
-	{ GDBUS_SIGNAL("PropertyChanged",
-			GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
-	{ }
-};
-
-static void update_watcher(gpointer data, gpointer user_data)
-{
-	struct watcher *w = data;
-	struct measurement *m = user_data;
-	DBusConnection *conn = w->t->conn;
-	DBusMessageIter iter;
-	DBusMessageIter dict;
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call(w->srv, w->path,
-				"org.bluez.ThermometerWatcher",
-				"MeasurementReceived");
-	if (msg == NULL)
-		return;
-
-	dbus_message_iter_init_append(msg, &iter);
-
-	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-	dict_append_entry(&dict, "Exponent", DBUS_TYPE_INT16, &m->exp);
-	dict_append_entry(&dict, "Mantissa", DBUS_TYPE_INT32, &m->mant);
-	dict_append_entry(&dict, "Unit", DBUS_TYPE_STRING, &m->unit);
-
-	if (m->suptime)
-		dict_append_entry(&dict, "Time", DBUS_TYPE_UINT64, &m->time);
-
-	dict_append_entry(&dict, "Type", DBUS_TYPE_STRING, &m->type);
-	dict_append_entry(&dict, "Measurement", DBUS_TYPE_STRING, &m->value);
-
-	dbus_message_iter_close_container(&iter, &dict);
-
-	dbus_message_set_no_reply(msg, TRUE);
-	g_dbus_send_message(conn, msg);
-}
-
-static void recv_measurement(struct thermometer *t, struct measurement *m)
-{
-	GSList *wlist;
-
-	if (g_strcmp0(m->value, "Intermediate") == 0)
-		wlist = t->iwatchers;
-	else
-		wlist = t->fwatchers;
-
-	g_slist_foreach(wlist, update_watcher, m);
-}
-
-static void proc_measurement(struct thermometer *t, const uint8_t *pdu,
-						uint16_t len, gboolean final)
-{
-	struct measurement m;
-	const char *type;
-	uint8_t flags;
-	uint32_t raw;
-
-	if (len < 4) {
-		DBG("Mandatory flags are not provided");
-		return;
-	}
-
-	flags = pdu[3];
-	if (flags & TEMP_UNITS)
-		m.unit = "Fahrenheit";
-	else
-		m.unit = "Celsius";
-
-	if (len < 8) {
-		DBG("Temperature measurement value is not provided");
-		return;
-	}
-
-	raw = att_get_u32(&pdu[4]);
-	m.mant = raw & 0x00FFFFFF;
-	m.exp = ((int32_t) raw) >> 24;
-
-	if (m.mant & 0x00800000) {
-		/* convert to C2 negative value */
-		m.mant = m.mant - FLOAT_MAX_MANTISSA;
-	}
-
-	if (flags & TEMP_TIME_STAMP) {
-		struct tm ts;
-		time_t time;
-
-		if (len < 15) {
-			DBG("Can't get time stamp value");
-			return;
-		}
-
-		ts.tm_year = att_get_u16(&pdu[8]) - 1900;
-		ts.tm_mon = pdu[10] - 1;
-		ts.tm_mday = pdu[11];
-		ts.tm_hour = pdu[12];
-		ts.tm_min = pdu[13];
-		ts.tm_sec = pdu[14];
-		ts.tm_isdst = -1;
-
-		time = mktime(&ts);
-		m.time = (uint64_t) time;
-		m.suptime = TRUE;
-	} else
-		m.suptime = FALSE;
-
-	if (flags & TEMP_TYPE) {
-		uint8_t index;
-
-		if (m.suptime && len >= 16)
-			index = 15;
-		else if (!m.suptime && len >= 9)
-			index = 9;
-		else {
-			DBG("Can't get temperature type");
-			return;
-		}
-
-		type = temptype2str(pdu[index]);
-	} else if (t->has_type)
-		type = temptype2str(t->type);
-	else
-		type = NULL;
-
-	m.type = type ? g_strdup(type) : NULL;
-	m.value = final ? "Final" : "Intermediate";
-
-	recv_measurement(t, &m);
-	g_free(m.type);
-}
-
-static void proc_measurement_interval(struct thermometer *t, const uint8_t *pdu,
-								uint16_t len)
-{
-	uint16_t interval;
-
-	if (len < 5) {
-		DBG("Measurement interval value is not provided");
-		return;
-	}
-
-	interval = att_get_u16(&pdu[3]);
-
-	change_property(t, "Interval", &interval);
-}
-
-static void ind_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
-{
-	struct thermometer *t = user_data;
-	const struct characteristic *ch;
-	uint8_t *opdu;
-	uint16_t handle, olen;
-	GSList *l;
-	int plen;
-
-	if (len < 3) {
-		DBG("Bad pdu received");
-		return;
-	}
-
-	handle = att_get_u16(&pdu[1]);
-	l = g_slist_find_custom(t->chars, &handle, cmp_char_val_handle);
-	if (l == NULL) {
-		DBG("Unexpected handle: 0x%04x", handle);
-		return;
-	}
-
-	ch = l->data;
-
-	if (g_strcmp0(ch->attr.uuid, TEMPERATURE_MEASUREMENT_UUID) == 0)
-		proc_measurement(t, pdu, len, TRUE);
-	else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
-		proc_measurement_interval(t, pdu, len);
-
-	opdu = g_attrib_get_buffer(t->attrib, &plen);
-	olen = enc_confirmation(opdu, plen);
-
-	if (olen > 0)
-		g_attrib_send(t->attrib, 0, opdu[0], opdu, olen, NULL, NULL,
-									NULL);
-}
-
-static void notif_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
-{
-	struct thermometer *t = user_data;
-	const struct characteristic *ch;
-	uint16_t handle;
-	GSList *l;
-
-	if (len < 3) {
-		DBG("Bad pdu received");
-		return;
-	}
-
-	handle = att_get_u16(&pdu[1]);
-	l = g_slist_find_custom(t->chars, &handle, cmp_char_val_handle);
-	if (l == NULL) {
-		DBG("Unexpected handle: 0x%04x", handle);
-		return;
-	}
-
-	ch = l->data;
-	if (g_strcmp0(ch->attr.uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0)
-		proc_measurement(t, pdu, len, FALSE);
-}
-
-static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
-{
-	struct thermometer *t = user_data;
-
-	t->attrib = g_attrib_ref(attrib);
-
-	t->attindid = g_attrib_register(t->attrib, ATT_OP_HANDLE_IND,
-							ind_handler, t, NULL);
-	t->attnotid = g_attrib_register(t->attrib, ATT_OP_HANDLE_NOTIFY,
-							notif_handler, t, NULL);
-	gatt_discover_char(t->attrib, t->svc_range->start, t->svc_range->end,
-					NULL, configure_thermometer_cb, t);
-}
-
-static void attio_disconnected_cb(gpointer user_data)
-{
-	struct thermometer *t = user_data;
-
-	DBG("GATT Disconnected");
-
-	if (t->attindid > 0) {
-		g_attrib_unregister(t->attrib, t->attindid);
-		t->attindid = 0;
-	}
-
-	if (t->attnotid > 0) {
-		g_attrib_unregister(t->attrib, t->attnotid);
-		t->attnotid = 0;
-	}
-
-	g_attrib_unref(t->attrib);
-	t->attrib = NULL;
-}
-
-int thermometer_register(DBusConnection *connection, struct btd_device *device,
-						struct gatt_primary *tattr)
-{
-	const gchar *path = device_get_path(device);
-	struct thermometer *t;
-
-	t = g_new0(struct thermometer, 1);
-	t->conn = dbus_connection_ref(connection);
-	t->dev = btd_device_ref(device);
-	t->svc_range = g_new0(struct att_range, 1);
-	t->svc_range->start = tattr->range.start;
-	t->svc_range->end = tattr->range.end;
-
-	if (!g_dbus_register_interface(t->conn, path, THERMOMETER_INTERFACE,
-				thermometer_methods, thermometer_signals,
-				NULL, t, destroy_thermometer)) {
-		error("D-Bus failed to register %s interface",
-							THERMOMETER_INTERFACE);
-		destroy_thermometer(t);
-		return -EIO;
-	}
-
-	thermometers = g_slist_prepend(thermometers, t);
-
-	t->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
-						attio_disconnected_cb, t);
-	return 0;
-}
-
-void thermometer_unregister(struct btd_device *device)
-{
-	struct thermometer *t;
-	GSList *l;
-
-	l = g_slist_find_custom(thermometers, device, cmp_device);
-	if (l == NULL)
-		return;
-
-	t = l->data;
-	thermometers = g_slist_remove(thermometers, t);
-	g_dbus_unregister_interface(t->conn, device_get_path(t->dev),
-							THERMOMETER_INTERFACE);
-}
diff --git a/thermometer/thermometer.h b/thermometer/thermometer.h
deleted file mode 100644
index 330503c..0000000
--- a/thermometer/thermometer.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-int thermometer_register(DBusConnection *connection, struct btd_device *device,
-						struct gatt_primary *tattr);
-void thermometer_unregister(struct btd_device *device);
-- 
1.7.10.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH -v3 13/19] time: move to the profiles folder
  2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
                   ` (9 preceding siblings ...)
  2012-07-04 12:51 ` [PATCH -v3 12/19] thermometer: move to the " Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 16/19] serial: move it " Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 18/19] cups: move it to " Gustavo Padovan
  12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

---
 Makefile.am            |    3 +-
 profiles/time/main.c   |   58 ++++++++++++++++++
 profiles/time/server.c |  154 ++++++++++++++++++++++++++++++++++++++++++++++++
 profiles/time/server.h |   26 ++++++++
 time/main.c            |   58 ------------------
 time/server.c          |  154 ------------------------------------------------
 time/server.h          |   26 --------
 7 files changed, 240 insertions(+), 239 deletions(-)
 create mode 100644 profiles/time/main.c
 create mode 100644 profiles/time/server.c
 create mode 100644 profiles/time/server.h
 delete mode 100644 time/main.c
 delete mode 100644 time/server.c
 delete mode 100644 time/server.h

diff --git a/Makefile.am b/Makefile.am
index b816e20..3a5f616 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -224,7 +224,8 @@ builtin_sources += profiles/thermometer/main.c \
 		       	profiles/thermometer/thermometer.c \
 			profiles/alert/main.c profiles/alert/server.h \
 			profiles/alert/server.c \
-			time/main.c time/server.h time/server.c \
+			profiles/time/main.c profiles/time/server.h \
+			profiles/time/server.c \
 			plugins/gatt-example.c \
 			profiles/proximity/main.c profiles/proximity/manager.h \
 		       	profiles/proximity/manager.c \
diff --git a/profiles/time/main.c b/profiles/time/main.c
new file mode 100644
index 0000000..d876725
--- /dev/null
+++ b/profiles/time/main.c
@@ -0,0 +1,58 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <glib.h>
+#include <errno.h>
+
+#include "plugin.h"
+#include "hcid.h"
+#include "log.h"
+#include "server.h"
+
+static int time_init(void)
+{
+	if (!main_opts.gatt_enabled) {
+		DBG("GATT is disabled");
+		return -ENOTSUP;
+	}
+
+	return time_server_init();
+}
+
+static void time_exit(void)
+{
+	if (!main_opts.gatt_enabled)
+		return;
+
+	time_server_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(time, VERSION,
+			BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+			time_init, time_exit)
diff --git a/profiles/time/server.c b/profiles/time/server.c
new file mode 100644
index 0000000..13a7bbe
--- /dev/null
+++ b/profiles/time/server.c
@@ -0,0 +1,154 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <time.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+#include <adapter.h>
+
+#include "gattrib.h"
+#include "att.h"
+#include "gatt.h"
+#include "att-database.h"
+#include "attrib-server.h"
+#include "gatt-service.h"
+#include "log.h"
+#include "server.h"
+
+#define CURRENT_TIME_SVC_UUID		0x1805
+
+#define LOCAL_TIME_INFO_CHR_UUID	0x2A0F
+#define CT_TIME_CHR_UUID		0x2A2B
+
+static int encode_current_time(uint8_t value[10])
+{
+	struct timespec tp;
+	struct tm tm;
+
+	if (clock_gettime(CLOCK_REALTIME, &tp) == -1) {
+		int err = -errno;
+
+		error("clock_gettime: %s", strerror(-err));
+		return err;
+	}
+
+	if (localtime_r(&tp.tv_sec, &tm) == NULL) {
+		error("localtime_r() failed");
+		/* localtime_r() does not set errno */
+		return -EINVAL;
+	}
+
+	att_put_u16(1900 + tm.tm_year, &value[0]); /* Year */
+	value[2] = tm.tm_mon + 1; /* Month */
+	value[3] = tm.tm_mday; /* Day */
+	value[4] = tm.tm_hour; /* Hours */
+	value[5] = tm.tm_min; /* Minutes */
+	value[6] = tm.tm_sec; /* Seconds */
+	value[7] = tm.tm_wday == 0 ? 7 : tm.tm_wday; /* Day of Week */
+	/* From Time Profile spec: "The number of 1/256 fractions of a second."
+	 * In 1s there are 256 fractions, in 1ns there are 256/10^9 fractions.
+	 * To avoid integer overflow, we use the equivalent 1/3906250 ratio. */
+	value[8] = tp.tv_nsec / 3906250; /* Fractions256 */
+	value[9] = 0x00; /* Adjust Reason */
+
+	return 0;
+}
+
+static uint8_t current_time_read(struct attribute *a,
+				 struct btd_device *device, gpointer user_data)
+{
+	uint8_t value[10];
+
+	if (encode_current_time(value) < 0)
+		return ATT_ECODE_IO;
+
+	/* FIXME: Provide the adapter in next function */
+	attrib_db_update(NULL, a->handle, NULL, value, sizeof(value), NULL);
+
+	return 0;
+}
+
+static uint8_t local_time_info_read(struct attribute *a,
+				struct btd_device *device, gpointer user_data)
+{
+	uint8_t value[2];
+
+	DBG("a=%p", a);
+
+	tzset();
+
+	/* FIXME: POSIX "daylight" variable only indicates whether there is DST
+	 * for the local time or not. The offset is unknown. */
+	value[0] = daylight ? 0xff : 0x00;
+
+	/* Convert POSIX "timezone" (seconds West of GMT) to Time Profile
+	 * format (offset from UTC in number of 15 minutes increments). */
+	value[1] = (uint8_t) (-1 * timezone / (60 * 15));
+
+	/* FIXME: Provide the adapter in next function */
+	attrib_db_update(NULL, a->handle, NULL, value, sizeof(value), NULL);
+
+	return 0;
+}
+
+static void register_current_time_service(void)
+{
+	bt_uuid_t uuid;
+
+	bt_uuid16_create(&uuid, CURRENT_TIME_SVC_UUID);
+
+	/* Current Time service */
+	/* FIXME: Provide the adapter in next function */
+	gatt_service_add(NULL, GATT_PRIM_SVC_UUID, &uuid,
+				/* CT Time characteristic */
+				GATT_OPT_CHR_UUID, CT_TIME_CHR_UUID,
+				GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
+							ATT_CHAR_PROPER_NOTIFY,
+				GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+						current_time_read, NULL,
+
+				/* Local Time Information characteristic */
+				GATT_OPT_CHR_UUID, LOCAL_TIME_INFO_CHR_UUID,
+				GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
+				GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+						local_time_info_read, NULL,
+
+				GATT_OPT_INVALID);
+}
+
+int time_server_init(void)
+{
+	register_current_time_service();
+
+	return 0;
+}
+
+void time_server_exit(void)
+{
+}
diff --git a/profiles/time/server.h b/profiles/time/server.h
new file mode 100644
index 0000000..621bf2b
--- /dev/null
+++ b/profiles/time/server.h
@@ -0,0 +1,26 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int time_server_init(void);
+void time_server_exit(void);
diff --git a/time/main.c b/time/main.c
deleted file mode 100644
index d876725..0000000
--- a/time/main.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  Nokia Corporation
- *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdint.h>
-#include <glib.h>
-#include <errno.h>
-
-#include "plugin.h"
-#include "hcid.h"
-#include "log.h"
-#include "server.h"
-
-static int time_init(void)
-{
-	if (!main_opts.gatt_enabled) {
-		DBG("GATT is disabled");
-		return -ENOTSUP;
-	}
-
-	return time_server_init();
-}
-
-static void time_exit(void)
-{
-	if (!main_opts.gatt_enabled)
-		return;
-
-	time_server_exit();
-}
-
-BLUETOOTH_PLUGIN_DEFINE(time, VERSION,
-			BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
-			time_init, time_exit)
diff --git a/time/server.c b/time/server.c
deleted file mode 100644
index 13a7bbe..0000000
--- a/time/server.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  Nokia Corporation
- *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-#include <time.h>
-#include <errno.h>
-#include <bluetooth/uuid.h>
-#include <adapter.h>
-
-#include "gattrib.h"
-#include "att.h"
-#include "gatt.h"
-#include "att-database.h"
-#include "attrib-server.h"
-#include "gatt-service.h"
-#include "log.h"
-#include "server.h"
-
-#define CURRENT_TIME_SVC_UUID		0x1805
-
-#define LOCAL_TIME_INFO_CHR_UUID	0x2A0F
-#define CT_TIME_CHR_UUID		0x2A2B
-
-static int encode_current_time(uint8_t value[10])
-{
-	struct timespec tp;
-	struct tm tm;
-
-	if (clock_gettime(CLOCK_REALTIME, &tp) == -1) {
-		int err = -errno;
-
-		error("clock_gettime: %s", strerror(-err));
-		return err;
-	}
-
-	if (localtime_r(&tp.tv_sec, &tm) == NULL) {
-		error("localtime_r() failed");
-		/* localtime_r() does not set errno */
-		return -EINVAL;
-	}
-
-	att_put_u16(1900 + tm.tm_year, &value[0]); /* Year */
-	value[2] = tm.tm_mon + 1; /* Month */
-	value[3] = tm.tm_mday; /* Day */
-	value[4] = tm.tm_hour; /* Hours */
-	value[5] = tm.tm_min; /* Minutes */
-	value[6] = tm.tm_sec; /* Seconds */
-	value[7] = tm.tm_wday == 0 ? 7 : tm.tm_wday; /* Day of Week */
-	/* From Time Profile spec: "The number of 1/256 fractions of a second."
-	 * In 1s there are 256 fractions, in 1ns there are 256/10^9 fractions.
-	 * To avoid integer overflow, we use the equivalent 1/3906250 ratio. */
-	value[8] = tp.tv_nsec / 3906250; /* Fractions256 */
-	value[9] = 0x00; /* Adjust Reason */
-
-	return 0;
-}
-
-static uint8_t current_time_read(struct attribute *a,
-				 struct btd_device *device, gpointer user_data)
-{
-	uint8_t value[10];
-
-	if (encode_current_time(value) < 0)
-		return ATT_ECODE_IO;
-
-	/* FIXME: Provide the adapter in next function */
-	attrib_db_update(NULL, a->handle, NULL, value, sizeof(value), NULL);
-
-	return 0;
-}
-
-static uint8_t local_time_info_read(struct attribute *a,
-				struct btd_device *device, gpointer user_data)
-{
-	uint8_t value[2];
-
-	DBG("a=%p", a);
-
-	tzset();
-
-	/* FIXME: POSIX "daylight" variable only indicates whether there is DST
-	 * for the local time or not. The offset is unknown. */
-	value[0] = daylight ? 0xff : 0x00;
-
-	/* Convert POSIX "timezone" (seconds West of GMT) to Time Profile
-	 * format (offset from UTC in number of 15 minutes increments). */
-	value[1] = (uint8_t) (-1 * timezone / (60 * 15));
-
-	/* FIXME: Provide the adapter in next function */
-	attrib_db_update(NULL, a->handle, NULL, value, sizeof(value), NULL);
-
-	return 0;
-}
-
-static void register_current_time_service(void)
-{
-	bt_uuid_t uuid;
-
-	bt_uuid16_create(&uuid, CURRENT_TIME_SVC_UUID);
-
-	/* Current Time service */
-	/* FIXME: Provide the adapter in next function */
-	gatt_service_add(NULL, GATT_PRIM_SVC_UUID, &uuid,
-				/* CT Time characteristic */
-				GATT_OPT_CHR_UUID, CT_TIME_CHR_UUID,
-				GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
-							ATT_CHAR_PROPER_NOTIFY,
-				GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
-						current_time_read, NULL,
-
-				/* Local Time Information characteristic */
-				GATT_OPT_CHR_UUID, LOCAL_TIME_INFO_CHR_UUID,
-				GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
-				GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
-						local_time_info_read, NULL,
-
-				GATT_OPT_INVALID);
-}
-
-int time_server_init(void)
-{
-	register_current_time_service();
-
-	return 0;
-}
-
-void time_server_exit(void)
-{
-}
diff --git a/time/server.h b/time/server.h
deleted file mode 100644
index 621bf2b..0000000
--- a/time/server.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  Nokia Corporation
- *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-int time_server_init(void);
-void time_server_exit(void);
-- 
1.7.10.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH -v3 16/19] serial: move it to the profiles folder
  2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
                   ` (10 preceding siblings ...)
  2012-07-04 12:51 ` [PATCH -v3 13/19] time: " Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
  2012-07-04 12:51 ` [PATCH -v3 18/19] cups: move it to " Gustavo Padovan
  12 siblings, 0 replies; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

---
 Makefile.am                 |    8 +-
 profiles/serial/main.c      |   59 ++++++
 profiles/serial/manager.c   |  127 ++++++++++++
 profiles/serial/manager.h   |   25 +++
 profiles/serial/port.c      |  452 +++++++++++++++++++++++++++++++++++++++++++
 profiles/serial/port.h      |   29 +++
 profiles/serial/serial.conf |   10 +
 serial/main.c               |   59 ------
 serial/manager.c            |  127 ------------
 serial/manager.h            |   25 ---
 serial/port.c               |  452 -------------------------------------------
 serial/port.h               |   29 ---
 serial/serial.conf          |   10 -
 13 files changed, 706 insertions(+), 706 deletions(-)
 create mode 100644 profiles/serial/main.c
 create mode 100644 profiles/serial/manager.c
 create mode 100644 profiles/serial/manager.h
 create mode 100644 profiles/serial/port.c
 create mode 100644 profiles/serial/port.h
 create mode 100644 profiles/serial/serial.conf
 delete mode 100644 serial/main.c
 delete mode 100644 serial/manager.c
 delete mode 100644 serial/manager.h
 delete mode 100644 serial/port.c
 delete mode 100644 serial/port.h
 delete mode 100644 serial/serial.conf

diff --git a/Makefile.am b/Makefile.am
index a0d99f8..3807a42 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -188,9 +188,9 @@ endif
 
 if SERIALPLUGIN
 builtin_modules += serial
-builtin_sources += serial/main.c \
-			serial/manager.h serial/manager.c \
-			serial/port.h serial/port.c
+builtin_sources += profiles/serial/main.c \
+			profiles/serial/manager.h profiles/serial/manager.c \
+			profiles/serial/port.h profiles/serial/port.c
 endif
 
 if NETWORKPLUGIN
@@ -337,7 +337,7 @@ endif
 
 EXTRA_DIST += src/genbuiltin src/bluetooth.conf src/org.bluez.service \
 			src/main.conf network/network.conf \
-			profiles/input/input.conf serial/serial.conf \
+			profiles/input/input.conf profiles/serial/serial.conf \
 			audio/audio.conf audio/telephony-dummy.c \
 			audio/telephony-maemo5.c audio/telephony-ofono.c \
 			audio/telephony-maemo6.c sap/sap-dummy.c sap/sap-u8500.c \
diff --git a/profiles/serial/main.c b/profiles/serial/main.c
new file mode 100644
index 0000000..38ded03
--- /dev/null
+++ b/profiles/serial/main.c
@@ -0,0 +1,59 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <gdbus.h>
+
+#include "plugin.h"
+#include "manager.h"
+
+static DBusConnection *connection;
+
+static int serial_init(void)
+{
+	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+	if (connection == NULL)
+		return -EIO;
+
+	if (serial_manager_init(connection) < 0) {
+		dbus_connection_unref(connection);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void serial_exit(void)
+{
+	serial_manager_exit();
+
+	dbus_connection_unref(connection);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(serial, VERSION,
+			BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, serial_init, serial_exit)
diff --git a/profiles/serial/manager.c b/profiles/serial/manager.c
new file mode 100644
index 0000000..6f3fc1f
--- /dev/null
+++ b/profiles/serial/manager.c
@@ -0,0 +1,127 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
+
+#include <gdbus.h>
+
+#include "adapter.h"
+#include "device.h"
+
+#include "log.h"
+
+#include "port.h"
+#include "manager.h"
+
+static DBusConnection *connection = NULL;
+
+static int serial_probe(struct btd_device *device, const char *uuid)
+{
+	struct btd_adapter *adapter = device_get_adapter(device);
+	const gchar *path = device_get_path(device);
+	sdp_list_t *protos;
+	int ch;
+	bdaddr_t src, dst;
+	const sdp_record_t *rec;
+
+	DBG("path %s: %s", path, uuid);
+
+	rec = btd_device_get_record(device, uuid);
+	if (!rec)
+		return -EINVAL;
+
+	if (sdp_get_access_protos(rec, &protos) < 0)
+		return -EINVAL;
+
+	ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+	sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+	sdp_list_free(protos, NULL);
+
+	if (ch < 1 || ch > 30) {
+		error("Channel out of range: %d", ch);
+		return -EINVAL;
+	}
+
+	adapter_get_address(adapter, &src);
+	device_get_address(device, &dst, NULL);
+
+	return port_register(connection, path, &src, &dst, uuid, ch);
+}
+
+static void serial_remove(struct btd_device *device)
+{
+	const gchar *path = device_get_path(device);
+
+	DBG("path %s", path);
+
+	port_unregister(path);
+}
+
+
+static int port_probe(struct btd_device *device, GSList *uuids)
+{
+	while (uuids) {
+		serial_probe(device, uuids->data);
+		uuids = uuids->next;
+	}
+
+	return 0;
+}
+
+static void port_remove(struct btd_device *device)
+{
+	return serial_remove(device);
+}
+
+static struct btd_device_driver serial_port_driver = {
+	.name	= "serial-port",
+	.uuids	= BTD_UUIDS(RFCOMM_UUID_STR),
+	.probe	= port_probe,
+	.remove	= port_remove,
+};
+
+int serial_manager_init(DBusConnection *conn)
+{
+	connection = dbus_connection_ref(conn);
+
+	btd_register_device_driver(&serial_port_driver);
+
+	return 0;
+}
+
+void serial_manager_exit(void)
+{
+	btd_unregister_device_driver(&serial_port_driver);
+
+	dbus_connection_unref(connection);
+	connection = NULL;
+}
diff --git a/profiles/serial/manager.h b/profiles/serial/manager.h
new file mode 100644
index 0000000..c8b96e8
--- /dev/null
+++ b/profiles/serial/manager.h
@@ -0,0 +1,25 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int serial_manager_init(DBusConnection *conn);
+void serial_manager_exit(void);
diff --git a/profiles/serial/port.c b/profiles/serial/port.c
new file mode 100644
index 0000000..f2b7184
--- /dev/null
+++ b/profiles/serial/port.c
@@ -0,0 +1,452 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "log.h"
+#include "glib-helper.h"
+#include "sdp-client.h"
+#include "btio.h"
+
+#include "error.h"
+#include "manager.h"
+#include "adapter.h"
+#include "device.h"
+#include "storage.h"
+#include "port.h"
+
+#define SERIAL_PORT_INTERFACE	"org.bluez.Serial"
+
+#define MAX_OPEN_TRIES		5
+#define OPEN_WAIT		300	/* ms. udev node creation retry wait */
+
+struct serial_device {
+	DBusConnection	*conn;		/* for name listener handling */
+	bdaddr_t	src;		/* Source (local) address */
+	bdaddr_t	dst;		/* Destination address */
+	char		*path;		/* Device path */
+	GSList		*ports;		/* Available ports */
+};
+
+struct serial_port {
+	DBusMessage	*msg;		/* for name listener handling */
+	int16_t		id;		/* RFCOMM device id */
+	uint8_t		channel;	/* RFCOMM channel */
+	char		*uuid;		/* service identification */
+	GIOChannel	*io;		/* BtIO channel */
+	guint		listener_id;
+	struct serial_device *device;
+};
+
+static GSList *devices = NULL;
+
+static struct serial_device *find_device(GSList *devices, const char *path)
+{
+	GSList *l;
+
+	for (l = devices; l != NULL; l = l->next) {
+		struct serial_device *device = l->data;
+
+		if (!strcmp(device->path, path))
+			return device;
+	}
+
+	return NULL;
+}
+
+static struct serial_port *find_port(GSList *ports, const char *pattern)
+{
+	GSList *l;
+	int channel;
+	char *endptr = NULL;
+
+	channel = strtol(pattern, &endptr, 10);
+
+	for (l = ports; l != NULL; l = l->next) {
+		struct serial_port *port = l->data;
+		char *uuid_str;
+		int ret;
+
+		if (port->uuid && !strcasecmp(port->uuid, pattern))
+			return port;
+
+		if (endptr && *endptr == '\0' && port->channel == channel)
+			return port;
+
+		if (!port->uuid)
+			continue;
+
+		uuid_str = bt_name2string(pattern);
+		if (!uuid_str)
+			continue;
+
+		ret = strcasecmp(port->uuid, uuid_str);
+		g_free(uuid_str);
+		if (ret == 0)
+			return port;
+	}
+
+	return NULL;
+}
+
+static void port_release(struct serial_port *port)
+{
+	if (port->id < 0) {
+		if (port->io) {
+			g_io_channel_shutdown(port->io, TRUE, NULL);
+			g_io_channel_unref(port->io);
+			port->io = NULL;
+		} else
+			bt_cancel_discovery(&port->device->src,
+						&port->device->dst);
+
+	}
+}
+
+static void serial_port_free(void *data)
+{
+	struct serial_port *port = data;
+	struct serial_device *device = port->device;
+
+	if (device && port->listener_id > 0)
+		g_dbus_remove_watch(device->conn, port->listener_id);
+
+	port_release(port);
+
+	g_free(port->uuid);
+	g_free(port);
+}
+
+static void serial_device_free(void *data)
+{
+	struct serial_device *device = data;
+
+	g_free(device->path);
+	if (device->conn)
+		dbus_connection_unref(device->conn);
+	g_free(device);
+}
+
+static void port_owner_exited(DBusConnection *conn, void *user_data)
+{
+	struct serial_port *port = user_data;
+
+	port_release(port);
+
+	port->listener_id = 0;
+}
+
+static void path_unregister(void *data)
+{
+	struct serial_device *device = data;
+
+	DBG("Unregistered interface %s on path %s", SERIAL_PORT_INTERFACE,
+		device->path);
+
+	devices = g_slist_remove(devices, device);
+	serial_device_free(device);
+}
+
+void port_release_all(void)
+{
+	g_slist_free_full(devices, serial_device_free);
+}
+
+static void rfcomm_connect_cb(GIOChannel *chan, GError *conn_err,
+							gpointer user_data)
+{
+	struct serial_port *port = user_data;
+	struct serial_device *device = port->device;
+	int sk;
+	DBusMessage *reply;
+
+	/* Owner exited? */
+	if (!port->listener_id)
+		return;
+
+	if (conn_err) {
+		error("%s", conn_err->message);
+		reply = btd_error_failed(port->msg, conn_err->message);
+		g_dbus_send_message(device->conn, reply);
+		goto fail;
+	}
+
+	sk = g_io_channel_unix_get_fd(chan);
+	reply = g_dbus_create_reply(port->msg, DBUS_TYPE_UNIX_FD, &sk,
+						DBUS_TYPE_INVALID);
+	g_dbus_send_message(device->conn, reply);
+
+	close(sk);
+
+fail:
+	g_dbus_remove_watch(device->conn, port->listener_id);
+	port->listener_id = 0;
+}
+
+static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
+{
+	struct serial_port *port = user_data;
+	struct serial_device *device = port->device;
+	sdp_record_t *record = NULL;
+	sdp_list_t *protos;
+	DBusMessage *reply;
+	GError *gerr = NULL;
+
+	if (!port->listener_id)
+		return;
+
+	if (err < 0) {
+		error("Unable to get service record: %s (%d)", strerror(-err),
+			-err);
+		reply = btd_error_failed(port->msg, strerror(-err));
+		goto failed;
+	}
+
+	if (!recs || !recs->data) {
+		error("No record found");
+		reply = btd_error_failed(port->msg, "No record found");
+		goto failed;
+	}
+
+	record = recs->data;
+
+	if (sdp_get_access_protos(record, &protos) < 0) {
+		error("Unable to get access protos from port record");
+		reply = btd_error_failed(port->msg, "Invalid channel");
+		goto failed;
+	}
+
+	port->channel = sdp_get_proto_port(protos, RFCOMM_UUID);
+
+	sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+	sdp_list_free(protos, NULL);
+
+	port->io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, port,
+				NULL, &gerr,
+				BT_IO_OPT_SOURCE_BDADDR, &device->src,
+				BT_IO_OPT_DEST_BDADDR, &device->dst,
+				BT_IO_OPT_CHANNEL, port->channel,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+				BT_IO_OPT_INVALID);
+	if (!port->io) {
+		error("%s", gerr->message);
+		reply = btd_error_failed(port->msg, gerr->message);
+		g_error_free(gerr);
+		goto failed;
+	}
+
+	return;
+
+failed:
+	g_dbus_remove_watch(device->conn, port->listener_id);
+	port->listener_id = 0;
+	g_dbus_send_message(device->conn, reply);
+}
+
+static int connect_port(struct serial_port *port)
+{
+	struct serial_device *device = port->device;
+	uuid_t uuid;
+	int err;
+
+	if (!port->uuid)
+		goto connect;
+
+	err = bt_string2uuid(&uuid, port->uuid);
+	if (err < 0)
+		return err;
+
+	sdp_uuid128_to_uuid(&uuid);
+
+	return bt_search_service(&device->src, &device->dst, &uuid,
+				get_record_cb, port, NULL);
+
+connect:
+	port->io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, port,
+				NULL, NULL,
+				BT_IO_OPT_SOURCE_BDADDR, &device->src,
+				BT_IO_OPT_DEST_BDADDR, &device->dst,
+				BT_IO_OPT_CHANNEL, port->channel,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+				BT_IO_OPT_INVALID);
+	if (port->io == NULL)
+		return -EIO;
+
+	return 0;
+}
+
+static struct serial_port *create_port(struct serial_device *device,
+					const char *uuid, uint8_t channel)
+{
+	struct serial_port *port;
+
+	port = g_new0(struct serial_port, 1);
+	port->uuid = g_strdup(uuid);
+	port->channel = channel;
+	port->device = device;
+	port->id = -1;
+
+	device->ports = g_slist_append(device->ports, port);
+
+	return port;
+}
+
+static DBusMessage *port_connect(DBusConnection *conn,
+					DBusMessage *msg, void *user_data)
+{
+	struct serial_device *device = user_data;
+	struct serial_port *port;
+	const char *pattern;
+	int err;
+
+	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
+						DBUS_TYPE_INVALID) == FALSE)
+		return NULL;
+
+	port = find_port(device->ports, pattern);
+	if (!port) {
+		char *endptr = NULL;
+		int channel;
+
+		channel = strtol(pattern, &endptr, 10);
+		if ((endptr && *endptr != '\0') || channel < 1 || channel > 30)
+			return btd_error_does_not_exist(msg);
+
+		port = create_port(device, NULL, channel);
+	}
+
+	if (port->listener_id)
+		return btd_error_failed(msg, "Port already in use");
+
+	port->listener_id = g_dbus_add_disconnect_watch(conn,
+						dbus_message_get_sender(msg),
+						port_owner_exited, port,
+						NULL);
+
+	port->msg = dbus_message_ref(msg);
+
+	err = connect_port(port);
+	if (err < 0) {
+		error("%s", strerror(-err));
+		g_dbus_remove_watch(conn, port->listener_id);
+		port->listener_id = 0;
+
+		return btd_error_failed(msg, strerror(-err));
+	}
+
+	return NULL;
+}
+
+static const GDBusMethodTable port_methods[] = {
+	{ GDBUS_ASYNC_METHOD("Connect",
+		GDBUS_ARGS({ "pattern", "s" }),	GDBUS_ARGS({ "fd", "s" }),
+		port_connect) },
+	{ }
+};
+
+static struct serial_device *create_serial_device(DBusConnection *conn,
+					const char *path, bdaddr_t *src,
+					bdaddr_t *dst)
+{
+	struct serial_device *device;
+
+	device = g_new0(struct serial_device, 1);
+	device->conn = dbus_connection_ref(conn);
+	bacpy(&device->dst, dst);
+	bacpy(&device->src, src);
+	device->path = g_strdup(path);
+
+	if (!g_dbus_register_interface(conn, path,
+				SERIAL_PORT_INTERFACE,
+				port_methods, NULL, NULL,
+				device, path_unregister)) {
+		error("D-Bus failed to register %s interface",
+				SERIAL_PORT_INTERFACE);
+		serial_device_free(device);
+		return NULL;
+	}
+
+	DBG("Registered interface %s on path %s",
+		SERIAL_PORT_INTERFACE, path);
+
+	return device;
+}
+
+int port_register(DBusConnection *conn, const char *path, bdaddr_t *src,
+			bdaddr_t *dst, const char *uuid, uint8_t channel)
+{
+	struct serial_device *device;
+	struct serial_port *port;
+
+	device = find_device(devices, path);
+	if (!device) {
+		device = create_serial_device(conn, path, src, dst);
+		if (!device)
+			return -1;
+		devices = g_slist_append(devices, device);
+	}
+
+	if (find_port(device->ports, uuid))
+		return 0;
+
+	port = g_new0(struct serial_port, 1);
+	port->uuid = g_strdup(uuid);
+	port->channel = channel;
+	port->device = device;
+	port->id = -1;
+
+	device->ports = g_slist_append(device->ports, port);
+
+	return 0;
+}
+
+int port_unregister(const char *path)
+{
+	struct serial_device *device;
+
+	device = find_device(devices, path);
+	if (!device)
+		return -ENOENT;
+
+	g_slist_free_full(device->ports, serial_port_free);
+
+	g_dbus_unregister_interface(device->conn, path, SERIAL_PORT_INTERFACE);
+
+	return 0;
+}
diff --git a/profiles/serial/port.h b/profiles/serial/port.h
new file mode 100644
index 0000000..74ac9f0
--- /dev/null
+++ b/profiles/serial/port.h
@@ -0,0 +1,29 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+void port_release_all(void);
+
+int port_register(DBusConnection *conn, const char *path, bdaddr_t *src,
+		  bdaddr_t *dst, const char *name, uint8_t channel);
+
+int port_unregister(const char *path);
diff --git a/profiles/serial/serial.conf b/profiles/serial/serial.conf
new file mode 100644
index 0000000..43ee6af
--- /dev/null
+++ b/profiles/serial/serial.conf
@@ -0,0 +1,10 @@
+# Configuration file for serial
+
+# There could be multiple proxy sections, the format is [Proxy <user chosen name>]
+#[Proxy DUN]
+
+# UUID for DUN proxy service
+#UUID=00001103-0000-1000-8000-00805F9B34FB
+
+# Address for device node
+#Address=/dev/ttyx
diff --git a/serial/main.c b/serial/main.c
deleted file mode 100644
index 38ded03..0000000
--- a/serial/main.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-
-#include <gdbus.h>
-
-#include "plugin.h"
-#include "manager.h"
-
-static DBusConnection *connection;
-
-static int serial_init(void)
-{
-	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-	if (connection == NULL)
-		return -EIO;
-
-	if (serial_manager_init(connection) < 0) {
-		dbus_connection_unref(connection);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static void serial_exit(void)
-{
-	serial_manager_exit();
-
-	dbus_connection_unref(connection);
-}
-
-BLUETOOTH_PLUGIN_DEFINE(serial, VERSION,
-			BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, serial_init, serial_exit)
diff --git a/serial/manager.c b/serial/manager.c
deleted file mode 100644
index 6f3fc1f..0000000
--- a/serial/manager.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-#include <bluetooth/uuid.h>
-
-#include <gdbus.h>
-
-#include "adapter.h"
-#include "device.h"
-
-#include "log.h"
-
-#include "port.h"
-#include "manager.h"
-
-static DBusConnection *connection = NULL;
-
-static int serial_probe(struct btd_device *device, const char *uuid)
-{
-	struct btd_adapter *adapter = device_get_adapter(device);
-	const gchar *path = device_get_path(device);
-	sdp_list_t *protos;
-	int ch;
-	bdaddr_t src, dst;
-	const sdp_record_t *rec;
-
-	DBG("path %s: %s", path, uuid);
-
-	rec = btd_device_get_record(device, uuid);
-	if (!rec)
-		return -EINVAL;
-
-	if (sdp_get_access_protos(rec, &protos) < 0)
-		return -EINVAL;
-
-	ch = sdp_get_proto_port(protos, RFCOMM_UUID);
-	sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
-	sdp_list_free(protos, NULL);
-
-	if (ch < 1 || ch > 30) {
-		error("Channel out of range: %d", ch);
-		return -EINVAL;
-	}
-
-	adapter_get_address(adapter, &src);
-	device_get_address(device, &dst, NULL);
-
-	return port_register(connection, path, &src, &dst, uuid, ch);
-}
-
-static void serial_remove(struct btd_device *device)
-{
-	const gchar *path = device_get_path(device);
-
-	DBG("path %s", path);
-
-	port_unregister(path);
-}
-
-
-static int port_probe(struct btd_device *device, GSList *uuids)
-{
-	while (uuids) {
-		serial_probe(device, uuids->data);
-		uuids = uuids->next;
-	}
-
-	return 0;
-}
-
-static void port_remove(struct btd_device *device)
-{
-	return serial_remove(device);
-}
-
-static struct btd_device_driver serial_port_driver = {
-	.name	= "serial-port",
-	.uuids	= BTD_UUIDS(RFCOMM_UUID_STR),
-	.probe	= port_probe,
-	.remove	= port_remove,
-};
-
-int serial_manager_init(DBusConnection *conn)
-{
-	connection = dbus_connection_ref(conn);
-
-	btd_register_device_driver(&serial_port_driver);
-
-	return 0;
-}
-
-void serial_manager_exit(void)
-{
-	btd_unregister_device_driver(&serial_port_driver);
-
-	dbus_connection_unref(connection);
-	connection = NULL;
-}
diff --git a/serial/manager.h b/serial/manager.h
deleted file mode 100644
index c8b96e8..0000000
--- a/serial/manager.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-int serial_manager_init(DBusConnection *conn);
-void serial_manager_exit(void);
diff --git a/serial/port.c b/serial/port.c
deleted file mode 100644
index f2b7184..0000000
--- a/serial/port.c
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <glib.h>
-#include <gdbus.h>
-
-#include "log.h"
-#include "glib-helper.h"
-#include "sdp-client.h"
-#include "btio.h"
-
-#include "error.h"
-#include "manager.h"
-#include "adapter.h"
-#include "device.h"
-#include "storage.h"
-#include "port.h"
-
-#define SERIAL_PORT_INTERFACE	"org.bluez.Serial"
-
-#define MAX_OPEN_TRIES		5
-#define OPEN_WAIT		300	/* ms. udev node creation retry wait */
-
-struct serial_device {
-	DBusConnection	*conn;		/* for name listener handling */
-	bdaddr_t	src;		/* Source (local) address */
-	bdaddr_t	dst;		/* Destination address */
-	char		*path;		/* Device path */
-	GSList		*ports;		/* Available ports */
-};
-
-struct serial_port {
-	DBusMessage	*msg;		/* for name listener handling */
-	int16_t		id;		/* RFCOMM device id */
-	uint8_t		channel;	/* RFCOMM channel */
-	char		*uuid;		/* service identification */
-	GIOChannel	*io;		/* BtIO channel */
-	guint		listener_id;
-	struct serial_device *device;
-};
-
-static GSList *devices = NULL;
-
-static struct serial_device *find_device(GSList *devices, const char *path)
-{
-	GSList *l;
-
-	for (l = devices; l != NULL; l = l->next) {
-		struct serial_device *device = l->data;
-
-		if (!strcmp(device->path, path))
-			return device;
-	}
-
-	return NULL;
-}
-
-static struct serial_port *find_port(GSList *ports, const char *pattern)
-{
-	GSList *l;
-	int channel;
-	char *endptr = NULL;
-
-	channel = strtol(pattern, &endptr, 10);
-
-	for (l = ports; l != NULL; l = l->next) {
-		struct serial_port *port = l->data;
-		char *uuid_str;
-		int ret;
-
-		if (port->uuid && !strcasecmp(port->uuid, pattern))
-			return port;
-
-		if (endptr && *endptr == '\0' && port->channel == channel)
-			return port;
-
-		if (!port->uuid)
-			continue;
-
-		uuid_str = bt_name2string(pattern);
-		if (!uuid_str)
-			continue;
-
-		ret = strcasecmp(port->uuid, uuid_str);
-		g_free(uuid_str);
-		if (ret == 0)
-			return port;
-	}
-
-	return NULL;
-}
-
-static void port_release(struct serial_port *port)
-{
-	if (port->id < 0) {
-		if (port->io) {
-			g_io_channel_shutdown(port->io, TRUE, NULL);
-			g_io_channel_unref(port->io);
-			port->io = NULL;
-		} else
-			bt_cancel_discovery(&port->device->src,
-						&port->device->dst);
-
-	}
-}
-
-static void serial_port_free(void *data)
-{
-	struct serial_port *port = data;
-	struct serial_device *device = port->device;
-
-	if (device && port->listener_id > 0)
-		g_dbus_remove_watch(device->conn, port->listener_id);
-
-	port_release(port);
-
-	g_free(port->uuid);
-	g_free(port);
-}
-
-static void serial_device_free(void *data)
-{
-	struct serial_device *device = data;
-
-	g_free(device->path);
-	if (device->conn)
-		dbus_connection_unref(device->conn);
-	g_free(device);
-}
-
-static void port_owner_exited(DBusConnection *conn, void *user_data)
-{
-	struct serial_port *port = user_data;
-
-	port_release(port);
-
-	port->listener_id = 0;
-}
-
-static void path_unregister(void *data)
-{
-	struct serial_device *device = data;
-
-	DBG("Unregistered interface %s on path %s", SERIAL_PORT_INTERFACE,
-		device->path);
-
-	devices = g_slist_remove(devices, device);
-	serial_device_free(device);
-}
-
-void port_release_all(void)
-{
-	g_slist_free_full(devices, serial_device_free);
-}
-
-static void rfcomm_connect_cb(GIOChannel *chan, GError *conn_err,
-							gpointer user_data)
-{
-	struct serial_port *port = user_data;
-	struct serial_device *device = port->device;
-	int sk;
-	DBusMessage *reply;
-
-	/* Owner exited? */
-	if (!port->listener_id)
-		return;
-
-	if (conn_err) {
-		error("%s", conn_err->message);
-		reply = btd_error_failed(port->msg, conn_err->message);
-		g_dbus_send_message(device->conn, reply);
-		goto fail;
-	}
-
-	sk = g_io_channel_unix_get_fd(chan);
-	reply = g_dbus_create_reply(port->msg, DBUS_TYPE_UNIX_FD, &sk,
-						DBUS_TYPE_INVALID);
-	g_dbus_send_message(device->conn, reply);
-
-	close(sk);
-
-fail:
-	g_dbus_remove_watch(device->conn, port->listener_id);
-	port->listener_id = 0;
-}
-
-static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
-{
-	struct serial_port *port = user_data;
-	struct serial_device *device = port->device;
-	sdp_record_t *record = NULL;
-	sdp_list_t *protos;
-	DBusMessage *reply;
-	GError *gerr = NULL;
-
-	if (!port->listener_id)
-		return;
-
-	if (err < 0) {
-		error("Unable to get service record: %s (%d)", strerror(-err),
-			-err);
-		reply = btd_error_failed(port->msg, strerror(-err));
-		goto failed;
-	}
-
-	if (!recs || !recs->data) {
-		error("No record found");
-		reply = btd_error_failed(port->msg, "No record found");
-		goto failed;
-	}
-
-	record = recs->data;
-
-	if (sdp_get_access_protos(record, &protos) < 0) {
-		error("Unable to get access protos from port record");
-		reply = btd_error_failed(port->msg, "Invalid channel");
-		goto failed;
-	}
-
-	port->channel = sdp_get_proto_port(protos, RFCOMM_UUID);
-
-	sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
-	sdp_list_free(protos, NULL);
-
-	port->io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, port,
-				NULL, &gerr,
-				BT_IO_OPT_SOURCE_BDADDR, &device->src,
-				BT_IO_OPT_DEST_BDADDR, &device->dst,
-				BT_IO_OPT_CHANNEL, port->channel,
-				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
-				BT_IO_OPT_INVALID);
-	if (!port->io) {
-		error("%s", gerr->message);
-		reply = btd_error_failed(port->msg, gerr->message);
-		g_error_free(gerr);
-		goto failed;
-	}
-
-	return;
-
-failed:
-	g_dbus_remove_watch(device->conn, port->listener_id);
-	port->listener_id = 0;
-	g_dbus_send_message(device->conn, reply);
-}
-
-static int connect_port(struct serial_port *port)
-{
-	struct serial_device *device = port->device;
-	uuid_t uuid;
-	int err;
-
-	if (!port->uuid)
-		goto connect;
-
-	err = bt_string2uuid(&uuid, port->uuid);
-	if (err < 0)
-		return err;
-
-	sdp_uuid128_to_uuid(&uuid);
-
-	return bt_search_service(&device->src, &device->dst, &uuid,
-				get_record_cb, port, NULL);
-
-connect:
-	port->io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, port,
-				NULL, NULL,
-				BT_IO_OPT_SOURCE_BDADDR, &device->src,
-				BT_IO_OPT_DEST_BDADDR, &device->dst,
-				BT_IO_OPT_CHANNEL, port->channel,
-				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
-				BT_IO_OPT_INVALID);
-	if (port->io == NULL)
-		return -EIO;
-
-	return 0;
-}
-
-static struct serial_port *create_port(struct serial_device *device,
-					const char *uuid, uint8_t channel)
-{
-	struct serial_port *port;
-
-	port = g_new0(struct serial_port, 1);
-	port->uuid = g_strdup(uuid);
-	port->channel = channel;
-	port->device = device;
-	port->id = -1;
-
-	device->ports = g_slist_append(device->ports, port);
-
-	return port;
-}
-
-static DBusMessage *port_connect(DBusConnection *conn,
-					DBusMessage *msg, void *user_data)
-{
-	struct serial_device *device = user_data;
-	struct serial_port *port;
-	const char *pattern;
-	int err;
-
-	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
-						DBUS_TYPE_INVALID) == FALSE)
-		return NULL;
-
-	port = find_port(device->ports, pattern);
-	if (!port) {
-		char *endptr = NULL;
-		int channel;
-
-		channel = strtol(pattern, &endptr, 10);
-		if ((endptr && *endptr != '\0') || channel < 1 || channel > 30)
-			return btd_error_does_not_exist(msg);
-
-		port = create_port(device, NULL, channel);
-	}
-
-	if (port->listener_id)
-		return btd_error_failed(msg, "Port already in use");
-
-	port->listener_id = g_dbus_add_disconnect_watch(conn,
-						dbus_message_get_sender(msg),
-						port_owner_exited, port,
-						NULL);
-
-	port->msg = dbus_message_ref(msg);
-
-	err = connect_port(port);
-	if (err < 0) {
-		error("%s", strerror(-err));
-		g_dbus_remove_watch(conn, port->listener_id);
-		port->listener_id = 0;
-
-		return btd_error_failed(msg, strerror(-err));
-	}
-
-	return NULL;
-}
-
-static const GDBusMethodTable port_methods[] = {
-	{ GDBUS_ASYNC_METHOD("Connect",
-		GDBUS_ARGS({ "pattern", "s" }),	GDBUS_ARGS({ "fd", "s" }),
-		port_connect) },
-	{ }
-};
-
-static struct serial_device *create_serial_device(DBusConnection *conn,
-					const char *path, bdaddr_t *src,
-					bdaddr_t *dst)
-{
-	struct serial_device *device;
-
-	device = g_new0(struct serial_device, 1);
-	device->conn = dbus_connection_ref(conn);
-	bacpy(&device->dst, dst);
-	bacpy(&device->src, src);
-	device->path = g_strdup(path);
-
-	if (!g_dbus_register_interface(conn, path,
-				SERIAL_PORT_INTERFACE,
-				port_methods, NULL, NULL,
-				device, path_unregister)) {
-		error("D-Bus failed to register %s interface",
-				SERIAL_PORT_INTERFACE);
-		serial_device_free(device);
-		return NULL;
-	}
-
-	DBG("Registered interface %s on path %s",
-		SERIAL_PORT_INTERFACE, path);
-
-	return device;
-}
-
-int port_register(DBusConnection *conn, const char *path, bdaddr_t *src,
-			bdaddr_t *dst, const char *uuid, uint8_t channel)
-{
-	struct serial_device *device;
-	struct serial_port *port;
-
-	device = find_device(devices, path);
-	if (!device) {
-		device = create_serial_device(conn, path, src, dst);
-		if (!device)
-			return -1;
-		devices = g_slist_append(devices, device);
-	}
-
-	if (find_port(device->ports, uuid))
-		return 0;
-
-	port = g_new0(struct serial_port, 1);
-	port->uuid = g_strdup(uuid);
-	port->channel = channel;
-	port->device = device;
-	port->id = -1;
-
-	device->ports = g_slist_append(device->ports, port);
-
-	return 0;
-}
-
-int port_unregister(const char *path)
-{
-	struct serial_device *device;
-
-	device = find_device(devices, path);
-	if (!device)
-		return -ENOENT;
-
-	g_slist_free_full(device->ports, serial_port_free);
-
-	g_dbus_unregister_interface(device->conn, path, SERIAL_PORT_INTERFACE);
-
-	return 0;
-}
diff --git a/serial/port.h b/serial/port.h
deleted file mode 100644
index 74ac9f0..0000000
--- a/serial/port.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-void port_release_all(void);
-
-int port_register(DBusConnection *conn, const char *path, bdaddr_t *src,
-		  bdaddr_t *dst, const char *name, uint8_t channel);
-
-int port_unregister(const char *path);
diff --git a/serial/serial.conf b/serial/serial.conf
deleted file mode 100644
index 43ee6af..0000000
--- a/serial/serial.conf
+++ /dev/null
@@ -1,10 +0,0 @@
-# Configuration file for serial
-
-# There could be multiple proxy sections, the format is [Proxy <user chosen name>]
-#[Proxy DUN]
-
-# UUID for DUN proxy service
-#UUID=00001103-0000-1000-8000-00805F9B34FB
-
-# Address for device node
-#Address=/dev/ttyx
-- 
1.7.10.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH -v3 18/19] cups: move it to profiles folder
  2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
                   ` (11 preceding siblings ...)
  2012-07-04 12:51 ` [PATCH -v3 16/19] serial: move it " Gustavo Padovan
@ 2012-07-04 12:51 ` Gustavo Padovan
  2012-07-04 13:34   ` Marcel Holtmann
  12 siblings, 1 reply; 15+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

---
 Makefile.tools       |   12 +-
 cups/cups.h          |   38 ---
 cups/hcrp.c          |  368 ---------------------
 cups/main.c          |  896 --------------------------------------------------
 cups/sdp.c           |  119 -------
 cups/spp.c           |  118 -------
 profiles/cups/cups.h |   38 +++
 profiles/cups/hcrp.c |  368 +++++++++++++++++++++
 profiles/cups/main.c |  896 ++++++++++++++++++++++++++++++++++++++++++++++++++
 profiles/cups/sdp.c  |  119 +++++++
 profiles/cups/spp.c  |  118 +++++++
 11 files changed, 1547 insertions(+), 1543 deletions(-)
 delete mode 100644 cups/cups.h
 delete mode 100644 cups/hcrp.c
 delete mode 100644 cups/main.c
 delete mode 100644 cups/sdp.c
 delete mode 100644 cups/spp.c
 create mode 100644 profiles/cups/cups.h
 create mode 100644 profiles/cups/hcrp.c
 create mode 100644 profiles/cups/main.c
 create mode 100644 profiles/cups/sdp.c
 create mode 100644 profiles/cups/spp.c

diff --git a/Makefile.tools b/Makefile.tools
index e4cf238..db2d844 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -148,12 +148,16 @@ EXTRA_DIST += tools/dfubabel.1 tools/avctrl.8
 if CUPS
 cupsdir = $(libdir)/cups/backend
 
-cups_PROGRAMS = cups/bluetooth
+cups_PROGRAMS = profiles/cups/bluetooth
 
-cups_bluetooth_SOURCES = $(gdbus_sources) cups/main.c cups/cups.h \
-					cups/sdp.c cups/spp.c cups/hcrp.c
+profiles_cups_bluetooth_SOURCES = $(gdbus_sources) profiles/cups/main.c \
+					profiles/cups/cups.h \
+					profiles/cups/sdp.c \
+					profiles/cups/spp.c \
+					profiles/cups/hcrp.c
 
-cups_bluetooth_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ lib/libbluetooth-private.la
+profiles_cups_bluetooth_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ \
+				lib/libbluetooth-private.la
 endif
 
 
diff --git a/cups/cups.h b/cups/cups.h
deleted file mode 100644
index f4e0c01..0000000
--- a/cups/cups.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-enum {					/**** Backend exit codes ****/
-	CUPS_BACKEND_OK = 0,		/* Job completed successfully */
-	CUPS_BACKEND_FAILED = 1,	/* Job failed, use error-policy */
-	CUPS_BACKEND_AUTH_REQUIRED = 2,	/* Job failed, authentication required */
-	CUPS_BACKEND_HOLD = 3,		/* Job failed, hold job */
-	CUPS_BACKEND_STOP = 4,		/* Job failed, stop queue */
-	CUPS_BACKEND_CANCEL = 5,	/* Job failed, cancel job */
-	CUPS_BACKEND_RETRY = 6,		/* Failure requires us to retry (BlueZ specific) */
-};
-
-int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel);
-int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm);
-
-int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies, const char *cups_class);
-int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies, const char *cups_class);
diff --git a/cups/hcrp.c b/cups/hcrp.c
deleted file mode 100644
index a93dda0..0000000
--- a/cups/hcrp.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <netinet/in.h>
-
-#include "cups.h"
-
-#define HCRP_PDU_CREDIT_GRANT		0x0001
-#define HCRP_PDU_CREDIT_REQUEST		0x0002
-#define HCRP_PDU_GET_LPT_STATUS		0x0005
-
-#define HCRP_STATUS_FEATURE_UNSUPPORTED	0x0000
-#define HCRP_STATUS_SUCCESS		0x0001
-#define HCRP_STATUS_CREDIT_SYNC_ERROR	0x0002
-#define HCRP_STATUS_GENERIC_FAILURE	0xffff
-
-struct hcrp_pdu_hdr {
-	uint16_t pid;
-	uint16_t tid;
-	uint16_t plen;
-} __attribute__ ((packed));
-#define HCRP_PDU_HDR_SIZE 6
-
-struct hcrp_credit_grant_cp {
-	uint32_t credit;
-} __attribute__ ((packed));
-#define HCRP_CREDIT_GRANT_CP_SIZE 4
-
-struct hcrp_credit_grant_rp {
-	uint16_t status;
-} __attribute__ ((packed));
-#define HCRP_CREDIT_GRANT_RP_SIZE 2
-
-struct hcrp_credit_request_rp {
-	uint16_t status;
-	uint32_t credit;
-} __attribute__ ((packed));
-#define HCRP_CREDIT_REQUEST_RP_SIZE 6
-
-struct hcrp_get_lpt_status_rp {
-	uint16_t status;
-	uint8_t  lpt_status;
-} __attribute__ ((packed));
-#define HCRP_GET_LPT_STATUS_RP_SIZE 3
-
-static int hcrp_credit_grant(int sk, uint16_t tid, uint32_t credit)
-{
-	struct hcrp_pdu_hdr hdr;
-	struct hcrp_credit_grant_cp cp;
-	struct hcrp_credit_grant_rp rp;
-	unsigned char buf[128];
-	int len;
-
-	hdr.pid = htons(HCRP_PDU_CREDIT_GRANT);
-	hdr.tid = htons(tid);
-	hdr.plen = htons(HCRP_CREDIT_GRANT_CP_SIZE);
-	cp.credit = credit;
-	memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
-	memcpy(buf + HCRP_PDU_HDR_SIZE, &cp, HCRP_CREDIT_GRANT_CP_SIZE);
-	len = write(sk, buf, HCRP_PDU_HDR_SIZE + HCRP_CREDIT_GRANT_CP_SIZE);
-	if (len < 0)
-		return len;
-
-	len = read(sk, buf, sizeof(buf));
-	if (len < 0)
-		return len;
-
-	memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
-	memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_GRANT_RP_SIZE);
-
-	if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
-		errno = EIO;
-		return -1;
-	}
-
-	return 0;
-}
-
-static int hcrp_credit_request(int sk, uint16_t tid, uint32_t *credit)
-{
-	struct hcrp_pdu_hdr hdr;
-	struct hcrp_credit_request_rp rp;
-	unsigned char buf[128];
-	int len;
-
-	hdr.pid = htons(HCRP_PDU_CREDIT_REQUEST);
-	hdr.tid = htons(tid);
-	hdr.plen = htons(0);
-	memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
-	len = write(sk, buf, HCRP_PDU_HDR_SIZE);
-	if (len < 0)
-		return len;
-
-	len = read(sk, buf, sizeof(buf));
-	if (len < 0)
-		return len;
-
-	memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
-	memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_REQUEST_RP_SIZE);
-
-	if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
-		errno = EIO;
-		return -1;
-	}
-
-	if (credit)
-		*credit = ntohl(rp.credit);
-
-	return 0;
-}
-
-static int hcrp_get_lpt_status(int sk, uint16_t tid, uint8_t *lpt_status)
-{
-	struct hcrp_pdu_hdr hdr;
-	struct hcrp_get_lpt_status_rp rp;
-	unsigned char buf[128];
-	int len;
-
-	hdr.pid = htons(HCRP_PDU_GET_LPT_STATUS);
-	hdr.tid = htons(tid);
-	hdr.plen = htons(0);
-	memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
-	len = write(sk, buf, HCRP_PDU_HDR_SIZE);
-	if (len < 0)
-		return len;
-
-	len = read(sk, buf, sizeof(buf));
-	if (len < 0)
-		return len;
-
-	memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
-	memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_GET_LPT_STATUS_RP_SIZE);
-
-	if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
-		errno = EIO;
-		return -1;
-	}
-
-	if (lpt_status)
-		*lpt_status = rp.lpt_status;
-
-	return 0;
-}
-
-static inline int hcrp_get_next_tid(int tid)
-{
-	if (tid > 0xf000)
-		return 0;
-	else
-		return tid + 1;
-}
-
-int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies, const char *cups_class)
-{
-	struct sockaddr_l2 addr;
-	struct l2cap_options opts;
-	socklen_t size;
-	unsigned char buf[2048];
-	int i, ctrl_sk, data_sk, count, len, timeout = 0;
-	unsigned int mtu;
-	uint8_t status;
-	uint16_t tid = 0;
-	uint32_t tmp, credit = 0;
-
-	if ((ctrl_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) {
-		perror("ERROR: Can't create socket");
-		if (cups_class)
-			return CUPS_BACKEND_FAILED;
-		else
-			return CUPS_BACKEND_RETRY;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.l2_family = AF_BLUETOOTH;
-	bacpy(&addr.l2_bdaddr, src);
-
-	if (bind(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("ERROR: Can't bind socket");
-		close(ctrl_sk);
-		if (cups_class)
-			return CUPS_BACKEND_FAILED;
-		else
-			return CUPS_BACKEND_RETRY;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.l2_family = AF_BLUETOOTH;
-	bacpy(&addr.l2_bdaddr, dst);
-	addr.l2_psm = htobs(ctrl_psm);
-
-	if (connect(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("ERROR: Can't connect to device");
-		close(ctrl_sk);
-		if (cups_class)
-			return CUPS_BACKEND_FAILED;
-		else
-			return CUPS_BACKEND_RETRY;
-	}
-
-	if ((data_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) {
-		perror("ERROR: Can't create socket");
-		close(ctrl_sk);
-		if (cups_class)
-			return CUPS_BACKEND_FAILED;
-		else
-			return CUPS_BACKEND_RETRY;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.l2_family = AF_BLUETOOTH;
-	bacpy(&addr.l2_bdaddr, src);
-
-	if (bind(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("ERROR: Can't bind socket");
-		close(data_sk);
-		close(ctrl_sk);
-		if (cups_class)
-			return CUPS_BACKEND_FAILED;
-		else
-			return CUPS_BACKEND_RETRY;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.l2_family = AF_BLUETOOTH;
-	bacpy(&addr.l2_bdaddr, dst);
-	addr.l2_psm = htobs(data_psm);
-
-	if (connect(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("ERROR: Can't connect to device");
-		close(data_sk);
-		close(ctrl_sk);
-		if (cups_class)
-			return CUPS_BACKEND_FAILED;
-		else
-			return CUPS_BACKEND_RETRY;
-	}
-
-	fputs("STATE: -connecting-to-device\n", stderr);
-
-	memset(&opts, 0, sizeof(opts));
-	size = sizeof(opts);
-
-	if (getsockopt(data_sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &size) < 0) {
-		perror("ERROR: Can't get socket options");
-		close(data_sk);
-		close(ctrl_sk);
-		if (cups_class)
-			return CUPS_BACKEND_FAILED;
-		else
-			return CUPS_BACKEND_RETRY;
-	}
-
-	mtu = opts.omtu;
-
-	/* Ignore SIGTERM signals if printing from stdin */
-	if (fd == 0) {
-#ifdef HAVE_SIGSET
-		sigset(SIGTERM, SIG_IGN);
-#elif defined(HAVE_SIGACTION)
-		memset(&action, 0, sizeof(action));
-		sigemptyset(&action.sa_mask);
-		action.sa_handler = SIG_IGN;
-		sigaction(SIGTERM, &action, NULL);
-#else
-		signal(SIGTERM, SIG_IGN);
-#endif /* HAVE_SIGSET */
-	}
-
-	tid = hcrp_get_next_tid(tid);
-	if (hcrp_credit_grant(ctrl_sk, tid, 0) < 0) {
-		fprintf(stderr, "ERROR: Can't grant initial credits\n");
-		close(data_sk);
-		close(ctrl_sk);
-		if (cups_class)
-			return CUPS_BACKEND_FAILED;
-		else
-			return CUPS_BACKEND_RETRY;
-	}
-
-	for (i = 0; i < copies; i++) {
-
-		if (fd != 0) {
-			fprintf(stderr, "PAGE: 1 1\n");
-			lseek(fd, 0, SEEK_SET);
-		}
-
-		while (1) {
-			if (credit < mtu) {
-				tid = hcrp_get_next_tid(tid);
-				if (!hcrp_credit_request(ctrl_sk, tid, &tmp)) {
-					credit += tmp;
-					timeout = 0;
-				}
-			}
-
-			if (!credit) {
-				if (timeout++ > 300) {
-					tid = hcrp_get_next_tid(tid);
-					if (!hcrp_get_lpt_status(ctrl_sk, tid, &status))
-						fprintf(stderr, "ERROR: LPT status 0x%02x\n", status);
-					break;
-				}
-
-				sleep(1);
-				continue;
-			}
-
-			count = read(fd, buf, (credit > mtu) ? mtu : credit);
-			if (count <= 0)
-				break;
-
-			len = write(data_sk, buf, count);
-			if (len < 0) {
-				perror("ERROR: Error writing to device");
-				close(data_sk);
-				close(ctrl_sk);
-				return CUPS_BACKEND_FAILED;
-			}
-
-			if (len != count)
-				fprintf(stderr, "ERROR: Can't send complete data\n");
-
-			credit -= len;
-		}
-
-	}
-
-	close(data_sk);
-	close(ctrl_sk);
-
-	return CUPS_BACKEND_OK;
-}
diff --git a/cups/main.c b/cups/main.c
deleted file mode 100644
index a884c6e..0000000
--- a/cups/main.c
+++ /dev/null
@@ -1,896 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <sys/socket.h>
-#include <glib.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <gdbus.h>
-
-#include "cups.h"
-
-struct cups_device {
-	char *bdaddr;
-	char *name;
-	char *id;
-};
-
-static GSList *device_list = NULL;
-static GMainLoop *loop = NULL;
-static DBusConnection *conn = NULL;
-static gboolean doing_disco = FALSE;
-
-#define ATTRID_1284ID 0x0300
-
-struct context_data {
-	gboolean found;
-	char *id;
-};
-
-static void element_start(GMarkupParseContext *context,
-				const gchar *element_name,
-				const gchar **attribute_names,
-				const gchar **attribute_values,
-				gpointer user_data, GError **err)
-{
-	struct context_data *ctx_data = user_data;
-
-	if (!strcmp(element_name, "record"))
-		return;
-
-	if (!strcmp(element_name, "attribute")) {
-		int i;
-		for (i = 0; attribute_names[i]; i++) {
-			if (strcmp(attribute_names[i], "id") != 0)
-				continue;
-			if (strtol(attribute_values[i], 0, 0) == ATTRID_1284ID)
-				ctx_data->found = TRUE;
-			break;
-		}
-		return;
-	}
-
-	if (ctx_data->found  && !strcmp(element_name, "text")) {
-		int i;
-		for (i = 0; attribute_names[i]; i++) {
-			if (!strcmp(attribute_names[i], "value")) {
-				ctx_data->id = g_strdup(attribute_values[i] + 2);
-				ctx_data->found = FALSE;
-			}
-		}
-	}
-}
-
-static GMarkupParser parser = {
-	element_start, NULL, NULL, NULL, NULL
-};
-
-static char *sdp_xml_parse_record(const char *data)
-{
-	GMarkupParseContext *ctx;
-	struct context_data ctx_data;
-	int size;
-
-	size = strlen(data);
-	ctx_data.found = FALSE;
-	ctx_data.id = NULL;
-	ctx = g_markup_parse_context_new(&parser, 0, &ctx_data, NULL);
-
-	if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) {
-		g_markup_parse_context_free(ctx);
-		g_free(ctx_data.id);
-		return NULL;
-	}
-
-	g_markup_parse_context_free(ctx);
-
-	return ctx_data.id;
-}
-
-static char *device_get_ieee1284_id(const char *adapter, const char *device)
-{
-	DBusMessage *message, *reply;
-	DBusMessageIter iter, reply_iter;
-	DBusMessageIter reply_iter_entry;
-	const char *hcr_print = "00001126-0000-1000-8000-00805f9b34fb";
-	const char *xml;
-	char *id = NULL;
-
-	/* Look for the service handle of the HCRP service */
-	message = dbus_message_new_method_call("org.bluez", device,
-						"org.bluez.Device",
-						"DiscoverServices");
-	dbus_message_iter_init_append(message, &iter);
-	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &hcr_print);
-
-	reply = dbus_connection_send_with_reply_and_block(conn,
-							message, -1, NULL);
-
-	dbus_message_unref(message);
-
-	if (!reply)
-		return NULL;
-
-	dbus_message_iter_init(reply, &reply_iter);
-
-	if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
-		dbus_message_unref(reply);
-		return NULL;
-	}
-
-	dbus_message_iter_recurse(&reply_iter, &reply_iter_entry);
-
-	/* Hopefully we only get one handle, or take a punt */
-	while (dbus_message_iter_get_arg_type(&reply_iter_entry) ==
-							DBUS_TYPE_DICT_ENTRY) {
-		guint32 key;
-		DBusMessageIter dict_entry;
-
-		dbus_message_iter_recurse(&reply_iter_entry, &dict_entry);
-
-		/* Key ? */
-		dbus_message_iter_get_basic(&dict_entry, &key);
-		if (!key) {
-			dbus_message_iter_next(&reply_iter_entry);
-			continue;
-		}
-
-		/* Try to get the value */
-		if (!dbus_message_iter_next(&dict_entry)) {
-			dbus_message_iter_next(&reply_iter_entry);
-			continue;
-		}
-
-		dbus_message_iter_get_basic(&dict_entry, &xml);
-
-		id = sdp_xml_parse_record(xml);
-		if (id != NULL)
-			break;
-		dbus_message_iter_next(&reply_iter_entry);
-	}
-
-	dbus_message_unref(reply);
-
-	return id;
-}
-
-static void print_printer_details(const char *name, const char *bdaddr,
-								const char *id)
-{
-	char *uri, *escaped;
-
-	escaped = g_strdelimit(g_strdup(name), "\"", '\'');
-	uri = g_strdup_printf("bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c",
-				bdaddr[0], bdaddr[1],
-				bdaddr[3], bdaddr[4],
-				bdaddr[6], bdaddr[7],
-				bdaddr[9], bdaddr[10],
-				bdaddr[12], bdaddr[13],
-				bdaddr[15], bdaddr[16]);
-	printf("direct %s \"%s\" \"%s (Bluetooth)\"", uri, escaped, escaped);
-	if (id != NULL)
-		printf(" \"%s\"\n", id);
-	else
-		printf("\n");
-	g_free(escaped);
-	g_free(uri);
-}
-
-static void add_device_to_list(const char *name, const char *bdaddr,
-								const char *id)
-{
-	struct cups_device *device;
-	GSList *l;
-
-	/* Look for the device in the list */
-	for (l = device_list; l != NULL; l = l->next) {
-		device = (struct cups_device *) l->data;
-
-		if (strcmp(device->bdaddr, bdaddr) == 0) {
-			if (device->name != name) {
-				g_free(device->name);
-				device->name = g_strdup(name);
-			}
-			g_free(device->id);
-			device->id = g_strdup(id);
-			return;
-		}
-	}
-
-	/* Or add it to the list if it's not there */
-	device = g_new0(struct cups_device, 1);
-	device->bdaddr = g_strdup(bdaddr);
-	device->name = g_strdup(name);
-	device->id = g_strdup(id);
-
-	device_list = g_slist_prepend(device_list, device);
-	print_printer_details(device->name, device->bdaddr, device->id);
-}
-
-static gboolean parse_device_properties(DBusMessageIter *reply_iter,
-						char **name, char **bdaddr)
-{
-	guint32 class = 0;
-	DBusMessageIter reply_iter_entry;
-
-	if (dbus_message_iter_get_arg_type(reply_iter) != DBUS_TYPE_ARRAY)
-		return FALSE;
-
-	dbus_message_iter_recurse(reply_iter, &reply_iter_entry);
-
-	while (dbus_message_iter_get_arg_type(&reply_iter_entry) ==
-							DBUS_TYPE_DICT_ENTRY) {
-		const char *key;
-		DBusMessageIter dict_entry, iter_dict_val;
-
-		dbus_message_iter_recurse(&reply_iter_entry, &dict_entry);
-
-		/* Key == Class ? */
-		dbus_message_iter_get_basic(&dict_entry, &key);
-		if (!key) {
-			dbus_message_iter_next(&reply_iter_entry);
-			continue;
-		}
-
-		if (strcmp(key, "Class") != 0 &&
-				strcmp(key, "Alias") != 0 &&
-				strcmp(key, "Address") != 0) {
-			dbus_message_iter_next(&reply_iter_entry);
-			continue;
-		}
-
-		/* Try to get the value */
-		if (!dbus_message_iter_next(&dict_entry)) {
-			dbus_message_iter_next(&reply_iter_entry);
-			continue;
-		}
-		dbus_message_iter_recurse(&dict_entry, &iter_dict_val);
-		if (strcmp(key, "Class") == 0) {
-			dbus_message_iter_get_basic(&iter_dict_val, &class);
-		} else {
-			const char *value;
-			dbus_message_iter_get_basic(&iter_dict_val, &value);
-			if (strcmp(key, "Alias") == 0) {
-				*name = g_strdup(value);
-			} else if (bdaddr) {
-				*bdaddr = g_strdup(value);
-			}
-		}
-		dbus_message_iter_next(&reply_iter_entry);
-	}
-
-	if (class == 0)
-		return FALSE;
-	if (((class & 0x1f00) >> 8) == 0x06 && (class & 0x80))
-		return TRUE;
-
-	return FALSE;
-}
-
-static gboolean device_is_printer(const char *adapter, const char *device_path, char **name, char **bdaddr)
-{
-	DBusMessage *message, *reply;
-	DBusMessageIter reply_iter;
-	gboolean retval;
-
-	message = dbus_message_new_method_call("org.bluez", device_path,
-							"org.bluez.Device",
-							"GetProperties");
-
-	reply = dbus_connection_send_with_reply_and_block(conn,
-							message, -1, NULL);
-
-	dbus_message_unref(message);
-
-	if (!reply)
-		return FALSE;
-
-	dbus_message_iter_init(reply, &reply_iter);
-
-	retval = parse_device_properties(&reply_iter, name, bdaddr);
-
-	dbus_message_unref(reply);
-
-	return retval;
-}
-
-static void remote_device_found(const char *adapter, const char *bdaddr,
-							const char *name)
-{
-	DBusMessage *message, *reply, *adapter_reply;
-	DBusMessageIter iter;
-	char *object_path = NULL;
-	char *id;
-
-	adapter_reply = NULL;
-
-	if (adapter == NULL) {
-		message = dbus_message_new_method_call("org.bluez", "/",
-							"org.bluez.Manager",
-							"DefaultAdapter");
-
-		adapter_reply = dbus_connection_send_with_reply_and_block(conn,
-							message, -1, NULL);
-
-		dbus_message_unref(message);
-
-		if (!adapter_reply)
-			return;
-
-		if (dbus_message_get_args(adapter_reply, NULL,
-					DBUS_TYPE_OBJECT_PATH, &adapter,
-					DBUS_TYPE_INVALID) == FALSE) {
-			dbus_message_unref(adapter_reply);
-			return;
-		}
-	}
-
-	message = dbus_message_new_method_call("org.bluez", adapter,
-							"org.bluez.Adapter",
-							"FindDevice");
-	dbus_message_iter_init_append(message, &iter);
-	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
-
-	if (adapter_reply != NULL)
-		dbus_message_unref(adapter_reply);
-
-	reply = dbus_connection_send_with_reply_and_block(conn,
-							message, -1, NULL);
-
-	dbus_message_unref(message);
-
-	if (!reply) {
-		message = dbus_message_new_method_call("org.bluez", adapter,
-							"org.bluez.Adapter",
-							"CreateDevice");
-		dbus_message_iter_init_append(message, &iter);
-		dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
-
-		reply = dbus_connection_send_with_reply_and_block(conn,
-							message, -1, NULL);
-
-		dbus_message_unref(message);
-
-		if (!reply)
-			return;
-	}
-
-	if (dbus_message_get_args(reply, NULL,
-					DBUS_TYPE_OBJECT_PATH, &object_path,
-					DBUS_TYPE_INVALID) == FALSE) {
-		dbus_message_unref(reply);
-		return;
-	}
-
-	id = device_get_ieee1284_id(adapter, object_path);
-	add_device_to_list(name, bdaddr, id);
-	g_free(id);
-
-	dbus_message_unref(reply);
-}
-
-static void discovery_completed(void)
-{
-	g_slist_free(device_list);
-	device_list = NULL;
-
-	g_main_loop_quit(loop);
-}
-
-static void remote_device_disappeared(const char *bdaddr)
-{
-	GSList *l;
-
-	for (l = device_list; l != NULL; l = l->next) {
-		struct cups_device *device = l->data;
-
-		if (strcmp(device->bdaddr, bdaddr) == 0) {
-			g_free(device->name);
-			g_free(device->bdaddr);
-			g_free(device);
-			device_list = g_slist_delete_link(device_list, l);
-			return;
-		}
-	}
-}
-
-static gboolean list_known_printers(const char *adapter)
-{
-	DBusMessageIter reply_iter, iter_array;
-	DBusError error;
-	DBusMessage *message, *reply;
-
-	message = dbus_message_new_method_call("org.bluez", adapter,
-						"org.bluez.Adapter",
-						"ListDevices");
-	if (message == NULL)
-		return FALSE;
-
-	dbus_error_init(&error);
-	reply = dbus_connection_send_with_reply_and_block(conn, message,
-								-1, &error);
-
-	dbus_message_unref(message);
-
-	if (dbus_error_is_set(&error))
-		return FALSE;
-
-	dbus_message_iter_init(reply, &reply_iter);
-	if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
-		dbus_message_unref(reply);
-		return FALSE;
-	}
-
-	dbus_message_iter_recurse(&reply_iter, &iter_array);
-	while (dbus_message_iter_get_arg_type(&iter_array) ==
-						DBUS_TYPE_OBJECT_PATH) {
-		const char *object_path;
-		char *name = NULL;
-		char *bdaddr = NULL;
-
-		dbus_message_iter_get_basic(&iter_array, &object_path);
-		if (device_is_printer(adapter, object_path, &name, &bdaddr)) {
-			char *id;
-
-			id = device_get_ieee1284_id(adapter, object_path);
-			add_device_to_list(name, bdaddr, id);
-			g_free(id);
-		}
-		g_free(name);
-		g_free(bdaddr);
-		dbus_message_iter_next(&iter_array);
-	}
-
-	dbus_message_unref(reply);
-
-	return FALSE;
-}
-
-static DBusHandlerResult filter_func(DBusConnection *connection,
-					DBusMessage *message, void *user_data)
-{
-	if (dbus_message_is_signal(message, "org.bluez.Adapter",
-						"DeviceFound")) {
-		const char *adapter, *bdaddr;
-		char *name;
-		DBusMessageIter iter;
-
-		dbus_message_iter_init(message, &iter);
-		dbus_message_iter_get_basic(&iter, &bdaddr);
-		dbus_message_iter_next(&iter);
-
-		adapter = dbus_message_get_path(message);
-		if (parse_device_properties(&iter, &name, NULL))
-			remote_device_found(adapter, bdaddr, name);
-		g_free (name);
-	} else if (dbus_message_is_signal(message, "org.bluez.Adapter",
-						"DeviceDisappeared")) {
-		const char *bdaddr;
-
-		dbus_message_get_args(message, NULL,
-					DBUS_TYPE_STRING, &bdaddr,
-					DBUS_TYPE_INVALID);
-		remote_device_disappeared(bdaddr);
-	} else if (dbus_message_is_signal(message, "org.bluez.Adapter",
-						"PropertyChanged")) {
-		DBusMessageIter iter, value_iter;
-		const char *name;
-		gboolean discovering;
-
-		dbus_message_iter_init(message, &iter);
-		dbus_message_iter_get_basic(&iter, &name);
-		if (name == NULL || strcmp(name, "Discovering") != 0)
-			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-		dbus_message_iter_next(&iter);
-		dbus_message_iter_recurse(&iter, &value_iter);
-		dbus_message_iter_get_basic(&value_iter, &discovering);
-
-		if (discovering == FALSE && doing_disco) {
-			doing_disco = FALSE;
-			discovery_completed();
-		}
-	}
-
-	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static gboolean list_printers(void)
-{
-	/* 1. Connect to the bus
-	 * 2. Get the manager
-	 * 3. Get the default adapter
-	 * 4. Get a list of devices
-	 * 5. Get the class of each device
-	 * 6. Print the details from each printer device
-	 */
-	DBusError error;
-	dbus_bool_t hcid_exists;
-	DBusMessage *reply, *message;
-	DBusMessageIter reply_iter;
-	char *adapter, *match;
-
-	conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
-	if (conn == NULL)
-		return TRUE;
-
-	dbus_error_init(&error);
-	hcid_exists = dbus_bus_name_has_owner(conn, "org.bluez", &error);
-	if (dbus_error_is_set(&error))
-		return TRUE;
-
-	if (!hcid_exists)
-		return TRUE;
-
-	/* Get the default adapter */
-	message = dbus_message_new_method_call("org.bluez", "/",
-						"org.bluez.Manager",
-						"DefaultAdapter");
-	if (message == NULL) {
-		dbus_connection_unref(conn);
-		return FALSE;
-	}
-
-	reply = dbus_connection_send_with_reply_and_block(conn,
-							message, -1, &error);
-
-	dbus_message_unref(message);
-
-	if (dbus_error_is_set(&error)) {
-		dbus_connection_unref(conn);
-		/* No adapter */
-		return TRUE;
-	}
-
-	dbus_message_iter_init(reply, &reply_iter);
-	if (dbus_message_iter_get_arg_type(&reply_iter) !=
-						DBUS_TYPE_OBJECT_PATH) {
-		dbus_message_unref(reply);
-		dbus_connection_unref(conn);
-		return FALSE;
-	}
-
-	dbus_message_iter_get_basic(&reply_iter, &adapter);
-	adapter = g_strdup(adapter);
-	dbus_message_unref(reply);
-
-	if (!dbus_connection_add_filter(conn, filter_func, adapter, g_free)) {
-		g_free(adapter);
-		dbus_connection_unref(conn);
-		return FALSE;
-	}
-
-#define MATCH_FORMAT				\
-	"type='signal',"			\
-	"interface='org.bluez.Adapter',"	\
-	"sender='org.bluez',"			\
-	"path='%s'"
-
-	match = g_strdup_printf(MATCH_FORMAT, adapter);
-	dbus_bus_add_match(conn, match, &error);
-	g_free(match);
-
-	/* Add the the recent devices */
-	list_known_printers(adapter);
-
-	doing_disco = TRUE;
-	message = dbus_message_new_method_call("org.bluez", adapter,
-					"org.bluez.Adapter",
-					"StartDiscovery");
-
-	if (!dbus_connection_send_with_reply(conn, message, NULL, -1)) {
-		dbus_message_unref(message);
-		dbus_connection_unref(conn);
-		g_free(adapter);
-		return FALSE;
-	}
-	dbus_message_unref(message);
-
-	loop = g_main_loop_new(NULL, TRUE);
-	g_main_loop_run(loop);
-
-	g_free(adapter);
-	dbus_connection_unref(conn);
-
-	return TRUE;
-}
-
-static gboolean print_ieee1284(const char *bdaddr)
-{
-	DBusMessage *message, *reply, *adapter_reply;
-	DBusMessageIter iter;
-	char *object_path = NULL;
-	char *adapter;
-	char *id;
-
-	adapter_reply = NULL;
-
-	conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
-	if (conn == NULL)
-		return FALSE;
-
-	message = dbus_message_new_method_call("org.bluez", "/",
-			"org.bluez.Manager",
-			"DefaultAdapter");
-
-	adapter_reply = dbus_connection_send_with_reply_and_block(conn,
-			message, -1, NULL);
-
-	dbus_message_unref(message);
-
-	if (!adapter_reply)
-		return FALSE;
-
-	if (dbus_message_get_args(adapter_reply, NULL,
-			DBUS_TYPE_OBJECT_PATH, &adapter,
-			DBUS_TYPE_INVALID) == FALSE) {
-		dbus_message_unref(adapter_reply);
-		return FALSE;
-	}
-
-	message = dbus_message_new_method_call("org.bluez", adapter,
-			"org.bluez.Adapter",
-			"FindDevice");
-	dbus_message_iter_init_append(message, &iter);
-	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
-
-	if (adapter_reply != NULL)
-		dbus_message_unref(adapter_reply);
-
-	reply = dbus_connection_send_with_reply_and_block(conn,
-			message, -1, NULL);
-
-	dbus_message_unref(message);
-
-	if (!reply) {
-		message = dbus_message_new_method_call("org.bluez", adapter,
-				"org.bluez.Adapter",
-				"CreateDevice");
-		dbus_message_iter_init_append(message, &iter);
-		dbus_message_iter_append_basic(&iter,
-				DBUS_TYPE_STRING, &bdaddr);
-
-		reply = dbus_connection_send_with_reply_and_block(conn,
-				message, -1, NULL);
-
-		dbus_message_unref(message);
-
-		if (!reply)
-			return FALSE;
-	}
-
-	if (dbus_message_get_args(reply, NULL,
-					DBUS_TYPE_OBJECT_PATH, &object_path,
-					DBUS_TYPE_INVALID) == FALSE) {
-		dbus_message_unref(reply);
-		return FALSE;
-	}
-
-	id = device_get_ieee1284_id(adapter, object_path);
-	if (id == NULL) {
-		dbus_message_unref(reply);
-		return FALSE;
-	}
-	printf("%s", id);
-	g_free(id);
-
-	dbus_message_unref(reply);
-
-	return TRUE;
-}
-
-/*
- *  Usage: printer-uri job-id user title copies options [file]
- *
- */
-
-int main(int argc, char *argv[])
-{
-	sdp_session_t *sdp;
-	bdaddr_t bdaddr;
-	unsigned short ctrl_psm, data_psm;
-	uint8_t channel, b[6];
-	char *ptr, str[3], device[18], service[12];
-	const char *uri, *cups_class;
-	int i, err, fd, copies, proto;
-
-	/* Make sure status messages are not buffered */
-	setbuf(stderr, NULL);
-
-	/* Make sure output is not buffered */
-	setbuf(stdout, NULL);
-
-	/* Ignore SIGPIPE signals */
-#ifdef HAVE_SIGSET
-	sigset(SIGPIPE, SIG_IGN);
-#elif defined(HAVE_SIGACTION)
-	memset(&action, 0, sizeof(action));
-	action.sa_handler = SIG_IGN;
-	sigaction(SIGPIPE, &action, NULL);
-#else
-	signal(SIGPIPE, SIG_IGN);
-#endif /* HAVE_SIGSET */
-
-	if (argc == 1) {
-		if (list_printers() == TRUE)
-			return CUPS_BACKEND_OK;
-		else
-			return CUPS_BACKEND_FAILED;
-	} else if (argc == 3 && strcmp(argv[1], "--get-deviceid") == 0) {
-		if (bachk(argv[2]) < 0) {
-			fprintf(stderr, "Invalid Bluetooth address '%s'\n",
-					argv[2]);
-			return CUPS_BACKEND_FAILED;
-		}
-		if (print_ieee1284(argv[2]) == FALSE)
-			return CUPS_BACKEND_FAILED;
-		return CUPS_BACKEND_OK;
-	}
-
-	if (argc < 6 || argc > 7) {
-		fprintf(stderr, "Usage: bluetooth job-id user title copies"
-				" options [file]\n");
-		fprintf(stderr, "       bluetooth --get-deviceid [bdaddr]\n");
-		return CUPS_BACKEND_FAILED;
-	}
-
-	if (argc == 6) {
-		fd = 0;
-		copies = 1;
-	} else {
-		if ((fd = open(argv[6], O_RDONLY)) < 0) {
-			perror("ERROR: Unable to open print file");
-			return CUPS_BACKEND_FAILED;
-		}
-		copies = atoi(argv[4]);
-	}
-
-	uri = getenv("DEVICE_URI");
-	if (!uri)
-		uri = argv[0];
-
-	if (strncasecmp(uri, "bluetooth://", 12)) {
-		fprintf(stderr, "ERROR: No device URI found\n");
-		return CUPS_BACKEND_FAILED;
-	}
-
-	ptr = argv[0] + 12;
-	for (i = 0; i < 6; i++) {
-		strncpy(str, ptr, 2);
-		b[i] = (uint8_t) strtol(str, NULL, 16);
-		ptr += 2;
-	}
-	sprintf(device, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
-			b[0], b[1], b[2], b[3], b[4], b[5]);
-
-	str2ba(device, &bdaddr);
-
-	ptr = strchr(ptr, '/');
-	if (ptr) {
-		strncpy(service, ptr + 1, 12);
-
-		if (!strncasecmp(ptr + 1, "spp", 3))
-			proto = 1;
-		else if (!strncasecmp(ptr + 1, "hcrp", 4))
-			proto = 2;
-		else
-			proto = 0;
-	} else {
-		strcpy(service, "auto");
-		proto = 0;
-	}
-
-	cups_class = getenv("CLASS");
-
-	fprintf(stderr,
-		"DEBUG: %s device %s service %s fd %d copies %d class %s\n",
-			argv[0], device, service, fd, copies,
-			cups_class ? cups_class : "(none)");
-
-	fputs("STATE: +connecting-to-device\n", stderr);
-
-service_search:
-	sdp = sdp_connect(BDADDR_ANY, &bdaddr, SDP_RETRY_IF_BUSY);
-	if (!sdp) {
-		fprintf(stderr, "ERROR: Can't open Bluetooth connection\n");
-		return CUPS_BACKEND_FAILED;
-	}
-
-	switch (proto) {
-	case 1:
-		err = sdp_search_spp(sdp, &channel);
-		break;
-	case 2:
-		err = sdp_search_hcrp(sdp, &ctrl_psm, &data_psm);
-		break;
-	default:
-		proto = 2;
-		err = sdp_search_hcrp(sdp, &ctrl_psm, &data_psm);
-		if (err) {
-			proto = 1;
-			err = sdp_search_spp(sdp, &channel);
-		}
-		break;
-	}
-
-	sdp_close(sdp);
-
-	if (err) {
-		if (cups_class) {
-			fputs("INFO: Unable to contact printer, queuing on "
-					"next printer in class...\n", stderr);
-			sleep(5);
-			return CUPS_BACKEND_FAILED;
-		}
-		sleep(20);
-		fprintf(stderr, "ERROR: Can't get service information\n");
-		goto service_search;
-	}
-
-connect:
-	switch (proto) {
-	case 1:
-		err = spp_print(BDADDR_ANY, &bdaddr, channel,
-						fd, copies, cups_class);
-		break;
-	case 2:
-		err = hcrp_print(BDADDR_ANY, &bdaddr, ctrl_psm, data_psm,
-						fd, copies, cups_class);
-		break;
-	default:
-		err = CUPS_BACKEND_FAILED;
-		fprintf(stderr, "ERROR: Unsupported protocol\n");
-		break;
-	}
-
-	if (err == CUPS_BACKEND_FAILED && cups_class) {
-		fputs("INFO: Unable to contact printer, queuing on "
-					"next printer in class...\n", stderr);
-		sleep(5);
-		return CUPS_BACKEND_FAILED;
-	} else if (err == CUPS_BACKEND_RETRY) {
-		sleep(20);
-		goto connect;
-	}
-
-	if (fd != 0)
-		close(fd);
-
-	if (!err)
-		fprintf(stderr, "INFO: Ready to print\n");
-
-	return err;
-}
diff --git a/cups/sdp.c b/cups/sdp.c
deleted file mode 100644
index c7f17a4..0000000
--- a/cups/sdp.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include "cups.h"
-
-int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm)
-{
-	sdp_list_t *srch, *attrs, *rsp;
-	uuid_t svclass;
-	uint16_t attr1, attr2;
-	int err;
-
-	if (!sdp)
-		return -1;
-
-	sdp_uuid16_create(&svclass, HCR_PRINT_SVCLASS_ID);
-	srch = sdp_list_append(NULL, &svclass);
-
-	attr1 = SDP_ATTR_PROTO_DESC_LIST;
-	attrs = sdp_list_append(NULL, &attr1);
-	attr2 = SDP_ATTR_ADD_PROTO_DESC_LIST;
-	attrs = sdp_list_append(attrs, &attr2);
-
-	err = sdp_service_search_attr_req(sdp, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp);
-	if (err)
-		return -1;
-
-	for (; rsp; rsp = rsp->next) {
-		sdp_record_t *rec = (sdp_record_t *) rsp->data;
-		sdp_list_t *protos;
-
-		if (!sdp_get_access_protos(rec, &protos)) {
-			unsigned short psm = sdp_get_proto_port(protos, L2CAP_UUID);
-			if (psm > 0) {
-				*ctrl_psm = psm;
-			}
-		}
-
-		if (!sdp_get_add_access_protos(rec, &protos)) {
-			unsigned short psm = sdp_get_proto_port(protos, L2CAP_UUID);
-			if (psm > 0 && *ctrl_psm > 0) {
-				*data_psm = psm;
-				return 0;
-			}
-		}
-	}
-
-	return -1;
-}
-
-int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel)
-{
-	sdp_list_t *srch, *attrs, *rsp;
-	uuid_t svclass;
-	uint16_t attr;
-	int err;
-
-	if (!sdp)
-		return -1;
-
-	sdp_uuid16_create(&svclass, SERIAL_PORT_SVCLASS_ID);
-	srch = sdp_list_append(NULL, &svclass);
-
-	attr = SDP_ATTR_PROTO_DESC_LIST;
-	attrs = sdp_list_append(NULL, &attr);
-
-	err = sdp_service_search_attr_req(sdp, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp);
-	if (err)
-		return -1;
-
-	for (; rsp; rsp = rsp->next) {
-		sdp_record_t *rec = (sdp_record_t *) rsp->data;
-		sdp_list_t *protos;
-
-		if (!sdp_get_access_protos(rec, &protos)) {
-			uint8_t ch = sdp_get_proto_port(protos, RFCOMM_UUID);
-			if (ch > 0) {
-				*channel = ch;
-				return 0;
-			}
-		}
-	}
-
-	return -1;
-}
diff --git a/cups/spp.c b/cups/spp.c
deleted file mode 100644
index d906ed2..0000000
--- a/cups/spp.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include "cups.h"
-
-int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies, const char *cups_class)
-{
-	struct sockaddr_rc addr;
-	unsigned char buf[2048];
-	int i, sk, err, len;
-
-	if ((sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
-		perror("ERROR: Can't create socket");
-		if (cups_class)
-			return CUPS_BACKEND_FAILED;
-		else
-			return CUPS_BACKEND_RETRY;
-	}
-
-	addr.rc_family = AF_BLUETOOTH;
-	bacpy(&addr.rc_bdaddr, src);
-	addr.rc_channel = 0;
-
-	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("ERROR: Can't bind socket");
-		close(sk);
-		if (cups_class)
-			return CUPS_BACKEND_FAILED;
-		else
-			return CUPS_BACKEND_RETRY;
-	}
-
-	addr.rc_family = AF_BLUETOOTH;
-	bacpy(&addr.rc_bdaddr, dst);
-	addr.rc_channel = channel;
-
-	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("ERROR: Can't connect to device");
-		close(sk);
-		if (cups_class)
-			return CUPS_BACKEND_FAILED;
-		else
-			return CUPS_BACKEND_RETRY;
-	}
-
-	fputs("STATE: -connecting-to-device\n", stderr);
-
-	/* Ignore SIGTERM signals if printing from stdin */
-	if (fd == 0) {
-#ifdef HAVE_SIGSET
-		sigset(SIGTERM, SIG_IGN);
-#elif defined(HAVE_SIGACTION)
-		memset(&action, 0, sizeof(action));
-		sigemptyset(&action.sa_mask);
-		action.sa_handler = SIG_IGN;
-		sigaction(SIGTERM, &action, NULL);
-#else
-		signal(SIGTERM, SIG_IGN);
-#endif /* HAVE_SIGSET */
-	}
-
-	for (i = 0; i < copies; i++) {
-
-		if (fd != 0) {
-			fprintf(stderr, "PAGE: 1 1\n");
-			lseek(fd, 0, SEEK_SET);
-		}
-
-		while ((len = read(fd, buf, sizeof(buf))) > 0) {
-			err = write(sk, buf, len);
-			if (err < 0) {
-				perror("ERROR: Error writing to device");
-				close(sk);
-				return CUPS_BACKEND_FAILED;
-			}
-		}
-
-	}
-
-	close(sk);
-
-	return CUPS_BACKEND_OK;
-}
diff --git a/profiles/cups/cups.h b/profiles/cups/cups.h
new file mode 100644
index 0000000..f4e0c01
--- /dev/null
+++ b/profiles/cups/cups.h
@@ -0,0 +1,38 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+enum {					/**** Backend exit codes ****/
+	CUPS_BACKEND_OK = 0,		/* Job completed successfully */
+	CUPS_BACKEND_FAILED = 1,	/* Job failed, use error-policy */
+	CUPS_BACKEND_AUTH_REQUIRED = 2,	/* Job failed, authentication required */
+	CUPS_BACKEND_HOLD = 3,		/* Job failed, hold job */
+	CUPS_BACKEND_STOP = 4,		/* Job failed, stop queue */
+	CUPS_BACKEND_CANCEL = 5,	/* Job failed, cancel job */
+	CUPS_BACKEND_RETRY = 6,		/* Failure requires us to retry (BlueZ specific) */
+};
+
+int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel);
+int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm);
+
+int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies, const char *cups_class);
+int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies, const char *cups_class);
diff --git a/profiles/cups/hcrp.c b/profiles/cups/hcrp.c
new file mode 100644
index 0000000..a93dda0
--- /dev/null
+++ b/profiles/cups/hcrp.c
@@ -0,0 +1,368 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <netinet/in.h>
+
+#include "cups.h"
+
+#define HCRP_PDU_CREDIT_GRANT		0x0001
+#define HCRP_PDU_CREDIT_REQUEST		0x0002
+#define HCRP_PDU_GET_LPT_STATUS		0x0005
+
+#define HCRP_STATUS_FEATURE_UNSUPPORTED	0x0000
+#define HCRP_STATUS_SUCCESS		0x0001
+#define HCRP_STATUS_CREDIT_SYNC_ERROR	0x0002
+#define HCRP_STATUS_GENERIC_FAILURE	0xffff
+
+struct hcrp_pdu_hdr {
+	uint16_t pid;
+	uint16_t tid;
+	uint16_t plen;
+} __attribute__ ((packed));
+#define HCRP_PDU_HDR_SIZE 6
+
+struct hcrp_credit_grant_cp {
+	uint32_t credit;
+} __attribute__ ((packed));
+#define HCRP_CREDIT_GRANT_CP_SIZE 4
+
+struct hcrp_credit_grant_rp {
+	uint16_t status;
+} __attribute__ ((packed));
+#define HCRP_CREDIT_GRANT_RP_SIZE 2
+
+struct hcrp_credit_request_rp {
+	uint16_t status;
+	uint32_t credit;
+} __attribute__ ((packed));
+#define HCRP_CREDIT_REQUEST_RP_SIZE 6
+
+struct hcrp_get_lpt_status_rp {
+	uint16_t status;
+	uint8_t  lpt_status;
+} __attribute__ ((packed));
+#define HCRP_GET_LPT_STATUS_RP_SIZE 3
+
+static int hcrp_credit_grant(int sk, uint16_t tid, uint32_t credit)
+{
+	struct hcrp_pdu_hdr hdr;
+	struct hcrp_credit_grant_cp cp;
+	struct hcrp_credit_grant_rp rp;
+	unsigned char buf[128];
+	int len;
+
+	hdr.pid = htons(HCRP_PDU_CREDIT_GRANT);
+	hdr.tid = htons(tid);
+	hdr.plen = htons(HCRP_CREDIT_GRANT_CP_SIZE);
+	cp.credit = credit;
+	memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
+	memcpy(buf + HCRP_PDU_HDR_SIZE, &cp, HCRP_CREDIT_GRANT_CP_SIZE);
+	len = write(sk, buf, HCRP_PDU_HDR_SIZE + HCRP_CREDIT_GRANT_CP_SIZE);
+	if (len < 0)
+		return len;
+
+	len = read(sk, buf, sizeof(buf));
+	if (len < 0)
+		return len;
+
+	memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
+	memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_GRANT_RP_SIZE);
+
+	if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
+		errno = EIO;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int hcrp_credit_request(int sk, uint16_t tid, uint32_t *credit)
+{
+	struct hcrp_pdu_hdr hdr;
+	struct hcrp_credit_request_rp rp;
+	unsigned char buf[128];
+	int len;
+
+	hdr.pid = htons(HCRP_PDU_CREDIT_REQUEST);
+	hdr.tid = htons(tid);
+	hdr.plen = htons(0);
+	memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
+	len = write(sk, buf, HCRP_PDU_HDR_SIZE);
+	if (len < 0)
+		return len;
+
+	len = read(sk, buf, sizeof(buf));
+	if (len < 0)
+		return len;
+
+	memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
+	memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_REQUEST_RP_SIZE);
+
+	if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
+		errno = EIO;
+		return -1;
+	}
+
+	if (credit)
+		*credit = ntohl(rp.credit);
+
+	return 0;
+}
+
+static int hcrp_get_lpt_status(int sk, uint16_t tid, uint8_t *lpt_status)
+{
+	struct hcrp_pdu_hdr hdr;
+	struct hcrp_get_lpt_status_rp rp;
+	unsigned char buf[128];
+	int len;
+
+	hdr.pid = htons(HCRP_PDU_GET_LPT_STATUS);
+	hdr.tid = htons(tid);
+	hdr.plen = htons(0);
+	memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
+	len = write(sk, buf, HCRP_PDU_HDR_SIZE);
+	if (len < 0)
+		return len;
+
+	len = read(sk, buf, sizeof(buf));
+	if (len < 0)
+		return len;
+
+	memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
+	memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_GET_LPT_STATUS_RP_SIZE);
+
+	if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
+		errno = EIO;
+		return -1;
+	}
+
+	if (lpt_status)
+		*lpt_status = rp.lpt_status;
+
+	return 0;
+}
+
+static inline int hcrp_get_next_tid(int tid)
+{
+	if (tid > 0xf000)
+		return 0;
+	else
+		return tid + 1;
+}
+
+int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies, const char *cups_class)
+{
+	struct sockaddr_l2 addr;
+	struct l2cap_options opts;
+	socklen_t size;
+	unsigned char buf[2048];
+	int i, ctrl_sk, data_sk, count, len, timeout = 0;
+	unsigned int mtu;
+	uint8_t status;
+	uint16_t tid = 0;
+	uint32_t tmp, credit = 0;
+
+	if ((ctrl_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) {
+		perror("ERROR: Can't create socket");
+		if (cups_class)
+			return CUPS_BACKEND_FAILED;
+		else
+			return CUPS_BACKEND_RETRY;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.l2_family = AF_BLUETOOTH;
+	bacpy(&addr.l2_bdaddr, src);
+
+	if (bind(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("ERROR: Can't bind socket");
+		close(ctrl_sk);
+		if (cups_class)
+			return CUPS_BACKEND_FAILED;
+		else
+			return CUPS_BACKEND_RETRY;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.l2_family = AF_BLUETOOTH;
+	bacpy(&addr.l2_bdaddr, dst);
+	addr.l2_psm = htobs(ctrl_psm);
+
+	if (connect(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("ERROR: Can't connect to device");
+		close(ctrl_sk);
+		if (cups_class)
+			return CUPS_BACKEND_FAILED;
+		else
+			return CUPS_BACKEND_RETRY;
+	}
+
+	if ((data_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) {
+		perror("ERROR: Can't create socket");
+		close(ctrl_sk);
+		if (cups_class)
+			return CUPS_BACKEND_FAILED;
+		else
+			return CUPS_BACKEND_RETRY;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.l2_family = AF_BLUETOOTH;
+	bacpy(&addr.l2_bdaddr, src);
+
+	if (bind(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("ERROR: Can't bind socket");
+		close(data_sk);
+		close(ctrl_sk);
+		if (cups_class)
+			return CUPS_BACKEND_FAILED;
+		else
+			return CUPS_BACKEND_RETRY;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.l2_family = AF_BLUETOOTH;
+	bacpy(&addr.l2_bdaddr, dst);
+	addr.l2_psm = htobs(data_psm);
+
+	if (connect(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("ERROR: Can't connect to device");
+		close(data_sk);
+		close(ctrl_sk);
+		if (cups_class)
+			return CUPS_BACKEND_FAILED;
+		else
+			return CUPS_BACKEND_RETRY;
+	}
+
+	fputs("STATE: -connecting-to-device\n", stderr);
+
+	memset(&opts, 0, sizeof(opts));
+	size = sizeof(opts);
+
+	if (getsockopt(data_sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &size) < 0) {
+		perror("ERROR: Can't get socket options");
+		close(data_sk);
+		close(ctrl_sk);
+		if (cups_class)
+			return CUPS_BACKEND_FAILED;
+		else
+			return CUPS_BACKEND_RETRY;
+	}
+
+	mtu = opts.omtu;
+
+	/* Ignore SIGTERM signals if printing from stdin */
+	if (fd == 0) {
+#ifdef HAVE_SIGSET
+		sigset(SIGTERM, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+		memset(&action, 0, sizeof(action));
+		sigemptyset(&action.sa_mask);
+		action.sa_handler = SIG_IGN;
+		sigaction(SIGTERM, &action, NULL);
+#else
+		signal(SIGTERM, SIG_IGN);
+#endif /* HAVE_SIGSET */
+	}
+
+	tid = hcrp_get_next_tid(tid);
+	if (hcrp_credit_grant(ctrl_sk, tid, 0) < 0) {
+		fprintf(stderr, "ERROR: Can't grant initial credits\n");
+		close(data_sk);
+		close(ctrl_sk);
+		if (cups_class)
+			return CUPS_BACKEND_FAILED;
+		else
+			return CUPS_BACKEND_RETRY;
+	}
+
+	for (i = 0; i < copies; i++) {
+
+		if (fd != 0) {
+			fprintf(stderr, "PAGE: 1 1\n");
+			lseek(fd, 0, SEEK_SET);
+		}
+
+		while (1) {
+			if (credit < mtu) {
+				tid = hcrp_get_next_tid(tid);
+				if (!hcrp_credit_request(ctrl_sk, tid, &tmp)) {
+					credit += tmp;
+					timeout = 0;
+				}
+			}
+
+			if (!credit) {
+				if (timeout++ > 300) {
+					tid = hcrp_get_next_tid(tid);
+					if (!hcrp_get_lpt_status(ctrl_sk, tid, &status))
+						fprintf(stderr, "ERROR: LPT status 0x%02x\n", status);
+					break;
+				}
+
+				sleep(1);
+				continue;
+			}
+
+			count = read(fd, buf, (credit > mtu) ? mtu : credit);
+			if (count <= 0)
+				break;
+
+			len = write(data_sk, buf, count);
+			if (len < 0) {
+				perror("ERROR: Error writing to device");
+				close(data_sk);
+				close(ctrl_sk);
+				return CUPS_BACKEND_FAILED;
+			}
+
+			if (len != count)
+				fprintf(stderr, "ERROR: Can't send complete data\n");
+
+			credit -= len;
+		}
+
+	}
+
+	close(data_sk);
+	close(ctrl_sk);
+
+	return CUPS_BACKEND_OK;
+}
diff --git a/profiles/cups/main.c b/profiles/cups/main.c
new file mode 100644
index 0000000..a884c6e
--- /dev/null
+++ b/profiles/cups/main.c
@@ -0,0 +1,896 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <glib.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <gdbus.h>
+
+#include "cups.h"
+
+struct cups_device {
+	char *bdaddr;
+	char *name;
+	char *id;
+};
+
+static GSList *device_list = NULL;
+static GMainLoop *loop = NULL;
+static DBusConnection *conn = NULL;
+static gboolean doing_disco = FALSE;
+
+#define ATTRID_1284ID 0x0300
+
+struct context_data {
+	gboolean found;
+	char *id;
+};
+
+static void element_start(GMarkupParseContext *context,
+				const gchar *element_name,
+				const gchar **attribute_names,
+				const gchar **attribute_values,
+				gpointer user_data, GError **err)
+{
+	struct context_data *ctx_data = user_data;
+
+	if (!strcmp(element_name, "record"))
+		return;
+
+	if (!strcmp(element_name, "attribute")) {
+		int i;
+		for (i = 0; attribute_names[i]; i++) {
+			if (strcmp(attribute_names[i], "id") != 0)
+				continue;
+			if (strtol(attribute_values[i], 0, 0) == ATTRID_1284ID)
+				ctx_data->found = TRUE;
+			break;
+		}
+		return;
+	}
+
+	if (ctx_data->found  && !strcmp(element_name, "text")) {
+		int i;
+		for (i = 0; attribute_names[i]; i++) {
+			if (!strcmp(attribute_names[i], "value")) {
+				ctx_data->id = g_strdup(attribute_values[i] + 2);
+				ctx_data->found = FALSE;
+			}
+		}
+	}
+}
+
+static GMarkupParser parser = {
+	element_start, NULL, NULL, NULL, NULL
+};
+
+static char *sdp_xml_parse_record(const char *data)
+{
+	GMarkupParseContext *ctx;
+	struct context_data ctx_data;
+	int size;
+
+	size = strlen(data);
+	ctx_data.found = FALSE;
+	ctx_data.id = NULL;
+	ctx = g_markup_parse_context_new(&parser, 0, &ctx_data, NULL);
+
+	if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) {
+		g_markup_parse_context_free(ctx);
+		g_free(ctx_data.id);
+		return NULL;
+	}
+
+	g_markup_parse_context_free(ctx);
+
+	return ctx_data.id;
+}
+
+static char *device_get_ieee1284_id(const char *adapter, const char *device)
+{
+	DBusMessage *message, *reply;
+	DBusMessageIter iter, reply_iter;
+	DBusMessageIter reply_iter_entry;
+	const char *hcr_print = "00001126-0000-1000-8000-00805f9b34fb";
+	const char *xml;
+	char *id = NULL;
+
+	/* Look for the service handle of the HCRP service */
+	message = dbus_message_new_method_call("org.bluez", device,
+						"org.bluez.Device",
+						"DiscoverServices");
+	dbus_message_iter_init_append(message, &iter);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &hcr_print);
+
+	reply = dbus_connection_send_with_reply_and_block(conn,
+							message, -1, NULL);
+
+	dbus_message_unref(message);
+
+	if (!reply)
+		return NULL;
+
+	dbus_message_iter_init(reply, &reply_iter);
+
+	if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
+		dbus_message_unref(reply);
+		return NULL;
+	}
+
+	dbus_message_iter_recurse(&reply_iter, &reply_iter_entry);
+
+	/* Hopefully we only get one handle, or take a punt */
+	while (dbus_message_iter_get_arg_type(&reply_iter_entry) ==
+							DBUS_TYPE_DICT_ENTRY) {
+		guint32 key;
+		DBusMessageIter dict_entry;
+
+		dbus_message_iter_recurse(&reply_iter_entry, &dict_entry);
+
+		/* Key ? */
+		dbus_message_iter_get_basic(&dict_entry, &key);
+		if (!key) {
+			dbus_message_iter_next(&reply_iter_entry);
+			continue;
+		}
+
+		/* Try to get the value */
+		if (!dbus_message_iter_next(&dict_entry)) {
+			dbus_message_iter_next(&reply_iter_entry);
+			continue;
+		}
+
+		dbus_message_iter_get_basic(&dict_entry, &xml);
+
+		id = sdp_xml_parse_record(xml);
+		if (id != NULL)
+			break;
+		dbus_message_iter_next(&reply_iter_entry);
+	}
+
+	dbus_message_unref(reply);
+
+	return id;
+}
+
+static void print_printer_details(const char *name, const char *bdaddr,
+								const char *id)
+{
+	char *uri, *escaped;
+
+	escaped = g_strdelimit(g_strdup(name), "\"", '\'');
+	uri = g_strdup_printf("bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c",
+				bdaddr[0], bdaddr[1],
+				bdaddr[3], bdaddr[4],
+				bdaddr[6], bdaddr[7],
+				bdaddr[9], bdaddr[10],
+				bdaddr[12], bdaddr[13],
+				bdaddr[15], bdaddr[16]);
+	printf("direct %s \"%s\" \"%s (Bluetooth)\"", uri, escaped, escaped);
+	if (id != NULL)
+		printf(" \"%s\"\n", id);
+	else
+		printf("\n");
+	g_free(escaped);
+	g_free(uri);
+}
+
+static void add_device_to_list(const char *name, const char *bdaddr,
+								const char *id)
+{
+	struct cups_device *device;
+	GSList *l;
+
+	/* Look for the device in the list */
+	for (l = device_list; l != NULL; l = l->next) {
+		device = (struct cups_device *) l->data;
+
+		if (strcmp(device->bdaddr, bdaddr) == 0) {
+			if (device->name != name) {
+				g_free(device->name);
+				device->name = g_strdup(name);
+			}
+			g_free(device->id);
+			device->id = g_strdup(id);
+			return;
+		}
+	}
+
+	/* Or add it to the list if it's not there */
+	device = g_new0(struct cups_device, 1);
+	device->bdaddr = g_strdup(bdaddr);
+	device->name = g_strdup(name);
+	device->id = g_strdup(id);
+
+	device_list = g_slist_prepend(device_list, device);
+	print_printer_details(device->name, device->bdaddr, device->id);
+}
+
+static gboolean parse_device_properties(DBusMessageIter *reply_iter,
+						char **name, char **bdaddr)
+{
+	guint32 class = 0;
+	DBusMessageIter reply_iter_entry;
+
+	if (dbus_message_iter_get_arg_type(reply_iter) != DBUS_TYPE_ARRAY)
+		return FALSE;
+
+	dbus_message_iter_recurse(reply_iter, &reply_iter_entry);
+
+	while (dbus_message_iter_get_arg_type(&reply_iter_entry) ==
+							DBUS_TYPE_DICT_ENTRY) {
+		const char *key;
+		DBusMessageIter dict_entry, iter_dict_val;
+
+		dbus_message_iter_recurse(&reply_iter_entry, &dict_entry);
+
+		/* Key == Class ? */
+		dbus_message_iter_get_basic(&dict_entry, &key);
+		if (!key) {
+			dbus_message_iter_next(&reply_iter_entry);
+			continue;
+		}
+
+		if (strcmp(key, "Class") != 0 &&
+				strcmp(key, "Alias") != 0 &&
+				strcmp(key, "Address") != 0) {
+			dbus_message_iter_next(&reply_iter_entry);
+			continue;
+		}
+
+		/* Try to get the value */
+		if (!dbus_message_iter_next(&dict_entry)) {
+			dbus_message_iter_next(&reply_iter_entry);
+			continue;
+		}
+		dbus_message_iter_recurse(&dict_entry, &iter_dict_val);
+		if (strcmp(key, "Class") == 0) {
+			dbus_message_iter_get_basic(&iter_dict_val, &class);
+		} else {
+			const char *value;
+			dbus_message_iter_get_basic(&iter_dict_val, &value);
+			if (strcmp(key, "Alias") == 0) {
+				*name = g_strdup(value);
+			} else if (bdaddr) {
+				*bdaddr = g_strdup(value);
+			}
+		}
+		dbus_message_iter_next(&reply_iter_entry);
+	}
+
+	if (class == 0)
+		return FALSE;
+	if (((class & 0x1f00) >> 8) == 0x06 && (class & 0x80))
+		return TRUE;
+
+	return FALSE;
+}
+
+static gboolean device_is_printer(const char *adapter, const char *device_path, char **name, char **bdaddr)
+{
+	DBusMessage *message, *reply;
+	DBusMessageIter reply_iter;
+	gboolean retval;
+
+	message = dbus_message_new_method_call("org.bluez", device_path,
+							"org.bluez.Device",
+							"GetProperties");
+
+	reply = dbus_connection_send_with_reply_and_block(conn,
+							message, -1, NULL);
+
+	dbus_message_unref(message);
+
+	if (!reply)
+		return FALSE;
+
+	dbus_message_iter_init(reply, &reply_iter);
+
+	retval = parse_device_properties(&reply_iter, name, bdaddr);
+
+	dbus_message_unref(reply);
+
+	return retval;
+}
+
+static void remote_device_found(const char *adapter, const char *bdaddr,
+							const char *name)
+{
+	DBusMessage *message, *reply, *adapter_reply;
+	DBusMessageIter iter;
+	char *object_path = NULL;
+	char *id;
+
+	adapter_reply = NULL;
+
+	if (adapter == NULL) {
+		message = dbus_message_new_method_call("org.bluez", "/",
+							"org.bluez.Manager",
+							"DefaultAdapter");
+
+		adapter_reply = dbus_connection_send_with_reply_and_block(conn,
+							message, -1, NULL);
+
+		dbus_message_unref(message);
+
+		if (!adapter_reply)
+			return;
+
+		if (dbus_message_get_args(adapter_reply, NULL,
+					DBUS_TYPE_OBJECT_PATH, &adapter,
+					DBUS_TYPE_INVALID) == FALSE) {
+			dbus_message_unref(adapter_reply);
+			return;
+		}
+	}
+
+	message = dbus_message_new_method_call("org.bluez", adapter,
+							"org.bluez.Adapter",
+							"FindDevice");
+	dbus_message_iter_init_append(message, &iter);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+
+	if (adapter_reply != NULL)
+		dbus_message_unref(adapter_reply);
+
+	reply = dbus_connection_send_with_reply_and_block(conn,
+							message, -1, NULL);
+
+	dbus_message_unref(message);
+
+	if (!reply) {
+		message = dbus_message_new_method_call("org.bluez", adapter,
+							"org.bluez.Adapter",
+							"CreateDevice");
+		dbus_message_iter_init_append(message, &iter);
+		dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+
+		reply = dbus_connection_send_with_reply_and_block(conn,
+							message, -1, NULL);
+
+		dbus_message_unref(message);
+
+		if (!reply)
+			return;
+	}
+
+	if (dbus_message_get_args(reply, NULL,
+					DBUS_TYPE_OBJECT_PATH, &object_path,
+					DBUS_TYPE_INVALID) == FALSE) {
+		dbus_message_unref(reply);
+		return;
+	}
+
+	id = device_get_ieee1284_id(adapter, object_path);
+	add_device_to_list(name, bdaddr, id);
+	g_free(id);
+
+	dbus_message_unref(reply);
+}
+
+static void discovery_completed(void)
+{
+	g_slist_free(device_list);
+	device_list = NULL;
+
+	g_main_loop_quit(loop);
+}
+
+static void remote_device_disappeared(const char *bdaddr)
+{
+	GSList *l;
+
+	for (l = device_list; l != NULL; l = l->next) {
+		struct cups_device *device = l->data;
+
+		if (strcmp(device->bdaddr, bdaddr) == 0) {
+			g_free(device->name);
+			g_free(device->bdaddr);
+			g_free(device);
+			device_list = g_slist_delete_link(device_list, l);
+			return;
+		}
+	}
+}
+
+static gboolean list_known_printers(const char *adapter)
+{
+	DBusMessageIter reply_iter, iter_array;
+	DBusError error;
+	DBusMessage *message, *reply;
+
+	message = dbus_message_new_method_call("org.bluez", adapter,
+						"org.bluez.Adapter",
+						"ListDevices");
+	if (message == NULL)
+		return FALSE;
+
+	dbus_error_init(&error);
+	reply = dbus_connection_send_with_reply_and_block(conn, message,
+								-1, &error);
+
+	dbus_message_unref(message);
+
+	if (dbus_error_is_set(&error))
+		return FALSE;
+
+	dbus_message_iter_init(reply, &reply_iter);
+	if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
+		dbus_message_unref(reply);
+		return FALSE;
+	}
+
+	dbus_message_iter_recurse(&reply_iter, &iter_array);
+	while (dbus_message_iter_get_arg_type(&iter_array) ==
+						DBUS_TYPE_OBJECT_PATH) {
+		const char *object_path;
+		char *name = NULL;
+		char *bdaddr = NULL;
+
+		dbus_message_iter_get_basic(&iter_array, &object_path);
+		if (device_is_printer(adapter, object_path, &name, &bdaddr)) {
+			char *id;
+
+			id = device_get_ieee1284_id(adapter, object_path);
+			add_device_to_list(name, bdaddr, id);
+			g_free(id);
+		}
+		g_free(name);
+		g_free(bdaddr);
+		dbus_message_iter_next(&iter_array);
+	}
+
+	dbus_message_unref(reply);
+
+	return FALSE;
+}
+
+static DBusHandlerResult filter_func(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	if (dbus_message_is_signal(message, "org.bluez.Adapter",
+						"DeviceFound")) {
+		const char *adapter, *bdaddr;
+		char *name;
+		DBusMessageIter iter;
+
+		dbus_message_iter_init(message, &iter);
+		dbus_message_iter_get_basic(&iter, &bdaddr);
+		dbus_message_iter_next(&iter);
+
+		adapter = dbus_message_get_path(message);
+		if (parse_device_properties(&iter, &name, NULL))
+			remote_device_found(adapter, bdaddr, name);
+		g_free (name);
+	} else if (dbus_message_is_signal(message, "org.bluez.Adapter",
+						"DeviceDisappeared")) {
+		const char *bdaddr;
+
+		dbus_message_get_args(message, NULL,
+					DBUS_TYPE_STRING, &bdaddr,
+					DBUS_TYPE_INVALID);
+		remote_device_disappeared(bdaddr);
+	} else if (dbus_message_is_signal(message, "org.bluez.Adapter",
+						"PropertyChanged")) {
+		DBusMessageIter iter, value_iter;
+		const char *name;
+		gboolean discovering;
+
+		dbus_message_iter_init(message, &iter);
+		dbus_message_iter_get_basic(&iter, &name);
+		if (name == NULL || strcmp(name, "Discovering") != 0)
+			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+		dbus_message_iter_next(&iter);
+		dbus_message_iter_recurse(&iter, &value_iter);
+		dbus_message_iter_get_basic(&value_iter, &discovering);
+
+		if (discovering == FALSE && doing_disco) {
+			doing_disco = FALSE;
+			discovery_completed();
+		}
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static gboolean list_printers(void)
+{
+	/* 1. Connect to the bus
+	 * 2. Get the manager
+	 * 3. Get the default adapter
+	 * 4. Get a list of devices
+	 * 5. Get the class of each device
+	 * 6. Print the details from each printer device
+	 */
+	DBusError error;
+	dbus_bool_t hcid_exists;
+	DBusMessage *reply, *message;
+	DBusMessageIter reply_iter;
+	char *adapter, *match;
+
+	conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+	if (conn == NULL)
+		return TRUE;
+
+	dbus_error_init(&error);
+	hcid_exists = dbus_bus_name_has_owner(conn, "org.bluez", &error);
+	if (dbus_error_is_set(&error))
+		return TRUE;
+
+	if (!hcid_exists)
+		return TRUE;
+
+	/* Get the default adapter */
+	message = dbus_message_new_method_call("org.bluez", "/",
+						"org.bluez.Manager",
+						"DefaultAdapter");
+	if (message == NULL) {
+		dbus_connection_unref(conn);
+		return FALSE;
+	}
+
+	reply = dbus_connection_send_with_reply_and_block(conn,
+							message, -1, &error);
+
+	dbus_message_unref(message);
+
+	if (dbus_error_is_set(&error)) {
+		dbus_connection_unref(conn);
+		/* No adapter */
+		return TRUE;
+	}
+
+	dbus_message_iter_init(reply, &reply_iter);
+	if (dbus_message_iter_get_arg_type(&reply_iter) !=
+						DBUS_TYPE_OBJECT_PATH) {
+		dbus_message_unref(reply);
+		dbus_connection_unref(conn);
+		return FALSE;
+	}
+
+	dbus_message_iter_get_basic(&reply_iter, &adapter);
+	adapter = g_strdup(adapter);
+	dbus_message_unref(reply);
+
+	if (!dbus_connection_add_filter(conn, filter_func, adapter, g_free)) {
+		g_free(adapter);
+		dbus_connection_unref(conn);
+		return FALSE;
+	}
+
+#define MATCH_FORMAT				\
+	"type='signal',"			\
+	"interface='org.bluez.Adapter',"	\
+	"sender='org.bluez',"			\
+	"path='%s'"
+
+	match = g_strdup_printf(MATCH_FORMAT, adapter);
+	dbus_bus_add_match(conn, match, &error);
+	g_free(match);
+
+	/* Add the the recent devices */
+	list_known_printers(adapter);
+
+	doing_disco = TRUE;
+	message = dbus_message_new_method_call("org.bluez", adapter,
+					"org.bluez.Adapter",
+					"StartDiscovery");
+
+	if (!dbus_connection_send_with_reply(conn, message, NULL, -1)) {
+		dbus_message_unref(message);
+		dbus_connection_unref(conn);
+		g_free(adapter);
+		return FALSE;
+	}
+	dbus_message_unref(message);
+
+	loop = g_main_loop_new(NULL, TRUE);
+	g_main_loop_run(loop);
+
+	g_free(adapter);
+	dbus_connection_unref(conn);
+
+	return TRUE;
+}
+
+static gboolean print_ieee1284(const char *bdaddr)
+{
+	DBusMessage *message, *reply, *adapter_reply;
+	DBusMessageIter iter;
+	char *object_path = NULL;
+	char *adapter;
+	char *id;
+
+	adapter_reply = NULL;
+
+	conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+	if (conn == NULL)
+		return FALSE;
+
+	message = dbus_message_new_method_call("org.bluez", "/",
+			"org.bluez.Manager",
+			"DefaultAdapter");
+
+	adapter_reply = dbus_connection_send_with_reply_and_block(conn,
+			message, -1, NULL);
+
+	dbus_message_unref(message);
+
+	if (!adapter_reply)
+		return FALSE;
+
+	if (dbus_message_get_args(adapter_reply, NULL,
+			DBUS_TYPE_OBJECT_PATH, &adapter,
+			DBUS_TYPE_INVALID) == FALSE) {
+		dbus_message_unref(adapter_reply);
+		return FALSE;
+	}
+
+	message = dbus_message_new_method_call("org.bluez", adapter,
+			"org.bluez.Adapter",
+			"FindDevice");
+	dbus_message_iter_init_append(message, &iter);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+
+	if (adapter_reply != NULL)
+		dbus_message_unref(adapter_reply);
+
+	reply = dbus_connection_send_with_reply_and_block(conn,
+			message, -1, NULL);
+
+	dbus_message_unref(message);
+
+	if (!reply) {
+		message = dbus_message_new_method_call("org.bluez", adapter,
+				"org.bluez.Adapter",
+				"CreateDevice");
+		dbus_message_iter_init_append(message, &iter);
+		dbus_message_iter_append_basic(&iter,
+				DBUS_TYPE_STRING, &bdaddr);
+
+		reply = dbus_connection_send_with_reply_and_block(conn,
+				message, -1, NULL);
+
+		dbus_message_unref(message);
+
+		if (!reply)
+			return FALSE;
+	}
+
+	if (dbus_message_get_args(reply, NULL,
+					DBUS_TYPE_OBJECT_PATH, &object_path,
+					DBUS_TYPE_INVALID) == FALSE) {
+		dbus_message_unref(reply);
+		return FALSE;
+	}
+
+	id = device_get_ieee1284_id(adapter, object_path);
+	if (id == NULL) {
+		dbus_message_unref(reply);
+		return FALSE;
+	}
+	printf("%s", id);
+	g_free(id);
+
+	dbus_message_unref(reply);
+
+	return TRUE;
+}
+
+/*
+ *  Usage: printer-uri job-id user title copies options [file]
+ *
+ */
+
+int main(int argc, char *argv[])
+{
+	sdp_session_t *sdp;
+	bdaddr_t bdaddr;
+	unsigned short ctrl_psm, data_psm;
+	uint8_t channel, b[6];
+	char *ptr, str[3], device[18], service[12];
+	const char *uri, *cups_class;
+	int i, err, fd, copies, proto;
+
+	/* Make sure status messages are not buffered */
+	setbuf(stderr, NULL);
+
+	/* Make sure output is not buffered */
+	setbuf(stdout, NULL);
+
+	/* Ignore SIGPIPE signals */
+#ifdef HAVE_SIGSET
+	sigset(SIGPIPE, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+	memset(&action, 0, sizeof(action));
+	action.sa_handler = SIG_IGN;
+	sigaction(SIGPIPE, &action, NULL);
+#else
+	signal(SIGPIPE, SIG_IGN);
+#endif /* HAVE_SIGSET */
+
+	if (argc == 1) {
+		if (list_printers() == TRUE)
+			return CUPS_BACKEND_OK;
+		else
+			return CUPS_BACKEND_FAILED;
+	} else if (argc == 3 && strcmp(argv[1], "--get-deviceid") == 0) {
+		if (bachk(argv[2]) < 0) {
+			fprintf(stderr, "Invalid Bluetooth address '%s'\n",
+					argv[2]);
+			return CUPS_BACKEND_FAILED;
+		}
+		if (print_ieee1284(argv[2]) == FALSE)
+			return CUPS_BACKEND_FAILED;
+		return CUPS_BACKEND_OK;
+	}
+
+	if (argc < 6 || argc > 7) {
+		fprintf(stderr, "Usage: bluetooth job-id user title copies"
+				" options [file]\n");
+		fprintf(stderr, "       bluetooth --get-deviceid [bdaddr]\n");
+		return CUPS_BACKEND_FAILED;
+	}
+
+	if (argc == 6) {
+		fd = 0;
+		copies = 1;
+	} else {
+		if ((fd = open(argv[6], O_RDONLY)) < 0) {
+			perror("ERROR: Unable to open print file");
+			return CUPS_BACKEND_FAILED;
+		}
+		copies = atoi(argv[4]);
+	}
+
+	uri = getenv("DEVICE_URI");
+	if (!uri)
+		uri = argv[0];
+
+	if (strncasecmp(uri, "bluetooth://", 12)) {
+		fprintf(stderr, "ERROR: No device URI found\n");
+		return CUPS_BACKEND_FAILED;
+	}
+
+	ptr = argv[0] + 12;
+	for (i = 0; i < 6; i++) {
+		strncpy(str, ptr, 2);
+		b[i] = (uint8_t) strtol(str, NULL, 16);
+		ptr += 2;
+	}
+	sprintf(device, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+			b[0], b[1], b[2], b[3], b[4], b[5]);
+
+	str2ba(device, &bdaddr);
+
+	ptr = strchr(ptr, '/');
+	if (ptr) {
+		strncpy(service, ptr + 1, 12);
+
+		if (!strncasecmp(ptr + 1, "spp", 3))
+			proto = 1;
+		else if (!strncasecmp(ptr + 1, "hcrp", 4))
+			proto = 2;
+		else
+			proto = 0;
+	} else {
+		strcpy(service, "auto");
+		proto = 0;
+	}
+
+	cups_class = getenv("CLASS");
+
+	fprintf(stderr,
+		"DEBUG: %s device %s service %s fd %d copies %d class %s\n",
+			argv[0], device, service, fd, copies,
+			cups_class ? cups_class : "(none)");
+
+	fputs("STATE: +connecting-to-device\n", stderr);
+
+service_search:
+	sdp = sdp_connect(BDADDR_ANY, &bdaddr, SDP_RETRY_IF_BUSY);
+	if (!sdp) {
+		fprintf(stderr, "ERROR: Can't open Bluetooth connection\n");
+		return CUPS_BACKEND_FAILED;
+	}
+
+	switch (proto) {
+	case 1:
+		err = sdp_search_spp(sdp, &channel);
+		break;
+	case 2:
+		err = sdp_search_hcrp(sdp, &ctrl_psm, &data_psm);
+		break;
+	default:
+		proto = 2;
+		err = sdp_search_hcrp(sdp, &ctrl_psm, &data_psm);
+		if (err) {
+			proto = 1;
+			err = sdp_search_spp(sdp, &channel);
+		}
+		break;
+	}
+
+	sdp_close(sdp);
+
+	if (err) {
+		if (cups_class) {
+			fputs("INFO: Unable to contact printer, queuing on "
+					"next printer in class...\n", stderr);
+			sleep(5);
+			return CUPS_BACKEND_FAILED;
+		}
+		sleep(20);
+		fprintf(stderr, "ERROR: Can't get service information\n");
+		goto service_search;
+	}
+
+connect:
+	switch (proto) {
+	case 1:
+		err = spp_print(BDADDR_ANY, &bdaddr, channel,
+						fd, copies, cups_class);
+		break;
+	case 2:
+		err = hcrp_print(BDADDR_ANY, &bdaddr, ctrl_psm, data_psm,
+						fd, copies, cups_class);
+		break;
+	default:
+		err = CUPS_BACKEND_FAILED;
+		fprintf(stderr, "ERROR: Unsupported protocol\n");
+		break;
+	}
+
+	if (err == CUPS_BACKEND_FAILED && cups_class) {
+		fputs("INFO: Unable to contact printer, queuing on "
+					"next printer in class...\n", stderr);
+		sleep(5);
+		return CUPS_BACKEND_FAILED;
+	} else if (err == CUPS_BACKEND_RETRY) {
+		sleep(20);
+		goto connect;
+	}
+
+	if (fd != 0)
+		close(fd);
+
+	if (!err)
+		fprintf(stderr, "INFO: Ready to print\n");
+
+	return err;
+}
diff --git a/profiles/cups/sdp.c b/profiles/cups/sdp.c
new file mode 100644
index 0000000..c7f17a4
--- /dev/null
+++ b/profiles/cups/sdp.c
@@ -0,0 +1,119 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "cups.h"
+
+int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm)
+{
+	sdp_list_t *srch, *attrs, *rsp;
+	uuid_t svclass;
+	uint16_t attr1, attr2;
+	int err;
+
+	if (!sdp)
+		return -1;
+
+	sdp_uuid16_create(&svclass, HCR_PRINT_SVCLASS_ID);
+	srch = sdp_list_append(NULL, &svclass);
+
+	attr1 = SDP_ATTR_PROTO_DESC_LIST;
+	attrs = sdp_list_append(NULL, &attr1);
+	attr2 = SDP_ATTR_ADD_PROTO_DESC_LIST;
+	attrs = sdp_list_append(attrs, &attr2);
+
+	err = sdp_service_search_attr_req(sdp, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp);
+	if (err)
+		return -1;
+
+	for (; rsp; rsp = rsp->next) {
+		sdp_record_t *rec = (sdp_record_t *) rsp->data;
+		sdp_list_t *protos;
+
+		if (!sdp_get_access_protos(rec, &protos)) {
+			unsigned short psm = sdp_get_proto_port(protos, L2CAP_UUID);
+			if (psm > 0) {
+				*ctrl_psm = psm;
+			}
+		}
+
+		if (!sdp_get_add_access_protos(rec, &protos)) {
+			unsigned short psm = sdp_get_proto_port(protos, L2CAP_UUID);
+			if (psm > 0 && *ctrl_psm > 0) {
+				*data_psm = psm;
+				return 0;
+			}
+		}
+	}
+
+	return -1;
+}
+
+int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel)
+{
+	sdp_list_t *srch, *attrs, *rsp;
+	uuid_t svclass;
+	uint16_t attr;
+	int err;
+
+	if (!sdp)
+		return -1;
+
+	sdp_uuid16_create(&svclass, SERIAL_PORT_SVCLASS_ID);
+	srch = sdp_list_append(NULL, &svclass);
+
+	attr = SDP_ATTR_PROTO_DESC_LIST;
+	attrs = sdp_list_append(NULL, &attr);
+
+	err = sdp_service_search_attr_req(sdp, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp);
+	if (err)
+		return -1;
+
+	for (; rsp; rsp = rsp->next) {
+		sdp_record_t *rec = (sdp_record_t *) rsp->data;
+		sdp_list_t *protos;
+
+		if (!sdp_get_access_protos(rec, &protos)) {
+			uint8_t ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+			if (ch > 0) {
+				*channel = ch;
+				return 0;
+			}
+		}
+	}
+
+	return -1;
+}
diff --git a/profiles/cups/spp.c b/profiles/cups/spp.c
new file mode 100644
index 0000000..d906ed2
--- /dev/null
+++ b/profiles/cups/spp.c
@@ -0,0 +1,118 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "cups.h"
+
+int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies, const char *cups_class)
+{
+	struct sockaddr_rc addr;
+	unsigned char buf[2048];
+	int i, sk, err, len;
+
+	if ((sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
+		perror("ERROR: Can't create socket");
+		if (cups_class)
+			return CUPS_BACKEND_FAILED;
+		else
+			return CUPS_BACKEND_RETRY;
+	}
+
+	addr.rc_family = AF_BLUETOOTH;
+	bacpy(&addr.rc_bdaddr, src);
+	addr.rc_channel = 0;
+
+	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("ERROR: Can't bind socket");
+		close(sk);
+		if (cups_class)
+			return CUPS_BACKEND_FAILED;
+		else
+			return CUPS_BACKEND_RETRY;
+	}
+
+	addr.rc_family = AF_BLUETOOTH;
+	bacpy(&addr.rc_bdaddr, dst);
+	addr.rc_channel = channel;
+
+	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("ERROR: Can't connect to device");
+		close(sk);
+		if (cups_class)
+			return CUPS_BACKEND_FAILED;
+		else
+			return CUPS_BACKEND_RETRY;
+	}
+
+	fputs("STATE: -connecting-to-device\n", stderr);
+
+	/* Ignore SIGTERM signals if printing from stdin */
+	if (fd == 0) {
+#ifdef HAVE_SIGSET
+		sigset(SIGTERM, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+		memset(&action, 0, sizeof(action));
+		sigemptyset(&action.sa_mask);
+		action.sa_handler = SIG_IGN;
+		sigaction(SIGTERM, &action, NULL);
+#else
+		signal(SIGTERM, SIG_IGN);
+#endif /* HAVE_SIGSET */
+	}
+
+	for (i = 0; i < copies; i++) {
+
+		if (fd != 0) {
+			fprintf(stderr, "PAGE: 1 1\n");
+			lseek(fd, 0, SEEK_SET);
+		}
+
+		while ((len = read(fd, buf, sizeof(buf))) > 0) {
+			err = write(sk, buf, len);
+			if (err < 0) {
+				perror("ERROR: Error writing to device");
+				close(sk);
+				return CUPS_BACKEND_FAILED;
+			}
+		}
+
+	}
+
+	close(sk);
+
+	return CUPS_BACKEND_OK;
+}
-- 
1.7.10.2


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH -v3 18/19] cups: move it to profiles folder
  2012-07-04 12:51 ` [PATCH -v3 18/19] cups: move it to " Gustavo Padovan
@ 2012-07-04 13:34   ` Marcel Holtmann
  0 siblings, 0 replies; 15+ messages in thread
From: Marcel Holtmann @ 2012-07-04 13:34 UTC (permalink / raw)
  To: Gustavo Padovan; +Cc: linux-bluetooth, Gustavo Padovan

Hi Gustavo,

> ---
>  Makefile.tools       |   12 +-
>  cups/cups.h          |   38 ---
>  cups/hcrp.c          |  368 ---------------------
>  cups/main.c          |  896 --------------------------------------------------
>  cups/sdp.c           |  119 -------
>  cups/spp.c           |  118 -------
>  profiles/cups/cups.h |   38 +++
>  profiles/cups/hcrp.c |  368 +++++++++++++++++++++
>  profiles/cups/main.c |  896 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  profiles/cups/sdp.c  |  119 +++++++
>  profiles/cups/spp.c  |  118 +++++++
>  11 files changed, 1547 insertions(+), 1543 deletions(-)
>  delete mode 100644 cups/cups.h
>  delete mode 100644 cups/hcrp.c
>  delete mode 100644 cups/main.c
>  delete mode 100644 cups/sdp.c
>  delete mode 100644 cups/spp.c
>  create mode 100644 profiles/cups/cups.h
>  create mode 100644 profiles/cups/hcrp.c
>  create mode 100644 profiles/cups/main.c
>  create mode 100644 profiles/cups/sdp.c
>  create mode 100644 profiles/cups/spp.c

please stop moving things around until I agreed with any new directory
structure.

Regards

Marcel



^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2012-07-04 13:34 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-04 12:51 [PATCH -v3 01/19] headset: remove deprecated D-Bus methods Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 02/19] sink: remove deprecated D-Bus method Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 03/19] serial: remove SerialProxy interface Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 04/19] serial: remove unneeded headers include Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 05/19] input: remove unneeded header inclusions Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 06/19] serial: remove old way to connect to a serial port Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 07/19] emulator: move it to the tools folder Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 08/19] btmgmt: move to " Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 09/19] alert: move alert to profiles dir Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 10/19] deviceinfo: move to profiles folder Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 12/19] thermometer: move to the " Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 13/19] time: " Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 16/19] serial: move it " Gustavo Padovan
2012-07-04 12:51 ` [PATCH -v3 18/19] cups: move it to " Gustavo Padovan
2012-07-04 13:34   ` Marcel Holtmann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.