All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] network: fix network Connect() method parameters
@ 2012-07-04  8:17 Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 02/28] remove the hciops plugin Gustavo Padovan
                   ` (21 more replies)
  0 siblings, 22 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

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

---
 network/connection.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/network/connection.c b/network/connection.c
index 544ec3a..59423a9 100644
--- a/network/connection.c
+++ b/network/connection.c
@@ -554,7 +554,9 @@ static void path_unregister(void *data)
 
 static const GDBusMethodTable connection_methods[] = {
 	{ GDBUS_ASYNC_METHOD("Connect",
-			NULL, NULL, connection_connect) },
+				GDBUS_ARGS({"uuid", "s"}),
+				GDBUS_ARGS({"interface", "s"}),
+				connection_connect) },
 	{ GDBUS_METHOD("Disconnect",
 			NULL, NULL, connection_disconnect) },
 	{ GDBUS_METHOD("GetProperties",
-- 
1.7.10.2


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

* [PATCH -v2 02/28] remove the hciops plugin
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 03/28] headset: remove deprecated DBus methods Gustavo Padovan
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

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

hciops was replaced by mgmtops, it should not be maintained anymore and is
now removed.
---
 Makefile.am      |    4 +-
 plugins/hciops.c | 3943 ------------------------------------------------------
 2 files changed, 2 insertions(+), 3945 deletions(-)
 delete mode 100644 plugins/hciops.c

diff --git a/Makefile.am b/Makefile.am
index 7415979..5009ca8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -236,8 +236,8 @@ builtin_sources += thermometer/main.c \
 endif
 
 
-builtin_modules += hciops mgmtops
-builtin_sources += plugins/hciops.c plugins/mgmtops.c
+builtin_modules += mgmtops
+builtin_sources += plugins/mgmtops.c
 
 if HAL
 builtin_modules += hal
diff --git a/plugins/hciops.c b/plugins/hciops.c
deleted file mode 100644
index d74f2ea..0000000
--- a/plugins/hciops.c
+++ /dev/null
@@ -1,3943 +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 <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <glib.h>
-
-#include "hcid.h"
-#include "sdpd.h"
-#include "btio.h"
-#include "adapter.h"
-#include "device.h"
-#include "plugin.h"
-#include "log.h"
-#include "storage.h"
-#include "event.h"
-#include "manager.h"
-#include "oob.h"
-#include "eir.h"
-
-#define DISCOV_HALTED 0
-#define DISCOV_INQ 1
-#define DISCOV_SCAN 2
-#define DISCOV_NAMES 3
-
-#define TIMEOUT_BR_LE_SCAN 5120 /* TGAP(100)/2 */
-#define TIMEOUT_LE_SCAN 10240 /* TGAP(gen_disc_scan_min) */
-
-#define LENGTH_BR_INQ 0x08
-#define LENGTH_BR_LE_INQ 0x04
-
-static int start_scanning(int index, int timeout);
-
-static int child_pipe[2] = { -1, -1 };
-
-static guint child_io_id = 0;
-static guint ctl_io_id = 0;
-
-enum adapter_type {
-	BR_EDR,
-	LE_ONLY,
-	BR_EDR_LE,
-	UNKNOWN,
-};
-
-/* Commands sent by kernel on starting an adapter */
-enum {
-	PENDING_BDADDR,
-	PENDING_VERSION,
-	PENDING_FEATURES,
-	PENDING_NAME,
-};
-
-struct bt_conn {
-	struct dev_info *dev;
-	bdaddr_t bdaddr;
-	uint16_t handle;
-	uint8_t loc_cap;
-	uint8_t loc_auth;
-	uint8_t rem_cap;
-	uint8_t rem_auth;
-	uint8_t rem_oob_data;
-	gboolean bonding_initiator;
-	gboolean secmode3;
-	GIOChannel *io; /* For raw L2CAP socket (bonding) */
-};
-
-struct oob_data {
-	bdaddr_t bdaddr;
-	uint8_t hash[16];
-	uint8_t randomizer[16];
-};
-
-enum name_state {
-	NAME_UNKNOWN,
-	NAME_NEEDED,
-	NAME_NOT_NEEDED,
-	NAME_PENDING,
-};
-
-struct found_dev {
-	bdaddr_t bdaddr;
-	int8_t rssi;
-	enum name_state name_state;
-};
-
-static int max_dev = -1;
-static struct dev_info {
-	int id;
-	int sk;
-	bdaddr_t bdaddr;
-	char name[249];
-	uint8_t eir[HCI_MAX_EIR_LENGTH];
-	uint8_t features[8];
-	uint8_t extfeatures[8];
-	uint8_t ssp_mode;
-
-	int8_t tx_power;
-
-	int discov_state;
-
-	uint32_t current_cod;
-	uint32_t wanted_cod;
-	uint32_t pending_cod;
-	gboolean cache_enable;
-	gboolean already_up;
-	gboolean registered;
-	gboolean pairable;
-
-	uint8_t io_capability;
-
-	struct hci_version ver;
-
-	uint16_t did_source;
-	uint16_t did_vendor;
-	uint16_t did_product;
-	uint16_t did_version;
-
-	gboolean up;
-	uint32_t pending;
-
-	GIOChannel *io;
-	guint watch_id;
-
-	gboolean debug_keys;
-	GSList *keys;
-	uint8_t pin_length;
-
-	GSList *oob_data;
-
-	GSList *uuids;
-
-	GSList *connections;
-
-	GSList *found_devs;
-	GSList *need_name;
-
-	guint stop_scan_id;
-
-	uint16_t discoverable_timeout;
-	guint discoverable_id;
-} *devs = NULL;
-
-static int found_dev_rssi_cmp(gconstpointer a, gconstpointer b)
-{
-	const struct found_dev *d1 = a, *d2 = b;
-	int rssi1, rssi2;
-
-	if (d2->name_state == NAME_NOT_NEEDED)
-		return -1;
-
-	rssi1 = d1->rssi < 0 ? -d1->rssi : d1->rssi;
-	rssi2 = d2->rssi < 0 ? -d2->rssi : d2->rssi;
-
-	return rssi1 - rssi2;
-}
-
-static int found_dev_bda_cmp(gconstpointer a, gconstpointer b)
-{
-	const struct found_dev *d1 = a, *d2 = b;
-
-	return bacmp(&d1->bdaddr, &d2->bdaddr);
-}
-
-static void found_dev_cleanup(struct dev_info *info)
-{
-	g_slist_free_full(info->found_devs, g_free);
-	info->found_devs = NULL;
-
-	g_slist_free_full(info->need_name, g_free);
-	info->need_name = NULL;
-}
-
-static int resolve_name(struct dev_info *info, bdaddr_t *bdaddr)
-{
-	remote_name_req_cp cp;
-	char addr[18];
-
-	ba2str(bdaddr, addr);
-	DBG("hci%d dba %s", info->id, addr);
-
-	memset(&cp, 0, sizeof(cp));
-	bacpy(&cp.bdaddr, bdaddr);
-	cp.pscan_rep_mode = 0x02;
-
-	if (hci_send_cmd(info->sk, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ,
-					REMOTE_NAME_REQ_CP_SIZE, &cp) < 0)
-		return -errno;
-
-	return 0;
-}
-
-static int resolve_names(struct dev_info *info, struct btd_adapter *adapter)
-{
-	struct found_dev *dev;
-
-	DBG("found_dev %u need_name %u", g_slist_length(info->found_devs),
-					g_slist_length(info->need_name));
-
-	if (g_slist_length(info->need_name) == 0)
-		return -ENOENT;
-
-	dev = info->need_name->data;
-	resolve_name(info, &dev->bdaddr);
-	dev->name_state = NAME_PENDING;
-
-	return 0;
-}
-
-static void set_state(int index, int state)
-{
-	struct btd_adapter *adapter;
-	struct dev_info *dev = &devs[index];
-
-	if (dev->discov_state == state)
-		return;
-
-	adapter = manager_find_adapter_by_id(index);
-	if (!adapter) {
-		error("No matching adapter found");
-		return;
-	}
-
-	dev->discov_state = state;
-
-	DBG("hci%d: new state %d", index, dev->discov_state);
-
-	switch (dev->discov_state) {
-	case DISCOV_HALTED:
-		found_dev_cleanup(dev);
-		adapter_set_discovering(adapter, FALSE);
-		break;
-	case DISCOV_INQ:
-	case DISCOV_SCAN:
-		adapter_set_discovering(adapter, TRUE);
-		break;
-	case DISCOV_NAMES:
-		if (resolve_names(dev, adapter) < 0)
-			set_state(index, DISCOV_HALTED);
-		break;
-	}
-}
-
-static inline gboolean is_le_capable(int index)
-{
-	struct dev_info *dev = &devs[index];
-
-	return (dev->features[4] & LMP_LE &&
-			dev->extfeatures[0] & LMP_HOST_LE) ? TRUE : FALSE;
-}
-
-static inline gboolean is_bredr_capable(int index)
-{
-	struct dev_info *dev = &devs[index];
-
-	return (dev->features[4] & LMP_NO_BREDR) == 0 ? TRUE : FALSE;
-}
-
-static int get_adapter_type(int index)
-{
-	if (is_le_capable(index) && is_bredr_capable(index))
-		return BR_EDR_LE;
-	else if (is_le_capable(index))
-		return LE_ONLY;
-	else if (is_bredr_capable(index))
-		return BR_EDR;
-
-	return UNKNOWN;
-}
-
-static int ignore_device(struct hci_dev_info *di)
-{
-	return hci_test_bit(HCI_RAW, &di->flags) || di->type >> 4 != HCI_BREDR;
-}
-
-static struct dev_info *init_dev_info(int index, int sk, gboolean registered,
-							gboolean already_up)
-{
-	struct dev_info *dev = &devs[index];
-
-	memset(dev, 0, sizeof(*dev));
-
-	dev->id = index;
-	dev->sk = sk;
-	dev->cache_enable = TRUE;
-	dev->registered = registered;
-	dev->already_up = already_up;
-	dev->io_capability = 0x03; /* No Input No Output */
-	dev->discov_state = DISCOV_HALTED;
-
-	return dev;
-}
-
-/* Async HCI command handling with callback support */
-
-struct hci_cmd_data {
-	bt_hci_result_t		cb;
-	uint16_t		handle;
-	uint16_t		ocf;
-	gpointer		caller_data;
-};
-
-static gboolean hci_event_watch(GIOChannel *io,
-			GIOCondition cond, gpointer user_data)
-{
-	unsigned char buf[HCI_MAX_EVENT_SIZE], *body;
-	struct hci_cmd_data *cmd = user_data;
-	evt_cmd_status *evt_status;
-	evt_auth_complete *evt_auth;
-	evt_encrypt_change *evt_enc;
-	hci_event_hdr *hdr;
-	set_conn_encrypt_cp cp;
-	int dd;
-	uint16_t ocf;
-	uint8_t status = HCI_OE_POWER_OFF;
-
-	if (cond & G_IO_NVAL) {
-		cmd->cb(status, cmd->caller_data);
-		return FALSE;
-	}
-
-	if (cond & (G_IO_ERR | G_IO_HUP))
-		goto failed;
-
-	dd = g_io_channel_unix_get_fd(io);
-
-	if (read(dd, buf, sizeof(buf)) < 0)
-		goto failed;
-
-	hdr = (hci_event_hdr *) (buf + 1);
-	body = buf + (1 + HCI_EVENT_HDR_SIZE);
-
-	switch (hdr->evt) {
-	case EVT_CMD_STATUS:
-		evt_status = (evt_cmd_status *) body;
-		ocf = cmd_opcode_ocf(evt_status->opcode);
-		if (ocf != cmd->ocf)
-			return TRUE;
-		switch (ocf) {
-		case OCF_AUTH_REQUESTED:
-		case OCF_SET_CONN_ENCRYPT:
-			if (evt_status->status != 0) {
-				/* Baseband rejected command */
-				status = evt_status->status;
-				goto failed;
-			}
-			break;
-		default:
-			return TRUE;
-		}
-		/* Wait for the next event */
-		return TRUE;
-	case EVT_AUTH_COMPLETE:
-		evt_auth = (evt_auth_complete *) body;
-		if (evt_auth->handle != cmd->handle) {
-			/* Skipping */
-			return TRUE;
-		}
-
-		if (evt_auth->status != 0x00) {
-			status = evt_auth->status;
-			/* Abort encryption */
-			goto failed;
-		}
-
-		memset(&cp, 0, sizeof(cp));
-		cp.handle  = cmd->handle;
-		cp.encrypt = 1;
-
-		cmd->ocf = OCF_SET_CONN_ENCRYPT;
-
-		if (hci_send_cmd(dd, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT,
-					SET_CONN_ENCRYPT_CP_SIZE, &cp) < 0) {
-			status = HCI_COMMAND_DISALLOWED;
-			goto failed;
-		}
-		/* Wait for encrypt change event */
-		return TRUE;
-	case EVT_ENCRYPT_CHANGE:
-		evt_enc = (evt_encrypt_change *) body;
-		if (evt_enc->handle != cmd->handle)
-			return TRUE;
-
-		/* Procedure finished: reporting status */
-		status = evt_enc->status;
-		break;
-	default:
-		/* Skipping */
-		return TRUE;
-	}
-
-failed:
-	cmd->cb(status, cmd->caller_data);
-	g_io_channel_shutdown(io, TRUE, NULL);
-
-	return FALSE;
-}
-
-static int write_inq_mode(int index, uint8_t mode)
-{
-	struct dev_info *dev = &devs[index];
-	write_inquiry_mode_cp cp;
-
-	memset(&cp, 0, sizeof(cp));
-	cp.mode = mode;
-
-	if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_INQUIRY_MODE,
-					WRITE_INQUIRY_MODE_CP_SIZE, &cp) < 0)
-		return -errno;
-
-	return 0;
-}
-
-static uint8_t get_inquiry_mode(int index)
-{
-	struct dev_info *dev = &devs[index];
-
-	if (dev->features[6] & LMP_EXT_INQ)
-		return 2;
-
-	if (dev->features[3] & LMP_RSSI_INQ)
-		return 1;
-
-	if (dev->ver.manufacturer == 11 && dev->ver.hci_rev == 0x00 &&
-					dev->ver.lmp_subver == 0x0757)
-		return 1;
-
-	if (dev->ver.manufacturer == 15) {
-		if (dev->ver.hci_rev == 0x03 &&
-					dev->ver.lmp_subver == 0x6963)
-			return 1;
-		if (dev->ver.hci_rev == 0x09 &&
-					dev->ver.lmp_subver == 0x6963)
-			return 1;
-		if (dev->ver.hci_rev == 0x00 &&
-					dev->ver.lmp_subver == 0x6965)
-			return 1;
-	}
-
-	if (dev->ver.manufacturer == 31 && dev->ver.hci_rev == 0x2005 &&
-					dev->ver.lmp_subver == 0x1805)
-		return 1;
-
-	return 0;
-}
-
-static int init_ssp_mode(int index)
-{
-	struct dev_info *dev = &devs[index];
-	write_simple_pairing_mode_cp cp;
-
-	if (ioctl(dev->sk, HCIGETAUTHINFO, NULL) < 0 && errno == EINVAL)
-		return 0;
-
-	memset(&cp, 0, sizeof(cp));
-	cp.mode = 0x01;
-
-	if (hci_send_cmd(dev->sk, OGF_HOST_CTL,
-				OCF_WRITE_SIMPLE_PAIRING_MODE,
-				WRITE_SIMPLE_PAIRING_MODE_CP_SIZE, &cp) < 0)
-		return -errno;
-
-	return 0;
-}
-
-static int hciops_set_discoverable(int index, gboolean discoverable,
-							uint16_t timeout)
-{
-	struct dev_info *dev = &devs[index];
-	uint8_t mode;
-
-	if (discoverable)
-		mode = (SCAN_PAGE | SCAN_INQUIRY);
-	else
-		mode = SCAN_PAGE;
-
-	DBG("hci%d discoverable %d", index, discoverable);
-
-	if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
-								1, &mode) < 0)
-		return -errno;
-
-	dev->discoverable_timeout = timeout;
-
-	return 0;
-}
-
-static int hciops_set_pairable(int index, gboolean pairable)
-{
-	struct btd_adapter *adapter;
-
-	DBG("hci%d pairable %d", index, pairable);
-
-	adapter = manager_find_adapter(&devs[index].bdaddr);
-	if (adapter)
-		btd_adapter_pairable_changed(adapter, pairable);
-
-	devs[index].pairable = pairable;
-
-	return 0;
-}
-
-static int hciops_power_off(int index)
-{
-	struct dev_info *dev = &devs[index];
-
-	DBG("hci%d", index);
-
-	if (ioctl(dev->sk, HCIDEVDOWN, index) < 0 && errno != EALREADY)
-		return -errno;
-
-	return 0;
-}
-
-static void set_event_mask(int index)
-{
-	struct dev_info *dev = &devs[index];
-	/* The second byte is 0xff instead of 0x9f (two reserved bits
-	 * disabled) since a Broadcom 1.2 dongle doesn't respond to the
-	 * command otherwise */
-	uint8_t events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
-
-	/* Events for 1.2 and newer controllers */
-	if (dev->ver.lmp_ver > 1) {
-		events[4] |= 0x01; /* Flow Specification Complete */
-		events[4] |= 0x02; /* Inquiry Result with RSSI */
-		events[4] |= 0x04; /* Read Remote Extended Features Complete */
-		events[5] |= 0x08; /* Synchronous Connection Complete */
-		events[5] |= 0x10; /* Synchronous Connection Changed */
-	}
-
-	if (dev->features[3] & LMP_RSSI_INQ)
-		events[4] |= 0x02; /* Inquiry Result with RSSI */
-
-	if (dev->features[5] & LMP_SNIFF_SUBR)
-		events[5] |= 0x20; /* Sniff Subrating */
-
-	if (dev->features[5] & LMP_PAUSE_ENC)
-		events[5] |= 0x80; /* Encryption Key Refresh Complete */
-
-	if (dev->features[6] & LMP_EXT_INQ)
-		events[5] |= 0x40; /* Extended Inquiry Result */
-
-	if (dev->features[6] & LMP_NFLUSH_PKTS)
-		events[7] |= 0x01; /* Enhanced Flush Complete */
-
-	if (dev->features[7] & LMP_LSTO)
-		events[6] |= 0x80; /* Link Supervision Timeout Changed */
-
-	if (dev->features[6] & LMP_SIMPLE_PAIR) {
-		events[6] |= 0x01;	/* IO Capability Request */
-		events[6] |= 0x02;	/* IO Capability Response */
-		events[6] |= 0x04;	/* User Confirmation Request */
-		events[6] |= 0x08;	/* User Passkey Request */
-		events[6] |= 0x10;	/* Remote OOB Data Request */
-		events[6] |= 0x20;	/* Simple Pairing Complete */
-		events[7] |= 0x04;	/* User Passkey Notification */
-		events[7] |= 0x08;	/* Keypress Notification */
-		events[7] |= 0x10;	/* Remote Host Supported
-					 * Features Notification */
-	}
-
-	if (dev->features[4] & LMP_LE)
-		events[7] |= 0x20;	/* LE Meta-Event */
-
-	hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_SET_EVENT_MASK,
-						sizeof(events), events);
-}
-
-static void start_adapter(int index)
-{
-	struct dev_info *dev = &devs[index];
-	uint8_t inqmode;
-	uint16_t link_policy;
-
-	set_event_mask(index);
-
-	if (dev->features[6] & LMP_SIMPLE_PAIR)
-		init_ssp_mode(index);
-
-	inqmode = get_inquiry_mode(index);
-	if (inqmode)
-		write_inq_mode(index, inqmode);
-
-	if (dev->features[7] & LMP_INQ_TX_PWR)
-		hci_send_cmd(dev->sk, OGF_HOST_CTL,
-				OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL, 0, NULL);
-
-	/* Set default link policy */
-	link_policy = main_opts.link_policy;
-
-	if (!(dev->features[0] & LMP_RSWITCH))
-		link_policy &= ~HCI_LP_RSWITCH;
-	if (!(dev->features[0] & LMP_HOLD))
-		link_policy &= ~HCI_LP_HOLD;
-	if (!(dev->features[0] & LMP_SNIFF))
-		link_policy &= ~HCI_LP_SNIFF;
-	if (!(dev->features[1] & LMP_PARK))
-		link_policy &= ~HCI_LP_PARK;
-
-	link_policy = htobs(link_policy);
-	hci_send_cmd(dev->sk, OGF_LINK_POLICY, OCF_WRITE_DEFAULT_LINK_POLICY,
-					sizeof(link_policy), &link_policy);
-
-	dev->current_cod = 0;
-	memset(dev->eir, 0, sizeof(dev->eir));
-}
-
-static int hciops_stop_inquiry(int index)
-{
-	struct dev_info *dev = &devs[index];
-
-	DBG("hci%d", index);
-
-	if (hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_INQUIRY_CANCEL, 0, 0) < 0)
-		return -errno;
-
-	return 0;
-}
-
-static void update_ext_inquiry_response(int index)
-{
-	struct dev_info *dev = &devs[index];
-	write_ext_inquiry_response_cp cp;
-
-	DBG("hci%d", index);
-
-	if (!(dev->features[6] & LMP_EXT_INQ))
-		return;
-
-	if (dev->ssp_mode == 0)
-		return;
-
-	if (dev->cache_enable)
-		return;
-
-	memset(&cp, 0, sizeof(cp));
-
-	eir_create(dev->name, dev->tx_power, dev->did_vendor, dev->did_product,
-			dev->did_version, dev->did_source, dev->uuids,
-			cp.data);
-
-	if (memcmp(cp.data, dev->eir, sizeof(cp.data)) == 0)
-		return;
-
-	memcpy(dev->eir, cp.data, sizeof(cp.data));
-
-	if (hci_send_cmd(dev->sk, OGF_HOST_CTL,
-				OCF_WRITE_EXT_INQUIRY_RESPONSE,
-				WRITE_EXT_INQUIRY_RESPONSE_CP_SIZE, &cp) < 0)
-		error("Unable to write EIR data: %s (%d)",
-						strerror(errno), errno);
-}
-
-static int hciops_set_name(int index, const char *name)
-{
-	struct dev_info *dev = &devs[index];
-	change_local_name_cp cp;
-
-	DBG("hci%d, name %s", index, name);
-
-	memset(&cp, 0, sizeof(cp));
-	strncpy((char *) cp.name, name, sizeof(cp.name));
-
-	if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME,
-				CHANGE_LOCAL_NAME_CP_SIZE, &cp) < 0)
-		return -errno;
-
-	memcpy(dev->name, cp.name, 248);
-	update_ext_inquiry_response(index);
-
-	return 0;
-}
-
-static int write_class(int index, uint32_t class)
-{
-	struct dev_info *dev = &devs[index];
-	write_class_of_dev_cp cp;
-
-	DBG("hci%d class 0x%06x", index, class);
-
-	memcpy(cp.dev_class, &class, 3);
-
-	if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV,
-					WRITE_CLASS_OF_DEV_CP_SIZE, &cp) < 0)
-		return -errno;
-
-	dev->pending_cod = class;
-
-	return 0;
-}
-
-static int hciops_set_dev_class(int index, uint8_t major, uint8_t minor)
-{
-	struct dev_info *dev = &devs[index];
-	int err;
-
-	DBG("hci%d major %u minor %u", index, major, minor);
-
-	/* Update only the major and minor class bits keeping remaining bits
-	 * intact*/
-	dev->wanted_cod &= 0xffe000;
-	dev->wanted_cod |= ((major & 0x1f) << 8) | minor;
-
-	if (dev->wanted_cod == dev->current_cod ||
-			dev->cache_enable || dev->pending_cod)
-		return 0;
-
-	DBG("Changing Major/Minor class to 0x%06x", dev->wanted_cod);
-
-	err = write_class(index, dev->wanted_cod);
-	if (err < 0)
-		error("Adapter class update failed: %s (%d)",
-						strerror(-err), -err);
-
-	return err;
-}
-
-static gboolean init_adapter(int index)
-{
-	struct dev_info *dev = &devs[index];
-	struct btd_adapter *adapter = NULL;
-	gboolean existing_adapter = dev->registered;
-	uint8_t mode, on_mode, major, minor;
-	gboolean pairable, discoverable;
-	const char *name;
-	uint16_t discoverable_timeout;
-
-	if (!dev->registered) {
-		adapter = btd_manager_register_adapter(index, TRUE);
-		if (adapter)
-			dev->registered = TRUE;
-	} else {
-		adapter = manager_find_adapter(&dev->bdaddr);
-		/* FIXME: manager_find_adapter should return a new ref */
-		btd_adapter_ref(adapter);
-	}
-
-	if (adapter == NULL)
-		return FALSE;
-
-	btd_adapter_get_mode(adapter, &mode, &on_mode,
-						&discoverable_timeout,
-						&pairable);
-
-	if (existing_adapter)
-		mode = on_mode;
-
-	if (mode == MODE_OFF) {
-		hciops_power_off(index);
-		goto done;
-	}
-
-	start_adapter(index);
-
-	name = btd_adapter_get_name(adapter);
-	if (name)
-		hciops_set_name(index, name);
-
-	btd_adapter_get_class(adapter, &major, &minor);
-	hciops_set_dev_class(index, major, minor);
-
-	btd_adapter_start(adapter);
-
-	discoverable = (mode == MODE_DISCOVERABLE);
-
-	hciops_set_discoverable(index, discoverable, discoverable_timeout);
-	hciops_set_pairable(index, pairable);
-
-	if (dev->already_up)
-		hciops_stop_inquiry(index);
-
-done:
-	btd_adapter_unref(adapter);
-	return TRUE;
-}
-
-static int hciops_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb,
-							gpointer user_data)
-{
-	GIOChannel *io;
-	struct hci_cmd_data *cmd;
-	struct hci_conn_info_req *cr;
-	auth_requested_cp cp;
-	struct hci_filter nf;
-	int dd, err;
-	uint32_t link_mode;
-	uint16_t handle;
-
-	dd = hci_open_dev(index);
-	if (dd < 0)
-		return -errno;
-
-	cr = g_malloc0(sizeof(*cr) + sizeof(struct hci_conn_info));
-	cr->type = ACL_LINK;
-	bacpy(&cr->bdaddr, dst);
-
-	err = ioctl(dd, HCIGETCONNINFO, cr);
-	link_mode = cr->conn_info->link_mode;
-	handle = cr->conn_info->handle;
-	g_free(cr);
-
-	if (err < 0) {
-		err = -errno;
-		goto fail;
-	}
-
-	if (link_mode & HCI_LM_ENCRYPT) {
-		err = -EALREADY;
-		goto fail;
-	}
-
-	memset(&cp, 0, sizeof(cp));
-	cp.handle = htobs(handle);
-
-	if (hci_send_cmd(dd, OGF_LINK_CTL, OCF_AUTH_REQUESTED,
-				AUTH_REQUESTED_CP_SIZE, &cp) < 0) {
-		err = -errno;
-		goto fail;
-	}
-
-	cmd = g_new0(struct hci_cmd_data, 1);
-	cmd->handle = handle;
-	cmd->ocf = OCF_AUTH_REQUESTED;
-	cmd->cb	= cb;
-	cmd->caller_data = user_data;
-
-	hci_filter_clear(&nf);
-	hci_filter_set_ptype(HCI_EVENT_PKT, &nf);
-	hci_filter_set_event(EVT_CMD_STATUS, &nf);
-	hci_filter_set_event(EVT_AUTH_COMPLETE, &nf);
-	hci_filter_set_event(EVT_ENCRYPT_CHANGE, &nf);
-
-	if (setsockopt(dd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0) {
-		err = -errno;
-		g_free(cmd);
-		goto fail;
-	}
-
-	io = g_io_channel_unix_new(dd);
-	g_io_channel_set_close_on_unref(io, FALSE);
-	g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
-			G_IO_HUP | G_IO_ERR | G_IO_NVAL | G_IO_IN,
-			hci_event_watch, cmd, g_free);
-	g_io_channel_unref(io);
-
-	return 0;
-
-fail:
-	close(dd);
-	return err;
-}
-
-static int hciops_set_did(int index, uint16_t vendor, uint16_t product,
-					uint16_t version, uint16_t source)
-{
-	struct dev_info *dev = &devs[index];
-
-	dev->did_vendor = vendor;
-	dev->did_product = product;
-	dev->did_version = version;
-	dev->did_source = source;
-
-	return 0;
-}
-
-/* End async HCI command handling */
-
-/* Start of HCI event callbacks */
-
-static gint conn_handle_cmp(gconstpointer a, gconstpointer b)
-{
-	const struct bt_conn *conn = a;
-	uint16_t handle = *((const uint16_t *) b);
-
-	return (int) conn->handle - (int) handle;
-}
-
-static struct bt_conn *find_conn_by_handle(struct dev_info *dev,
-							uint16_t handle)
-{
-	GSList *match;
-
-	match = g_slist_find_custom(dev->connections, &handle,
-							conn_handle_cmp);
-	if (match)
-		return match->data;
-
-	return NULL;
-}
-
-static gint conn_bdaddr_cmp(gconstpointer a, gconstpointer b)
-{
-	const struct bt_conn *conn = a;
-	const bdaddr_t *bdaddr = b;
-
-	return bacmp(&conn->bdaddr, bdaddr);
-}
-
-static struct bt_conn *find_connection(struct dev_info *dev, bdaddr_t *bdaddr)
-{
-	GSList *match;
-
-	match = g_slist_find_custom(dev->connections, bdaddr, conn_bdaddr_cmp);
-	if (match)
-		return match->data;
-
-	return NULL;
-}
-
-static struct bt_conn *get_connection(struct dev_info *dev, bdaddr_t *bdaddr)
-{
-	struct bt_conn *conn;
-
-	conn = find_connection(dev, bdaddr);
-	if (conn)
-		return conn;
-
-	conn = g_new0(struct bt_conn, 1);
-
-	conn->dev = dev;
-	conn->loc_cap = dev->io_capability;
-	conn->loc_auth = 0xff;
-	conn->rem_auth = 0xff;
-	bacpy(&conn->bdaddr, bdaddr);
-
-	dev->connections = g_slist_append(dev->connections, conn);
-
-	return conn;
-}
-
-static int get_handle(int index, bdaddr_t *bdaddr, uint16_t *handle)
-{
-	struct dev_info *dev = &devs[index];
-	struct bt_conn *conn;
-	char addr[18];
-
-	ba2str(bdaddr, addr);
-	DBG("hci%d dba %s", index, addr);
-
-	conn = find_connection(dev, bdaddr);
-	if (conn == NULL)
-		return -ENOENT;
-
-	*handle = conn->handle;
-
-	return 0;
-}
-
-static int disconnect_addr(int index, bdaddr_t *dba, uint8_t reason)
-{
-	disconnect_cp cp;
-	uint16_t handle;
-	int err;
-
-	err = get_handle(index, dba, &handle);
-	if (err < 0)
-		return err;
-
-	memset(&cp, 0, sizeof(cp));
-	cp.handle = htobs(handle);
-	cp.reason = reason;
-
-	if (hci_send_cmd(devs[index].sk, OGF_LINK_CTL, OCF_DISCONNECT,
-						DISCONNECT_CP_SIZE, &cp) < 0)
-		return -errno;
-
-	return 0;
-}
-
-static void bonding_complete(struct dev_info *dev, struct bt_conn *conn,
-								uint8_t status)
-{
-	struct btd_adapter *adapter;
-
-	DBG("status 0x%02x", status);
-
-	if (conn->io != NULL) {
-		/* bonding_connect_cb takes care of the successul case */
-		if (status != 0)
-			g_io_channel_shutdown(conn->io, TRUE, NULL);
-		g_io_channel_unref(conn->io);
-		conn->io = NULL;
-	}
-
-	conn->bonding_initiator = FALSE;
-
-	adapter = manager_find_adapter(&dev->bdaddr);
-	if (adapter)
-		adapter_bonding_complete(adapter, &conn->bdaddr, status);
-}
-
-static int get_auth_info(int index, bdaddr_t *bdaddr, uint8_t *auth)
-{
-	struct dev_info *dev = &devs[index];
-	struct hci_auth_info_req req;
-	char addr[18];
-
-	ba2str(bdaddr, addr);
-	DBG("hci%d dba %s", index, addr);
-
-	memset(&req, 0, sizeof(req));
-	bacpy(&req.bdaddr, bdaddr);
-
-	if (ioctl(dev->sk, HCIGETAUTHINFO, (unsigned long) &req) < 0)
-		return -errno;
-
-	if (auth)
-		*auth = req.type;
-
-	return 0;
-}
-
-/* Link Key handling */
-
-static void link_key_request(int index, bdaddr_t *dba)
-{
-	struct dev_info *dev = &devs[index];
-	struct link_key_info *key_info;
-	struct bt_conn *conn;
-	GSList *match;
-	char da[18];
-
-	ba2str(dba, da);
-	DBG("hci%d dba %s", index, da);
-
-	conn = get_connection(dev, dba);
-	if (conn->handle == 0)
-		conn->secmode3 = TRUE;
-
-	get_auth_info(index, dba, &conn->loc_auth);
-
-	DBG("kernel auth requirements = 0x%02x", conn->loc_auth);
-
-	match = g_slist_find_custom(dev->keys, dba, (GCompareFunc) bacmp);
-	if (match)
-		key_info = match->data;
-	else
-		key_info = NULL;
-
-	DBG("Matching key %s", key_info ? "found" : "not found");
-
-	if (key_info == NULL || (!dev->debug_keys && key_info->type == 0x03)) {
-		/* Link key not found */
-		hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_LINK_KEY_NEG_REPLY,
-								6, dba);
-		return;
-	}
-
-	/* Link key found */
-
-	DBG("link key type 0x%02x", key_info->type);
-
-	/* Don't use unauthenticated combination keys if MITM is
-	 * required */
-	if (key_info->type == 0x04 && conn->loc_auth != 0xff &&
-						(conn->loc_auth & 0x01))
-		hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_LINK_KEY_NEG_REPLY,
-								6, dba);
-	else {
-		link_key_reply_cp lr;
-
-		memcpy(lr.link_key, key_info->key, 16);
-		bacpy(&lr.bdaddr, dba);
-
-		hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_LINK_KEY_REPLY,
-						LINK_KEY_REPLY_CP_SIZE, &lr);
-	}
-}
-
-static void link_key_notify(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_link_key_notify *evt = ptr;
-	bdaddr_t *dba = &evt->bdaddr;
-	struct link_key_info *key_info;
-	uint8_t old_key_type, key_type;
-	struct bt_conn *conn;
-	GSList *match;
-	char da[18];
-	uint8_t status = 0;
-
-	ba2str(dba, da);
-	DBG("hci%d dba %s type %d", index, da, evt->key_type);
-
-	conn = get_connection(dev, &evt->bdaddr);
-
-	match = g_slist_find_custom(dev->keys, dba, (GCompareFunc) bacmp);
-	if (match)
-		key_info = match->data;
-	else
-		key_info = NULL;
-
-	if (key_info == NULL) {
-		key_info = g_new0(struct link_key_info, 1);
-		bacpy(&key_info->bdaddr, &evt->bdaddr);
-		old_key_type = 0xff;
-	} else {
-		dev->keys = g_slist_remove(dev->keys, key_info);
-		old_key_type = key_info->type;
-	}
-
-	memcpy(key_info->key, evt->link_key, sizeof(evt->link_key));
-	key_info->type = evt->key_type;
-	key_info->pin_len = dev->pin_length;
-
-	key_type = evt->key_type;
-
-	DBG("key type 0x%02x old key type 0x%02x", key_type, old_key_type);
-	DBG("local auth 0x%02x and remote auth 0x%02x",
-					conn->loc_auth, conn->rem_auth);
-
-	if (key_type == HCI_LK_CHANGED_COMBINATION) {
-		/* Some buggy controller combinations generate a changed
-		 * combination key for legacy pairing even when there's no
-		 * previous key */
-		if (conn->rem_auth == 0xff && old_key_type == 0xff)
-			key_type = HCI_LK_COMBINATION;
-		else if (old_key_type != 0xff)
-			key_type = old_key_type;
-		else
-			/* This is Changed Combination Link Key for
-			 * a temporary link key.*/
-			goto done;
-	}
-
-	key_info->type = key_type;
-
-	/* Skip the storage check if this is a debug key */
-	if (key_type == HCI_LK_DEBUG_COMBINATION)
-		goto done;
-
-	/* Store the link key persistently if one of the following is true:
-	 * 1. this is a legacy link key
-	 * 2. this is a changed combination key and there was a previously
-	 *    stored one
-	 * 3. neither local nor remote side had no-bonding as a requirement
-	 * 4. the local side had dedicated bonding as a requirement
-	 * 5. the remote side is using dedicated bonding since in that case
-	 *    also the local requirements are set to dedicated bonding
-	 * If none of the above match only keep the link key around for
-	 * this connection and set the temporary flag for the device.
-	 */
-	if (key_type < HCI_LK_DEBUG_COMBINATION ||
-			(key_type == HCI_LK_CHANGED_COMBINATION
-					&& old_key_type != HCI_LK_INVALID) ||
-			(conn->loc_auth > 0x01 && conn->rem_auth > 0x01) ||
-			(conn->loc_auth == 0x02 || conn->loc_auth == 0x03) ||
-			(conn->rem_auth == 0x02 || conn->rem_auth == 0x03)) {
-		int err;
-
-		err = btd_event_link_key_notify(&dev->bdaddr, dba,
-						evt->link_key, key_type,
-						dev->pin_length);
-
-		if (err == -ENODEV)
-			status = HCI_OE_LOW_RESOURCES;
-		else if (err < 0)
-			status = HCI_MEMORY_FULL;
-
-		goto done;
-	}
-
-done:
-	dev->pin_length = 0;
-
-	if (status != 0) {
-		g_free(key_info);
-		bonding_complete(dev, conn, status);
-		disconnect_addr(index, dba, status);
-		return;
-	}
-
-	dev->keys = g_slist_prepend(dev->keys, key_info);
-
-	/* If we're connected and not dedicated bonding initiators we're
-	 * done with the bonding process */
-	if (!conn->bonding_initiator && conn->handle != 0)
-		bonding_complete(dev, conn, 0);
-}
-
-static void return_link_keys(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_return_link_keys *evt = ptr;
-	uint8_t num = evt->num_keys;
-	unsigned char key[16];
-	char da[18];
-	bdaddr_t dba;
-	int i;
-
-	DBG("hci%d num_keys %u", index, num);
-
-	ptr++;
-
-	for (i = 0; i < num; i++) {
-		bacpy(&dba, ptr); ba2str(&dba, da);
-		memcpy(key, ptr + 6, 16);
-
-		DBG("hci%d returned key for %s", index, da);
-
-		btd_event_returned_link_key(&dev->bdaddr, &dba);
-
-		ptr += 22;
-	}
-}
-
-/* Simple Pairing handling */
-
-static int hciops_confirm_reply(int index, bdaddr_t *bdaddr, uint8_t bdaddr_type,
-							gboolean success)
-{
-	struct dev_info *dev = &devs[index];
-	user_confirm_reply_cp cp;
-	char addr[18];
-	int err;
-
-	ba2str(bdaddr, addr);
-	DBG("hci%d dba %s success %d", index, addr, success);
-
-	memset(&cp, 0, sizeof(cp));
-	bacpy(&cp.bdaddr, bdaddr);
-
-	if (success)
-		err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
-					OCF_USER_CONFIRM_REPLY,
-					USER_CONFIRM_REPLY_CP_SIZE, &cp);
-	else
-		err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
-					OCF_USER_CONFIRM_NEG_REPLY,
-					USER_CONFIRM_REPLY_CP_SIZE, &cp);
-
-	if (err < 0)
-		err = -errno;
-
-	return err;
-}
-
-static void user_confirm_request(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_user_confirm_request *req = ptr;
-	gboolean loc_mitm, rem_mitm;
-	struct bt_conn *conn;
-
-	DBG("hci%d", index);
-
-	conn = find_connection(dev, &req->bdaddr);
-	if (conn == NULL)
-		return;
-
-	loc_mitm = (conn->loc_auth & 0x01) ? TRUE : FALSE;
-	rem_mitm = (conn->rem_auth & 0x01) ? TRUE : FALSE;
-
-	/* If we require MITM but the remote device can't provide that
-	 * (it has NoInputNoOutput) then reject the confirmation
-	 * request. The only exception is when we're dedicated bonding
-	 * initiators since then we always have the MITM bit set. */
-	if (!conn->bonding_initiator && loc_mitm && conn->rem_cap == 0x03) {
-		error("Rejecting request: remote device can't provide MITM");
-		goto fail;
-	}
-
-	/* If no side requires MITM protection; auto-accept */
-	if ((conn->loc_auth == 0xff || !loc_mitm || conn->rem_cap == 0x03) &&
-					(!rem_mitm || conn->loc_cap == 0x03)) {
-		DBG("auto accept of confirmation");
-
-		/* Wait 5 milliseconds before doing auto-accept */
-		usleep(5000);
-
-		if (hciops_confirm_reply(index, &req->bdaddr,
-						BDADDR_BREDR, TRUE) < 0)
-			goto fail;
-
-		return;
-	}
-
-	if (btd_event_user_confirm(&dev->bdaddr, &req->bdaddr,
-						btohl(req->passkey)) == 0)
-		return;
-
-fail:
-	hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY,
-								6, ptr);
-}
-
-static void user_passkey_request(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_user_passkey_request *req = ptr;
-
-	DBG("hci%d", index);
-
-	if (btd_event_user_passkey(&dev->bdaddr, &req->bdaddr) < 0)
-		hci_send_cmd(dev->sk, OGF_LINK_CTL,
-				OCF_USER_PASSKEY_NEG_REPLY, 6, ptr);
-}
-
-static void user_passkey_notify(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_user_passkey_notify *req = ptr;
-
-	DBG("hci%d", index);
-
-	btd_event_user_notify(&dev->bdaddr, &req->bdaddr,
-						btohl(req->passkey));
-}
-
-static gint oob_bdaddr_cmp(gconstpointer a, gconstpointer b)
-{
-	const struct oob_data *data = a;
-	const bdaddr_t *bdaddr = b;
-
-	return bacmp(&data->bdaddr, bdaddr);
-}
-
-static void remote_oob_data_request(int index, bdaddr_t *bdaddr)
-{
-	struct dev_info *dev = &devs[index];
-	GSList *match;
-
-	DBG("hci%d", index);
-
-	match = g_slist_find_custom(dev->oob_data, bdaddr, oob_bdaddr_cmp);
-
-	if (match) {
-		struct oob_data *data;
-		remote_oob_data_reply_cp cp;
-
-		data = match->data;
-
-		bacpy(&cp.bdaddr, &data->bdaddr);
-		memcpy(cp.hash, data->hash, sizeof(cp.hash));
-		memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer));
-
-		dev->oob_data = g_slist_delete_link(dev->oob_data, match);
-
-		hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_REMOTE_OOB_DATA_REPLY,
-				REMOTE_OOB_DATA_REPLY_CP_SIZE, &cp);
-
-	} else {
-		hci_send_cmd(dev->sk, OGF_LINK_CTL,
-				OCF_REMOTE_OOB_DATA_NEG_REPLY, 6, bdaddr);
-	}
-}
-
-static int get_io_cap(int index, bdaddr_t *bdaddr, uint8_t *cap, uint8_t *auth)
-{
-	struct dev_info *dev = &devs[index];
-	struct bt_conn *conn;
-	int err;
-
-	conn = find_connection(dev, bdaddr);
-	if (conn == NULL)
-		return -ENOENT;
-
-	err = get_auth_info(index, bdaddr, &conn->loc_auth);
-	if (err < 0)
-		return err;
-
-	DBG("initial authentication requirement is 0x%02x", conn->loc_auth);
-
-	if (!dev->pairable && !conn->bonding_initiator) {
-		if (conn->rem_auth < 0x02) {
-			DBG("Allowing no bonding in non-bondable mode");
-			/* Kernel defaults to general bonding and so
-			 * overwrite for this special case. Otherwise
-			 * non-pairable test cases will fail. */
-			conn->loc_auth = conn->rem_auth;
-			goto done;
-		}
-
-		return -EPERM;
-	}
-
-	/* If the kernel doesn't know the local requirement just mirror
-	 * the remote one */
-	if (conn->loc_auth == 0xff)
-		conn->loc_auth = conn->rem_auth;
-
-	if (conn->loc_auth == 0x00 || conn->loc_auth == 0x04) {
-		/* If remote requests dedicated bonding follow that lead */
-		if (conn->rem_auth == 0x02 || conn->rem_auth == 0x03) {
-
-			/* If both remote and local IO capabilities allow MITM
-			 * then require it, otherwise don't */
-			if (conn->rem_cap == 0x03 || conn->loc_cap == 0x03)
-				conn->loc_auth = 0x02;
-			else
-				conn->loc_auth = 0x03;
-		}
-
-		/* If remote indicates no bonding then follow that. This
-		 * is important since the kernel might give general bonding
-		 * as default. */
-		if (conn->rem_auth == 0x00 || conn->rem_auth == 0x01)
-			conn->loc_auth = 0x00;
-
-		/* If remote requires MITM then also require it, unless
-		 * our IO capability is NoInputNoOutput (so some
-		 * just-works security cases can be tested) */
-		if (conn->rem_auth != 0xff && (conn->rem_auth & 0x01) &&
-							conn->loc_cap != 0x03)
-			conn->loc_auth |= 0x01;
-	}
-
-done:
-	*cap = conn->loc_cap;
-	*auth = conn->loc_auth;
-
-	DBG("final authentication requirement is 0x%02x", *auth);
-
-	return 0;
-}
-
-static void io_capa_request(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	bdaddr_t *dba = ptr;
-	uint8_t cap, auth = 0xff;
-	char da[18];
-	int err;
-
-	ba2str(dba, da);
-	DBG("hci%d IO capability request for %s", index, da);
-
-	err = get_io_cap(index, dba, &cap, &auth);
-	if (err < 0) {
-		io_capability_neg_reply_cp cp;
-
-		error("Getting IO capability failed: %s (%d)",
-						strerror(-err), -err);
-
-		memset(&cp, 0, sizeof(cp));
-		bacpy(&cp.bdaddr, dba);
-		cp.reason = HCI_PAIRING_NOT_ALLOWED;
-		hci_send_cmd(dev->sk, OGF_LINK_CTL,
-					OCF_IO_CAPABILITY_NEG_REPLY,
-					IO_CAPABILITY_NEG_REPLY_CP_SIZE, &cp);
-	} else {
-		io_capability_reply_cp cp;
-		struct bt_conn *conn;
-		GSList *match;
-
-		memset(&cp, 0, sizeof(cp));
-		bacpy(&cp.bdaddr, dba);
-		cp.capability = cap;
-		cp.authentication = auth;
-
-		conn = find_connection(dev, dba);
-		match = g_slist_find_custom(dev->oob_data, dba, oob_bdaddr_cmp);
-
-		if ((conn->bonding_initiator || conn->rem_oob_data == 0x01) &&
-				match)
-			cp.oob_data = 0x01;
-		else
-			cp.oob_data = 0x00;
-
-		hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_IO_CAPABILITY_REPLY,
-					IO_CAPABILITY_REPLY_CP_SIZE, &cp);
-	}
-}
-
-static void io_capa_response(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_io_capability_response *evt = ptr;
-	struct bt_conn *conn;
-	char da[18];
-
-	ba2str(&evt->bdaddr, da);
-	DBG("hci%d IO capability response from %s", index, da);
-
-	conn = find_connection(dev, &evt->bdaddr);
-	if (conn) {
-		conn->rem_cap = evt->capability;
-		conn->rem_auth = evt->authentication;
-		conn->rem_oob_data = evt->oob_data;
-	}
-}
-
-/* PIN code handling */
-
-static void pin_code_request(int index, bdaddr_t *dba)
-{
-	struct dev_info *dev = &devs[index];
-	struct bt_conn *conn;
-	char addr[18];
-	int err;
-
-	ba2str(dba, addr);
-	DBG("hci%d PIN request for %s", index, addr);
-
-	conn = get_connection(dev, dba);
-	if (conn->handle == 0)
-		conn->secmode3 = TRUE;
-
-	/* Check if the adapter is not pairable and if there isn't a bonding in
-	 * progress */
-	if (!dev->pairable && !conn->bonding_initiator) {
-		DBG("Rejecting PIN request in non-pairable mode");
-		goto reject;
-	}
-
-	err = btd_event_request_pin(&dev->bdaddr, dba, FALSE);
-	if (err < 0) {
-		error("PIN code negative reply: %s", strerror(-err));
-		goto reject;
-	}
-
-	return;
-
-reject:
-	hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, dba);
-}
-
-static inline void remote_features_notify(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_remote_host_features_notify *evt = ptr;
-
-	if (evt->features[0] & 0x01)
-		btd_event_set_legacy_pairing(&dev->bdaddr, &evt->bdaddr,
-									FALSE);
-	else
-		btd_event_set_legacy_pairing(&dev->bdaddr, &evt->bdaddr,
-									TRUE);
-
-	write_features_info(&dev->bdaddr, &evt->bdaddr, NULL, evt->features);
-}
-
-static void read_local_version_complete(int index,
-				const read_local_version_rp *rp)
-{
-	struct dev_info *dev = &devs[index];
-
-	if (rp->status)
-		return;
-
-	dev->ver.manufacturer = btohs(bt_get_unaligned(&rp->manufacturer));
-	dev->ver.hci_ver = rp->hci_ver;
-	dev->ver.hci_rev = btohs(bt_get_unaligned(&rp->hci_rev));
-	dev->ver.lmp_ver = rp->lmp_ver;
-	dev->ver.lmp_subver = btohs(bt_get_unaligned(&rp->lmp_subver));
-
-	if (!dev->pending)
-		return;
-
-	hci_clear_bit(PENDING_VERSION, &dev->pending);
-
-	DBG("Got version for hci%d", index);
-
-	if (!dev->pending && dev->up)
-		init_adapter(index);
-}
-
-static void read_local_features_complete(int index,
-				const read_local_features_rp *rp)
-{
-	struct dev_info *dev = &devs[index];
-
-	if (rp->status)
-		return;
-
-	memcpy(dev->features, rp->features, 8);
-
-	if (!dev->pending)
-		return;
-
-	hci_clear_bit(PENDING_FEATURES, &dev->pending);
-
-	DBG("Got features for hci%d", index);
-
-	if (!dev->pending && dev->up)
-		init_adapter(index);
-}
-
-static void update_name(int index, const char *name)
-{
-	struct btd_adapter *adapter;
-
-	adapter = manager_find_adapter_by_id(index);
-	if (adapter)
-		adapter_name_changed(adapter, name);
-
-	update_ext_inquiry_response(index);
-}
-
-static void read_local_name_complete(int index, read_local_name_rp *rp)
-{
-	struct dev_info *dev = &devs[index];
-
-	DBG("hci%d status %u", index, rp->status);
-
-	if (rp->status)
-		return;
-
-	memcpy(dev->name, rp->name, 248);
-
-	if (!dev->pending) {
-		update_name(index, (char *) rp->name);
-		return;
-	}
-
-	hci_clear_bit(PENDING_NAME, &dev->pending);
-
-	DBG("Got name for hci%d", index);
-
-	if (!dev->pending && dev->up)
-		init_adapter(index);
-}
-
-static void read_tx_power_complete(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-
-	read_inq_response_tx_power_level_rp *rp = ptr;
-
-	DBG("hci%d status %u", index, rp->status);
-
-	if (rp->status)
-		return;
-
-	dev->tx_power = rp->level;
-	update_ext_inquiry_response(index);
-}
-
-static void read_simple_pairing_mode_complete(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	read_simple_pairing_mode_rp *rp = ptr;
-
-	DBG("hci%d status %u", index, rp->status);
-
-	if (rp->status)
-		return;
-
-	dev->ssp_mode = rp->mode;
-	update_ext_inquiry_response(index);
-}
-
-static void read_local_ext_features_complete(int index,
-				const read_local_ext_features_rp *rp)
-{
-	struct dev_info *dev = &devs[index];
-
-	DBG("hci%d status %u", index, rp->status);
-
-	if (rp->status)
-		return;
-
-	/* Local Extended feature page number is 1 */
-	if (rp->page_num != 1)
-		return;
-
-	memcpy(dev->extfeatures, rp->features, sizeof(dev->extfeatures));
-}
-
-static void read_bd_addr_complete(int index, read_bd_addr_rp *rp)
-{
-	struct dev_info *dev = &devs[index];
-
-	DBG("hci%d status %u", index, rp->status);
-
-	if (rp->status)
-		return;
-
-	bacpy(&dev->bdaddr, &rp->bdaddr);
-
-	if (!dev->pending)
-		return;
-
-	hci_clear_bit(PENDING_BDADDR, &dev->pending);
-
-	DBG("Got bdaddr for hci%d", index);
-
-	if (!dev->pending && dev->up)
-		init_adapter(index);
-}
-
-static inline void cs_inquiry_evt(int index, uint8_t status)
-{
-	if (status) {
-		error("Inquiry Failed with status 0x%02x", status);
-		return;
-	}
-
-	set_state(index, DISCOV_INQ);
-}
-
-static inline void cmd_status(int index, void *ptr)
-{
-	evt_cmd_status *evt = ptr;
-	uint16_t opcode = btohs(evt->opcode);
-
-	if (opcode == cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY))
-		cs_inquiry_evt(index, evt->status);
-}
-
-static gboolean discoverable_timeout_handler(gpointer user_data)
-{
-	struct dev_info *dev = user_data;
-
-	hciops_set_discoverable(dev->id, FALSE, 0);
-
-	return FALSE;
-}
-
-/* Limited Discoverable bit mask in CoD */
-#define LIMITED_BIT			0x002000
-
-static int hciops_set_limited_discoverable(int index, gboolean limited)
-{
-	struct dev_info *dev = &devs[index];
-	int num = (limited ? 2 : 1);
-	uint8_t lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
-	write_current_iac_lap_cp cp;
-
-	DBG("hci%d limited %d", index, limited);
-
-	/* Check if limited bit needs to be set/reset */
-	if (limited)
-		dev->wanted_cod |= LIMITED_BIT;
-	else
-		dev->wanted_cod &= ~LIMITED_BIT;
-
-	/* If we dont need the toggling, save an unnecessary CoD write */
-	if (dev->pending_cod || dev->wanted_cod == dev->current_cod)
-		return 0;
-
-	/*
-	 * 1: giac
-	 * 2: giac + liac
-	 */
-	memset(&cp, 0, sizeof(cp));
-	cp.num_current_iac = num;
-	memcpy(&cp.lap, lap, num * 3);
-
-	if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_CURRENT_IAC_LAP,
-						(num * 3 + 1), &cp) < 0)
-		return -errno;
-
-	return write_class(index, dev->wanted_cod);
-}
-
-static void reset_discoverable_timeout(int index)
-{
-	struct dev_info *dev = &devs[index];
-
-	if (dev->discoverable_id > 0) {
-		g_source_remove(dev->discoverable_id);
-		dev->discoverable_id = 0;
-	}
-}
-
-static void set_discoverable_timeout(int index)
-{
-	struct dev_info *dev = &devs[index];
-
-	reset_discoverable_timeout(index);
-
-	if (dev->discoverable_timeout == 0) {
-		hciops_set_limited_discoverable(index, FALSE);
-		return;
-	}
-
-	/* Set limited discoverable if pairable and interval between 0 to 60
-	   sec */
-	if (dev->pairable && dev->discoverable_timeout <= 60)
-		hciops_set_limited_discoverable(index, TRUE);
-	else
-		hciops_set_limited_discoverable(index, FALSE);
-
-	dev->discoverable_id = g_timeout_add_seconds(dev->discoverable_timeout,
-						discoverable_timeout_handler,
-						dev);
-}
-
-static void read_scan_complete(int index, uint8_t status, void *ptr)
-{
-	struct btd_adapter *adapter;
-	read_scan_enable_rp *rp = ptr;
-
-	DBG("hci%d status %u", index, status);
-
-	switch (rp->enable) {
-	case (SCAN_PAGE | SCAN_INQUIRY):
-	case SCAN_INQUIRY:
-		set_discoverable_timeout(index);
-		break;
-	default:
-		reset_discoverable_timeout(index);
-		hciops_set_limited_discoverable(index, FALSE);
-	}
-
-	adapter = manager_find_adapter_by_id(index);
-	if (!adapter) {
-		error("Unable to find matching adapter");
-		return;
-	}
-
-	adapter_mode_changed(adapter, rp->enable);
-}
-
-static void write_class_complete(int index, uint8_t status)
-{
-	struct dev_info *dev = &devs[index];
-	struct btd_adapter *adapter;
-
-	if (status)
-		return;
-
-	if (dev->pending_cod == 0)
-		return;
-
-	dev->current_cod = dev->pending_cod;
-	dev->pending_cod = 0;
-
-	adapter = manager_find_adapter(&dev->bdaddr);
-	if (adapter)
-		btd_adapter_class_changed(adapter, dev->current_cod);
-
-	update_ext_inquiry_response(index);
-
-	if (dev->wanted_cod == dev->current_cod)
-		return;
-
-	if (dev->wanted_cod & LIMITED_BIT &&
-			!(dev->current_cod & LIMITED_BIT))
-		hciops_set_limited_discoverable(index, TRUE);
-	else if (!(dev->wanted_cod & LIMITED_BIT) &&
-					(dev->current_cod & LIMITED_BIT))
-		hciops_set_limited_discoverable(index, FALSE);
-	else
-		write_class(index, dev->wanted_cod);
-}
-
-static void read_local_oob_data_complete(int index, uint8_t status,
-						read_local_oob_data_rp *rp)
-{
-	struct btd_adapter *adapter = manager_find_adapter_by_id(index);
-
-	if (!adapter)
-		return;
-
-	if (status)
-		oob_read_local_data_complete(adapter, NULL, NULL);
-	else
-		oob_read_local_data_complete(adapter, rp->hash, rp->randomizer);
-}
-
-static inline void inquiry_complete_evt(int index, uint8_t status)
-{
-	int adapter_type;
-	struct btd_adapter *adapter;
-
-	if (status) {
-		error("Inquiry Failed with status 0x%02x", status);
-		return;
-	}
-
-	adapter = manager_find_adapter_by_id(index);
-	if (!adapter) {
-		error("No matching adapter found");
-		return;
-	}
-
-	adapter_type = get_adapter_type(index);
-
-	if (adapter_type == BR_EDR_LE &&
-			start_scanning(index, TIMEOUT_BR_LE_SCAN) == 0)
-		return;
-
-	set_state(index, DISCOV_NAMES);
-}
-
-static inline void cc_inquiry_cancel(int index, uint8_t status)
-{
-	if (status) {
-		error("Inquiry Cancel Failed with status 0x%02x", status);
-		return;
-	}
-
-	set_state(index, DISCOV_HALTED);
-}
-
-static inline void cc_le_set_scan_enable(int index, uint8_t status)
-{
-	struct dev_info *info = &devs[index];
-
-	if (status) {
-		error("LE Set Scan Enable Failed with status 0x%02x", status);
-		return;
-	}
-
-	if (info->discov_state == DISCOV_SCAN)
-		set_state(index, DISCOV_HALTED);
-	else
-		set_state(index, DISCOV_SCAN);
-}
-
-static inline void cmd_complete(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_cmd_complete *evt = ptr;
-	uint16_t opcode = btohs(evt->opcode);
-	uint8_t status = *((uint8_t *) ptr + EVT_CMD_COMPLETE_SIZE);
-
-	switch (opcode) {
-	case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION):
-		ptr += sizeof(evt_cmd_complete);
-		read_local_version_complete(index, ptr);
-		break;
-	case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES):
-		ptr += sizeof(evt_cmd_complete);
-		read_local_features_complete(index, ptr);
-		break;
-	case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_EXT_FEATURES):
-		ptr += sizeof(evt_cmd_complete);
-		read_local_ext_features_complete(index, ptr);
-		break;
-	case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BD_ADDR):
-		ptr += sizeof(evt_cmd_complete);
-		read_bd_addr_complete(index, ptr);
-		break;
-	case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL):
-		cc_inquiry_cancel(index, status);
-		break;
-	case cmd_opcode_pack(OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE):
-		cc_le_set_scan_enable(index, status);
-		break;
-	case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME):
-		if (!status)
-			hci_send_cmd(dev->sk, OGF_HOST_CTL,
-						OCF_READ_LOCAL_NAME, 0, 0);
-		break;
-	case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):
-		hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_SCAN_ENABLE,
-								0, NULL);
-		break;
-	case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SCAN_ENABLE):
-		ptr += sizeof(evt_cmd_complete);
-		read_scan_complete(index, status, ptr);
-		break;
-	case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV):
-		write_class_complete(index, status);
-		break;
-	case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SIMPLE_PAIRING_MODE):
-		if (!status)
-			hci_send_cmd(dev->sk, OGF_HOST_CTL,
-					OCF_READ_SIMPLE_PAIRING_MODE, 0, NULL);
-		break;
-	case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SIMPLE_PAIRING_MODE):
-		ptr += sizeof(evt_cmd_complete);
-		read_simple_pairing_mode_complete(index, ptr);
-		break;
-	case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_NAME):
-		ptr += sizeof(evt_cmd_complete);
-		read_local_name_complete(index, ptr);
-		break;
-	case cmd_opcode_pack(OGF_HOST_CTL,
-					OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL):
-		ptr += sizeof(evt_cmd_complete);
-		read_tx_power_complete(index, ptr);
-		break;
-	case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_OOB_DATA):
-		ptr += sizeof(evt_cmd_complete);
-		read_local_oob_data_complete(index, status, ptr);
-		break;
-	};
-}
-
-static inline void remote_name_information(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_remote_name_req_complete *evt = ptr;
-	struct btd_adapter *adapter;
-	char name[MAX_NAME_LENGTH + 1];
-	struct found_dev *found;
-
-	GSList *match;
-
-	DBG("hci%d status %u", index, evt->status);
-
-	memset(name, 0, sizeof(name));
-
-	if (evt->status == 0) {
-		memcpy(name, evt->name, MAX_NAME_LENGTH);
-		btd_event_remote_name(&dev->bdaddr, &evt->bdaddr, name);
-	}
-
-	adapter = manager_find_adapter_by_id(index);
-	if (!adapter) {
-		error("No matching adapter found");
-		return;
-	}
-
-	match = g_slist_find_custom(dev->need_name, &evt->bdaddr,
-							found_dev_bda_cmp);
-	if (match == NULL)
-		return;
-
-	found = match->data;
-	found->name_state = NAME_NOT_NEEDED;
-
-	dev->need_name = g_slist_remove_link(dev->need_name, match);
-
-	match->next = dev->found_devs;
-	dev->found_devs = match;
-	dev->found_devs = g_slist_sort(dev->found_devs, found_dev_rssi_cmp);
-
-	if (resolve_names(dev, adapter) < 0)
-		set_state(index, DISCOV_HALTED);
-}
-
-static inline void remote_version_information(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_read_remote_version_complete *evt = ptr;
-	struct bt_conn *conn;
-
-	DBG("hci%d status %u", index, evt->status);
-
-	if (evt->status)
-		return;
-
-	conn = find_conn_by_handle(dev, btohs(evt->handle));
-	if (conn == NULL)
-		return;
-
-	write_version_info(&dev->bdaddr, &conn->bdaddr,
-				btohs(evt->manufacturer), evt->lmp_ver,
-				btohs(evt->lmp_subver));
-}
-
-static void dev_found(struct dev_info *info, bdaddr_t *dba, uint8_t bdaddr_type,
-				uint8_t *cod, int8_t rssi, uint8_t cfm_name,
-				uint8_t *eir, size_t eir_len)
-{
-	struct found_dev *dev;
-	GSList *match;
-
-	match = g_slist_find_custom(info->found_devs, dba, found_dev_bda_cmp);
-	if (match != NULL) {
-		cfm_name = 0;
-		goto event;
-	}
-
-	dev = g_new0(struct found_dev, 1);
-	bacpy(&dev->bdaddr, dba);
-	dev->rssi = rssi;
-	if (cfm_name)
-		dev->name_state = NAME_UNKNOWN;
-	else
-		dev->name_state = NAME_NOT_NEEDED;
-
-	if (cod && !eir_has_data_type(eir, eir_len, EIR_CLASS_OF_DEV))
-		eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
-								cod, 3);
-
-	info->found_devs = g_slist_prepend(info->found_devs, dev);
-
-event:
-	btd_event_device_found(&info->bdaddr, dba, bdaddr_type, rssi, cfm_name,
-								eir, eir_len);
-}
-
-static inline void inquiry_result(int index, int plen, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	uint8_t num = *(uint8_t *) ptr++;
-	int i;
-
-	for (i = 0; i < num; i++) {
-		inquiry_info *info = ptr;
-		uint8_t eir[5];
-
-		memset(eir, 0, sizeof(eir));
-		dev_found(dev, &info->bdaddr, BDADDR_BREDR, info->dev_class,
-								0, 1, eir, 0);
-		ptr += INQUIRY_INFO_SIZE;
-	}
-}
-
-static inline void inquiry_result_with_rssi(int index, int plen, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	uint8_t num = *(uint8_t *) ptr++;
-	uint8_t eir[5];
-	int i;
-
-	if (!num)
-		return;
-
-	if ((plen - 1) / num == INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE) {
-		for (i = 0; i < num; i++) {
-			inquiry_info_with_rssi_and_pscan_mode *info = ptr;
-
-			memset(eir, 0, sizeof(eir));
-			dev_found(dev, &info->bdaddr, BDADDR_BREDR,
-						info->dev_class, info->rssi,
-						1, eir, 0);
-			ptr += INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE;
-		}
-	} else {
-		for (i = 0; i < num; i++) {
-			inquiry_info_with_rssi *info = ptr;
-
-			memset(eir, 0, sizeof(eir));
-			dev_found(dev, &info->bdaddr, BDADDR_BREDR,
-						info->dev_class, info->rssi,
-						1, eir, 0);
-			ptr += INQUIRY_INFO_WITH_RSSI_SIZE;
-		}
-	}
-}
-
-static inline void extended_inquiry_result(int index, int plen, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	uint8_t num = *(uint8_t *) ptr++;
-	int i;
-
-	for (i = 0; i < num; i++) {
-		extended_inquiry_info *info = ptr;
-		uint8_t eir[sizeof(info->data) + 5];
-		gboolean cfm_name;
-		size_t eir_len;
-
-		eir_len = eir_length(info->data, sizeof(info->data));
-
-		memset(eir, 0, sizeof(eir));
-		memcpy(eir, info->data, eir_len);
-
-		if (eir_has_data_type(eir, eir_len, EIR_NAME_COMPLETE))
-			cfm_name = FALSE;
-		else
-			cfm_name = TRUE;
-
-		dev_found(dev, &info->bdaddr, BDADDR_BREDR, info->dev_class,
-					info->rssi, cfm_name, eir, eir_len);
-		ptr += EXTENDED_INQUIRY_INFO_SIZE;
-	}
-}
-
-static inline void remote_features_information(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_read_remote_features_complete *evt = ptr;
-	struct bt_conn *conn;
-
-	DBG("hci%d status %u", index, evt->status);
-
-	if (evt->status)
-		return;
-
-	conn = find_conn_by_handle(dev, btohs(evt->handle));
-	if (conn == NULL)
-		return;
-
-	write_features_info(&dev->bdaddr, &conn->bdaddr, evt->features, NULL);
-}
-
-struct remote_version_req {
-	int index;
-	uint16_t handle;
-};
-
-static gboolean __get_remote_version(gpointer user_data)
-{
-	struct remote_version_req *req = user_data;
-	struct dev_info *dev = &devs[req->index];
-	read_remote_version_cp cp;
-
-	DBG("hci%d handle %u", req->index, req->handle);
-
-	memset(&cp, 0, sizeof(cp));
-	cp.handle = htobs(req->handle);
-
-	hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_READ_REMOTE_VERSION,
-					READ_REMOTE_VERSION_CP_SIZE, &cp);
-
-	return FALSE;
-}
-
-static void get_remote_version(int index, uint16_t handle)
-{
-	struct remote_version_req *req;
-
-	req = g_new0(struct remote_version_req, 1);
-	req->handle = handle;
-	req->index = index;
-
-	g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, 1, __get_remote_version,
-								req, g_free);
-}
-
-static void conn_free(struct bt_conn *conn)
-{
-	if (conn->io != NULL) {
-		g_io_channel_shutdown(conn->io, TRUE, NULL);
-		g_io_channel_unref(conn->io);
-	}
-
-	g_free(conn);
-}
-
-static inline void conn_failed(int index, bdaddr_t *bdaddr, uint8_t status)
-{
-	struct dev_info *dev = &devs[index];
-	struct bt_conn *conn;
-
-	btd_event_conn_failed(&dev->bdaddr, bdaddr, status);
-
-	conn = find_connection(dev, bdaddr);
-	if (conn == NULL)
-		return;
-
-	bonding_complete(dev, conn, status);
-
-	dev->connections = g_slist_remove(dev->connections, conn);
-	conn_free(conn);
-}
-
-static inline void conn_complete(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_conn_complete *evt = ptr;
-	char filename[PATH_MAX];
-	char local_addr[18], peer_addr[18], *str;
-	struct bt_conn *conn;
-
-	if (evt->link_type != ACL_LINK)
-		return;
-
-	DBG("status 0x%02x", evt->status);
-
-	if (evt->status != 0) {
-		conn_failed(index, &evt->bdaddr, evt->status);
-		return;
-	}
-
-	conn = get_connection(dev, &evt->bdaddr);
-	conn->handle = btohs(evt->handle);
-
-	btd_event_conn_complete(&dev->bdaddr, &evt->bdaddr, BDADDR_BREDR,
-								NULL, NULL);
-
-	if (conn->secmode3)
-		bonding_complete(dev, conn, 0);
-
-	/* check if the remote version needs be requested */
-	ba2str(&dev->bdaddr, local_addr);
-	ba2str(&evt->bdaddr, peer_addr);
-
-	create_name(filename, sizeof(filename), STORAGEDIR, local_addr,
-							"manufacturers");
-
-	str = textfile_get(filename, peer_addr);
-	if (!str)
-		get_remote_version(index, btohs(evt->handle));
-	else
-		free(str);
-}
-
-static inline uint8_t le_addr_type(uint8_t bdaddr_type)
-{
-	switch (bdaddr_type) {
-	case LE_RANDOM_ADDRESS:
-		return BDADDR_LE_RANDOM;
-	case LE_PUBLIC_ADDRESS:
-	default:
-		return BDADDR_LE_PUBLIC;
-	}
-}
-
-static inline void le_conn_complete(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_le_connection_complete *evt = ptr;
-	char filename[PATH_MAX];
-	char local_addr[18], peer_addr[18], *str;
-	struct bt_conn *conn;
-	uint8_t bdaddr_type;
-
-	if (evt->status) {
-		btd_event_conn_failed(&dev->bdaddr, &evt->peer_bdaddr,
-								evt->status);
-		return;
-	}
-
-	conn = get_connection(dev, &evt->peer_bdaddr);
-	conn->handle = btohs(evt->handle);
-
-	bdaddr_type = le_addr_type(evt->peer_bdaddr_type);
-	btd_event_conn_complete(&dev->bdaddr, &evt->peer_bdaddr, bdaddr_type,
-								NULL, NULL);
-
-	/* check if the remote version needs be requested */
-	ba2str(&dev->bdaddr, local_addr);
-	ba2str(&evt->peer_bdaddr, peer_addr);
-
-	create_name(filename, sizeof(filename), STORAGEDIR, local_addr,
-							"manufacturers");
-
-	str = textfile_get(filename, peer_addr);
-	if (!str)
-		get_remote_version(index, btohs(evt->handle));
-	else
-		free(str);
-}
-
-static inline void disconn_complete(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_disconn_complete *evt = ptr;
-	struct bt_conn *conn;
-
-	DBG("handle %u status 0x%02x", btohs(evt->handle), evt->status);
-
-	if (evt->status != 0)
-		return;
-
-	conn = find_conn_by_handle(dev, btohs(evt->handle));
-	if (conn == NULL)
-		return;
-
-	dev->connections = g_slist_remove(dev->connections, conn);
-
-	btd_event_disconn_complete(&dev->bdaddr, &conn->bdaddr);
-
-	conn_free(conn);
-}
-
-static inline void auth_complete(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_auth_complete *evt = ptr;
-	struct bt_conn *conn;
-
-	DBG("hci%d status %u", index, evt->status);
-
-	conn = find_conn_by_handle(dev, btohs(evt->handle));
-	if (conn == NULL)
-		return;
-
-	bonding_complete(dev, conn, evt->status);
-}
-
-static inline void simple_pairing_complete(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_simple_pairing_complete *evt = ptr;
-
-	DBG("hci%d status %u", index, evt->status);
-
-	btd_event_simple_pairing_complete(&dev->bdaddr, &evt->bdaddr,
-								evt->status);
-}
-
-static inline void conn_request(int index, void *ptr)
-{
-	struct dev_info *dev = &devs[index];
-	evt_conn_request *evt = ptr;
-	uint32_t class = evt->dev_class[0] | (evt->dev_class[1] << 8)
-				| (evt->dev_class[2] << 16);
-
-	btd_event_remote_class(&dev->bdaddr, &evt->bdaddr, class);
-}
-
-static inline void le_advertising_report(int index, evt_le_meta_event *meta)
-{
-	struct dev_info *dev = &devs[index];
-	le_advertising_info *info;
-	uint8_t num_reports, rssi;
-	const uint8_t RSSI_SIZE = 1;
-
-	num_reports = meta->data[0];
-
-	info = (le_advertising_info *) &meta->data[1];
-	rssi = *(info->data + info->length);
-
-	dev_found(dev, &info->bdaddr, le_addr_type(info->bdaddr_type), NULL,
-					rssi, 0, info->data, info->length);
-
-	num_reports--;
-
-	while (num_reports--) {
-		info = (le_advertising_info *) (info->data + info->length +
-								RSSI_SIZE);
-		rssi = *(info->data + info->length);
-
-		dev_found(dev, &info->bdaddr, le_addr_type(info->bdaddr_type),
-				NULL, rssi, 0, info->data, info->length);
-	}
-}
-
-static inline void le_metaevent(int index, void *ptr)
-{
-	evt_le_meta_event *meta = ptr;
-
-	DBG("hci%d LE Meta Event %u", index, meta->subevent);
-
-	switch (meta->subevent) {
-	case EVT_LE_ADVERTISING_REPORT:
-		le_advertising_report(index, meta);
-		break;
-
-	case EVT_LE_CONN_COMPLETE:
-		le_conn_complete(index, meta->data);
-		break;
-	}
-}
-
-static void stop_hci_dev(int index)
-{
-	struct dev_info *dev = &devs[index];
-
-	if (dev->sk < 0)
-		return;
-
-	info("Stopping hci%d event socket", index);
-
-	if (dev->watch_id > 0)
-		g_source_remove(dev->watch_id);
-
-	if (dev->stop_scan_id > 0)
-		g_source_remove(dev->stop_scan_id);
-
-	if (dev->io != NULL)
-		g_io_channel_unref(dev->io);
-
-	hci_close_dev(dev->sk);
-
-	g_slist_free_full(dev->keys, g_free);
-	g_slist_free_full(dev->uuids, g_free);
-	g_slist_free_full(dev->connections, g_free);
-
-	init_dev_info(index, -1, dev->registered, dev->already_up);
-}
-
-static gboolean io_security_event(GIOChannel *chan, GIOCondition cond,
-								gpointer data)
-{
-	unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr = buf;
-	int type, index = GPOINTER_TO_INT(data);
-	struct dev_info *dev = &devs[index];
-	struct hci_dev_info di;
-	ssize_t len;
-	hci_event_hdr *eh;
-	evt_cmd_status *evt;
-	int fd;
-
-	if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
-		stop_hci_dev(index);
-		return FALSE;
-	}
-
-	fd = g_io_channel_unix_get_fd(chan);
-
-	len = read(fd, buf, sizeof(buf));
-	if (len < 0) {
-		if (errno == EAGAIN)
-			return TRUE;
-		stop_hci_dev(index);
-		return FALSE;
-	}
-
-	type = *ptr++;
-
-	if (type != HCI_EVENT_PKT)
-		return TRUE;
-
-	eh = (hci_event_hdr *) ptr;
-	ptr += HCI_EVENT_HDR_SIZE;
-
-	memset(&di, 0, sizeof(di));
-	if (hci_devinfo(index, &di) == 0) {
-		bacpy(&dev->bdaddr, &di.bdaddr);
-
-		if (ignore_device(&di))
-			return TRUE;
-	}
-
-	switch (eh->evt) {
-	case EVT_CMD_STATUS:
-		cmd_status(index, ptr);
-		break;
-
-	case EVT_CMD_COMPLETE:
-		cmd_complete(index, ptr);
-		break;
-
-	case EVT_REMOTE_NAME_REQ_COMPLETE:
-		remote_name_information(index, ptr);
-		break;
-
-	case EVT_READ_REMOTE_VERSION_COMPLETE:
-		remote_version_information(index, ptr);
-		break;
-
-	case EVT_READ_REMOTE_FEATURES_COMPLETE:
-		remote_features_information(index, ptr);
-		break;
-
-	case EVT_REMOTE_HOST_FEATURES_NOTIFY:
-		remote_features_notify(index, ptr);
-		break;
-
-	case EVT_INQUIRY_COMPLETE:
-		evt = (evt_cmd_status *) ptr;
-		inquiry_complete_evt(index, evt->status);
-		break;
-
-	case EVT_INQUIRY_RESULT:
-		inquiry_result(index, eh->plen, ptr);
-		break;
-
-	case EVT_INQUIRY_RESULT_WITH_RSSI:
-		inquiry_result_with_rssi(index, eh->plen, ptr);
-		break;
-
-	case EVT_EXTENDED_INQUIRY_RESULT:
-		extended_inquiry_result(index, eh->plen, ptr);
-		break;
-
-	case EVT_CONN_COMPLETE:
-		conn_complete(index, ptr);
-		break;
-
-	case EVT_DISCONN_COMPLETE:
-		disconn_complete(index, ptr);
-		break;
-
-	case EVT_AUTH_COMPLETE:
-		auth_complete(index, ptr);
-		break;
-
-	case EVT_SIMPLE_PAIRING_COMPLETE:
-		simple_pairing_complete(index, ptr);
-		break;
-
-	case EVT_CONN_REQUEST:
-		conn_request(index, ptr);
-		break;
-	case EVT_LE_META_EVENT:
-		le_metaevent(index, ptr);
-		break;
-	case EVT_PIN_CODE_REQ:
-		pin_code_request(index, (bdaddr_t *) ptr);
-		break;
-
-	case EVT_LINK_KEY_REQ:
-		link_key_request(index, (bdaddr_t *) ptr);
-		break;
-
-	case EVT_LINK_KEY_NOTIFY:
-		link_key_notify(index, ptr);
-		break;
-
-	case EVT_RETURN_LINK_KEYS:
-		return_link_keys(index, ptr);
-		break;
-
-	case EVT_IO_CAPABILITY_REQUEST:
-		io_capa_request(index, ptr);
-		break;
-
-	case EVT_IO_CAPABILITY_RESPONSE:
-		io_capa_response(index, ptr);
-		break;
-
-	case EVT_USER_CONFIRM_REQUEST:
-		user_confirm_request(index, ptr);
-		break;
-
-	case EVT_USER_PASSKEY_REQUEST:
-		user_passkey_request(index, ptr);
-		break;
-
-	case EVT_USER_PASSKEY_NOTIFY:
-		user_passkey_notify(index, ptr);
-		break;
-
-	case EVT_REMOTE_OOB_DATA_REQUEST:
-		remote_oob_data_request(index, (bdaddr_t *) ptr);
-		break;
-	}
-
-	return TRUE;
-}
-
-static void start_hci_dev(int index)
-{
-	struct dev_info *dev = &devs[index];
-	GIOChannel *chan = dev->io;
-	GIOCondition cond;
-	struct hci_filter flt;
-
-	if (chan)
-		return;
-
-	info("Listening for HCI events on hci%d", index);
-
-	/* Set filter */
-	hci_filter_clear(&flt);
-	hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
-	hci_filter_set_event(EVT_CMD_STATUS, &flt);
-	hci_filter_set_event(EVT_CMD_COMPLETE, &flt);
-	hci_filter_set_event(EVT_PIN_CODE_REQ, &flt);
-	hci_filter_set_event(EVT_LINK_KEY_REQ, &flt);
-	hci_filter_set_event(EVT_LINK_KEY_NOTIFY, &flt);
-	hci_filter_set_event(EVT_RETURN_LINK_KEYS, &flt);
-	hci_filter_set_event(EVT_IO_CAPABILITY_REQUEST, &flt);
-	hci_filter_set_event(EVT_IO_CAPABILITY_RESPONSE, &flt);
-	hci_filter_set_event(EVT_USER_CONFIRM_REQUEST, &flt);
-	hci_filter_set_event(EVT_USER_PASSKEY_REQUEST, &flt);
-	hci_filter_set_event(EVT_REMOTE_OOB_DATA_REQUEST, &flt);
-	hci_filter_set_event(EVT_USER_PASSKEY_NOTIFY, &flt);
-	hci_filter_set_event(EVT_KEYPRESS_NOTIFY, &flt);
-	hci_filter_set_event(EVT_SIMPLE_PAIRING_COMPLETE, &flt);
-	hci_filter_set_event(EVT_AUTH_COMPLETE, &flt);
-	hci_filter_set_event(EVT_REMOTE_NAME_REQ_COMPLETE, &flt);
-	hci_filter_set_event(EVT_READ_REMOTE_VERSION_COMPLETE, &flt);
-	hci_filter_set_event(EVT_READ_REMOTE_FEATURES_COMPLETE, &flt);
-	hci_filter_set_event(EVT_REMOTE_HOST_FEATURES_NOTIFY, &flt);
-	hci_filter_set_event(EVT_INQUIRY_COMPLETE, &flt);
-	hci_filter_set_event(EVT_INQUIRY_RESULT, &flt);
-	hci_filter_set_event(EVT_INQUIRY_RESULT_WITH_RSSI, &flt);
-	hci_filter_set_event(EVT_EXTENDED_INQUIRY_RESULT, &flt);
-	hci_filter_set_event(EVT_CONN_REQUEST, &flt);
-	hci_filter_set_event(EVT_CONN_COMPLETE, &flt);
-	hci_filter_set_event(EVT_DISCONN_COMPLETE, &flt);
-	hci_filter_set_event(EVT_LE_META_EVENT, &flt);
-	if (setsockopt(dev->sk, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
-		error("Can't set filter on hci%d: %s (%d)",
-						index, strerror(errno), errno);
-		return;
-	}
-
-	chan = g_io_channel_unix_new(dev->sk);
-	cond = G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR;
-	dev->watch_id = g_io_add_watch_full(chan, G_PRIORITY_LOW, cond,
-						io_security_event,
-						GINT_TO_POINTER(index), NULL);
-	dev->io = chan;
-	dev->pin_length = 0;
-
-}
-
-/* End of HCI event callbacks */
-
-static gboolean child_exit(GIOChannel *io, GIOCondition cond, void *user_data)
-{
-	int status, fd = g_io_channel_unix_get_fd(io);
-	pid_t child_pid;
-
-	if (read(fd, &child_pid, sizeof(child_pid)) != sizeof(child_pid)) {
-		error("child_exit: unable to read child pid from pipe");
-		return TRUE;
-	}
-
-	if (waitpid(child_pid, &status, 0) != child_pid)
-		error("waitpid(%d) failed", child_pid);
-	else
-		DBG("child %d exited", child_pid);
-
-	return TRUE;
-}
-
-static void at_child_exit(void)
-{
-	pid_t pid = getpid();
-
-	if (write(child_pipe[1], &pid, sizeof(pid)) != sizeof(pid))
-		error("unable to write to child pipe");
-}
-
-static void device_devup_setup(int index)
-{
-	struct dev_info *dev = &devs[index];
-	struct hci_dev_info di;
-	read_stored_link_key_cp cp;
-
-	DBG("hci%d", index);
-
-	if (hci_devinfo(index, &di) < 0)
-		return;
-
-	if (ignore_device(&di))
-		return;
-
-	bacpy(&dev->bdaddr, &di.bdaddr);
-	memcpy(dev->features, di.features, 8);
-
-	if (dev->features[7] & LMP_EXT_FEAT) {
-		uint8_t page_num = 0x01;
-
-		hci_send_cmd(dev->sk, OGF_INFO_PARAM,
-				OCF_READ_LOCAL_EXT_FEATURES, 1, &page_num);
-	}
-
-	/* Set page timeout */
-	if ((main_opts.flags & (1 << HCID_SET_PAGETO))) {
-		write_page_timeout_cp cp;
-
-		cp.timeout = htobs(main_opts.pageto);
-		hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_PAGE_TIMEOUT,
-					WRITE_PAGE_TIMEOUT_CP_SIZE, &cp);
-	}
-
-	bacpy(&cp.bdaddr, BDADDR_ANY);
-	cp.read_all = 1;
-	hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_STORED_LINK_KEY,
-					READ_STORED_LINK_KEY_CP_SIZE, &cp);
-
-	if (!dev->pending) {
-		init_adapter(index);
-		return;
-	}
-
-	/* Even though it shouldn't happen (assuming the kernel behaves
-	 * properly) it seems like we might miss the very first
-	 * initialization commands that the kernel sends. So check for
-	 * it here and resend the ones we haven't seen their results yet */
-
-	if (hci_test_bit(PENDING_FEATURES, &dev->pending))
-		hci_send_cmd(dev->sk, OGF_INFO_PARAM,
-					OCF_READ_LOCAL_FEATURES, 0, NULL);
-
-	if (hci_test_bit(PENDING_VERSION, &dev->pending))
-		hci_send_cmd(dev->sk, OGF_INFO_PARAM,
-					OCF_READ_LOCAL_VERSION, 0, NULL);
-
-	if (hci_test_bit(PENDING_NAME, &dev->pending))
-		hci_send_cmd(dev->sk, OGF_HOST_CTL,
-					OCF_READ_LOCAL_NAME, 0, 0);
-
-	if (hci_test_bit(PENDING_BDADDR, &dev->pending))
-		hci_send_cmd(dev->sk, OGF_INFO_PARAM,
-					OCF_READ_BD_ADDR, 0, NULL);
-}
-
-static void init_pending(int index)
-{
-	struct dev_info *dev = &devs[index];
-
-	hci_set_bit(PENDING_BDADDR, &dev->pending);
-	hci_set_bit(PENDING_VERSION, &dev->pending);
-	hci_set_bit(PENDING_FEATURES, &dev->pending);
-	hci_set_bit(PENDING_NAME, &dev->pending);
-}
-
-static struct dev_info *init_device(int index, gboolean already_up)
-{
-	struct dev_info *dev;
-	struct hci_dev_req dr;
-	int dd;
-	pid_t pid;
-
-	DBG("hci%d", index);
-
-	dd = hci_open_dev(index);
-	if (dd < 0) {
-		error("Unable to open hci%d: %s (%d)", index,
-						strerror(errno), errno);
-		return NULL;
-	}
-
-	if (index > max_dev) {
-		max_dev = index;
-		devs = g_realloc(devs, sizeof(devs[0]) * (max_dev + 1));
-	}
-
-	dev = init_dev_info(index, dd, FALSE, already_up);
-	init_pending(index);
-	start_hci_dev(index);
-
-	/* Avoid forking if nothing else has to be done */
-	if (already_up)
-		return dev;
-
-	/* Do initialization in the separate process */
-	pid = fork();
-	switch (pid) {
-		case 0:
-			atexit(at_child_exit);
-			break;
-		case -1:
-			error("Fork failed. Can't init device hci%d: %s (%d)",
-					index, strerror(errno), errno);
-		default:
-			DBG("child %d forked", pid);
-			return dev;
-	}
-
-	memset(&dr, 0, sizeof(dr));
-	dr.dev_id = index;
-
-	/* Set link mode */
-	dr.dev_opt = main_opts.link_mode;
-	if (ioctl(dd, HCISETLINKMODE, (unsigned long) &dr) < 0)
-		error("Can't set link mode on hci%d: %s (%d)",
-						index, strerror(errno), errno);
-
-	/* Start HCI device */
-	if (ioctl(dd, HCIDEVUP, index) < 0 && errno != EALREADY) {
-		error("Can't init device hci%d: %s (%d)",
-					index, strerror(errno), errno);
-		goto fail;
-	}
-
-	hci_close_dev(dd);
-	exit(0);
-
-fail:
-	hci_close_dev(dd);
-	exit(1);
-}
-
-static void init_conn_list(int index)
-{
-	struct dev_info *dev = &devs[index];
-	struct hci_conn_list_req *cl;
-	struct hci_conn_info *ci;
-	int i;
-
-	DBG("hci%d", index);
-
-	cl = g_malloc0(10 * sizeof(*ci) + sizeof(*cl));
-
-	cl->dev_id = index;
-	cl->conn_num = 10;
-	ci = cl->conn_info;
-
-	if (ioctl(dev->sk, HCIGETCONNLIST, cl) < 0) {
-		error("Unable to get connection list: %s (%d)",
-						strerror(errno), errno);
-		goto failed;
-	}
-
-	for (i = 0; i < cl->conn_num; i++, ci++) {
-		struct bt_conn *conn;
-
-		if (ci->type != ACL_LINK)
-			continue;
-
-		conn = get_connection(dev, &ci->bdaddr);
-		conn->handle = ci->handle;
-	}
-
-failed:
-	g_free(cl);
-}
-
-static void device_event(int event, int index)
-{
-	switch (event) {
-	case HCI_DEV_REG:
-		info("HCI dev %d registered", index);
-		init_device(index, FALSE);
-		break;
-
-	case HCI_DEV_UNREG:
-		info("HCI dev %d unregistered", index);
-		stop_hci_dev(index);
-		if (devs[index].registered)
-			btd_manager_unregister_adapter(index);
-		break;
-
-	case HCI_DEV_UP:
-		info("HCI dev %d up", index);
-		devs[index].up = TRUE;
-		device_devup_setup(index);
-		break;
-
-	case HCI_DEV_DOWN:
-		info("HCI dev %d down", index);
-		devs[index].up = FALSE;
-		devs[index].pending_cod = 0;
-		devs[index].cache_enable = TRUE;
-		devs[index].discov_state = DISCOV_HALTED;
-		reset_discoverable_timeout(index);
-		if (!devs[index].pending) {
-			struct btd_adapter *adapter;
-
-			adapter = manager_find_adapter_by_id(index);
-			if (adapter)
-				btd_adapter_stop(adapter);
-
-			init_pending(index);
-		}
-		break;
-	}
-}
-
-static gboolean init_known_adapters(gpointer user_data)
-{
-	struct hci_dev_list_req *dl;
-	struct hci_dev_req *dr;
-	int i, err, ctl = GPOINTER_TO_INT(user_data);
-	size_t req_size;
-
-	DBG("");
-
-	req_size = HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t);
-
-	dl = g_try_malloc0(req_size);
-	if (!dl) {
-		error("Can't allocate devlist buffer");
-		return FALSE;
-	}
-
-	dl->dev_num = HCI_MAX_DEV;
-	dr = dl->dev_req;
-
-	if (ioctl(ctl, HCIGETDEVLIST, dl) < 0) {
-		err = -errno;
-		error("Can't get device list: %s (%d)", strerror(-err), -err);
-		g_free(dl);
-		return FALSE;
-	}
-
-	for (i = 0; i < dl->dev_num; i++, dr++) {
-		struct dev_info *dev;
-		gboolean already_up;
-
-		already_up = hci_test_bit(HCI_UP, &dr->dev_opt);
-
-		dev = init_device(dr->dev_id, already_up);
-		if (dev == NULL)
-			continue;
-
-		if (!dev->already_up)
-			continue;
-
-		init_conn_list(dr->dev_id);
-
-		dev->pending = 0;
-		hci_set_bit(PENDING_VERSION, &dev->pending);
-		hci_send_cmd(dev->sk, OGF_INFO_PARAM,
-					OCF_READ_LOCAL_VERSION, 0, NULL);
-		device_event(HCI_DEV_UP, dr->dev_id);
-	}
-
-	g_free(dl);
-
-	return FALSE;
-}
-
-static gboolean io_stack_event(GIOChannel *chan, GIOCondition cond,
-								gpointer data)
-{
-	unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;
-	evt_stack_internal *si;
-	evt_si_device *sd;
-	hci_event_hdr *eh;
-	int type, fd;
-	ssize_t len;
-
-	ptr = buf;
-
-	fd = g_io_channel_unix_get_fd(chan);
-
-	len = read(fd, buf, sizeof(buf));
-	if (len < 0) {
-		if (errno == EAGAIN)
-			return TRUE;
-
-		error("Read from control socket failed: %s (%d)",
-						strerror(errno), errno);
-		return FALSE;
-	}
-
-	type = *ptr++;
-
-	if (type != HCI_EVENT_PKT)
-		return TRUE;
-
-	eh = (hci_event_hdr *) ptr;
-	if (eh->evt != EVT_STACK_INTERNAL)
-		return TRUE;
-
-	ptr += HCI_EVENT_HDR_SIZE;
-
-	si = (evt_stack_internal *) ptr;
-	switch (si->type) {
-	case EVT_SI_DEVICE:
-		sd = (void *) &si->data;
-		device_event(sd->event, sd->dev_id);
-		break;
-	}
-
-	return TRUE;
-}
-
-static int hciops_setup(void)
-{
-	struct sockaddr_hci addr;
-	struct hci_filter flt;
-	GIOChannel *ctl_io, *child_io;
-	int sock, err;
-
-	DBG("");
-
-	if (child_pipe[0] != -1)
-		return -EALREADY;
-
-	if (pipe(child_pipe) < 0) {
-		err = -errno;
-		error("pipe(): %s (%d)", strerror(-err), -err);
-		return err;
-	}
-
-	child_io = g_io_channel_unix_new(child_pipe[0]);
-	g_io_channel_set_close_on_unref(child_io, TRUE);
-	child_io_id = g_io_add_watch(child_io,
-				G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-				child_exit, NULL);
-	g_io_channel_unref(child_io);
-
-	/* Create and bind HCI socket */
-	sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
-	if (sock < 0) {
-		err = -errno;
-		error("Can't open HCI socket: %s (%d)", strerror(-err),
-								-err);
-		return err;
-	}
-
-	/* Set filter */
-	hci_filter_clear(&flt);
-	hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
-	hci_filter_set_event(EVT_STACK_INTERNAL, &flt);
-	if (setsockopt(sock, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
-		err = -errno;
-		error("Can't set filter: %s (%d)", strerror(-err), -err);
-		return err;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.hci_family = AF_BLUETOOTH;
-	addr.hci_dev = HCI_DEV_NONE;
-	if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		err = -errno;
-		error("Can't bind HCI socket: %s (%d)", strerror(-err), -err);
-		return err;
-	}
-
-	ctl_io = g_io_channel_unix_new(sock);
-	g_io_channel_set_close_on_unref(ctl_io, TRUE);
-
-	ctl_io_id = g_io_add_watch(ctl_io, G_IO_IN, io_stack_event, NULL);
-
-	g_io_channel_unref(ctl_io);
-
-	g_idle_add(init_known_adapters, GINT_TO_POINTER(sock));
-
-	return 0;
-}
-
-static void hciops_cleanup(void)
-{
-	int i;
-
-	DBG("");
-
-	for (i = 0; i <= max_dev; i++)
-		stop_hci_dev(i);
-
-	g_free(devs);
-	devs = NULL;
-	max_dev = -1;
-
-	if (child_io_id) {
-		g_source_remove(child_io_id);
-		child_io_id = 0;
-	}
-
-	if (ctl_io_id) {
-		g_source_remove(ctl_io_id);
-		ctl_io_id = 0;
-	}
-
-	if (child_pipe[0] >= 0) {
-		close(child_pipe[0]);
-		child_pipe[0] = -1;
-	}
-
-	if (child_pipe[1] >= 0) {
-		close(child_pipe[1]);
-		child_pipe[1] = -1;
-	}
-}
-
-static int hciops_set_powered(int index, gboolean powered)
-{
-	struct dev_info *dev = &devs[index];
-	int err;
-
-	DBG("hci%d powered %d", index, powered);
-
-	if (powered == FALSE)
-		return hciops_power_off(index);
-
-	if (ioctl(dev->sk, HCIDEVUP, index) == 0)
-		return 0;
-
-	if (errno == EALREADY)
-		return 0;
-
-	err = -errno;
-	error("Can't init device hci%d: %s (%d)",
-					index, strerror(-err), -err);
-
-	return err;
-}
-
-static int start_inquiry(int index, uint8_t length)
-{
-	struct dev_info *dev = &devs[index];
-	uint8_t lap[3] = { 0x33, 0x8b, 0x9e };
-	inquiry_cp inq_cp;
-
-	DBG("hci%d length %u", index, length);
-
-	memset(&inq_cp, 0, sizeof(inq_cp));
-	memcpy(&inq_cp.lap, lap, 3);
-	inq_cp.length = length;
-	inq_cp.num_rsp = 0x00;
-
-	if (hci_send_cmd(dev->sk, OGF_LINK_CTL,
-			OCF_INQUIRY, INQUIRY_CP_SIZE, &inq_cp) < 0)
-		return -errno;
-
-	return 0;
-}
-
-static int le_set_scan_enable(int index, uint8_t enable)
-{
-	struct dev_info *dev = &devs[index];
-	le_set_scan_enable_cp cp;
-
-	DBG("hci%d enable %u", index, enable);
-
-	memset(&cp, 0, sizeof(cp));
-	cp.enable = enable;
-	cp.filter_dup = 0;
-
-	if (hci_send_cmd(dev->sk, OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE,
-				LE_SET_SCAN_ENABLE_CP_SIZE, &cp) < 0)
-		return -errno;
-
-	return 0;
-}
-
-static gboolean stop_le_scan_cb(gpointer user_data)
-{
-	struct dev_info *dev = user_data;
-	int err;
-
-	err = le_set_scan_enable(dev->id, 0);
-	if (err < 0)
-		return TRUE;
-
-	dev->stop_scan_id = 0;
-
-	return FALSE;
-}
-
-static int start_scanning(int index, int timeout)
-{
-	struct dev_info *dev = &devs[index];
-	le_set_scan_parameters_cp cp;
-	int err;
-
-	DBG("hci%d", index);
-
-	memset(&cp, 0, sizeof(cp));
-	cp.type = 0x01;			/* Active scanning */
-	/* The recommended value for scan interval and window is 11.25 msec.
-	 * It is calculated by: time = n * 0.625 msec */
-	cp.interval = htobs(0x0012);
-	cp.window = htobs(0x0012);
-	cp.own_bdaddr_type = 0;		/* Public address */
-	cp.filter = 0;			/* Accept all adv packets */
-
-	if (hci_send_cmd(dev->sk, OGF_LE_CTL, OCF_LE_SET_SCAN_PARAMETERS,
-				LE_SET_SCAN_PARAMETERS_CP_SIZE, &cp) < 0)
-		return -errno;
-
-	err = le_set_scan_enable(index, 1);
-	if (err < 0)
-		return err;
-
-	/* Schedule a le scan disable in 'timeout' milliseconds */
-	dev->stop_scan_id = g_timeout_add(timeout, stop_le_scan_cb, dev);
-
-	return 0;
-}
-
-static int hciops_stop_scanning(int index)
-{
-	struct dev_info *dev = &devs[index];
-
-	DBG("hci%d", index);
-
-	if (dev->stop_scan_id > 0) {
-		g_source_remove(dev->stop_scan_id);
-		dev->stop_scan_id = 0;
-	}
-
-	return le_set_scan_enable(index, 0);
-}
-
-static int cancel_resolve_name(int index)
-{
-	struct dev_info *info = &devs[index];
-	struct found_dev *dev;
-	remote_name_req_cancel_cp cp;
-	struct btd_adapter *adapter;
-
-	DBG("hci%d", index);
-
-	if (g_slist_length(info->need_name) == 0)
-		return 0;
-
-	dev = info->need_name->data;
-	if (dev->name_state != NAME_PENDING)
-		return 0;
-
-	memset(&cp, 0, sizeof(cp));
-	bacpy(&cp.bdaddr, &dev->bdaddr);
-
-	adapter = manager_find_adapter_by_id(index);
-	if (adapter)
-		adapter_set_discovering(adapter, FALSE);
-
-	found_dev_cleanup(info);
-
-	if (hci_send_cmd(info->sk, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ_CANCEL,
-				REMOTE_NAME_REQ_CANCEL_CP_SIZE, &cp) < 0)
-		return -errno;
-
-	return 0;
-}
-
-static int hciops_start_discovery(int index)
-{
-	int adapter_type = get_adapter_type(index);
-
-	DBG("hci%u", index);
-
-	switch (adapter_type) {
-	case BR_EDR_LE:
-		return start_inquiry(index, LENGTH_BR_LE_INQ);
-	case BR_EDR:
-		return start_inquiry(index, LENGTH_BR_INQ);
-	case LE_ONLY:
-		return start_scanning(index, TIMEOUT_LE_SCAN);
-	default:
-		return -EINVAL;
-	}
-}
-
-static int hciops_stop_discovery(int index)
-{
-	struct dev_info *dev = &devs[index];
-
-	DBG("index %d", index);
-
-	switch (dev->discov_state) {
-	case DISCOV_INQ:
-		return hciops_stop_inquiry(index);
-	case DISCOV_SCAN:
-		return hciops_stop_scanning(index);
-	case DISCOV_NAMES:
-		cancel_resolve_name(index);
-	default:
-		return -EINVAL;
-	}
-}
-
-static int hciops_set_fast_connectable(int index, gboolean enable)
-{
-	struct dev_info *dev = &devs[index];
-	write_page_activity_cp cp;
-	uint8_t type;
-
-	DBG("hci%d enable %d", index, enable);
-
-	if (enable) {
-		type = PAGE_SCAN_TYPE_INTERLACED;
-		cp.interval = 0x0024;	/* 22.5 msec page scan interval */
-	} else {
-		type = PAGE_SCAN_TYPE_STANDARD;	/* default */
-		cp.interval = 0x0800;	/* default 1.28 sec page scan */
-	}
-
-	cp.window = 0x0012;	/* default 11.25 msec page scan window */
-
-	if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_PAGE_ACTIVITY,
-					WRITE_PAGE_ACTIVITY_CP_SIZE, &cp) < 0)
-		return -errno;
-	else if (hci_send_cmd(dev->sk, OGF_HOST_CTL,
-				OCF_WRITE_PAGE_SCAN_TYPE, 1, &type) < 0)
-		return -errno;
-
-	return 0;
-}
-
-static int hciops_read_clock(int index, bdaddr_t *bdaddr, int which,
-						int timeout, uint32_t *clock,
-						uint16_t *accuracy)
-{
-	struct dev_info *dev = &devs[index];
-	uint16_t handle = 0;
-	char addr[18];
-	int ret;
-
-	ba2str(bdaddr, addr);
-	DBG("hci%d addr %s which %d timeout %d", index, addr, which, timeout);
-
-	ret = get_handle(index, bdaddr, &handle);
-	if (ret < 0)
-		return ret;
-
-	if (hci_read_clock(dev->sk, htobs(handle), which, clock, accuracy,
-								timeout) < 0)
-		return -errno;
-
-	return 0;
-}
-
-static int hciops_read_bdaddr(int index, bdaddr_t *bdaddr)
-{
-	struct dev_info *dev = &devs[index];
-
-	DBG("hci%d", index);
-
-	bacpy(bdaddr, &dev->bdaddr);
-
-	return 0;
-}
-
-static int hciops_block_device(int index, bdaddr_t *bdaddr,
-						uint8_t bdaddr_type)
-{
-	struct dev_info *dev = &devs[index];
-	char addr[18];
-
-	ba2str(bdaddr, addr);
-	DBG("hci%d dba %s", index, addr);
-
-	if (ioctl(dev->sk, HCIBLOCKADDR, bdaddr) < 0)
-		return -errno;
-
-	return 0;
-}
-
-static int hciops_unblock_device(int index, bdaddr_t *bdaddr,
-						uint8_t bdaddr_type)
-{
-	struct dev_info *dev = &devs[index];
-	char addr[18];
-
-	ba2str(bdaddr, addr);
-	DBG("hci%d dba %s", index, addr);
-
-	if (ioctl(dev->sk, HCIUNBLOCKADDR, bdaddr) < 0)
-		return -errno;
-
-	return 0;
-}
-
-static int hciops_get_conn_list(int index, GSList **conns)
-{
-	struct dev_info *dev = &devs[index];
-	GSList *l;
-
-	DBG("hci%d", index);
-
-	*conns = NULL;
-
-	for (l = dev->connections; l != NULL; l = g_slist_next(l)) {
-		struct bt_conn *conn = l->data;
-
-		*conns = g_slist_append(*conns,
-				g_memdup(&conn->bdaddr, sizeof(bdaddr_t)));
-	}
-
-	return 0;
-}
-
-static int hciops_disconnect(int index, bdaddr_t *bdaddr, uint8_t bdaddr_type)
-{
-	DBG("hci%d", index);
-
-	return disconnect_addr(index, bdaddr, HCI_OE_USER_ENDED_CONNECTION);
-}
-
-static int hciops_remove_bonding(int index, bdaddr_t *bdaddr,
-							uint8_t bdaddr_type)
-{
-	struct dev_info *dev = &devs[index];
-	delete_stored_link_key_cp cp;
-	GSList *match;
-	char addr[18];
-
-	ba2str(bdaddr, addr);
-	DBG("hci%d dba %s", index, addr);
-
-	match = g_slist_find_custom(dev->keys, bdaddr, (GCompareFunc) bacmp);
-	if (match) {
-		g_free(match->data);
-		dev->keys = g_slist_delete_link(dev->keys, match);
-	}
-
-	memset(&cp, 0, sizeof(cp));
-	bacpy(&cp.bdaddr, bdaddr);
-
-	/* Delete the link key from the Bluetooth chip */
-	if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_DELETE_STORED_LINK_KEY,
-				DELETE_STORED_LINK_KEY_CP_SIZE, &cp) < 0)
-		return -errno;
-
-	return 0;
-}
-
-static int hciops_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin,
-								size_t pin_len)
-{
-	struct dev_info *dev = &devs[index];
-	char addr[18];
-	int err;
-
-	ba2str(bdaddr, addr);
-	DBG("hci%d dba %s", index, addr);
-
-	if (pin) {
-		pin_code_reply_cp pr;
-
-		dev->pin_length = pin_len;
-
-		memset(&pr, 0, sizeof(pr));
-		bacpy(&pr.bdaddr, bdaddr);
-		memcpy(pr.pin_code, pin, pin_len);
-		pr.pin_len = pin_len;
-		err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
-						OCF_PIN_CODE_REPLY,
-						PIN_CODE_REPLY_CP_SIZE, &pr);
-	} else
-		err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
-					OCF_PIN_CODE_NEG_REPLY, 6, bdaddr);
-
-	if (err < 0)
-		err = -errno;
-
-	return err;
-}
-
-static int hciops_passkey_reply(int index, bdaddr_t *bdaddr,
-					uint8_t bdaddr_type, uint32_t passkey)
-{
-	struct dev_info *dev = &devs[index];
-	char addr[18];
-	int err;
-
-	ba2str(bdaddr, addr);
-	DBG("hci%d dba %s", index, addr);
-
-	if (passkey != INVALID_PASSKEY) {
-		user_passkey_reply_cp cp;
-
-		memset(&cp, 0, sizeof(cp));
-		bacpy(&cp.bdaddr, bdaddr);
-		cp.passkey = passkey;
-
-		err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
-					OCF_USER_PASSKEY_REPLY,
-					USER_PASSKEY_REPLY_CP_SIZE, &cp);
-	} else
-		err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
-					OCF_USER_PASSKEY_NEG_REPLY, 6, bdaddr);
-
-	if (err < 0)
-		err = -errno;
-
-	return err;
-}
-
-static uint8_t generate_service_class(int index)
-{
-	struct dev_info *dev = &devs[index];
-	GSList *l;
-	uint8_t val = 0;
-
-	for (l = dev->uuids; l != NULL; l = g_slist_next(l)) {
-		struct uuid_info *uuid = l->data;
-
-		val |= uuid->svc_hint;
-	}
-
-	return val;
-}
-
-static int update_service_classes(int index)
-{
-	struct dev_info *dev = &devs[index];
-	uint8_t value;
-	int err;
-
-	value = generate_service_class(index);
-
-	DBG("hci%d value %u", index, value);
-
-	/* Update only the service class, keep the limited bit,
-	 * major/minor class bits intact */
-	dev->wanted_cod &= 0x00ffff;
-	dev->wanted_cod |= (value << 16);
-
-	/* If the cache is enabled or an existing CoD write is in progress
-	 * just bail out */
-	if (dev->cache_enable || dev->pending_cod)
-		return 0;
-
-	/* If we already have the CoD we want, update EIR and return */
-	if (dev->current_cod == dev->wanted_cod) {
-		update_ext_inquiry_response(index);
-		return 0;
-	}
-
-	DBG("Changing service classes to 0x%06x", dev->wanted_cod);
-
-	err = write_class(index, dev->wanted_cod);
-	if (err < 0)
-		error("Adapter class update failed: %s (%d)",
-						strerror(-err), -err);
-
-	return err;
-}
-
-static int hciops_add_uuid(int index, uuid_t *uuid, uint8_t svc_hint)
-{
-	struct dev_info *dev = &devs[index];
-	struct uuid_info *info;
-
-	DBG("hci%d", index);
-
-	info = g_new0(struct uuid_info, 1);
-	memcpy(&info->uuid, uuid, sizeof(*uuid));
-	info->svc_hint = svc_hint;
-
-	dev->uuids = g_slist_append(dev->uuids, info);
-
-	return update_service_classes(index);
-}
-
-static int hciops_remove_uuid(int index, uuid_t *uuid)
-{
-	struct dev_info *dev = &devs[index];
-	GSList *match;
-
-	match = g_slist_find_custom(dev->uuids, uuid, sdp_uuid_cmp);
-	if (match) {
-		g_free(match->data);
-		dev->uuids = g_slist_delete_link(dev->uuids, match);
-	}
-
-	DBG("hci%d", index);
-
-	return update_service_classes(index);
-}
-
-static int hciops_disable_cod_cache(int index)
-{
-	struct dev_info *dev = &devs[index];
-
-	DBG("hci%d cache_enable %d", index, dev->cache_enable);
-
-	if (!dev->cache_enable)
-		return 0;
-
-	DBG("hci%d current_cod 0x%06x wanted_cod 0x%06x", index,
-					dev->current_cod, dev->wanted_cod);
-
-	/* Disable and flush svc cache. All successive service class
-	 * updates * will be written to the device */
-	dev->cache_enable = FALSE;
-
-	if (dev->current_cod == dev->wanted_cod) {
-		update_ext_inquiry_response(index);
-		return 0;
-	}
-
-	return write_class(index, dev->wanted_cod);
-}
-
-static int hciops_restore_powered(int index)
-{
-	struct dev_info *dev = &devs[index];
-
-	if (!dev->already_up && dev->up)
-		return hciops_power_off(index);
-
-	return 0;
-}
-
-static int hciops_load_keys(int index, GSList *keys, gboolean debug_keys)
-{
-	struct dev_info *dev = &devs[index];
-	GSList *l;
-
-	DBG("hci%d keys %d debug_keys %d", index, g_slist_length(keys),
-								debug_keys);
-
-	if (dev->keys != NULL)
-		return -EEXIST;
-
-	for (l = keys; l; l = l->next) {
-		struct link_key_info *orig, *dup;
-
-		orig = l->data;
-
-		dup = g_memdup(orig, sizeof(*orig));
-
-		dev->keys = g_slist_prepend(dev->keys, dup);
-	}
-
-	dev->debug_keys = debug_keys;
-
-	return 0;
-}
-
-static int hciops_set_io_capability(int index, uint8_t io_capability)
-{
-	struct dev_info *dev = &devs[index];
-
-	/* hciops is not to be used for SMP pairing for LE devices. So
-	 * change the IO capability from KeyboardDisplay to DisplayYesNo
-	 * in case it is set. */
-	dev->io_capability = (io_capability == 0x04) ? 0x01 : io_capability;
-
-	return 0;
-}
-
-static int request_authentication(int index, bdaddr_t *bdaddr)
-{
-	struct dev_info *dev = &devs[index];
-	auth_requested_cp cp;
-	uint16_t handle;
-	int err;
-
-	DBG("hci%d", index);
-
-	err = get_handle(index, bdaddr, &handle);
-	if (err < 0)
-		return err;
-
-	memset(&cp, 0, sizeof(cp));
-	cp.handle = htobs(handle);
-
-	if (hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_AUTH_REQUESTED,
-					AUTH_REQUESTED_CP_SIZE, &cp) < 0)
-		return -errno;
-
-	return 0;
-}
-
-static void bonding_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
-{
-	struct bt_conn *conn = user_data;
-	struct dev_info *dev = conn->dev;
-
-	if (!conn->io) {
-		if (!err)
-			g_io_channel_shutdown(io, TRUE, NULL);
-		return;
-	}
-
-	if (err)
-		/* Wait proper error to be propagated by bonding complete */
-		return;
-
-	if (request_authentication(dev->id, &conn->bdaddr) < 0)
-		goto failed;
-
-	return;
-
-failed:
-	bonding_complete(dev, conn, HCI_UNSPECIFIED_ERROR);
-}
-
-static int hciops_create_bonding(int index, bdaddr_t *bdaddr,
-					uint8_t bdaddr_type, uint8_t io_cap)
-{
-	struct dev_info *dev = &devs[index];
-	BtIOSecLevel sec_level;
-	struct bt_conn *conn;
-	GError *err = NULL;
-
-	conn = get_connection(dev, bdaddr);
-
-	if (conn->io != NULL)
-		return -EBUSY;
-
-	/* hciops is not to be used for SMP pairing for LE devices. So
-	 * change the IO capability from KeyboardDisplay to DisplayYesNo
-	 * in case it is set. */
-	conn->loc_cap = (io_cap == 0x04 ? 0x01 : io_cap);
-
-	/* If our IO capability is NoInputNoOutput use medium security
-	 * level (i.e. don't require MITM protection) else use high
-	 * security level */
-	if (io_cap == 0x03)
-		sec_level = BT_IO_SEC_MEDIUM;
-	else
-		sec_level = BT_IO_SEC_HIGH;
-
-	conn->io = bt_io_connect(BT_IO_L2RAW, bonding_connect_cb, conn,
-					NULL, &err,
-					BT_IO_OPT_SOURCE_BDADDR, &dev->bdaddr,
-					BT_IO_OPT_DEST_BDADDR, bdaddr,
-					BT_IO_OPT_SEC_LEVEL, sec_level,
-					BT_IO_OPT_INVALID);
-	if (conn->io == NULL) {
-		error("bt_io_connect: %s", err->message);
-		g_error_free(err);
-		return -EIO;
-	}
-
-	conn->bonding_initiator = TRUE;
-
-	return 0;
-}
-
-static int hciops_cancel_bonding(int index, bdaddr_t *bdaddr)
-{
-	struct dev_info *dev = &devs[index];
-	struct bt_conn *conn;
-
-	DBG("hci%d", index);
-
-	conn = find_connection(dev, bdaddr);
-	if (conn == NULL || conn->io == NULL)
-		return -ENOTCONN;
-
-	g_io_channel_shutdown(conn->io, TRUE, NULL);
-	g_io_channel_unref(conn->io);
-	conn->io = NULL;
-
-	return 0;
-}
-
-static int hciops_read_local_oob_data(int index)
-{
-	struct dev_info *dev = &devs[index];
-
-	DBG("hci%d", index);
-
-	if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_LOCAL_OOB_DATA, 0, 0)
-									< 0)
-		return -errno;
-
-	return 0;
-}
-
-static int hciops_add_remote_oob_data(int index, bdaddr_t *bdaddr,
-					uint8_t *hash, uint8_t *randomizer)
-{
-	char addr[18];
-	struct dev_info *dev = &devs[index];
-	GSList *match;
-	struct oob_data *data;
-
-	ba2str(bdaddr, addr);
-	DBG("hci%d bdaddr %s", index, addr);
-
-	match = g_slist_find_custom(dev->oob_data, bdaddr, oob_bdaddr_cmp);
-
-	if (match) {
-		data = match->data;
-	} else {
-		data = g_new(struct oob_data, 1);
-		bacpy(&data->bdaddr, bdaddr);
-		dev->oob_data = g_slist_prepend(dev->oob_data, data);
-	}
-
-	memcpy(data->hash, hash, sizeof(data->hash));
-	memcpy(data->randomizer, randomizer, sizeof(data->randomizer));
-
-	return 0;
-}
-
-static int hciops_remove_remote_oob_data(int index, bdaddr_t *bdaddr)
-{
-	char addr[18];
-	struct dev_info *dev = &devs[index];
-	GSList *match;
-
-	ba2str(bdaddr, addr);
-	DBG("hci%d bdaddr %s", index, addr);
-
-	match = g_slist_find_custom(dev->oob_data, bdaddr, oob_bdaddr_cmp);
-
-	if (!match)
-		return -ENOENT;
-
-	g_free(match->data);
-	dev->oob_data = g_slist_delete_link(dev->oob_data, match);
-
-	return 0;
-}
-
-static int hciops_confirm_name(int index, bdaddr_t *bdaddr,
-				uint8_t bdaddr_type, gboolean name_known)
-{
-	struct dev_info *info = &devs[index];
-	struct found_dev *dev;
-	GSList *match;
-	char addr[18];
-
-	ba2str(bdaddr, addr);
-	DBG("hci%u %s name_known %u", index, addr, name_known);
-
-	match = g_slist_find_custom(info->found_devs, bdaddr,
-						found_dev_bda_cmp);
-	if (match == NULL)
-		return -ENOENT;
-
-	dev = match->data;
-
-	if (name_known) {
-		dev->name_state = NAME_NOT_NEEDED;
-		info->found_devs = g_slist_sort(info->found_devs,
-							found_dev_rssi_cmp);
-		return 0;
-	}
-
-	dev->name_state = NAME_NEEDED;
-	info->found_devs = g_slist_remove_link(info->found_devs, match);
-
-	match->next = info->need_name;
-	info->need_name = match;
-	info->need_name = g_slist_sort(info->need_name, found_dev_rssi_cmp);
-
-	return 0;
-}
-
-static int hciops_load_ltks(int index, GSList *keys)
-{
-	return -ENOSYS;
-}
-
-static struct btd_adapter_ops hci_ops = {
-	.setup = hciops_setup,
-	.cleanup = hciops_cleanup,
-	.set_powered = hciops_set_powered,
-	.set_discoverable = hciops_set_discoverable,
-	.set_pairable = hciops_set_pairable,
-	.start_discovery = hciops_start_discovery,
-	.stop_discovery = hciops_stop_discovery,
-	.set_name = hciops_set_name,
-	.set_dev_class = hciops_set_dev_class,
-	.set_fast_connectable = hciops_set_fast_connectable,
-	.read_clock = hciops_read_clock,
-	.read_bdaddr = hciops_read_bdaddr,
-	.block_device = hciops_block_device,
-	.unblock_device = hciops_unblock_device,
-	.get_conn_list = hciops_get_conn_list,
-	.disconnect = hciops_disconnect,
-	.remove_bonding = hciops_remove_bonding,
-	.pincode_reply = hciops_pincode_reply,
-	.confirm_reply = hciops_confirm_reply,
-	.passkey_reply = hciops_passkey_reply,
-	.encrypt_link = hciops_encrypt_link,
-	.set_did = hciops_set_did,
-	.add_uuid = hciops_add_uuid,
-	.remove_uuid = hciops_remove_uuid,
-	.disable_cod_cache = hciops_disable_cod_cache,
-	.restore_powered = hciops_restore_powered,
-	.load_keys = hciops_load_keys,
-	.set_io_capability = hciops_set_io_capability,
-	.create_bonding = hciops_create_bonding,
-	.cancel_bonding = hciops_cancel_bonding,
-	.read_local_oob_data = hciops_read_local_oob_data,
-	.add_remote_oob_data = hciops_add_remote_oob_data,
-	.remove_remote_oob_data = hciops_remove_remote_oob_data,
-	.confirm_name = hciops_confirm_name,
-	.load_ltks = hciops_load_ltks,
-};
-
-static int hciops_init(void)
-{
-	DBG("");
-	return btd_register_adapter_ops(&hci_ops, FALSE);
-}
-
-static void hciops_exit(void)
-{
-	DBG("");
-	btd_adapter_cleanup_ops(&hci_ops);
-}
-
-BLUETOOTH_PLUGIN_DEFINE(hciops, VERSION,
-		BLUETOOTH_PLUGIN_PRIORITY_LOW, hciops_init, hciops_exit)
-- 
1.7.10.2


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

* [PATCH -v2 03/28] headset: remove deprecated DBus methods
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 02/28] remove the hciops plugin Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 04/28] sink: remove deprecated DBus method Gustavo Padovan
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 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] 25+ messages in thread

* [PATCH -v2 04/28] sink: remove deprecated DBus method
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 02/28] remove the hciops plugin Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 03/28] headset: remove deprecated DBus methods Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04 12:31   ` [PATCH -v3 04/22] manager: remove deprecated ListAdapters() method Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 05/28] adapter: remove deprecated ListDevices() method Gustavo Padovan
                   ` (18 subsequent siblings)
  21 siblings, 1 reply; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 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] 25+ messages in thread

* [PATCH -v2 05/28] adapter: remove deprecated ListDevices() method
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (2 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 04/28] sink: remove deprecated DBus method Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04 12:31   ` [PATCH -v3 03/22] " Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 06/28] manager: remove deprecated ListAdapters() method Gustavo Padovan
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

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

---
 doc/adapter-api.txt |   10 ----------
 src/adapter.c       |   35 -----------------------------------
 2 files changed, 45 deletions(-)

diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt
index 916e941..176843b 100644
--- a/doc/adapter-api.txt
+++ b/doc/adapter-api.txt
@@ -88,16 +88,6 @@ Methods		dict GetProperties()
 			Possible Errors: org.bluez.Error.DoesNotExist
 					 org.bluez.Error.InvalidArguments
 
-		array{object} ListDevices() {deprecated}
-
-			Returns list of device object paths.
-			This method is deprecated, instead use the Devices
-			Property to get the list of devices object paths.
-
-			Possible errors: org.bluez.Error.InvalidArguments
-					 org.bluez.Error.Failed
-					 org.bluez.Error.OutOfMemory
-
 		object CreateDevice(string address)
 
 			Creates a new object path for a remote device. This
diff --git a/src/adapter.c b/src/adapter.c
index f922876..9315922 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1307,38 +1307,6 @@ static DBusMessage *release_session(DBusConnection *conn,
 	return dbus_message_new_method_return(msg);
 }
 
-static DBusMessage *list_devices(DBusConnection *conn,
-						DBusMessage *msg, void *data)
-{
-	struct btd_adapter *adapter = data;
-	DBusMessage *reply;
-	GSList *l;
-	DBusMessageIter iter;
-	DBusMessageIter array_iter;
-	const gchar *dev_path;
-
-	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_OBJECT_PATH_AS_STRING, &array_iter);
-
-	for (l = adapter->devices; l; l = l->next) {
-		struct btd_device *device = l->data;
-
-		dev_path = device_get_path(device);
-
-		dbus_message_iter_append_basic(&array_iter,
-				DBUS_TYPE_OBJECT_PATH, &dev_path);
-	}
-
-	dbus_message_iter_close_container(&iter, &array_iter);
-
-	return reply;
-}
-
 static DBusMessage *cancel_device_creation(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
@@ -1662,9 +1630,6 @@ static const GDBusMethodTable adapter_methods[] = {
 			adapter_start_discovery) },
 	{ GDBUS_ASYNC_METHOD("StopDiscovery", NULL, NULL,
 			adapter_stop_discovery) },
-	{ GDBUS_DEPRECATED_METHOD("ListDevices",
-			NULL, GDBUS_ARGS({ "devices", "ao" }),
-			list_devices) },
 	{ GDBUS_ASYNC_METHOD("CreateDevice",
 			GDBUS_ARGS({ "address", "s" }),
 			GDBUS_ARGS({ "device", "o" }),
-- 
1.7.10.2


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

* [PATCH -v2 06/28] manager: remove deprecated ListAdapters() method
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (3 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 05/28] adapter: remove deprecated ListDevices() method Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 07/28] adapter: remove btd_adapter_encrypt_link() Gustavo Padovan
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

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

---
 src/manager.c |   33 ---------------------------------
 1 file changed, 33 deletions(-)

diff --git a/src/manager.c b/src/manager.c
index 7061f64..d588995 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -130,36 +130,6 @@ done:
 	return reply;
 }
 
-static DBusMessage *list_adapters(DBusConnection *conn,
-					DBusMessage *msg, void *data)
-{
-	DBusMessageIter iter;
-	DBusMessageIter array_iter;
-	DBusMessage *reply;
-	GSList *l;
-
-	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_OBJECT_PATH_AS_STRING, &array_iter);
-
-	for (l = adapters; l; l = l->next) {
-		struct btd_adapter *adapter = l->data;
-		const gchar *path = adapter_get_path(adapter);
-
-		dbus_message_iter_append_basic(&array_iter,
-					DBUS_TYPE_OBJECT_PATH, &path);
-	}
-
-	dbus_message_iter_close_container(&iter, &array_iter);
-
-	return reply;
-}
-
 static DBusMessage *get_properties(DBusConnection *conn,
 					DBusMessage *msg, void *data)
 {
@@ -207,9 +177,6 @@ static const GDBusMethodTable manager_methods[] = {
 			GDBUS_ARGS({ "pattern", "s" }),
 			GDBUS_ARGS({ "adapter", "o" }),
 			find_adapter) },
-	{ GDBUS_DEPRECATED_METHOD("ListAdapters",
-			NULL, GDBUS_ARGS({ "adapters", "ao" }),
-			list_adapters) },
 	{ }
 };
 
-- 
1.7.10.2


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

* [PATCH -v2 07/28] adapter: remove btd_adapter_encrypt_link()
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (4 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 06/28] manager: remove deprecated ListAdapters() method Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 08/28] adapter_ops: remove disable_cod_cache Gustavo Padovan
                   ` (15 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

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

After the removal of hciops this function is not necessary anymore, we now
use setsockopt to accomplish the encryption of the link.
---
 input/device.c    |   38 ++++++++++----------------------------
 plugins/mgmtops.c |   12 ------------
 src/adapter.c     |    6 ------
 src/adapter.h     |    5 -----
 4 files changed, 10 insertions(+), 51 deletions(-)

diff --git a/input/device.c b/input/device.c
index 09a9a39..c08ba18 100644
--- a/input/device.c
+++ b/input/device.c
@@ -653,22 +653,18 @@ static int hidp_add_connection(const struct input_device *idev,
 
 	/* Encryption is mandatory for keyboards */
 	if (req->subclass & 0x40) {
-		struct btd_adapter *adapter = device_get_adapter(idev->device);
-
-		err = btd_adapter_encrypt_link(adapter, (bdaddr_t *) &idev->dst,
-						encrypt_completed, req);
-		if (err == 0) {
-			/* Waiting async encryption */
-			return 0;
-		}
-
-		if (err == -ENOSYS)
-			goto nosys;
-
-		if (err != -EALREADY) {
-			error("encrypt_link: %s (%d)", strerror(-err), -err);
+		if (!bt_io_set(iconn->intr_io, BT_IO_L2CAP, &gerr,
+					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+					BT_IO_OPT_INVALID)) {
+			error("btio: %s", gerr->message);
+			g_error_free(gerr);
+			err = -EFAULT;
 			goto cleanup;
 		}
+
+		iconn->req = req;
+		iconn->sec_watch = g_io_add_watch(iconn->intr_io, G_IO_OUT,
+							encrypt_notify, iconn);
 	}
 
 	err = ioctl_connadd(req);
@@ -678,20 +674,6 @@ cleanup:
 	g_free(req);
 
 	return err;
-
-nosys:
-	if (!bt_io_set(iconn->intr_io, BT_IO_L2CAP, &gerr,
-				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
-				BT_IO_OPT_INVALID)) {
-		error("btio: %s", gerr->message);
-		g_error_free(gerr);
-		goto cleanup;
-	}
-
-	iconn->req = req;
-	iconn->sec_watch = g_io_add_watch(iconn->intr_io, G_IO_OUT,
-							encrypt_notify, iconn);
-	return 0;
 }
 
 static int is_connected(struct input_conn *iconn)
diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index 16a97c9..f734edc 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -2157,17 +2157,6 @@ static int mgmt_unpair_device(int index, bdaddr_t *bdaddr, uint8_t bdaddr_type)
 	return 0;
 }
 
-static int mgmt_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb,
-							gpointer user_data)
-{
-	char addr[18];
-
-	ba2str(dst, addr);
-	DBG("index %d addr %s", index, addr);
-
-	return -ENOSYS;
-}
-
 static int mgmt_set_did(int index, uint16_t vendor, uint16_t product,
 					uint16_t version, uint16_t source)
 {
@@ -2492,7 +2481,6 @@ static struct btd_adapter_ops mgmt_ops = {
 	.pincode_reply = mgmt_pincode_reply,
 	.confirm_reply = mgmt_confirm_reply,
 	.passkey_reply = mgmt_passkey_reply,
-	.encrypt_link = mgmt_encrypt_link,
 	.set_did = mgmt_set_did,
 	.add_uuid = mgmt_add_uuid,
 	.remove_uuid = mgmt_remove_uuid,
diff --git a/src/adapter.c b/src/adapter.c
index 9315922..b485c88 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -3478,12 +3478,6 @@ int btd_adapter_passkey_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
 								passkey);
 }
 
-int btd_adapter_encrypt_link(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-					bt_hci_result_t cb, gpointer user_data)
-{
-	return adapter_ops->encrypt_link(adapter->dev_id, bdaddr, cb, user_data);
-}
-
 int btd_adapter_set_did(struct btd_adapter *adapter, uint16_t vendor,
 					uint16_t product, uint16_t version,
 					uint16_t source)
diff --git a/src/adapter.h b/src/adapter.h
index b7ea62b..77d79c1 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -200,8 +200,6 @@ struct btd_adapter_ops {
 							gboolean success);
 	int (*passkey_reply) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type,
 							uint32_t passkey);
-	int (*encrypt_link) (int index, bdaddr_t *bdaddr, bt_hci_result_t cb,
-							gpointer user_data);
 	int (*set_did) (int index, uint16_t vendor, uint16_t product,
 					uint16_t version, uint16_t source);
 	int (*add_uuid) (int index, uuid_t *uuid, uint8_t svc_hint);
@@ -261,9 +259,6 @@ int btd_adapter_confirm_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
 int btd_adapter_passkey_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
 					uint8_t bdaddr_type, uint32_t passkey);
 
-int btd_adapter_encrypt_link(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-				bt_hci_result_t cb, gpointer user_data);
-
 int btd_adapter_set_did(struct btd_adapter *adapter, uint16_t vendor,
 					uint16_t product, uint16_t version,
 					uint16_t source);
-- 
1.7.10.2


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

* [PATCH -v2 08/28] adapter_ops: remove disable_cod_cache
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (5 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 07/28] adapter: remove btd_adapter_encrypt_link() Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 09/28] manager: remove unused manager_add_adapter() Gustavo Padovan
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

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

mgmt handles the cache automatically.
---
 plugins/mgmtops.c |    9 ---------
 src/adapter.c     |    2 --
 src/adapter.h     |    1 -
 3 files changed, 12 deletions(-)

diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index f734edc..7c77be8 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -2183,14 +2183,6 @@ static int mgmt_set_did(int index, uint16_t vendor, uint16_t product,
 	return 0;
 }
 
-static int mgmt_disable_cod_cache(int index)
-{
-	DBG("index %d", index);
-
-	/* The cache control is handled automatically for mgmt */
-	return 0;
-}
-
 static int mgmt_restore_powered(int index)
 {
 	DBG("index %d", index);
@@ -2484,7 +2476,6 @@ static struct btd_adapter_ops mgmt_ops = {
 	.set_did = mgmt_set_did,
 	.add_uuid = mgmt_add_uuid,
 	.remove_uuid = mgmt_remove_uuid,
-	.disable_cod_cache = mgmt_disable_cod_cache,
 	.restore_powered = mgmt_restore_powered,
 	.load_keys = mgmt_load_link_keys,
 	.set_io_capability = mgmt_set_io_capability,
diff --git a/src/adapter.c b/src/adapter.c
index b485c88..a043366 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2188,8 +2188,6 @@ void btd_adapter_start(struct btd_adapter *adapter)
 
 	call_adapter_powered_callbacks(adapter, TRUE);
 
-	adapter_ops->disable_cod_cache(adapter->dev_id);
-
 	info("Adapter %s has been enabled", adapter->path);
 }
 
diff --git a/src/adapter.h b/src/adapter.h
index 77d79c1..4c39a7b 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -204,7 +204,6 @@ struct btd_adapter_ops {
 					uint16_t version, uint16_t source);
 	int (*add_uuid) (int index, uuid_t *uuid, uint8_t svc_hint);
 	int (*remove_uuid) (int index, uuid_t *uuid);
-	int (*disable_cod_cache) (int index);
 	int (*restore_powered) (int index);
 	int (*load_keys) (int index, GSList *keys, gboolean debug_keys);
 	int (*set_io_capability) (int index, uint8_t io_capability);
-- 
1.7.10.2


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

* [PATCH -v2 09/28] manager: remove unused manager_add_adapter()
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (6 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 08/28] adapter_ops: remove disable_cod_cache Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 10/28] adapter: make restore powered work again Gustavo Padovan
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

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

---
 src/manager.c |   12 ------------
 src/manager.h |    1 -
 2 files changed, 13 deletions(-)

diff --git a/src/manager.c b/src/manager.c
index d588995..4a39461 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -344,18 +344,6 @@ GSList *manager_get_adapters(void)
 	return adapters;
 }
 
-void manager_add_adapter(const char *path)
-{
-	g_dbus_emit_signal(connection, "/",
-				MANAGER_INTERFACE, "AdapterAdded",
-				DBUS_TYPE_OBJECT_PATH, &path,
-				DBUS_TYPE_INVALID);
-
-	manager_update_adapters();
-
-	btd_stop_exit_timer();
-}
-
 struct btd_adapter *btd_manager_register_adapter(int id, gboolean up)
 {
 	struct btd_adapter *adapter;
diff --git a/src/manager.h b/src/manager.h
index 264cd25..f3c100e 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -40,4 +40,3 @@ void manager_foreach_adapter(adapter_cb func, gpointer user_data);
 GSList *manager_get_adapters(void);
 struct btd_adapter *btd_manager_register_adapter(int id, gboolean up);
 int btd_manager_unregister_adapter(int id);
-void manager_add_adapter(const char *path);
-- 
1.7.10.2


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

* [PATCH -v2 10/28] adapter: make restore powered work again
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (7 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 09/28] manager: remove unused manager_add_adapter() Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 11/28] serial: remove SerialProxy interface Gustavo Padovan
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

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

differently from hciops mgmtops had no support to restore the powered of a
adapter. We now do this directly inside adapter_remove()
---
 plugins/mgmtops.c |    7 -------
 src/adapter.c     |    5 ++++-
 src/adapter.h     |    1 -
 3 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index 7c77be8..c060ada 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -2183,12 +2183,6 @@ static int mgmt_set_did(int index, uint16_t vendor, uint16_t product,
 	return 0;
 }
 
-static int mgmt_restore_powered(int index)
-{
-	DBG("index %d", index);
-	return -ENOSYS;
-}
-
 static int mgmt_load_link_keys(int index, GSList *keys, gboolean debug_keys)
 {
 	char *buf;
@@ -2476,7 +2470,6 @@ static struct btd_adapter_ops mgmt_ops = {
 	.set_did = mgmt_set_did,
 	.add_uuid = mgmt_add_uuid,
 	.remove_uuid = mgmt_remove_uuid,
-	.restore_powered = mgmt_restore_powered,
 	.load_keys = mgmt_load_link_keys,
 	.set_io_capability = mgmt_set_io_capability,
 	.create_bonding = mgmt_create_bonding,
diff --git a/src/adapter.c b/src/adapter.c
index a043366..1546aed 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -109,6 +109,7 @@ struct service_auth {
 struct btd_adapter {
 	uint16_t dev_id;
 	gboolean up;
+	gboolean already_up;
 	char *path;			/* adapter object path */
 	bdaddr_t bdaddr;		/* adapter Bluetooth Address */
 	uint32_t dev_class;		/* Class of Device */
@@ -2389,6 +2390,7 @@ void btd_adapter_unref(struct btd_adapter *adapter)
 gboolean adapter_init(struct btd_adapter *adapter, gboolean up)
 {
 	adapter->up = up;
+	adapter->already_up = up;
 
 	adapter->allow_name_changes = TRUE;
 
@@ -2469,7 +2471,8 @@ void adapter_remove(struct btd_adapter *adapter)
 	g_slist_free(adapter->pin_callbacks);
 
 	/* Return adapter to down state if it was not up on init */
-	adapter_ops->restore_powered(adapter->dev_id);
+	if (!adapter->already_up && adapter->up)
+		adapter_ops->set_powered(adapter->dev_id, FALSE);
 }
 
 uint16_t adapter_get_dev_id(struct btd_adapter *adapter)
diff --git a/src/adapter.h b/src/adapter.h
index 4c39a7b..73cd770 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -204,7 +204,6 @@ struct btd_adapter_ops {
 					uint16_t version, uint16_t source);
 	int (*add_uuid) (int index, uuid_t *uuid, uint8_t svc_hint);
 	int (*remove_uuid) (int index, uuid_t *uuid);
-	int (*restore_powered) (int index);
 	int (*load_keys) (int index, GSList *keys, gboolean debug_keys);
 	int (*set_io_capability) (int index, uint8_t io_capability);
 	int (*create_bonding) (int index, bdaddr_t *bdaddr,
-- 
1.7.10.2


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

* [PATCH -v2 11/28] serial: remove SerialProxy interface
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (8 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 10/28] adapter: make restore powered work again Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 12/28] serial: remove unneeded headers include Gustavo Padovan
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 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] 25+ messages in thread

* [PATCH -v2 12/28] serial: remove unneeded headers include
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (9 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 11/28] serial: remove SerialProxy interface Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 13/28] input: remove unneeded header inclusions Gustavo Padovan
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 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] 25+ messages in thread

* [PATCH -v2 13/28] input: remove unneeded header inclusions
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (10 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 12/28] serial: remove unneeded headers include Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 14/28] serial: remove old way to connect to a serial port Gustavo Padovan
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 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] 25+ messages in thread

* [PATCH -v2 14/28] serial: remove old way to connect to a serial port
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (11 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 13/28] input: remove unneeded header inclusions Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 15/28] emulator: move it to the tools folder Gustavo Padovan
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 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] 25+ messages in thread

* [PATCH -v2 15/28] emulator: move it to the tools folder
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (12 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 14/28] serial: remove old way to connect to a serial port Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 16/28] btmgmt: move to " Gustavo Padovan
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 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] 25+ messages in thread

* [PATCH -v2 16/28] btmgmt: move to tools folder
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (13 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 15/28] emulator: move it to the tools folder Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 17/28] alert: move alert to profiles dir Gustavo Padovan
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 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] 25+ messages in thread

* [PATCH -v2 17/28] alert: move alert to profiles dir
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (14 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 16/28] btmgmt: move to " Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 18/28] deviceinfo: move to profiles folder Gustavo Padovan
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 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] 25+ messages in thread

* [PATCH -v2 18/28] deviceinfo: move to profiles folder
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (15 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 17/28] alert: move alert to profiles dir Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 20/28] thermometer: move to the " Gustavo Padovan
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 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] 25+ messages in thread

* [PATCH -v2 20/28] thermometer: move to the profiles folder
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (16 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 18/28] deviceinfo: move to profiles folder Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 21/28] time: " Gustavo Padovan
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 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] 25+ messages in thread

* [PATCH -v2 21/28] time: move to the profiles folder
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (17 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 20/28] thermometer: move to the " Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 23/28] test: add test-audiosource Gustavo Padovan
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 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] 25+ messages in thread

* [PATCH -v2 23/28] test: add test-audiosource
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (18 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 21/28] time: " Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 25/28] serial: move it to the profiles folder Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 27/28] cups: move it to " Gustavo Padovan
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

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

---
 Makefile.tools        |    2 +-
 test/test-audiosource |   46 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 1 deletion(-)
 create mode 100644 test/test-audiosource

diff --git a/Makefile.tools b/Makefile.tools
index e4cf238..3cfc6f3 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -222,4 +222,4 @@ EXTRA_DIST += test/sap-client test/hsplay test/hsmicro \
 		test/test-serial-proxy test/test-health test/test-health-sink \
 		test/service-record.dtd test/service-did.xml \
 		test/service-spp.xml test/service-opp.xml test/service-ftp.xml \
-		test/simple-player test/test-nap
+		test/simple-player test/test-nap test/test-audiosource
diff --git a/test/test-audiosource b/test/test-audiosource
new file mode 100644
index 0000000..c89ff7c
--- /dev/null
+++ b/test/test-audiosource
@@ -0,0 +1,46 @@
+#!/usr/bin/python
+
+import sys
+import dbus
+from optparse import OptionParser, make_option
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
+
+option_list = [
+		make_option("-i", "--device", action="store",
+				type="string", dest="dev_id"),
+		]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+	adapter_path = manager.FindAdapter(options.dev_id)
+else:
+	adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+							"org.bluez.Adapter")
+
+if len(args) < 2:
+	print """Usage: %s <command>
+
+	connect <bdaddr>
+	disconnect <bdaddr>
+	""" % sys.argv[0]
+	sys.exit(1)
+
+device = adapter.FindDevice(args[1])
+audio = dbus.Interface(bus.get_object("org.bluez", device),
+				"org.bluez.AudioSource")
+
+if args[0] == "connect":
+	audio.Connect()
+elif args[0] == "disconnect":
+	audio.Disconnect()
+else:
+	print "Unknown command"
+	sys.exit(1)
+
-- 
1.7.10.2


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

* [PATCH -v2 25/28] serial: move it to the profiles folder
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (19 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 23/28] test: add test-audiosource Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  2012-07-04  8:17 ` [PATCH -v2 27/28] cups: move it to " Gustavo Padovan
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 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] 25+ messages in thread

* [PATCH -v2 27/28] cups: move it to profiles folder
  2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
                   ` (20 preceding siblings ...)
  2012-07-04  8:17 ` [PATCH -v2 25/28] serial: move it to the profiles folder Gustavo Padovan
@ 2012-07-04  8:17 ` Gustavo Padovan
  21 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04  8:17 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 3cfc6f3..35e2644 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] 25+ messages in thread

* [PATCH -v3 03/22] adapter: remove deprecated ListDevices() method
  2012-07-04  8:17 ` [PATCH -v2 05/28] adapter: remove deprecated ListDevices() method Gustavo Padovan
@ 2012-07-04 12:31   ` Gustavo Padovan
  0 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

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

---
 doc/adapter-api.txt   |   10 ----------
 src/adapter.c         |   35 -----------------------------------
 test/test-attrib      |    2 +-
 test/test-device      |    2 +-
 test/test-health      |    2 +-
 test/test-health-sink |    2 +-
 6 files changed, 4 insertions(+), 49 deletions(-)

diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt
index 916e941..176843b 100644
--- a/doc/adapter-api.txt
+++ b/doc/adapter-api.txt
@@ -88,16 +88,6 @@ Methods		dict GetProperties()
 			Possible Errors: org.bluez.Error.DoesNotExist
 					 org.bluez.Error.InvalidArguments
 
-		array{object} ListDevices() {deprecated}
-
-			Returns list of device object paths.
-			This method is deprecated, instead use the Devices
-			Property to get the list of devices object paths.
-
-			Possible errors: org.bluez.Error.InvalidArguments
-					 org.bluez.Error.Failed
-					 org.bluez.Error.OutOfMemory
-
 		object CreateDevice(string address)
 
 			Creates a new object path for a remote device. This
diff --git a/src/adapter.c b/src/adapter.c
index eeba44d..a043366 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1307,38 +1307,6 @@ static DBusMessage *release_session(DBusConnection *conn,
 	return dbus_message_new_method_return(msg);
 }
 
-static DBusMessage *list_devices(DBusConnection *conn,
-						DBusMessage *msg, void *data)
-{
-	struct btd_adapter *adapter = data;
-	DBusMessage *reply;
-	GSList *l;
-	DBusMessageIter iter;
-	DBusMessageIter array_iter;
-	const gchar *dev_path;
-
-	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_OBJECT_PATH_AS_STRING, &array_iter);
-
-	for (l = adapter->devices; l; l = l->next) {
-		struct btd_device *device = l->data;
-
-		dev_path = device_get_path(device);
-
-		dbus_message_iter_append_basic(&array_iter,
-				DBUS_TYPE_OBJECT_PATH, &dev_path);
-	}
-
-	dbus_message_iter_close_container(&iter, &array_iter);
-
-	return reply;
-}
-
 static DBusMessage *cancel_device_creation(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
@@ -1662,9 +1630,6 @@ static const GDBusMethodTable adapter_methods[] = {
 			adapter_start_discovery) },
 	{ GDBUS_ASYNC_METHOD("StopDiscovery", NULL, NULL,
 			adapter_stop_discovery) },
-	{ GDBUS_DEPRECATED_METHOD("ListDevices",
-			NULL, GDBUS_ARGS({ "devices", "ao" }),
-			list_devices) },
 	{ GDBUS_ASYNC_METHOD("CreateDevice",
 			GDBUS_ARGS({ "address", "s" }),
 			GDBUS_ARGS({ "device", "o" }),
diff --git a/test/test-attrib b/test/test-attrib
index 52b399c..f83859d 100755
--- a/test/test-attrib
+++ b/test/test-attrib
@@ -46,7 +46,7 @@ if (len(args) < 1):
 	sys.exit(1)
 
 if (args[0] == "list"):
-	for path in adapter.ListDevices():
+	for path in adapter.GetProperties()["Devices"]:
 		device = dbus.Interface(bus.get_object("org.bluez", path),
 							"org.bluez.Device")
 		devprop = device.GetProperties()
diff --git a/test/test-device b/test/test-device
index 81a44f8..63a96d3 100755
--- a/test/test-device
+++ b/test/test-device
@@ -49,7 +49,7 @@ if (len(args) < 1):
 	sys.exit(1)
 
 if (args[0] == "list"):
-	for path in adapter.ListDevices():
+	for path in adapter.GetProperties()["Devices"]:
 		device = dbus.Interface(bus.get_object("org.bluez", path),
 							"org.bluez.Device")
 		properties = device.GetProperties()
diff --git a/test/test-health b/test/test-health
index f7d4241..307e880 100755
--- a/test/test-health
+++ b/test/test-health
@@ -157,7 +157,7 @@ while select == None:
 adapter =  dbus.Interface(bus.get_object("org.bluez", select),
 						"org.bluez.Adapter")
 
-devices = adapter.ListDevices()
+devices = adapter.GetProperties()["Devices"]
 
 if len(devices) == 0:
 	print("No devices available")
diff --git a/test/test-health-sink b/test/test-health-sink
index ce7337a..7ee5e1a 100755
--- a/test/test-health-sink
+++ b/test/test-health-sink
@@ -47,7 +47,7 @@ while select == None:
 adapter =  dbus.Interface(bus.get_object("org.bluez", select),
 						"org.bluez.Adapter")
 
-devices = adapter.ListDevices()
+devices = adapter.GetProperties()["Devices"]
 
 if len(devices) == 0:
 	print("No devices available")
-- 
1.7.10.2


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

* [PATCH -v3 04/22] manager: remove deprecated ListAdapters() method
  2012-07-04  8:17 ` [PATCH -v2 04/28] sink: remove deprecated DBus method Gustavo Padovan
@ 2012-07-04 12:31   ` Gustavo Padovan
  0 siblings, 0 replies; 25+ messages in thread
From: Gustavo Padovan @ 2012-07-04 12:31 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Gustavo Padovan

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

---
 src/manager.c         |   33 ---------------------------------
 test/list-devices     |    3 +--
 test/test-health      |    2 +-
 test/test-health-sink |    3 +--
 4 files changed, 3 insertions(+), 38 deletions(-)

diff --git a/src/manager.c b/src/manager.c
index 1637657..4a39461 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -130,36 +130,6 @@ done:
 	return reply;
 }
 
-static DBusMessage *list_adapters(DBusConnection *conn,
-					DBusMessage *msg, void *data)
-{
-	DBusMessageIter iter;
-	DBusMessageIter array_iter;
-	DBusMessage *reply;
-	GSList *l;
-
-	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_OBJECT_PATH_AS_STRING, &array_iter);
-
-	for (l = adapters; l; l = l->next) {
-		struct btd_adapter *adapter = l->data;
-		const gchar *path = adapter_get_path(adapter);
-
-		dbus_message_iter_append_basic(&array_iter,
-					DBUS_TYPE_OBJECT_PATH, &path);
-	}
-
-	dbus_message_iter_close_container(&iter, &array_iter);
-
-	return reply;
-}
-
 static DBusMessage *get_properties(DBusConnection *conn,
 					DBusMessage *msg, void *data)
 {
@@ -207,9 +177,6 @@ static const GDBusMethodTable manager_methods[] = {
 			GDBUS_ARGS({ "pattern", "s" }),
 			GDBUS_ARGS({ "adapter", "o" }),
 			find_adapter) },
-	{ GDBUS_DEPRECATED_METHOD("ListAdapters",
-			NULL, GDBUS_ARGS({ "adapters", "ao" }),
-			list_adapters) },
 	{ }
 };
 
diff --git a/test/list-devices b/test/list-devices
index 7ef6511..1683142 100755
--- a/test/list-devices
+++ b/test/list-devices
@@ -29,8 +29,7 @@ def extract_uuids(uuid_list):
 		list = list + val + " "
 	return list
 
-adapter_list = manager.ListAdapters()
-
+adapter_list = manager.GetProperties()["Adapters"]
 for i in adapter_list:
 	adapter = dbus.Interface(bus.get_object("org.bluez", i),
 							"org.bluez.Adapter")
diff --git a/test/test-health b/test/test-health
index 307e880..a7df679 100755
--- a/test/test-health
+++ b/test/test-health
@@ -134,7 +134,7 @@ if not con:
 manager = dbus.Interface(bus.get_object("org.bluez", "/"),
 						"org.bluez.Manager")
 
-adapters = manager.ListAdapters()
+adapters = manager.GetProperties()["Adapters"]
 
 i = 1
 for ad in adapters:
diff --git a/test/test-health-sink b/test/test-health-sink
index 7ee5e1a..333b2fb 100755
--- a/test/test-health-sink
+++ b/test/test-health-sink
@@ -24,8 +24,7 @@ print(app_path)
 manager = dbus.Interface(bus.get_object("org.bluez", "/"),
 						"org.bluez.Manager")
 
-adapters = manager.ListAdapters()
-
+adapters = manager.GetProperties()["Adapters"]
 i = 1
 for ad in adapters:
 	print("%d. %s" % (i, ad))
-- 
1.7.10.2


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

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

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-04  8:17 [PATCH] network: fix network Connect() method parameters Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 02/28] remove the hciops plugin Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 03/28] headset: remove deprecated DBus methods Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 04/28] sink: remove deprecated DBus method Gustavo Padovan
2012-07-04 12:31   ` [PATCH -v3 04/22] manager: remove deprecated ListAdapters() method Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 05/28] adapter: remove deprecated ListDevices() method Gustavo Padovan
2012-07-04 12:31   ` [PATCH -v3 03/22] " Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 06/28] manager: remove deprecated ListAdapters() method Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 07/28] adapter: remove btd_adapter_encrypt_link() Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 08/28] adapter_ops: remove disable_cod_cache Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 09/28] manager: remove unused manager_add_adapter() Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 10/28] adapter: make restore powered work again Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 11/28] serial: remove SerialProxy interface Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 12/28] serial: remove unneeded headers include Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 13/28] input: remove unneeded header inclusions Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 14/28] serial: remove old way to connect to a serial port Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 15/28] emulator: move it to the tools folder Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 16/28] btmgmt: move to " Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 17/28] alert: move alert to profiles dir Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 18/28] deviceinfo: move to profiles folder Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 20/28] thermometer: move to the " Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 21/28] time: " Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 23/28] test: add test-audiosource Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 25/28] serial: move it to the profiles folder Gustavo Padovan
2012-07-04  8:17 ` [PATCH -v2 27/28] cups: move it to " Gustavo Padovan

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.