Merge BlueZ 5.37 to master

Merge BlueZ 5.37 from gfiber-internal/upstream to master

Change-Id: Ic6402a8e57fe28a48608f8db5aec061ed7284007
diff --git a/AUTHORS b/AUTHORS
index a41a62a..16fb14c 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -57,11 +57,11 @@
 Andre Guedes <andre.guedes@openbossa.org>
 Sheldon Demario <sheldon.demario@openbossa.org>
 Lucas De Marchi <lucas.demarchi@profusion.mobi>
-Szymon Janc <szymon.janc@tieto.com>
+Szymon Janc <szymon.janc@codecoup.pl>
 Syam Sidhardhan <s.syam@samsung.com>
 Paulo Alcantara <pcacjr@gmail.com>
 Jefferson Delfes <jefferson.delfes@openbossa.org>
-Andrzej Kaczmarek <andrzej.kaczmarek@tieto.com>
+Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
 Eder Ruiz Maria <eder.ruiz@openbossa.org>
 Mikel Astiz <mikel.astiz@bmw-carit.de>
 Chan-yeol Park <chanyeol.park@samsung.com>
@@ -85,7 +85,7 @@
 Jakub Tyszkowski <jakub.tyszkowski@tieto.com>
 Grzegorz Kołodziejczyk <grzegorz.kolodziejczyk@tieto.com>
 Marcin Krąglak <marcin.kraglak@tieto.com>
-Łukasz Rymanowski <lukasz.rymanowski@tieto.com>
+Łukasz Rymanowski <lukasz.rymanowski@codecoup.pl>
 Jerzy Kasenberg <jerzy.kasenberg@tieto.com>
 Arman Uguray <armansito@chromium.org>
 Artem Rakhov <arakhov@chromium.org>
diff --git a/ChangeLog b/ChangeLog
index 6abb724..c7a4fc0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+ver 5.37:
+	Fix issue with registering external profiles.
+	Fix issue with connecting external profiles.
+	Fix issue with GATT service changed handling.
+	Fix issue with not emitting GattServices update.
+	Convert to unified HID over GATT profile support.
+	Convert to KeyboardDisplay as default IO capability.
+	Install btattach utility by default.
+
 ver 5.36:
 	Fix issue with PBAP headers for size query.
 	Fix issue with AVRCP current player handling.
diff --git a/HACKING b/HACKING
index ffca598..a8fb403 100644
--- a/HACKING
+++ b/HACKING
@@ -89,8 +89,9 @@
     # sudo ./src/bluetoothd -n -d
 
   Run daemon with valgrind
-   # sudo valgrind --trace-children=yes --track-origins=yes --track-fds=yes
-   --show-possibly-lost=no --leak-check=full ./src/bluetoothd -n -d
+   # sudo valgrind --trace-children=yes --track-origins=yes --track-fds=yes \
+   --show-possibly-lost=no --leak-check=full --suppressions=./tools/valgrind.supp \
+   ./src/bluetoothd -n -d
 
 For production installations or distribution packaging it is important that
 the "--enable-maintainer-mode" option is NOT used.
diff --git a/Makefile.am b/Makefile.am
index 356f650..1a48a71 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -80,7 +80,7 @@
 lib_LTLIBRARIES += lib/libbluetooth.la
 
 lib_libbluetooth_la_SOURCES = $(lib_headers) $(lib_sources)
-lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 21:9:18
+lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 21:10:18
 lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
 endif
 
@@ -163,6 +163,7 @@
 			$(attrib_sources) $(btio_sources) \
 			src/bluetooth.ver \
 			src/main.c src/log.h src/log.c \
+			src/backtrace.h src/backtrace.c \
 			src/systemd.h src/systemd.c \
 			src/rfkill.c src/hcid.h src/sdpd.h \
 			src/sdpd-server.c src/sdpd-request.c \
@@ -189,7 +190,7 @@
 src_bluetoothd_LDADD = lib/libbluetooth-internal.la \
 			gdbus/libgdbus-internal.la \
 			src/libshared-glib.la \
-			@GLIB_LIBS@ @DBUS_LIBS@ -ldl -lrt
+			@BACKTRACE_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ -ldl -lrt
 src_bluetoothd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic \
 				-Wl,--version-script=$(srcdir)/src/bluetooth.ver
 
@@ -399,10 +400,10 @@
 
 unit_test_hog_SOURCES = unit/test-hog.c \
 			$(btio_sources) \
-			android/hog.h android/hog.c \
-			android/scpp.h android/scpp.c \
-			android/bas.h android/bas.c \
-			android/dis.h android/dis.c \
+			profiles/input/hog-lib.h profiles/input/hog-lib.c \
+			profiles/scanparam/scpp.h profiles/scanparam/scpp.c \
+			profiles/battery/bas.h profiles/battery/bas.c \
+			profiles/deviceinfo/dis.h profiles/deviceinfo/dis.c \
 			src/log.h src/log.c \
 			attrib/att.h attrib/att.c \
 			attrib/gatt.h attrib/gatt.c \
diff --git a/Makefile.plugins b/Makefile.plugins
index 5234d4a..ca58610 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -63,6 +63,10 @@
 
 builtin_modules += hog
 builtin_sources += profiles/input/hog.c profiles/input/uhid_copy.h \
+			profiles/input/hog-lib.c profiles/input/hog-lib.h \
+			profiles/deviceinfo/dis.c profiles/deviceinfo/dis.h \
+			profiles/battery/bas.c profiles/battery/bas.h \
+			profiles/scanparam/scpp.c profiles/scanparam/scpp.h \
 			profiles/input/suspend.h profiles/input/suspend-none.c
 
 EXTRA_DIST += profiles/input/suspend-dummy.c
diff --git a/Makefile.tools b/Makefile.tools
index 7bac4ec..fa45436 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -27,6 +27,8 @@
 				monitor/l2cap.h monitor/l2cap.c \
 				monitor/sdp.h monitor/sdp.c \
 				monitor/avctp.h monitor/avctp.c \
+				monitor/avdtp.h monitor/avdtp.c \
+				monitor/a2dp.h monitor/a2dp.c \
 				monitor/rfcomm.h monitor/rfcomm.c \
 				monitor/bnep.h monitor/bnep.c \
 				monitor/uuid.h monitor/uuid.c \
@@ -248,10 +250,12 @@
 endif
 
 if EXPERIMENTAL
+bin_PROGRAMS += tools/btattach
+
 noinst_PROGRAMS += tools/bdaddr tools/avinfo tools/avtest \
 			tools/scotest tools/amptest tools/hwdb \
 			tools/hcieventmask tools/hcisecfilter \
-			tools/btinfo tools/btattach \
+			tools/btinfo \
 			tools/btsnoop tools/btproxy \
 			tools/btiotest tools/bneptest tools/mcaptest \
 			tools/cltest tools/oobtest tools/seq2bseq \
@@ -294,7 +298,7 @@
 				btio/btio.h btio/btio.c \
 				src/log.c src/log.h \
 				profiles/health/mcap.h profiles/health/mcap.c
-tools_mcaptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+tools_mcaptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@ -lrt
 
 tools_bneptest_SOURCES = tools/bneptest.c \
 				btio/btio.h btio/btio.c \
@@ -328,7 +332,11 @@
 tools_btgatt_server_LDADD = src/libshared-mainloop.la \
 						lib/libbluetooth-internal.la
 
+dist_man_MANS += tools/btattach.1
+
 EXTRA_DIST += tools/bdaddr.1
+else
+EXTRA_DIST += tools/btattach.1
 endif
 
 if READLINE
diff --git a/android/Android.mk b/android/Android.mk
index 89ca2c2..38ef4aa 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -39,10 +39,10 @@
 LOCAL_SRC_FILES := \
 	bluez/android/main.c \
 	bluez/android/bluetooth.c \
-	bluez/android/scpp.c \
-	bluez/android/dis.c \
-	bluez/android/bas.c \
-	bluez/android/hog.c \
+	bluez/profiles/scanparam/scpp.c \
+	bluez/profiles/deviceinfo/dis.c \
+	bluez/profiles/battery/bas.c \
+	bluez/profiles/input/hog-lib.c \
 	bluez/android/hidhost.c \
 	bluez/android/socket.c \
 	bluez/android/ipc.c \
@@ -339,6 +339,8 @@
 	bluez/monitor/packet.c \
 	bluez/monitor/l2cap.c \
 	bluez/monitor/avctp.c \
+	bluez/monitor/avdtp.c \
+	bluez/monitor/a2dp.c \
 	bluez/monitor/rfcomm.c \
 	bluez/monitor/bnep.c \
 	bluez/monitor/uuid.c \
diff --git a/android/Makefile.am b/android/Makefile.am
index cb32bc3..154f8db 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -28,10 +28,13 @@
 				src/eir.h src/eir.c \
 				android/bluetooth.h android/bluetooth.c \
 				android/hidhost.h android/hidhost.c \
-				android/scpp.h android/scpp.c \
-				android/dis.h android/dis.c \
-				android/bas.h android/bas.c \
-				android/hog.h android/hog.c \
+				profiles/scanparam/scpp.h \
+				profiles/scanparam/scpp.c \
+				profiles/deviceinfo/dis.h \
+				profiles/deviceinfo/dis.c \
+				profiles/battery/bas.h profiles/battery/bas.c \
+				profiles/input/hog-lib.h \
+				profiles/input/hog-lib.c \
 				android/ipc-common.h \
 				android/ipc.h android/ipc.c \
 				android/avdtp.h android/avdtp.c \
diff --git a/android/README b/android/README
index fff4562..fa4c42a 100644
--- a/android/README
+++ b/android/README
@@ -23,7 +23,7 @@
 
 - GLib - Android 4.2 or later don't provide GLib and one must provide it in
 'external/bluetooth/glib' folder of Android tree. Sample Android GLib port
-is available at https://code.google.com/p/aosp-bluez.glib/
+is available at https://github.com/bluez-android/glib
 
 - SBC - A2DP code requires SBC library (version 1.2 or higher) present in
 'external/bluetooth/sbc' directory. Library is build from Android.mk provided
@@ -33,7 +33,7 @@
 BlueZ on Android 4.4 requires backporting missing features (epoll_create1 and
 ppoll calls). Sample Bionic for Android 4.4 with all required features
 backported is available at
-https://code.google.com/p/aosp-bluez.platform-bionic/
+https://github.com/bluez-android/aosp_platform_bionic
 
 Runtime requirements
 --------------------
@@ -46,9 +46,9 @@
 import init.bluetooth.rc
 
 For convenience examples are provided at:
-https://code.google.com/p/aosp-bluez.device-lge-mako/    (Nexus 4)
-https://code.google.com/p/aosp-bluez.device-lge-ham/     (Nexus 5)
-https://code.google.com/p/aosp-bluez.device-asus-flo/    (Nexus 7 2013)
+https://github.com/bluez-android/aosp_device_lge_mako           (Nexus 4)
+https://github.com/bluez-android/aosp_device_lge_hammerhead     (Nexus 5)
+https://github.com/bluez-android/aosp_device_asus_flo           (Nexus 7 2013)
 
 Security-Enhanced Linux in Android
 ----------------------------------
@@ -62,14 +62,14 @@
 bluetoothd_snoop.te
 
 For convenience sepolicy.git with all required policies is available at:
-https://code.google.com/p/aosp-bluez.external-sepolicy/
+https://github.com/bluez-android/aosp_platform_external_sepolicy
 
 Downloading and building
 ------------------------
 
 Building for Android requires full Android AOSP source tree. Sample Android tree
 with all required components present is available at
-http://code.google.com/p/aosp-bluez/
+https://github.com/bluez-android
 
 This tree provides support for Nexus4 (mako), Nexus 5 (hammerhead) and
 Nexus 7 2013 (flo, deb). Tree does not provide binary blobs needed to run
@@ -81,7 +81,8 @@
 Android 5.0 - 'lollipop' branch
 Android 4.4 - 'kitkat' branch
 
-repo init -u https://code.google.com/p/aosp-bluez.platform-manifest -b lollipop
+repo init -u https://github.com/bluez-android/aosp_platform_manifest \
+	-b lollipop
 repo sync
 
 Building:
@@ -152,8 +153,7 @@
 If it is not possible to use new enough Linux kernel one can use updated
 bluetooth subsystem from Backports project. More information about Backports can
 be found at https://backports.wiki.kernel.org. Sample kernels using backports
-for running BlueZ on Android are available at
-https://code.google.com/p/aosp-bluez.
+for running BlueZ on Android are available at https://github.com/bluez-android.
 
 
 Running with Valgrind
@@ -176,7 +176,7 @@
 complete backtraces in Valgrind output. Otherwise, in many cases backtrace
 will break at e.g. g_free() function without prior callers. It's possible to
 have proper library installed automatically by appropriate entry in Android.mk,
-see https://code.google.com/p/aosp-bluez.glib/ for an example.
+see https://github.com/bluez-android/glib for an example.
 
 When running with valgrind SElinux needs to be set into permissive mode. This
 can be done by executing 'setenforce 0' from root shell.
@@ -207,7 +207,7 @@
 This may include enabling extra profiles or features inside HALs implementation
 These properties are read on Bluetooth stack startup only and require stack
 restart if changed. All customization properties names start with
-"persist.sys.bluetooth." or "ro.bluerooth." followed by specific HAL name e.g.
+"persist.sys.bluetooth." or "ro.bluetooth." followed by specific HAL name e.g.
 "persist.sys.bluetooth.handsfree". If both are present "persist.sys.bluetooth."
 takes precedence. This allows for read only properties to be set during build
 leaving enough flexibility for developing or debugging purposes.
diff --git a/android/avdtp.c b/android/avdtp.c
index 908c0ca..bab305b 100644
--- a/android/avdtp.c
+++ b/android/avdtp.c
@@ -3398,10 +3398,7 @@
 	DBG("SEP %p registered: type:%d codec:%d seid:%d", sep,
 			sep->info.type, sep->codec, sep->info.seid);
 
-	if (!queue_push_tail(lseps, sep)) {
-		g_free(sep);
-		return NULL;
-	}
+	queue_push_tail(lseps, sep);
 
 	return sep;
 }
diff --git a/android/avdtptest.c b/android/avdtptest.c
index 01d52ea..ce34443 100644
--- a/android/avdtptest.c
+++ b/android/avdtptest.c
@@ -869,10 +869,6 @@
 	}
 
 	lseps = queue_new();
-	if (!lseps) {
-		printf("Failed to allocate memory\n");
-		exit(1);
-	}
 
 	local_sep = avdtp_register_sep(lseps, dev_role, AVDTP_MEDIA_TYPE_AUDIO,
 					0x00, TRUE, &sep_ind, &sep_cfm, NULL);
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 4d0cd48..51a31fe 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -3961,9 +3961,6 @@
 	uint8_t adv = advertising ? 0x01 : 0x00;
 
 	data = new0(struct adv_user_data, 1);
-	if (!data)
-		return false;
-
 	data->cb = cb;
 	data->user_data = user_data;
 
@@ -4078,9 +4075,6 @@
 	cp.addr.type = dev->bredr ? BDADDR_BREDR : dev->bdaddr_type;
 
 	data = new0(struct read_rssi_user_data, 1);
-	if (!data)
-		return false;
-
 	data->cb = cb;
 	data->user_data = user_data;
 
@@ -5249,18 +5243,7 @@
 	DBG("mode 0x%x", mode);
 
 	unpaired_cb_list = queue_new();
-	if (!unpaired_cb_list) {
-		error("Cannot allocate queue for unpaired callbacks");
-		return false;
-	}
-
 	paired_cb_list = queue_new();
-	if (!paired_cb_list) {
-		error("Cannot allocate queue for paired callbacks");
-		queue_destroy(unpaired_cb_list, NULL);
-		unpaired_cb_list = NULL;
-		return false;
-	}
 
 	missing_settings = adapter.current_settings ^
 						adapter.supported_settings;
diff --git a/android/bluetoothd-snoop.c b/android/bluetoothd-snoop.c
index 75f58cc..7526782 100644
--- a/android/bluetoothd-snoop.c
+++ b/android/bluetoothd-snoop.c
@@ -148,7 +148,7 @@
 	struct sockaddr_hci addr;
 	int opt = 1;
 
-	snoop = btsnoop_create(path, BTSNOOP_TYPE_HCI);
+	snoop = btsnoop_create(path, BTSNOOP_FORMAT_HCI);
 	if (!snoop)
 		return -1;
 
diff --git a/android/gatt.c b/android/gatt.c
index 65f3142..28635ed 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -744,37 +744,14 @@
 	struct gatt_device *dev;
 
 	dev = new0(struct gatt_device, 1);
-	if (!dev)
-		return NULL;
 
 	bacpy(&dev->bdaddr, addr);
 
 	dev->services = queue_new();
-	if (!dev->services) {
-		error("gatt: Failed to allocate memory for client");
-		destroy_device(dev);
-		return NULL;
-	}
-
 	dev->autoconnect_apps = queue_new();
-	if (!dev->autoconnect_apps) {
-		error("gatt: Failed to allocate memory for client");
-		destroy_device(dev);
-		return NULL;
-	}
-
 	dev->pending_requests = queue_new();
-	if (!dev->pending_requests) {
-		error("gatt: Failed to allocate memory for client");
-		destroy_device(dev);
-		return NULL;
-	}
 
-	if (!queue_push_head(gatt_devices, dev)) {
-		error("gatt: Cannot push device to queue");
-		destroy_device(dev);
-		return NULL;
-	}
+	queue_push_head(gatt_devices, dev);
 
 	return device_ref(dev);
 }
@@ -1116,25 +1093,13 @@
 
 	/* Check if already connected */
 	new_conn = new0(struct app_connection, 1);
-	if (!new_conn)
-		return NULL;
 
 	/* Make connection id unique to connection record (app, device) pair */
 	new_conn->app = app;
 	new_conn->id = last_conn_id++;
-
 	new_conn->transactions = queue_new();
-	if (!new_conn->transactions) {
-		free(new_conn);
-		return NULL;
-	}
 
-	if (!queue_push_head(app_connections, new_conn)) {
-		error("gatt: Cannot push client on the client queue!?");
-		queue_destroy(new_conn->transactions, free);
-		free(new_conn);
-		return NULL;
-	}
+	queue_push_head(app_connections, new_conn);
 
 	new_conn->device = device_ref(device);
 
@@ -1147,33 +1112,15 @@
 	struct service *s;
 
 	s = new0(struct service, 1);
-	if (!s) {
-		error("gatt: Cannot allocate memory for gatt_primary");
+
+	if (bt_string_to_uuid(&s->id.uuid, uuid) < 0) {
+		error("gatt: Cannot convert string to uuid");
+		free(s);
 		return NULL;
 	}
 
 	s->chars = queue_new();
-	if (!s->chars) {
-		error("gatt: Cannot allocate memory for char cache");
-		free(s);
-		return NULL;
-	}
-
 	s->included = queue_new();
-	if (!s->included) {
-		error("gatt: Cannot allocate memory for included queue");
-		queue_destroy(s->chars, NULL);
-		free(s);
-		return NULL;
-	}
-
-	if (bt_string_to_uuid(&s->id.uuid, uuid) < 0) {
-		error("gatt: Cannot convert string to uuid");
-		queue_destroy(s->chars, NULL);
-		free(s);
-		return NULL;
-	}
-
 	s->id.instance = id;
 
 	/* Put primary service to our local list */
@@ -1256,12 +1203,7 @@
 			goto reply;
 		}
 
-		if (!queue_push_tail(dev->services, s)) {
-			error("gatt: Cannot push primary service to the list");
-			destroy_service(s);
-			gatt_status = GATT_FAILURE;
-			goto reply;
-		}
+		queue_push_tail(dev->services, s);
 
 		send_client_primary_notify(s, INT_TO_PTR(cb_data->conn->id));
 
@@ -1318,11 +1260,7 @@
 		if (!p)
 			continue;
 
-		if (!queue_push_tail(dev->services, p)) {
-			error("gatt: Cannot push primary service to the list");
-			free(p);
-			continue;
-		}
+		queue_push_tail(dev->services, p);
 
 		DBG("attr handle = 0x%04x, end grp handle = 0x%04x uuid: %s",
 			prim->range.start, prim->range.end, prim->uuid);
@@ -1412,11 +1350,6 @@
 	struct discover_srvc_data *cb_data;
 
 	cb_data = new0(struct discover_srvc_data, 1);
-	if (!cb_data) {
-		error("gatt: Cannot allocate cb data");
-		return 0;
-	}
-
 	cb_data->conn = conn;
 
 	if (uuid) {
@@ -1779,7 +1712,7 @@
 		dev = create_device(addr);
 	}
 
-	if (!dev || dev->state != DEVICE_CONNECT_INIT)
+	if (dev->state != DEVICE_CONNECT_INIT)
 		return;
 
 	device_set_state(dev, DEVICE_CONNECT_READY);
@@ -1802,38 +1735,20 @@
 	}
 
 	app = new0(struct gatt_app, 1);
-	if (!app) {
-		error("gatt: Cannot allocate memory for registering app");
-		return NULL;
-	}
 
 	app->type = type;
 
-	if (app->type == GATT_CLIENT) {
+	if (app->type == GATT_CLIENT)
 		app->notifications = queue_new();
-		if (!app->notifications) {
-			error("gatt: couldn't allocate notifications queue");
-			destroy_gatt_app(app);
-			return NULL;
-		}
-	}
 
 	memcpy(app->uuid, uuid, sizeof(app->uuid));
 
 	app->id = application_id++;
 
-	if (!queue_push_head(gatt_apps, app)) {
-		error("gatt: Cannot push app on the list");
-		destroy_gatt_app(app);
-		return NULL;
-	}
+	queue_push_head(gatt_apps, app);
 
-	if ((app->type == GATT_SERVER) &&
-			!queue_push_tail(listen_apps, INT_TO_PTR(app->id))) {
-		error("gatt: Cannot push server on the list");
-		destroy_gatt_app(app);
-		return NULL;
-	}
+	if (app->type == GATT_SERVER)
+		queue_push_tail(listen_apps, INT_TO_PTR(app->id));
 
 	return app;
 }
@@ -2056,9 +1971,6 @@
 	struct listen_data *d;
 
 	d = new0(struct listen_data, 1);
-	if (!d)
-		return NULL;
-
 	d->client_id = client_id;
 	d->start = start;
 
@@ -2108,11 +2020,6 @@
 
 	if (!advertising_cnt) {
 		data = create_listen_data(cmd->client_if, false);
-		if (!data) {
-			error("gatt: Could not allocate listen data");
-			status = HAL_STATUS_NOMEM;
-			goto reply;
-		}
 
 		if (!bt_le_set_advertising(data->start, set_advertising_cb,
 								data)) {
@@ -2144,11 +2051,8 @@
 		return HAL_STATUS_FAILED;
 
 	device = find_device_by_addr(addr);
-	if (!device) {
+	if (!device)
 		device = create_device(addr);
-		if (!device)
-			return HAL_STATUS_FAILED;
-	}
 
 	conn_match.device = device;
 	conn_match.app = app;
@@ -2229,12 +2133,7 @@
 			goto reply;
 		}
 
-		if (!queue_push_tail(listen_apps,
-						INT_TO_PTR(cmd->client_if))) {
-			error("gatt: Could not put client on listen queue");
-			status = HAL_STATUS_FAILED;
-			goto reply;
-		}
+		queue_push_tail(listen_apps, INT_TO_PTR(cmd->client_if));
 
 		/* If listen is already on just return success*/
 		if (advertising_cnt > 0) {
@@ -2264,11 +2163,6 @@
 	}
 
 	data = create_listen_data(cmd->client_if, cmd->start);
-	if (!data) {
-		error("gatt: Could not allocate listen data");
-		status = HAL_STATUS_NOMEM;
-		goto reply;
-	}
 
 	if (!bt_le_set_advertising(cmd->start, set_advertising_cb, data)) {
 		error("gatt: Could not set advertising");
@@ -2507,12 +2401,8 @@
 		 * 1. on services queue together with primary service
 		 * 2. on special queue inside primary service
 		 */
-		if (!queue_push_tail(service->included, incl) ||
-			!queue_push_tail(conn->device->services, incl)) {
-			error("gatt: Cannot push incl service to the list");
-			destroy_service(incl);
-			continue;
-		}
+		queue_push_tail(service->included, incl);
+		queue_push_tail(conn->device->services, incl);
 	}
 
 	/*
@@ -2525,18 +2415,13 @@
 	send_client_incl_service_notify(&service->id, incl, conn->id);
 }
 
-static bool search_included_services(struct app_connection *conn,
+static void search_included_services(struct app_connection *conn,
 							struct service *service)
 {
 	struct get_included_data *data;
 	uint16_t start, end;
 
 	data = new0(struct get_included_data, 1);
-	if (!data) {
-		error("gatt: failed to allocate memory for included_data");
-		return false;
-	}
-
 	data->prim = service;
 	data->conn = conn;
 
@@ -2550,8 +2435,6 @@
 
 	gatt_find_included(conn->device->attrib, start, end, get_included_cb,
 									data);
-
-	return true;
 }
 
 static bool find_service(int32_t conn_id, struct element_id *service_id,
@@ -2610,13 +2493,9 @@
 	}
 
 	if (!prim_service->incl_search_done) {
-		if (search_included_services(conn, prim_service)) {
-			status = HAL_STATUS_SUCCESS;
-			goto reply;
-		}
-
-		status = HAL_STATUS_FAILED;
-		goto notify;
+		search_included_services(conn, prim_service);
+		status = HAL_STATUS_SUCCESS;
+		goto reply;
 	}
 
 	/* Try to use cache here */
@@ -2696,17 +2575,7 @@
 		struct characteristic *ch;
 
 		ch = new0(struct characteristic, 1);
-		if (!ch) {
-			error("gatt: Error while caching characteristic");
-			continue;
-		}
-
 		ch->descriptors = queue_new();
-		if (!ch->descriptors) {
-			error("gatt: Error while caching characteristic");
-			free(ch);
-			continue;
-		}
 
 		memcpy(&ch->ch, characteristics->data, sizeof(ch->ch));
 
@@ -2732,10 +2601,7 @@
 		DBG("attr handle = 0x%04x, end handle = 0x%04x uuid: %s",
 				ch->ch.handle, ch->end_handle, ch->ch.uuid);
 
-		if (!queue_push_tail(srvc->chars, ch)) {
-			error("gatt: Error while caching characteristic");
-			destroy_characteristic(ch);
-		}
+		queue_push_tail(srvc->chars, ch);
 	}
 }
 
@@ -2797,12 +2663,6 @@
 		struct att_range range;
 
 		cb_data = new0(struct discover_char_data, 1);
-		if (!cb_data) {
-			error("gatt: Cannot allocate cb data");
-			status = HAL_STATUS_FAILED;
-			goto done;
-		}
-
 		cb_data->service = srvc;
 		cb_data->conn_id = conn->id;
 
@@ -2889,8 +2749,6 @@
 		bt_uuid_t uuid;
 
 		descr = new0(struct descriptor, 1);
-		if (!descr)
-			continue;
 
 		bt_string_to_uuid(&uuid, desc->uuid);
 		bt_uuid_to_uuid128(&uuid, &descr->id.uuid);
@@ -2900,8 +2758,7 @@
 
 		DBG("attr handle = 0x%04x, uuid: %s", desc->handle, desc->uuid);
 
-		if (!queue_push_tail(ch->descriptors, descr))
-			free(descr);
+		queue_push_tail(ch->descriptors, descr);
 	}
 
 reply:
@@ -2929,9 +2786,6 @@
 		return false;
 
 	cb_data = new0(struct discover_desc_data, 1);
-	if (!cb_data)
-		return false;
-
 	cb_data->conn = conn;
 	cb_data->srvc = srvc;
 	cb_data->ch = ch;
@@ -3033,9 +2887,6 @@
 	struct char_op_data *d;
 
 	d = new0(struct char_op_data, 1);
-	if (!d)
-		return NULL;
-
 	d->conn_id = conn_id;
 	d->srvc_id = s_id;
 	d->char_id = ch_id;
@@ -3216,11 +3067,6 @@
 
 	cb_data = create_char_op_data(cmd->conn_id, &srvc->id, &ch->id,
 						cmd->srvc_id.is_primary);
-	if (!cb_data) {
-		error("gatt: Cannot allocate cb data");
-		status = HAL_STATUS_NOMEM;
-		goto failed;
-	}
 
 	if (!set_auth_type(conn->device, cmd->auth_req)) {
 		error("gatt: Failed to set security %d", cmd->auth_req);
@@ -3354,11 +3200,6 @@
 				cmd->write_type == GATT_WRITE_TYPE_DEFAULT) {
 		cb_data = create_char_op_data(cmd->conn_id, &srvc->id, &ch->id,
 						cmd->srvc_id.is_primary);
-		if (!cb_data) {
-			error("gatt: Cannot allocate call data");
-			status = HAL_STATUS_NOMEM;
-			goto failed;
-		}
 	}
 
 	if (!set_auth_type(conn->device, cmd->auth_req)) {
@@ -3507,9 +3348,6 @@
 	struct desc_data *d;
 
 	d = new0(struct desc_data, 1);
-	if (!d)
-		return NULL;
-
 	d->conn_id = conn_id;
 	d->srvc_id = s_id;
 	d->char_id = ch_id;
@@ -3569,12 +3407,6 @@
 
 	cb_data = create_desc_data(conn_id, &srvc->id, &ch->id, &descr->id,
 								primary);
-	if (!cb_data) {
-		error("gatt: Read descr. could not allocate callback data");
-
-		status = HAL_STATUS_NOMEM;
-		goto failed;
-	}
 
 	if (!set_auth_type(conn->device, cmd->auth_req)) {
 		error("gatt: Failed to set security %d", cmd->auth_req);
@@ -3698,16 +3530,9 @@
 		goto failed;
 	}
 
-	if (cmd->write_type != GATT_WRITE_TYPE_NO_RESPONSE) {
+	if (cmd->write_type != GATT_WRITE_TYPE_NO_RESPONSE)
 		cb_data = create_desc_data(conn_id, &srvc->id, &ch->id,
 							&descr->id, primary);
-		if (!cb_data) {
-			error("gatt: Write descr. could not allocate cb_data");
-
-			status = HAL_STATUS_NOMEM;
-			goto failed;
-		}
-	}
 
 	if (!set_auth_type(conn->device, cmd->auth_req)) {
 		error("gatt: Failed to set security %d", cmd->auth_req);
@@ -3897,10 +3722,6 @@
 	}
 
 	notification = new0(struct notification_data, 1);
-	if (!notification) {
-		status = HAL_STATUS_NOMEM;
-		goto failed;
-	}
 
 	memcpy(&notification->ch, &cmd->char_id, sizeof(notification->ch));
 	memcpy(&notification->service, &cmd->srvc_id,
@@ -3947,11 +3768,7 @@
 	 */
 	notification->ref = 2;
 
-	if (!queue_push_tail(conn->app->notifications, notification)) {
-		unregister_notification(notification);
-		status = HAL_STATUS_FAILED;
-		goto failed;
-	}
+	queue_push_tail(conn->app->notifications, notification);
 
 	status = HAL_STATUS_SUCCESS;
 
@@ -4503,8 +4320,6 @@
 		struct queue *temp;
 
 		temp = queue_new();
-		if (!temp)
-			goto done;
 
 		val = queue_pop_head(device->pending_requests);
 		if (!val) {
@@ -4567,8 +4382,6 @@
 		struct queue *temp;
 
 		temp = queue_new();
-		if (!temp)
-			goto done;
 
 		val = queue_pop_head(device->pending_requests);
 		if (!val) {
@@ -4630,12 +4443,6 @@
 			}
 
 			range = new0(struct att_range, 1);
-			if (!range) {
-				destroy_pending_request(val);
-				error = ATT_ECODE_INSUFF_RESOURCES;
-				break;
-			}
-
 			range->start = gatt_db_attribute_get_handle(
 								val->attrib);
 
@@ -4878,19 +4685,13 @@
 	static int32_t trans_id = 1;
 
 	transaction = new0(struct pending_trans_data, 1);
-	if (!transaction)
-		return NULL;
-
-	if (!queue_push_tail(conn->transactions, transaction)) {
-		free(transaction);
-		return NULL;
-	}
-
 	transaction->id = trans_id++;
 	transaction->opcode = opcode;
 	transaction->attrib = attrib;
 	transaction->serial_id = serial_id;
 
+	queue_push_tail(conn->transactions, transaction);
+
 	return transaction;
 }
 
@@ -4949,8 +4750,6 @@
 
 	/* Store the request data, complete callback and transaction id */
 	transaction = conn_add_transact(conn, opcode, attrib, id);
-	if (!transaction)
-		goto failed;
 
 	bdaddr2android(&bdaddr, ev.bdaddr);
 	ev.conn_id = conn->id;
@@ -5009,8 +4808,6 @@
 
 	/* Store the request data, complete callback and transaction id */
 	transaction = conn_add_transact(conn, opcode, attrib, id);
-	if (!transaction)
-		goto failed;
 
 	memset(ev, 0, sizeof(*ev));
 
@@ -5313,9 +5110,6 @@
 		return NULL;
 
 	s = new0(struct service_sdp, 1);
-	if (!s)
-		return NULL;
-
 	s->service_handle = service_handle;
 	s->sdp_handle = add_sdp_record(&uuid, service_handle, end_handle, NULL);
 	if (!s->sdp_handle) {
@@ -5350,10 +5144,7 @@
 	if (!s)
 		return false;
 
-	if (!queue_push_tail(services_sdp, s)) {
-		free_service_sdp_record(s);
-		return false;
-	}
+	queue_push_tail(services_sdp, s);
 
 	return true;
 }
@@ -6080,8 +5871,6 @@
 		return ATT_ECODE_INVALID_HANDLE;
 
 	q = queue_new();
-	if (!q)
-		return ATT_ECODE_INSUFF_RESOURCES;
 
 	switch (cmd[0]) {
 	case ATT_OP_READ_BY_TYPE_REQ:
@@ -6104,17 +5893,8 @@
 		struct gatt_db_attribute *attrib = queue_pop_head(q);
 
 		data = new0(struct pending_request, 1);
-		if (!data) {
-			queue_destroy(q, NULL);
-			return ATT_ECODE_INSUFF_RESOURCES;
-		}
-
 		data->attrib = attrib;
-		if (!queue_push_tail(device->pending_requests, data)) {
-			free(data);
-			queue_destroy(q, NULL);
-			return ATT_ECODE_INSUFF_RESOURCES;
-		}
+		queue_push_tail(device->pending_requests, data);
 	}
 
 	queue_destroy(q, NULL);
@@ -6156,15 +5936,9 @@
 		return ATT_ECODE_INVALID_HANDLE;
 
 	data = new0(struct pending_request, 1);
-	if (!data)
-		return ATT_ECODE_INSUFF_RESOURCES;
-
 	data->offset = offset;
 	data->attrib = attrib;
-	if (!queue_push_tail(dev->pending_requests, data)) {
-		free(data);
-		return ATT_ECODE_INSUFF_RESOURCES;
-	}
+	queue_push_tail(dev->pending_requests, data);
 
 	process_dev_pending_requests(dev, cmd[0]);
 
@@ -6226,8 +6000,6 @@
 		return ATT_ECODE_INVALID_HANDLE;
 
 	q = queue_new();
-	if (!q)
-		return ATT_ECODE_UNLIKELY;
 
 	gatt_db_find_information(gatt_db, start, end, q);
 
@@ -6237,10 +6009,6 @@
 	}
 
 	temp = queue_new();
-	if (!temp) {
-		queue_destroy(q, NULL);
-		return ATT_ECODE_UNLIKELY;
-	}
 
 	attrib = queue_peek_head(q);
 	/* UUIDS can be only 128 bit and 16 bit */
@@ -6321,11 +6089,6 @@
 		return;
 
 	request_data = new0(struct pending_request, 1);
-	if (!request_data) {
-		find_data->error = ATT_ECODE_INSUFF_RESOURCES;
-		return;
-	}
-
 	request_data->filter_value = malloc0(find_data->search_vlen);
 	if (!request_data->filter_value) {
 		destroy_pending_request(request_data);
@@ -6338,11 +6101,7 @@
 	memcpy(request_data->filter_value, find_data->search_value,
 							find_data->search_vlen);
 
-	if (!queue_push_tail(find_data->device->pending_requests,
-							request_data)) {
-		destroy_pending_request(request_data);
-		find_data->error = ATT_ECODE_INSUFF_RESOURCES;
-	}
+	queue_push_tail(find_data->device->pending_requests, request_data);
 }
 
 static uint8_t find_by_type_request(const uint8_t *cmd, uint16_t cmd_len,
@@ -6511,7 +6270,6 @@
 
 	data->attrib = attrib;
 	data->error = error;
-
 	data->completed = true;
 }
 
@@ -6545,15 +6303,9 @@
 		return error;
 
 	data = new0(struct pending_request, 1);
-	if (!data)
-		return ATT_ECODE_INSUFF_RESOURCES;
-
 	data->attrib = attrib;
 
-	if (!queue_push_tail(dev->pending_requests, data)) {
-		free(data);
-		return ATT_ECODE_INSUFF_RESOURCES;
-	}
+	queue_push_tail(dev->pending_requests, data);
 
 	if (!gatt_db_attribute_write(attrib, 0, value, vlen, cmd[0],
 						g_attrib_get_att(dev->attrib),
@@ -6600,16 +6352,10 @@
 		return error;
 
 	data = new0(struct pending_request, 1);
-	if (!data)
-		return ATT_ECODE_INSUFF_RESOURCES;
-
 	data->attrib = attrib;
 	data->offset = offset;
 
-	if (!queue_push_tail(dev->pending_requests, data)) {
-		free(data);
-		return ATT_ECODE_INSUFF_RESOURCES;
-	}
+	queue_push_tail(dev->pending_requests, data);
 
 	data->value = g_memdup(value, vlen);
 	data->length = vlen;
@@ -6641,10 +6387,6 @@
 	ev->conn_id = conn->id;
 
 	transaction = conn_add_transact(conn, ATT_OP_EXEC_WRITE_REQ, NULL, 0);
-	if (!transaction) {
-		conn->wait_execute_write = false;
-		return;
-	}
 
 	ev->trans_id = transaction->id;
 
@@ -6674,13 +6416,8 @@
 	ev.exec_write = value;
 
 	data = new0(struct pending_request, 1);
-	if (!data)
-		return ATT_ECODE_INSUFF_RESOURCES;
 
-	if (!queue_push_tail(dev->pending_requests, data)) {
-		free(data);
-		return ATT_ECODE_INSUFF_RESOURCES;
-	}
+	queue_push_tail(dev->pending_requests, data);
 
 	queue_foreach(app_connections, send_server_write_execute_notify, &ev);
 	send_dev_complete_response(dev, cmd[0]);
@@ -6774,10 +6511,6 @@
 	dev = find_device_by_addr(&dst);
 	if (!dev) {
 		dev = create_device(&dst);
-		if (!dev) {
-			error("gatt: Could not create device");
-			goto drop;
-		}
 	} else {
 		if ((dev->state != DEVICE_DISCONNECTED) &&
 					!(dev->state == DEVICE_CONNECT_INIT &&
@@ -7227,9 +6960,8 @@
 	services_sdp = queue_new();
 	gatt_db = gatt_db_new();
 
-	if (!gatt_devices || !gatt_apps || !listen_apps || !app_connections ||
-						!services_sdp || !gatt_db) {
-		error("gatt: Failed to allocate memory for queues");
+	if (!gatt_db) {
+		error("gatt: Failed to allocate memory for database");
 		goto failed;
 	}
 
diff --git a/android/handsfree-client.c b/android/handsfree-client.c
index 0e2bd40..65659b8 100644
--- a/android/handsfree-client.c
+++ b/android/handsfree-client.c
@@ -177,14 +177,6 @@
 	struct device *dev;
 
 	dev = new0(struct device, 1);
-	if (!dev)
-		return NULL;
-
-	if (!queue_push_tail(devices, dev)) {
-		error("hf-client: Could not push dev on the list");
-		free(dev);
-		return NULL;
-	}
 
 	bacpy(&dev->bdaddr, bdaddr);
 	dev->state = HAL_HF_CLIENT_CONN_STATE_DISCONNECTED;
@@ -192,6 +184,8 @@
 
 	init_codecs(dev);
 
+	queue_push_tail(devices, dev);
+
 	return dev;
 }
 
@@ -2166,10 +2160,6 @@
 	DBG("");
 
 	devices = queue_new();
-	if (!devices) {
-		error("hf-client: Could not create devices list");
-		goto failed;
-	}
 
 	bacpy(&adapter_addr, addr);
 
diff --git a/android/handsfree.c b/android/handsfree.c
index 2f8a867..cb348ab 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -228,8 +228,6 @@
 	struct hf_device *dev;
 
 	dev = new0(struct hf_device, 1);
-	if (!dev)
-		return NULL;
 
 	bacpy(&dev->bdaddr, bdaddr);
 	dev->setup_state = HAL_HANDSFREE_CALL_STATE_IDLE;
@@ -240,10 +238,7 @@
 
 	init_codecs(dev);
 
-	if (!queue_push_head(devices, dev)) {
-		free(dev);
-		return NULL;
-	}
+	queue_push_head(devices, dev);
 
 	return dev;
 }
@@ -2968,8 +2963,6 @@
 		return false;
 
 	devices = queue_new();
-	if (!devices)
-		return false;
 
 	if (!enable_hsp_ag())
 		goto failed_queue;
diff --git a/android/health.c b/android/health.c
index f2895a2..eb02a64 100644
--- a/android/health.c
+++ b/android/health.c
@@ -822,9 +822,6 @@
 	DBG("");
 
 	app = new0(struct health_app, 1);
-	if (!app)
-		return NULL;
-
 	app->id = app_id++;
 	app->num_of_mdep = mdeps;
 	app->app_name = strdup(app_name);
@@ -848,12 +845,7 @@
 	}
 
 	app->mdeps = queue_new();
-	if (!app->mdeps)
-		goto fail;
-
 	app->devices = queue_new();
-	if (!app->devices)
-		goto fail;
 
 	return app;
 
@@ -906,8 +898,7 @@
 	if (!app)
 		goto fail;
 
-	if (!queue_push_tail(apps, app))
-		goto fail;
+	queue_push_tail(apps, app);
 
 	rsp.app_id = app->id;
 	ipc_send_rsp_full(hal_ipc, HAL_SERVICE_ID_HEALTH, HAL_OP_HEALTH_REG_APP,
@@ -948,11 +939,6 @@
 	}
 
 	mdep = new0(struct mdep_cfg, 1);
-	if (!mdep) {
-		status = HAL_STATUS_INVALID;
-		goto fail;
-	}
-
 	mdep->role = cmd->role;
 	mdep->data_type = cmd->data_type;
 	mdep->channel_type = android2channel_type(cmd->channel_type);
@@ -963,10 +949,7 @@
 		memcpy(mdep->descr, cmd->descr, cmd->descr_len);
 	}
 
-	if (!queue_push_tail(app->mdeps, mdep)) {
-		status = HAL_STATUS_FAILED;
-		goto fail;
-	}
+	queue_push_tail(app->mdeps, mdep);
 
 	if (app->num_of_mdep != queue_length(app->mdeps))
 		goto send_rsp;
@@ -1258,28 +1241,15 @@
 {
 	struct health_device *dev;
 
-	if (!app)
-		return NULL;
-
 	/* create device and push it to devices queue */
 	dev = new0(struct health_device, 1);
-	if (!dev)
-		return NULL;
 
 	android2bdaddr(addr, &dev->dst);
 	dev->channels = queue_new();
-	if (!dev->channels) {
-		free_health_device(dev);
-		return NULL;
-	}
-
-	if (!queue_push_tail(app->devices, dev)) {
-		free_health_device(dev);
-		return NULL;
-	}
-
 	dev->app_id = app->id;
 
+	queue_push_tail(app->devices, dev);
+
 	return dev;
 }
 
@@ -1314,34 +1284,24 @@
 	if (!mdep) {
 		if (mdep_index == MDEP_ECHO) {
 			mdep = new0(struct mdep_cfg, 1);
-			if (!mdep)
-				return NULL;
 
 			/* Leave other configuration zeroes */
 			mdep->id = MDEP_ECHO;
 
-			if (!queue_push_tail(app->mdeps, mdep)) {
-				free_mdep_cfg(mdep);
-				return NULL;
-			}
-		} else
+			queue_push_tail(app->mdeps, mdep);
+		} else {
 			return NULL;
+		}
 	}
 
 	/* create channel and push it to device */
 	channel = new0(struct health_channel, 1);
-	if (!channel)
-		return NULL;
-
 	channel->mdep_id = mdep->id;
 	channel->type = mdep->channel_type;
 	channel->id = channel_id++;
 	channel->dev = dev;
 
-	if (!queue_push_tail(dev->channels, channel)) {
-		free_health_channel(channel);
-		return NULL;
-	}
+	queue_push_tail(dev->channels, channel);
 
 	return channel;
 }
@@ -1351,7 +1311,6 @@
 							uint8_t mdepid)
 {
 	struct health_device *device;
-	struct health_channel *channel = NULL;
 	bdaddr_t addr;
 
 	DBG("app %p mdepid %u", app, mdepid);
@@ -1364,12 +1323,8 @@
 	}
 
 	device = get_device(app, (uint8_t *) &addr);
-	if (!device)
-		return NULL;
 
-	channel = create_channel(app, mdepid, device);
-
-	return channel;
+	return create_channel(app, mdepid, device);
 }
 
 static uint8_t conf_to_l2cap(uint8_t conf)
@@ -1899,8 +1854,6 @@
 		goto send_rsp;
 
 	dev = get_device(app, cmd->bdaddr);
-	if (!dev)
-		goto send_rsp;
 
 	channel = get_channel(app, cmd->mdep_index, dev);
 	if (!channel)
@@ -2076,8 +2029,6 @@
 
 	hal_ipc = ipc;
 	apps = queue_new();
-	if (!apps)
-		return false;
 
 	ipc_register(hal_ipc, HAL_SERVICE_ID_HEALTH, cmd_handlers,
 						G_N_ELEMENTS(cmd_handlers));
diff --git a/android/hidhost.c b/android/hidhost.c
index a2b820f..591ca95 100644
--- a/android/hidhost.c
+++ b/android/hidhost.c
@@ -44,13 +44,13 @@
 #include "src/sdp-client.h"
 #include "src/uuid-helper.h"
 #include "src/log.h"
+#include "profiles/input/hog-lib.h"
 
 #include "hal-msg.h"
 #include "ipc-common.h"
 #include "ipc.h"
 #include "bluetooth.h"
 #include "gatt.h"
-#include "hog.h"
 #include "hidhost.h"
 #include "utils.h"
 
diff --git a/android/log.c b/android/log.c
index 8013eba..35917c6 100644
--- a/android/log.c
+++ b/android/log.c
@@ -139,7 +139,7 @@
 	va_end(ap);
 }
 
-void btd_debug(const char *format, ...)
+void btd_debug(uint16_t index, const char *format, ...)
 {
 	va_list ap;
 
diff --git a/android/tester-a2dp.c b/android/tester-a2dp.c
index f7d82c9..8397eef 100644
--- a/android/tester-a2dp.c
+++ b/android/tester-a2dp.c
@@ -236,14 +236,9 @@
 	uint16_t i = 0;
 
 	list = queue_new();
-	if (!list)
-		return NULL;
 
 	for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
-		if (!queue_push_tail(list, &test_cases[i])) {
-			queue_destroy(list, NULL);
-			return NULL;
-		}
+		queue_push_tail(list, &test_cases[i]);
 
 	return list;
 }
diff --git a/android/tester-avrcp.c b/android/tester-avrcp.c
index cec9787..737602e 100644
--- a/android/tester-avrcp.c
+++ b/android/tester-avrcp.c
@@ -584,14 +584,9 @@
 	uint16_t i = 0;
 
 	list = queue_new();
-	if (!list)
-		return NULL;
 
 	for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
-		if (!queue_push_tail(list, &test_cases[i])) {
-			queue_destroy(list, NULL);
-			return NULL;
-		}
+		queue_push_tail(list, &test_cases[i]);
 
 	return list;
 }
diff --git a/android/tester-bluetooth.c b/android/tester-bluetooth.c
index dca8de9..22077a0 100644
--- a/android/tester-bluetooth.c
+++ b/android/tester-bluetooth.c
@@ -1224,14 +1224,9 @@
 	uint16_t i = 0;
 
 	list = queue_new();
-	if (!list)
-		return NULL;
 
 	for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
-		if (!queue_push_tail(list, &test_cases[i])) {
-			queue_destroy(list, NULL);
-			return NULL;
-		}
+		queue_push_tail(list, &test_cases[i]);
 
 	return list;
 }
diff --git a/android/tester-gatt.c b/android/tester-gatt.c
index b8b088b..88be3d8 100644
--- a/android/tester-gatt.c
+++ b/android/tester-gatt.c
@@ -3665,14 +3665,9 @@
 	uint16_t i = 0;
 
 	list = queue_new();
-	if (!list)
-		return NULL;
 
 	for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
-		if (!queue_push_tail(list, &test_cases[i])) {
-			queue_destroy(list, NULL);
-			return NULL;
-		}
+		queue_push_tail(list, &test_cases[i]);
 
 	return list;
 }
diff --git a/android/tester-hdp.c b/android/tester-hdp.c
index 80f3b5f..e849820 100644
--- a/android/tester-hdp.c
+++ b/android/tester-hdp.c
@@ -549,14 +549,9 @@
 	uint16_t i = 0;
 
 	list = queue_new();
-	if (!list)
-		return NULL;
 
 	for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
-		if (!queue_push_tail(list, &test_cases[i])) {
-			queue_destroy(list, NULL);
-			return NULL;
-		}
+		queue_push_tail(list, &test_cases[i]);
 
 	return list;
 }
diff --git a/android/tester-hidhost.c b/android/tester-hidhost.c
index ab5f12b..221b122 100644
--- a/android/tester-hidhost.c
+++ b/android/tester-hidhost.c
@@ -719,14 +719,9 @@
 	uint16_t i = 0;
 
 	list = queue_new();
-	if (!list)
-		return NULL;
 
 	for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
-		if (!queue_push_tail(list, &test_cases[i])) {
-			queue_destroy(list, NULL);
-			return NULL;
-		}
+		queue_push_tail(list, &test_cases[i]);
 
 	return list;
 }
diff --git a/android/tester-map-client.c b/android/tester-map-client.c
index 1f552a3..695c797 100644
--- a/android/tester-map-client.c
+++ b/android/tester-map-client.c
@@ -140,14 +140,9 @@
 	uint16_t i = 0;
 
 	list = queue_new();
-	if (!list)
-		return NULL;
 
 	for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
-		if (!queue_push_tail(list, &test_cases[i])) {
-			queue_destroy(list, NULL);
-			return NULL;
-		}
+		queue_push_tail(list, &test_cases[i]);
 
 	return list;
 }
diff --git a/android/tester-pan.c b/android/tester-pan.c
index e033e21..9da2488 100644
--- a/android/tester-pan.c
+++ b/android/tester-pan.c
@@ -226,14 +226,9 @@
 	uint16_t i = 0;
 
 	list = queue_new();
-	if (!list)
-		return NULL;
 
 	for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
-		if (!queue_push_tail(list, &test_cases[i])) {
-			queue_destroy(list, NULL);
-			return NULL;
-		}
+		queue_push_tail(list, &test_cases[i]);
 
 	return list;
 }
diff --git a/android/tester-socket.c b/android/tester-socket.c
index 41e1434..2264a1f 100644
--- a/android/tester-socket.c
+++ b/android/tester-socket.c
@@ -447,14 +447,9 @@
 	uint16_t i = 0;
 
 	list = queue_new();
-	if (!list)
-		return NULL;
 
 	for (; i < sizeof(test_cases) / sizeof(test_cases[0]); ++i)
-		if (!queue_push_tail(list, &test_cases[i])) {
-			queue_destroy(list, NULL);
-			return NULL;
-		}
+		queue_push_tail(list, &test_cases[i]);
 
 	return list;
 }
diff --git a/bootstrap-configure b/bootstrap-configure
index 29cd7bf..87766b1 100755
--- a/bootstrap-configure
+++ b/bootstrap-configure
@@ -12,6 +12,7 @@
 		--sysconfdir=/etc \
 		--localstatedir=/var \
 		--enable-manpages \
+		--enable-backtrace \
 		--enable-experimental \
 		--enable-android \
 		--enable-sixaxis \
diff --git a/client/gatt.c b/client/gatt.c
index 0a3adb8..7dd3c94 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -75,12 +75,13 @@
 	if (!text)
 		text = uuid;
 
-	rl_printf("%s%s%sService %s %s %s\n",
+	rl_printf("%s%s%s%s Service\n\t%s\n\t%s\n",
 				description ? "[" : "",
 				description ? : "",
 				description ? "] " : "",
+				primary ? "Primary" : "Secondary",
 				g_dbus_proxy_get_path(proxy),
-				text, primary ? "(Primary)" : "(Secondary)");
+				text);
 }
 
 void gatt_add_service(GDBusProxy *proxy)
@@ -92,7 +93,13 @@
 
 void gatt_remove_service(GDBusProxy *proxy)
 {
-	services = g_list_remove(services, proxy);
+	GList *l;
+
+	l = g_list_find(services, proxy);
+	if (!l)
+		return;
+
+	services = g_list_delete_link(services, l);
 
 	print_service(proxy, COLORED_DEL);
 }
@@ -111,7 +118,7 @@
 	if (!text)
 		text = uuid;
 
-	rl_printf("%s%s%sCharacteristic %s %s\n",
+	rl_printf("%s%s%sCharacteristic\n\t%s\n\t%s\n",
 				description ? "[" : "",
 				description ? : "",
 				description ? "] " : "",
@@ -154,10 +161,13 @@
 
 void gatt_remove_characteristic(GDBusProxy *proxy)
 {
-	if (!characteristic_is_child(proxy))
+	GList *l;
+
+	l = g_list_find(characteristics, proxy);
+	if (!l)
 		return;
 
-	characteristics = g_list_remove(characteristics, proxy);
+	characteristics = g_list_delete_link(characteristics, l);
 
 	print_characteristic(proxy, COLORED_DEL);
 }
@@ -176,7 +186,7 @@
 	if (!text)
 		text = uuid;
 
-	rl_printf("%s%s%sDescriptor %s %s\n",
+	rl_printf("%s%s%sDescriptor\n\t%s\n\t%s\n",
 				description ? "[" : "",
 				description ? : "",
 				description ? "] " : "",
@@ -219,10 +229,13 @@
 
 void gatt_remove_descriptor(GDBusProxy *proxy)
 {
-	if (!descriptor_is_child(proxy))
+	GList *l;
+
+	l = g_list_find(descriptors, proxy);
+	if (!l)
 		return;
 
-	descriptors = g_list_remove(descriptors, proxy);
+	descriptors = g_list_delete_link(descriptors, l);
 
 	print_descriptor(proxy, COLORED_DEL);
 }
diff --git a/client/main.c b/client/main.c
index 6863593..b695744 100644
--- a/client/main.c
+++ b/client/main.c
@@ -387,6 +387,8 @@
 
 done:
 	rl_set_prompt(desc ? desc : PROMPT_ON);
+	printf("\r");
+	rl_on_new_line();
 	rl_redisplay();
 	g_free(desc);
 }
@@ -436,12 +438,10 @@
 				agent_unregister(dbus_conn, NULL);
 		}
 	} else if (!strcmp(interface, "org.bluez.GattService1")) {
-		if (service_is_child(proxy)) {
-			gatt_remove_service(proxy);
+		gatt_remove_service(proxy);
 
-			if (default_attr == proxy)
-				set_default_attribute(NULL);
-		}
+		if (default_attr == proxy)
+			set_default_attribute(NULL);
 	} else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
 		gatt_remove_characteristic(proxy);
 
diff --git a/configure.ac b/configure.ac
index 2d3e5d7..7ec7c32 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
 AC_PREREQ(2.60)
-AC_INIT(bluez, 5.36)
+AC_INIT(bluez, 5.37)
 
 AM_INIT_AUTOMAKE([foreign subdir-objects color-tests silent-rules
 					tar-pax no-dist-gzip dist-xz])
@@ -118,6 +118,20 @@
 fi
 AC_SUBST(DBUS_SESSIONBUSDIR, [${path_dbussessionbusdir}])
 
+AC_ARG_ENABLE(backtrace, AC_HELP_STRING([--enable-backtrace],
+		[compile backtrace support]), [enable_backtrace=${enableval}])
+
+if (test "${enable_backtrace}" = "yes"); then
+	AC_CHECK_HEADER(elfutils/libdwfl.h, dummy=yes,
+			AC_MSG_ERROR(elfutils support is required))
+	AC_DEFINE(HAVE_BACKTRACE_SUPPORT, 1,
+			[Define to 1 if you have the backtrace support.])
+	BACKTRACE_CFLAGS=""
+	BACKTRACE_LIBS="-ldw"
+	AC_SUBST(BACKTRACE_CFLAGS)
+	AC_SUBST(BACKTRACE_LIBS)
+fi
+
 AC_ARG_ENABLE(library, AC_HELP_STRING([--enable-library],
 		[install Bluetooth library]), [enable_library=${enableval}])
 AM_CONDITIONAL(LIBRARY, test "${enable_library}" = "yes")
diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt
index cf7169f..284214e 100644
--- a/doc/adapter-api.txt
+++ b/doc/adapter-api.txt
@@ -167,7 +167,7 @@
 			value will fail.
 
 			When changing the Powered property the new state of
-			this property will be updated via a PropertyChanged
+			this property will be updated via a PropertiesChanged
 			signal.
 
 			For any new adapter this settings defaults to false.
diff --git a/doc/agent-api.txt b/doc/agent-api.txt
index 2e70931..801ccb6 100644
--- a/doc/agent-api.txt
+++ b/doc/agent-api.txt
@@ -37,7 +37,7 @@
 			agent.
 
 			If an empty string is used it will fallback to
-			"DisplayYesNo".
+			"KeyboardDisplay".
 
 			Possible errors: org.bluez.Error.InvalidArguments
 					 org.bluez.Error.AlreadyExists
diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
index c89ab42..d5b6c90 100644
--- a/doc/mgmt-api.txt
+++ b/doc/mgmt-api.txt
@@ -25,6 +25,7 @@
 Linux kernel v3.19	Version 1.8
 Linux kernel v4.1	Version 1.9
 Linux kernel v4.2	Version 1.10
+Linux kernel v4.5	Version 1.11 (not yet released)
 
 Version 1.1 introduces Set Device ID command.
 
@@ -68,6 +69,8 @@
 Version 1.10 does not introduce any new command or event. It extends the
 advertising feature to support 5 parallel advertising instances.
 
+Version 1.11 introduces Get Advertising Size Information command.
+
 
 Example
 =======
@@ -2712,10 +2715,50 @@
 				Invalid Index
 
 
+Get Advertising Size Information Command
+========================================
+
+	Command Code:		0x0040
+	Controller Index:	<controller id>
+	Command Parameters:	Instance (1 Octet)
+				Flags (4 Octets)
+	Return Parameters:	Instance (1 Octet)
+				Flags (4 Octets)
+				Max_Adv_Data_Len (1 Octet)
+				Max_Scan_Rsp_Len (1 Octet)
+
+	The Read Advertising Features command returns the overall maximum
+	size of advertising data and scan respone data fields. That size is
+	valid when no Flags are used. However when certain Flags are used,
+	then the size might decrease. This command can be used to request
+	detailed information about the maximum available size.
+
+	The following Flags values are defined:
+
+		0	Switch into Connectable mode
+		1	Advertise as Discoverable
+		2	Advertise as Limited Discoverable
+		3	Add Flags field to Adv_Data
+		4	Add TX Power field to Adv_Data
+		5	Add Appearance field to Scan_Rsp
+		6	Add Local Name in Scan_Rsp
+
+	To get accurate information about the available size, the same Flags
+	values should be used with the Add Advertising command.
+
+	The Max_Adv_Data_Len and Max_Scan_Rsp_Len fields provide information
+	about the maximum length of the data fields for the given Flags
+	values. When the Flags field is zero, then these fields would contain
+	the same values as Read Advertising Features.
+
+	Possible errors:	Invalid Parameters
+				Invalid Index
+
+
 Start Limited Discovery Command
 ===============================
 
-	Command Code:		0x0040
+	Command Code:		0x0041
 	Controller Index:	<controller id>
 	Command Parameters:	Address_Type (1 Octet)
 	Return Parameters:	Address_Type (1 Octet)
diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index 819ac50..5612ff0 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -39,8 +39,8 @@
 
 Application		Count	Description
 -------------------------------------------
-mgmt-tester		 302	Kernel management interface testing
-l2cap-tester		  27	Kernel L2CAP implementation testing
+mgmt-tester		 305	Kernel management interface testing
+l2cap-tester		  33	Kernel L2CAP implementation testing
 rfcomm-tester		   9	Kernel RFCOMM implementation testing
 bnep-tester		   1	Kernel BNEP implementation testing
 smp-tester		   8	Kernel SMP implementation testing
@@ -49,7 +49,7 @@
 hci-tester		  14	Controller hardware testing
 userchan-tester		   3	Kernel HCI User Channel testting
 			-----
-			 373
+			 382
 
 
 Android end-to-end testing
diff --git a/emulator/btdev.c b/emulator/btdev.c
index e8cead8..38769d8 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -675,6 +675,16 @@
 	return btdev->features;
 }
 
+uint8_t btdev_get_scan_enable(struct btdev *btdev)
+{
+	return btdev->scan_enable;
+}
+
+uint8_t btdev_get_le_scan_enable(struct btdev *btdev)
+{
+	return btdev->le_scan_enable;
+}
+
 static bool use_ssp(struct btdev *btdev1, struct btdev *btdev2)
 {
 	if (btdev1->auth_enable || btdev2->auth_enable)
diff --git a/emulator/btdev.h b/emulator/btdev.h
index 4b724a7..40c7219 100644
--- a/emulator/btdev.h
+++ b/emulator/btdev.h
@@ -80,6 +80,10 @@
 const uint8_t *btdev_get_bdaddr(struct btdev *btdev);
 uint8_t *btdev_get_features(struct btdev *btdev);
 
+uint8_t btdev_get_scan_enable(struct btdev *btdev);
+
+uint8_t btdev_get_le_scan_enable(struct btdev *btdev);
+
 void btdev_set_command_handler(struct btdev *btdev, btdev_command_func handler,
 							void *user_data);
 
diff --git a/emulator/bthost.c b/emulator/bthost.c
index 29bbe5d..3638fe4 100644
--- a/emulator/bthost.c
+++ b/emulator/bthost.c
@@ -2258,6 +2258,12 @@
 		if (addr_type == BDADDR_LE_RANDOM)
 			cc.peer_addr_type = 0x01;
 
+		cc.scan_interval = cpu_to_le16(0x0060);
+		cc.scan_window = cpu_to_le16(0x0030);
+		cc.min_interval = cpu_to_le16(0x0028);
+		cc.max_interval = cpu_to_le16(0x0038);
+		cc.supv_timeout = cpu_to_le16(0x002a);
+
 		send_command(bthost, BT_HCI_CMD_LE_CREATE_CONN,
 							&cc, sizeof(cc));
 	}
diff --git a/emulator/hciemu.c b/emulator/hciemu.c
index 4881a24..6a53499 100644
--- a/emulator/hciemu.c
+++ b/emulator/hciemu.c
@@ -427,6 +427,22 @@
 	return btdev_get_bdaddr(hciemu->client_dev);
 }
 
+uint8_t hciemu_get_master_scan_enable(struct hciemu *hciemu)
+{
+	if (!hciemu || !hciemu->master_dev)
+		return 0;
+
+	return btdev_get_scan_enable(hciemu->master_dev);
+}
+
+uint8_t hciemu_get_master_le_scan_enable(struct hciemu *hciemu)
+{
+	if (!hciemu || !hciemu->master_dev)
+		return 0;
+
+	return btdev_get_le_scan_enable(hciemu->master_dev);
+}
+
 bool hciemu_add_master_post_command_hook(struct hciemu *hciemu,
 			hciemu_command_func_t function, void *user_data)
 {
diff --git a/emulator/hciemu.h b/emulator/hciemu.h
index 41ca3fc..c5578d1 100644
--- a/emulator/hciemu.h
+++ b/emulator/hciemu.h
@@ -53,6 +53,10 @@
 const uint8_t *hciemu_get_master_bdaddr(struct hciemu *hciemu);
 const uint8_t *hciemu_get_client_bdaddr(struct hciemu *hciemu);
 
+uint8_t hciemu_get_master_scan_enable(struct hciemu *hciemu);
+
+uint8_t hciemu_get_master_le_scan_enable(struct hciemu *hciemu);
+
 typedef void (*hciemu_command_func_t)(uint16_t opcode, const void *data,
 						uint8_t len, void *user_data);
 
diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
index 9ece4b0..69fbc10 100644
--- a/gdbus/gdbus.h
+++ b/gdbus/gdbus.h
@@ -31,12 +31,6 @@
 #include <dbus/dbus.h>
 #include <glib.h>
 
-typedef enum GDBusMethodFlags GDBusMethodFlags;
-typedef enum GDBusSignalFlags GDBusSignalFlags;
-typedef enum GDBusPropertyFlags GDBusPropertyFlags;
-typedef enum GDBusSecurityFlags GDBusSecurityFlags;
-typedef enum GDbusPropertyChangedFlags GDbusPropertyChangedFlags;
-
 typedef struct GDBusArgInfo GDBusArgInfo;
 typedef struct GDBusMethodTable GDBusMethodTable;
 typedef struct GDBusSignalTable GDBusSignalTable;
@@ -120,6 +114,12 @@
 	G_DBUS_PROPERTY_CHANGED_FLAG_FLUSH = (1 << 0),
 };
 
+typedef enum GDBusMethodFlags GDBusMethodFlags;
+typedef enum GDBusSignalFlags GDBusSignalFlags;
+typedef enum GDBusPropertyFlags GDBusPropertyFlags;
+typedef enum GDBusSecurityFlags GDBusSecurityFlags;
+typedef enum GDbusPropertyChangedFlags GDbusPropertyChangedFlags;
+
 struct GDBusArgInfo {
 	const char *name;
 	const char *signature;
diff --git a/gdbus/object.c b/gdbus/object.c
index 4cf2e2f..a220101 100644
--- a/gdbus/object.c
+++ b/gdbus/object.c
@@ -258,7 +258,8 @@
 
 	reply = method->function(connection, message, iface_user_data);
 
-	if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY) {
+	if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY ||
+					dbus_message_get_no_reply(message)) {
 		if (reply != NULL)
 			dbus_message_unref(reply);
 		return DBUS_HANDLER_RESULT_HANDLED;
diff --git a/gdbus/watch.c b/gdbus/watch.c
index b60f650..447e486 100644
--- a/gdbus/watch.c
+++ b/gdbus/watch.c
@@ -204,6 +204,30 @@
 	return TRUE;
 }
 
+static void filter_data_free(struct filter_data *data)
+{
+	GSList *l;
+
+	/* Remove filter if there are no listeners left for the connection */
+	if (filter_data_find(data->connection) == NULL)
+		dbus_connection_remove_filter(data->connection, message_filter,
+									NULL);
+
+	for (l = data->callbacks; l != NULL; l = l->next)
+		g_free(l->data);
+
+	g_slist_free(data->callbacks);
+	g_dbus_remove_watch(data->connection, data->name_watch);
+	g_free(data->name);
+	g_free(data->owner);
+	g_free(data->path);
+	g_free(data->interface);
+	g_free(data->member);
+	g_free(data->argument);
+	dbus_connection_unref(data->connection);
+	g_free(data);
+}
+
 static struct filter_data *filter_data_get(DBusConnection *connection,
 					DBusHandleMessageFunction filter,
 					const char *sender,
@@ -248,7 +272,7 @@
 	data->argument = g_strdup(argument);
 
 	if (!add_match(data, filter)) {
-		g_free(data);
+		filter_data_free(data);
 		return NULL;
 	}
 
@@ -277,30 +301,6 @@
 	return NULL;
 }
 
-static void filter_data_free(struct filter_data *data)
-{
-	GSList *l;
-
-	/* Remove filter if there are no listeners left for the connection */
-	if (filter_data_find(data->connection) == NULL)
-		dbus_connection_remove_filter(data->connection, message_filter,
-									NULL);
-
-	for (l = data->callbacks; l != NULL; l = l->next)
-		g_free(l->data);
-
-	g_slist_free(data->callbacks);
-	g_dbus_remove_watch(data->connection, data->name_watch);
-	g_free(data->name);
-	g_free(data->owner);
-	g_free(data->path);
-	g_free(data->interface);
-	g_free(data->member);
-	g_free(data->argument);
-	dbus_connection_unref(data->connection);
-	g_free(data);
-}
-
 static void filter_data_call_and_free(struct filter_data *data)
 {
 	GSList *l;
diff --git a/lib/bluetooth.c b/lib/bluetooth.c
index d48d844..4a569c0 100644
--- a/lib/bluetooth.c
+++ b/lib/bluetooth.c
@@ -1360,7 +1360,7 @@
 	case 548:
 		return "Comarch SA";
 	case 549:
-		return "Nestl Nespresso S.A.";
+		return "Nestlé Nespresso S.A.";
 	case 550:
 		return "Merlinia A/S";
 	case 551:
@@ -1444,7 +1444,7 @@
 	case 590:
 		return "Microtronics Engineering GmbH";
 	case 591:
-		return "Schneider Schreibgerte GmbH";
+		return "Schneider Schreibgeräte GmbH";
 	case 592:
 		return "Sapphire Circuits LLC";
 	case 593:
@@ -1522,7 +1522,7 @@
 	case 629:
 		return "Geotab";
 	case 630:
-		return "E.G.O. Elektro-Gertebau GmbH";
+		return "E.G.O. Elektro-Gerätebau GmbH";
 	case 631:
 		return "bewhere inc";
 	case 632:
@@ -1635,6 +1635,116 @@
 		return "Rx Networks, Inc.";
 	case 686:
 		return "WeatherFlow, Inc.";
+	case 687:
+		return "Technicolor USA Inc.";
+	case 688:
+		return "Bestechnic(Shanghai),Ltd";
+	case 689:
+		return "Raden Inc";
+	case 690:
+		return "JouZen Oy";
+	case 691:
+		return "CLABER S.P.A.";
+	case 692:
+		return "Hyginex, Inc.";
+	case 693:
+		return "HANSHIN ELECTRIC RAILWAY CO.,LTD.";
+	case 694:
+		return "Schneider Electric";
+	case 695:
+		return "Oort Technologies LLC";
+	case 696:
+		return "Chrono Therapeutics";
+	case 697:
+		return "Rinnai Corporation";
+	case 698:
+		return "Swissprime Technologies AG";
+	case 699:
+		return "Koha.,Co.Ltd";
+	case 700:
+		return "Genevac Ltd";
+	case 701:
+		return "Chemtronics";
+	case 702:
+		return "Seguro Technology Sp. z o.o.";
+	case 703:
+		return "Redbird Flight Simulations";
+	case 704:
+		return "Dash Robotics";
+	case 705:
+		return "LINE Corporation";
+	case 706:
+		return "Guillemot Corporation";
+	case 707:
+		return "Techtronic Power Tools Technology Limited";
+	case 708:
+		return "Wilson Sporting Goods";
+	case 709:
+		return "Lenovo (Singapore) Pte Ltd. ( 联想(新加坡) )";
+	case 710:
+		return "Ayatan Sensors";
+	case 711:
+		return "Electronics Tomorrow Limited";
+	case 712:
+		return "VASCO Data Security International, Inc.";
+	case 713:
+		return "PayRange Inc.";
+	case 714:
+		return "ABOV Semiconductor";
+	case 715:
+		return "AINA-Wireless Inc.";
+	case 716:
+		return "Eijkelkamp Soil & Water";
+	case 717:
+		return "BMA ergonomics b.v.";
+	case 718:
+		return "Teva Branded Pharmaceutical Products R&D, Inc.";
+	case 719:
+		return "Anima";
+	case 720:
+		return "3M";
+	case 721:
+		return "Empatica Srl";
+	case 722:
+		return "Afero, Inc.";
+	case 723:
+		return "Powercast Corporation";
+	case 724:
+		return "Secuyou ApS";
+	case 725:
+		return "OMRON Corporation";
+	case 726:
+		return "Send Solutions";
+	case 727:
+		return "NIPPON SYSTEMWARE CO.,LTD.";
+	case 728:
+		return "Neosfar";
+	case 729:
+		return "Fliegl Agrartechnik GmbH";
+	case 730:
+		return "Gilvader";
+	case 731:
+		return "Digi International Inc (R)";
+	case 732:
+		return "DeWalch Technologies, Inc.";
+	case 733:
+		return "Flint Rehabilitation Devices, LLC";
+	case 734:
+		return "Samsung SDS Co., Ltd.";
+	case 735:
+		return "Blur Product Development";
+	case 736:
+		return "University of Michigan";
+	case 737:
+		return "Victron Energy BV";
+	case 738:
+		return "NTT docomo";
+	case 739:
+		return "Carmanah Technologies Corp.";
+	case 740:
+		return "Bytestorm Ltd.";
+	case 741:
+		return "Espressif Incorporated ( 乐鑫信息科技(上海)有限公司 )";
 	case 65535:
 		return "internal use";
 	default:
diff --git a/lib/hci.h b/lib/hci.h
index 9891dc5..cbc55af 100644
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -2361,6 +2361,7 @@
 #define HCI_CHANNEL_USER	1
 #define HCI_CHANNEL_MONITOR	2
 #define HCI_CHANNEL_CONTROL	3
+#define HCI_CHANNEL_LOGGING	4
 
 struct hci_filter {
 	uint32_t type_mask;
diff --git a/lib/mgmt.h b/lib/mgmt.h
index eb13c42..d76bdbb 100644
--- a/lib/mgmt.h
+++ b/lib/mgmt.h
@@ -515,6 +515,19 @@
 	uint8_t instance;
 } __packed;
 
+#define MGMT_OP_GET_ADV_SIZE_INFO	0x0040
+struct mgmt_cp_get_adv_size_info {
+	uint8_t  instance;
+	uint32_t flags;
+} __packed;
+#define MGMT_GET_ADV_SIZE_INFO_SIZE	5
+struct mgmt_rp_get_adv_size_info {
+	uint8_t  instance;
+	uint32_t flags;
+	uint8_t  max_adv_data_len;
+	uint8_t  max_scan_rsp_len;
+} __packed;
+
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
 	uint16_t opcode;
@@ -792,6 +805,8 @@
 	"Read Advertising Features",
 	"Add Advertising",
 	"Remove Advertising",
+	"Get Advertising Size Information",		/* 0x0040 */
+	"Start Limited Discovery",
 };
 
 static const char *mgmt_ev[] = {
@@ -803,7 +818,7 @@
 	"Index Removed",
 	"New Settings",
 	"Class of Device Changed",
-	"Local Name Changed",		/* 0x0008 */
+	"Local Name Changed",				/* 0x0008 */
 	"New Link Key",
 	"New Long Term Key",
 	"Device Connected",
@@ -811,7 +826,7 @@
 	"Connect Failed",
 	"PIN Code Request",
 	"User Confirm Request",
-	"User Passkey Request",		/* 0x0010 */
+	"User Passkey Request",				/* 0x0010 */
 	"Authentication Failed",
 	"Device Found",
 	"Discovering",
@@ -819,7 +834,7 @@
 	"Device Unblocked",
 	"Device Unpaired",
 	"Passkey Notify",
-	"New Identity Resolving Key",
+	"New Identity Resolving Key",			/* 0x0018 */
 	"New Signature Resolving Key",
 	"Device Added",
 	"Device Removed",
@@ -827,7 +842,7 @@
 	"Unconfigured Index Added",
 	"Unconfigured Index Removed",
 	"New Configuration Options",
-	"Extended Index Added",
+	"Extended Index Added",				/* 0x0020 */
 	"Extended Index Removed",
 	"Local Out Of Band Extended Data Updated",
 	"Advertising Added",
diff --git a/lib/sdp.c b/lib/sdp.c
index 155eca5..eb408a9 100644
--- a/lib/sdp.c
+++ b/lib/sdp.c
@@ -932,8 +932,12 @@
 
 void sdp_attr_replace(sdp_record_t *rec, uint16_t attr, sdp_data_t *d)
 {
-	sdp_data_t *p = sdp_data_get(rec, attr);
+	sdp_data_t *p;
 
+	if (!rec)
+		return;
+
+	p = sdp_data_get(rec, attr);
 	if (p) {
 		rec->attrlist = sdp_list_remove(rec->attrlist, p);
 		sdp_data_free(p);
@@ -1667,7 +1671,7 @@
 
 sdp_data_t *sdp_data_get(const sdp_record_t *rec, uint16_t attrId)
 {
-	if (rec->attrlist) {
+	if (rec && rec->attrlist) {
 		sdp_data_t sdpTemplate;
 		sdp_list_t *p;
 
diff --git a/lib/uuid.c b/lib/uuid.c
index 046b521..20b67d0 100644
--- a/lib/uuid.c
+++ b/lib/uuid.c
@@ -138,46 +138,35 @@
  */
 int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n)
 {
-	if (!uuid) {
+	bt_uuid_t tmp;
+	unsigned int   data0;
+	unsigned short data1;
+	unsigned short data2;
+	unsigned short data3;
+	unsigned int   data4;
+	unsigned short data5;
+	const uint8_t *data;
+
+	if (!uuid || uuid->type == BT_UUID_UNSPEC) {
 		snprintf(str, n, "NULL");
 		return -EINVAL;
 	}
 
-	switch (uuid->type) {
-	case BT_UUID16:
-		snprintf(str, n, "%.4x", uuid->value.u16);
-		break;
-	case BT_UUID32:
-		snprintf(str, n, "%.8x", uuid->value.u32);
-		break;
-	case BT_UUID128: {
-		unsigned int   data0;
-		unsigned short data1;
-		unsigned short data2;
-		unsigned short data3;
-		unsigned int   data4;
-		unsigned short data5;
+	/* Convert to 128 Bit format */
+	bt_uuid_to_uuid128(uuid, &tmp);
+	data = (uint8_t *) &tmp.value.u128;
 
-		const uint8_t *data = (uint8_t *) &uuid->value.u128;
+	memcpy(&data0, &data[0], 4);
+	memcpy(&data1, &data[4], 2);
+	memcpy(&data2, &data[6], 2);
+	memcpy(&data3, &data[8], 2);
+	memcpy(&data4, &data[10], 4);
+	memcpy(&data5, &data[14], 2);
 
-		memcpy(&data0, &data[0], 4);
-		memcpy(&data1, &data[4], 2);
-		memcpy(&data2, &data[6], 2);
-		memcpy(&data3, &data[8], 2);
-		memcpy(&data4, &data[10], 4);
-		memcpy(&data5, &data[14], 2);
-
-		snprintf(str, n, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
+	snprintf(str, n, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
 				ntohl(data0), ntohs(data1),
 				ntohs(data2), ntohs(data3),
 				ntohl(data4), ntohs(data5));
-		}
-		break;
-	case BT_UUID_UNSPEC:
-	default:
-		snprintf(str, n, "Type of UUID (%x) unknown.", uuid->type);
-		return -EINVAL;	/* Enum type of UUID not set */
-	}
 
 	return 0;
 }
diff --git a/monitor/a2dp.c b/monitor/a2dp.c
new file mode 100644
index 0000000..94f9758
--- /dev/null
+++ b/monitor/a2dp.c
@@ -0,0 +1,638 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; 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 <stdlib.h>
+#include <string.h>
+
+#include "lib/bluetooth.h"
+
+#include "src/shared/util.h"
+#include "bt.h"
+#include "packet.h"
+#include "display.h"
+#include "l2cap.h"
+#include "a2dp.h"
+
+#define BASE_INDENT	4
+
+/* Codec Types */
+#define A2DP_CODEC_SBC		0x00
+#define A2DP_CODEC_MPEG12	0x01
+#define A2DP_CODEC_MPEG24	0x02
+#define A2DP_CODEC_ATRAC	0x04
+#define A2DP_CODEC_VENDOR	0xff
+
+/* Vendor Specific A2DP Codecs */
+#define APTX_VENDOR_ID		0x0000004f
+#define APTX_CODEC_ID		0x0001
+#define LDAC_VENDOR_ID		0x0000012d
+#define LDAC_CODEC_ID		0x00aa
+
+struct bit_desc {
+	uint8_t bit_num;
+	const char *str;
+};
+
+static const struct bit_desc sbc_frequency_table[] = {
+	{  7, "16000" },
+	{  6, "32000" },
+	{  5, "44100" },
+	{  4, "48000" },
+	{ }
+};
+
+static const struct bit_desc sbc_channel_mode_table[] = {
+	{  3, "Mono" },
+	{  2, "Dual Channel" },
+	{  1, "Stereo" },
+	{  0, "Joint Stereo" },
+	{ }
+};
+
+static const struct bit_desc sbc_blocklen_table[] = {
+	{  7, "4" },
+	{  6, "8" },
+	{  5, "12" },
+	{  4, "16" },
+	{ }
+};
+
+static const struct bit_desc sbc_subbands_table[] = {
+	{  3, "4" },
+	{  2, "8" },
+	{ }
+};
+
+static const struct bit_desc sbc_allocation_table[] = {
+	{  1, "SNR" },
+	{  0, "Loudness" },
+	{ }
+};
+
+static const struct bit_desc mpeg12_layer_table[] = {
+	{  7, "Layer I (mp1)" },
+	{  6, "Layer II (mp2)" },
+	{  5, "Layer III (mp3)" },
+	{ }
+};
+
+static const struct bit_desc mpeg12_channel_mode_table[] = {
+	{  3, "Mono" },
+	{  2, "Dual Channel" },
+	{  1, "Stereo" },
+	{  0, "Joint Stereo" },
+	{ }
+};
+
+static const struct bit_desc mpeg12_frequency_table[] = {
+	{  5, "16000" },
+	{  4, "22050" },
+	{  3, "24000" },
+	{  2, "32000" },
+	{  1, "44100" },
+	{  0, "48000" },
+	{ }
+};
+
+static const struct bit_desc mpeg12_bitrate_table[] = {
+	{ 14, "1110" },
+	{ 13, "1101" },
+	{ 12, "1100" },
+	{ 11, "1011" },
+	{ 10, "1010" },
+	{  9, "1001" },
+	{  8, "1000" },
+	{  7, "0111" },
+	{  6, "0110" },
+	{  5, "0101" },
+	{  4, "0100" },
+	{  3, "0011" },
+	{  2, "0010" },
+	{  1, "0001" },
+	{  0, "0000" },
+	{ }
+};
+
+static const struct bit_desc aac_object_type_table[] = {
+	{  7, "MPEG-2 AAC LC" },
+	{  6, "MPEG-4 AAC LC" },
+	{  5, "MPEG-4 AAC LTP" },
+	{  4, "MPEG-4 AAC scalable" },
+	{  3, "RFA (b3)" },
+	{  2, "RFA (b2)" },
+	{  1, "RFA (b1)" },
+	{  0, "RFA (b0)" },
+	{ }
+};
+
+static const struct bit_desc aac_frequency_table[] = {
+	{ 15, "8000" },
+	{ 14, "11025" },
+	{ 13, "12000" },
+	{ 12, "16000" },
+	{ 11, "22050" },
+	{ 10, "24000" },
+	{  9, "32000" },
+	{  8, "44100" },
+	{  7, "48000" },
+	{  6, "64000" },
+	{  5, "88200" },
+	{  4, "96000" },
+	{ }
+};
+
+static const struct bit_desc aac_channels_table[] = {
+	{  3, "1" },
+	{  2, "2" },
+	{ }
+};
+
+static const struct bit_desc aptx_frequency_table[] = {
+	{  7, "16000" },
+	{  6, "32000" },
+	{  5, "44100" },
+	{  4, "48000" },
+	{ }
+};
+
+static const struct bit_desc aptx_channel_mode_table[] = {
+	{  0, "Mono" },
+	{  1, "Stereo" },
+	{ }
+};
+
+static void print_value_bits(uint8_t indent, uint32_t value,
+						const struct bit_desc *table)
+{
+	int i;
+
+	for (i = 0; table[i].str; i++) {
+		if (value & (1 << table[i].bit_num))
+			print_field("%*c%s", indent + 2, ' ', table[i].str);
+	}
+}
+
+static const char *find_value_bit(uint32_t value,
+						const struct bit_desc *table)
+{
+	int i;
+
+	for (i = 0; table[i].str; i++) {
+		if (value & (1 << table[i].bit_num))
+			return table[i].str;
+	}
+
+	return "Unknown";
+}
+
+static const char *vndcodec2str(uint32_t vendor_id, uint16_t codec_id)
+{
+	if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID)
+		return "aptX";
+	else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID)
+		return "LDAC";
+
+	return "Unknown";
+}
+
+static bool codec_sbc_cap(uint8_t losc, struct l2cap_frame *frame)
+{
+	uint8_t cap = 0;
+
+	if (losc != 4)
+		return false;
+
+	l2cap_frame_get_u8(frame, &cap);
+
+	print_field("%*cFrequency: 0x%02x", BASE_INDENT, ' ', cap & 0xf0);
+	print_value_bits(BASE_INDENT, cap & 0xf0, sbc_frequency_table);
+
+	print_field("%*cChannel Mode: 0x%02x", BASE_INDENT, ' ', cap & 0x0f);
+	print_value_bits(BASE_INDENT, cap & 0x0f, sbc_channel_mode_table);
+
+	l2cap_frame_get_u8(frame, &cap);
+
+	print_field("%*cBlock Length: 0x%02x", BASE_INDENT, ' ', cap & 0xf0);
+	print_value_bits(BASE_INDENT, cap & 0xf0, sbc_blocklen_table);
+
+	print_field("%*cSubbands: 0x%02x", BASE_INDENT, ' ', cap & 0x0c);
+	print_value_bits(BASE_INDENT, cap & 0x0c, sbc_subbands_table);
+
+	print_field("%*cAllocation Method: 0x%02x", BASE_INDENT, ' ',
+								cap & 0x03);
+	print_value_bits(BASE_INDENT, cap & 0x03, sbc_allocation_table);
+
+	l2cap_frame_get_u8(frame, &cap);
+
+	print_field("%*cMinimum Bitpool: %d", BASE_INDENT, ' ', cap);
+
+	l2cap_frame_get_u8(frame, &cap);
+
+	print_field("%*cMaximum Bitpool: %d", BASE_INDENT, ' ', cap);
+
+	return true;
+}
+
+static bool codec_sbc_cfg(uint8_t losc, struct l2cap_frame *frame)
+{
+	uint8_t cap = 0;
+
+	if (losc != 4)
+		return false;
+
+	l2cap_frame_get_u8(frame, &cap);
+
+	print_field("%*cFrequency: %s (0x%02x)", BASE_INDENT, ' ',
+			find_value_bit(cap & 0xf0, sbc_frequency_table),
+			cap & 0xf0);
+
+	print_field("%*cChannel Mode: %s (0x%02x)", BASE_INDENT, ' ',
+			find_value_bit(cap & 0x0f, sbc_channel_mode_table),
+			cap & 0x0f);
+
+	l2cap_frame_get_u8(frame, &cap);
+
+	print_field("%*cBlock Length: %s (0x%02x)", BASE_INDENT, ' ',
+			find_value_bit(cap & 0xf0, sbc_blocklen_table),
+			cap & 0xf0);
+
+	print_field("%*cSubbands: %s (0x%02x)", BASE_INDENT, ' ',
+			find_value_bit(cap & 0x0c, sbc_subbands_table),
+			cap & 0x0c);
+
+	print_field("%*cAllocation Method: %s (0x%02x)", BASE_INDENT, ' ',
+			find_value_bit(cap & 0x03, sbc_allocation_table),
+			cap & 0x03);
+
+	l2cap_frame_get_u8(frame, &cap);
+
+	print_field("%*cMinimum Bitpool: %d", BASE_INDENT, ' ', cap);
+
+	l2cap_frame_get_u8(frame, &cap);
+
+	print_field("%*cMaximum Bitpool: %d", BASE_INDENT, ' ', cap);
+
+	return true;
+}
+
+static bool codec_mpeg12_cap(uint8_t losc, struct l2cap_frame *frame)
+{
+	uint16_t cap = 0;
+	uint8_t layer;
+	uint8_t chan;
+	uint8_t freq;
+	uint16_t bitrate;
+	bool crc, mpf, vbr;
+
+	if (losc != 4)
+		return false;
+
+	l2cap_frame_get_be16(frame, &cap);
+
+	layer = (cap >> 8) & 0xe0;
+	crc = cap & 0x1000;
+	chan = (cap >> 8) & 0x0f;
+	mpf = cap & 0x0040;
+	freq = cap & 0x003f;
+
+	l2cap_frame_get_be16(frame, &cap);
+
+	vbr = cap & 0x8000;
+	bitrate = cap & 0x7fff;
+
+	print_field("%*cLayer: 0x%02x", BASE_INDENT, ' ', layer);
+	print_value_bits(BASE_INDENT, layer, mpeg12_layer_table);
+
+	print_field("%*cCRC: %s", BASE_INDENT, ' ', crc ? "Yes" : "No");
+
+	print_field("%*cChannel Mode: 0x%02x", BASE_INDENT, ' ', chan);
+	print_value_bits(BASE_INDENT, chan, mpeg12_channel_mode_table);
+
+	print_field("%*cMedia Payload Format: %s", BASE_INDENT, ' ',
+					mpf ? "RFC-2250 RFC-3119" : "RFC-2250");
+
+	print_field("%*cFrequency: 0x%02x", BASE_INDENT, ' ', freq);
+	print_value_bits(BASE_INDENT, freq, mpeg12_frequency_table);
+
+	if (!vbr) {
+		print_field("%*cBitrate Index: 0x%04x", BASE_INDENT, ' ',
+								bitrate);
+		print_value_bits(BASE_INDENT, freq, mpeg12_bitrate_table);
+	}
+
+	print_field("%*cVBR: %s", BASE_INDENT, ' ', vbr ? "Yes" : "No");
+
+	return true;
+}
+
+static bool codec_mpeg12_cfg(uint8_t losc, struct l2cap_frame *frame)
+{
+	uint16_t cap = 0;
+	uint8_t layer;
+	uint8_t chan;
+	uint8_t freq;
+	uint16_t bitrate;
+	bool crc, mpf, vbr;
+
+	if (losc != 4)
+		return false;
+
+	l2cap_frame_get_be16(frame, &cap);
+
+	layer = (cap >> 8) & 0xe0;
+	crc = cap & 0x1000;
+	chan = (cap >> 8) & 0x0f;
+	mpf = cap & 0x0040;
+	freq = cap & 0x003f;
+
+	l2cap_frame_get_be16(frame, &cap);
+
+	vbr = cap & 0x8000;
+	bitrate = cap & 0x7fff;
+
+	print_field("%*cLayer: %s (0x%02x)", BASE_INDENT, ' ',
+				find_value_bit(layer, mpeg12_layer_table),
+				layer);
+
+	print_field("%*cCRC: %s", BASE_INDENT, ' ', crc ? "Yes" : "No");
+
+	print_field("%*cChannel Mode: %s (0x%02x)", BASE_INDENT, ' ',
+				find_value_bit(chan, mpeg12_channel_mode_table),
+				chan);
+
+	print_field("%*cMedia Payload Format: %s", BASE_INDENT, ' ',
+					mpf ? "RFC-2250 RFC-3119" : "RFC-2250");
+
+	print_field("%*cFrequency: %s (0x%02x)", BASE_INDENT, ' ',
+				find_value_bit(freq, mpeg12_frequency_table),
+				freq);
+
+	if (!vbr)
+		print_field("%*cBitrate Index: %s (0x%04x)", BASE_INDENT, ' ',
+				find_value_bit(freq, mpeg12_bitrate_table),
+				bitrate);
+
+	print_field("%*cVBR: %s", BASE_INDENT, ' ', vbr ? "Yes" : "No");
+
+	return true;
+}
+
+static bool codec_aac_cap(uint8_t losc, struct l2cap_frame *frame)
+{
+	uint16_t cap = 0;
+	uint8_t type;
+	uint16_t freq;
+	uint8_t chan;
+	uint32_t bitrate;
+	bool vbr;
+
+	if (losc != 6)
+		return false;
+
+	l2cap_frame_get_be16(frame, &cap);
+
+	type = cap >> 8;
+	freq = cap << 8;
+
+	l2cap_frame_get_be16(frame, &cap);
+
+	freq |= (cap >> 8) & 0xf0;
+	chan = (cap >> 8) & 0x0c;
+	bitrate = (cap << 16) & 0x7f0000;
+	vbr = cap & 0x0080;
+
+	l2cap_frame_get_be16(frame, &cap);
+
+	bitrate |= cap;
+
+	print_field("%*cObject Type: 0x%02x", BASE_INDENT, ' ', type);
+	print_value_bits(BASE_INDENT, type, aac_object_type_table);
+
+	print_field("%*cFrequency: 0x%02x", BASE_INDENT, ' ', freq);
+	print_value_bits(BASE_INDENT, freq, aac_frequency_table);
+
+	print_field("%*cChannels: 0x%02x", BASE_INDENT, ' ', chan);
+	print_value_bits(BASE_INDENT, chan, aac_channels_table);
+
+	print_field("%*cBitrate: %ubps", BASE_INDENT, ' ', bitrate);
+	print_field("%*cVBR: %s", BASE_INDENT, ' ', vbr ? "Yes" : "No");
+
+	return true;
+}
+
+static bool codec_aac_cfg(uint8_t losc, struct l2cap_frame *frame)
+{
+	uint16_t cap = 0;
+	uint8_t type;
+	uint16_t freq;
+	uint8_t chan;
+	uint32_t bitrate;
+	bool vbr;
+
+	if (losc != 6)
+		return false;
+
+	l2cap_frame_get_be16(frame, &cap);
+
+	type = cap >> 8;
+	freq = cap << 8;
+
+	l2cap_frame_get_be16(frame, &cap);
+
+	freq |= (cap >> 8) & 0xf0;
+	chan = (cap >> 8) & 0x0c;
+	bitrate = (cap << 16) & 0x7f0000;
+	vbr = cap & 0x0080;
+
+	l2cap_frame_get_be16(frame, &cap);
+
+	bitrate |= cap;
+
+	print_field("%*cObject Type: %s (0x%02x)", BASE_INDENT, ' ',
+			find_value_bit(type, aac_object_type_table), type);
+
+	print_field("%*cFrequency: %s (0x%02x)", BASE_INDENT, ' ',
+			find_value_bit(freq, aac_frequency_table), freq);
+
+	print_field("%*cChannels: %s (0x%02x)", BASE_INDENT, ' ',
+			find_value_bit(chan, aac_channels_table), chan);
+
+	print_field("%*cBitrate: %ubps", BASE_INDENT, ' ', bitrate);
+	print_field("%*cVBR: %s", BASE_INDENT, ' ', vbr ? "Yes" : "No");
+
+	return true;
+}
+
+static bool codec_vendor_aptx_cap(uint8_t losc, struct l2cap_frame *frame)
+{
+	uint8_t cap = 0;
+
+	if (losc != 1)
+		return false;
+
+	l2cap_frame_get_u8(frame, &cap);
+
+	print_field("%*cFrequency: 0x%02x", BASE_INDENT + 2, ' ', cap & 0xf0);
+	print_value_bits(BASE_INDENT + 2, cap & 0xf0, aptx_frequency_table);
+
+	print_field("%*cChannel Mode: 0x%02x", BASE_INDENT + 2, ' ',
+								cap & 0x0f);
+	print_value_bits(BASE_INDENT + 2, cap & 0x0f, aptx_channel_mode_table);
+
+	return true;
+}
+
+static bool codec_vendor_ldac(uint8_t losc, struct l2cap_frame *frame)
+{
+	uint16_t cap = 0;
+
+	if (losc != 2)
+		return false;
+
+	l2cap_frame_get_le16(frame, &cap);
+
+	print_field("%*cUnknown: 0x%04x", BASE_INDENT + 2, ' ', cap);
+
+	return true;
+}
+
+static bool codec_vendor_cap(uint8_t losc, struct l2cap_frame *frame)
+{
+	uint32_t vendor_id = 0;
+	uint16_t codec_id = 0;
+
+	if (losc < 6)
+		return false;
+
+	l2cap_frame_get_le32(frame, &vendor_id);
+	l2cap_frame_get_le16(frame, &codec_id);
+
+	losc -= 6;
+
+	print_field("%*cVendor ID: %s (0x%08x)", BASE_INDENT, ' ',
+					bt_compidtostr(vendor_id),  vendor_id);
+
+	print_field("%*cVendor Specific Codec ID: %s (0x%04x)", BASE_INDENT,
+			' ', vndcodec2str(vendor_id, codec_id), codec_id);
+
+	if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID)
+		return codec_vendor_aptx_cap(losc, frame);
+	else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID)
+		return codec_vendor_ldac(losc, frame);
+
+	packet_hexdump(frame->data, losc);
+	l2cap_frame_pull(frame, frame, losc);
+
+	return true;
+}
+
+static bool codec_vendor_aptx_cfg(uint8_t losc, struct l2cap_frame *frame)
+{
+	uint8_t cap = 0;
+
+	if (losc != 1)
+		return false;
+
+	l2cap_frame_get_u8(frame, &cap);
+
+	print_field("%*cFrequency: %s (0x%02x)", BASE_INDENT + 2, ' ',
+			find_value_bit(cap & 0xf0, aptx_frequency_table),
+			cap & 0xf0);
+
+	print_field("%*cChannel Mode: %s (0x%02x)", BASE_INDENT + 2, ' ',
+			find_value_bit(cap & 0x0f, aptx_channel_mode_table),
+			cap & 0x0f);
+
+	return true;
+}
+
+static bool codec_vendor_cfg(uint8_t losc, struct l2cap_frame *frame)
+{
+	uint32_t vendor_id = 0;
+	uint16_t codec_id = 0;
+
+	if (losc < 6)
+		return false;
+
+	l2cap_frame_get_le32(frame, &vendor_id);
+	l2cap_frame_get_le16(frame, &codec_id);
+
+	losc -= 6;
+
+	print_field("%*cVendor ID: %s (0x%08x)", BASE_INDENT, ' ',
+					bt_compidtostr(vendor_id),  vendor_id);
+
+	print_field("%*cVendor Specific Codec ID: %s (0x%04x)", BASE_INDENT,
+			' ', vndcodec2str(vendor_id, codec_id), codec_id);
+
+	if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID)
+		return codec_vendor_aptx_cfg(losc, frame);
+	else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID)
+		return codec_vendor_ldac(losc, frame);
+
+	packet_hexdump(frame->data, losc);
+	l2cap_frame_pull(frame, frame, losc);
+
+	return true;
+}
+
+bool a2dp_codec_cap(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
+{
+	switch (codec) {
+	case A2DP_CODEC_SBC:
+		return codec_sbc_cap(losc, frame);
+	case A2DP_CODEC_MPEG12:
+		return codec_mpeg12_cap(losc, frame);
+	case A2DP_CODEC_MPEG24:
+		return codec_aac_cap(losc, frame);
+	case A2DP_CODEC_VENDOR:
+		return codec_vendor_cap(losc, frame);
+	default:
+		packet_hexdump(frame->data, losc);
+		l2cap_frame_pull(frame, frame, losc);
+		return true;
+	}
+}
+
+bool a2dp_codec_cfg(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
+{
+	switch (codec) {
+	case A2DP_CODEC_SBC:
+		return codec_sbc_cfg(losc, frame);
+	case A2DP_CODEC_MPEG12:
+		return codec_mpeg12_cfg(losc, frame);
+	case A2DP_CODEC_MPEG24:
+		return codec_aac_cfg(losc, frame);
+	case A2DP_CODEC_VENDOR:
+		return codec_vendor_cfg(losc, frame);
+	default:
+		packet_hexdump(frame->data, losc);
+		l2cap_frame_pull(frame, frame, losc);
+		return true;
+	}
+}
diff --git a/monitor/a2dp.h b/monitor/a2dp.h
new file mode 100644
index 0000000..72a8f1f
--- /dev/null
+++ b/monitor/a2dp.h
@@ -0,0 +1,26 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+bool a2dp_codec_cap(uint8_t codec, uint8_t losc, struct l2cap_frame *frame);
+
+bool a2dp_codec_cfg(uint8_t codec, uint8_t losc, struct l2cap_frame *frame);
diff --git a/monitor/analyze.c b/monitor/analyze.c
index 47ae45f..0f2d19a 100644
--- a/monitor/analyze.c
+++ b/monitor/analyze.c
@@ -255,18 +255,18 @@
 {
 	struct btsnoop *btsnoop_file;
 	unsigned long num_packets = 0;
-	uint32_t type;
+	uint32_t format;
 
 	btsnoop_file = btsnoop_open(path, BTSNOOP_FLAG_PKLG_SUPPORT);
 	if (!btsnoop_file)
 		return;
 
-	type = btsnoop_get_type(btsnoop_file);
+	format = btsnoop_get_format(btsnoop_file);
 
-	switch (type) {
-	case BTSNOOP_TYPE_HCI:
-	case BTSNOOP_TYPE_UART:
-	case BTSNOOP_TYPE_MONITOR:
+	switch (format) {
+	case BTSNOOP_FORMAT_HCI:
+	case BTSNOOP_FORMAT_UART:
+	case BTSNOOP_FORMAT_MONITOR:
 		break;
 	default:
 		fprintf(stderr, "Unsupported packet format\n");
diff --git a/monitor/avctp.c b/monitor/avctp.c
index 232365e..a024a0f 100644
--- a/monitor/avctp.c
+++ b/monitor/avctp.c
@@ -64,7 +64,7 @@
 #define AVC_SUBUNIT_PRINTER		0x02
 #define AVC_SUBUNIT_DISC		0x03
 #define AVC_SUBUNIT_TAPE		0x04
-#define AVC_SUBUNIT_TURNER		0x05
+#define AVC_SUBUNIT_TUNER		0x05
 #define AVC_SUBUNIT_CA			0x06
 #define AVC_SUBUNIT_CAMERA		0x07
 #define AVC_SUBUNIT_PANEL		0x09
@@ -259,8 +259,8 @@
 		return "Disc";
 	case AVC_SUBUNIT_TAPE:
 		return "Tape";
-	case AVC_SUBUNIT_TURNER:
-		return "Turner";
+	case AVC_SUBUNIT_TUNER:
+		return "Tuner";
 	case AVC_SUBUNIT_CA:
 		return "CA";
 	case AVC_SUBUNIT_CAMERA:
@@ -268,7 +268,7 @@
 	case AVC_SUBUNIT_PANEL:
 		return "Panel";
 	case AVC_SUBUNIT_BULLETIN_BOARD:
-		return "Bulleting Board";
+		return "Bulletin Board";
 	case AVC_SUBUNIT_CAMERA_STORAGE:
 		return "Camera Storage";
 	case AVC_SUBUNIT_VENDOR_UNIQUE:
@@ -368,7 +368,7 @@
 	case AVRCP_STATUS_INVALID_SCOPE:
 		return "Invalid Scope";
 	case AVRCP_STATUS_OUT_OF_BOUNDS:
-		return "Range Out of Bonds";
+		return "Range Out of Bounds";
 	case AVRCP_STATUS_MEDIA_IN_USE:
 		return "Media in Use";
 	case AVRCP_STATUS_IS_DIRECTORY:
@@ -376,7 +376,7 @@
 	case AVRCP_STATUS_NOW_PLAYING_LIST_FULL:
 		return "Now Playing List Full";
 	case AVRCP_STATUS_SEARCH_NOT_SUPPORTED:
-		return "Seach Not Supported";
+		return "Search Not Supported";
 	case AVRCP_STATUS_SEARCH_IN_PROGRESS:
 		return "Search in Progress";
 	case AVRCP_STATUS_INVALID_PLAYER_ID:
@@ -520,9 +520,9 @@
 		case 0x01:
 			return "OFF";
 		case 0x02:
-			return "All Track Suffle";
+			return "All Track Shuffle";
 		case 0x03:
-			return "Group Suffle";
+			return "Group Shuffle";
 		default:
 			return "Reserved";
 		}
@@ -759,7 +759,7 @@
 	case 0x01:
 		return "Titles";
 	case 0x02:
-		return "Albuns";
+		return "Albums";
 	case 0x03:
 		return "Artists";
 	case 0x04:
@@ -1425,7 +1425,7 @@
 			printf("(UNPLUGGED)\n");
 			break;
 		default:
-			printf("(UNKOWN)\n");
+			printf("(UNKNOWN)\n");
 			break;
 		}
 		break;
diff --git a/monitor/avdtp.c b/monitor/avdtp.c
new file mode 100644
index 0000000..3524faa
--- /dev/null
+++ b/monitor/avdtp.c
@@ -0,0 +1,787 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; 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 <stdlib.h>
+#include <string.h>
+
+#include "lib/bluetooth.h"
+
+#include "src/shared/util.h"
+#include "bt.h"
+#include "packet.h"
+#include "display.h"
+#include "l2cap.h"
+#include "avdtp.h"
+#include "a2dp.h"
+
+/* Message Types */
+#define AVDTP_MSG_TYPE_COMMAND		0x00
+#define AVDTP_MSG_TYPE_GENERAL_REJECT	0x01
+#define AVDTP_MSG_TYPE_RESPONSE_ACCEPT	0x02
+#define AVDTP_MSG_TYPE_RESPONSE_REJECT	0x03
+
+/* Signal Identifiers */
+#define AVDTP_DISCOVER			0x01
+#define AVDTP_GET_CAPABILITIES		0x02
+#define AVDTP_SET_CONFIGURATION		0x03
+#define AVDTP_GET_CONFIGURATION		0x04
+#define AVDTP_RECONFIGURE		0x05
+#define AVDTP_OPEN			0x06
+#define AVDTP_START			0x07
+#define AVDTP_CLOSE			0x08
+#define AVDTP_SUSPEND			0x09
+#define AVDTP_ABORT			0x0a
+#define AVDTP_SECURITY_CONTROL		0x0b
+#define AVDTP_GET_ALL_CAPABILITIES	0x0c
+#define AVDTP_DELAYREPORT		0x0d
+
+/* Service Categories */
+#define AVDTP_MEDIA_TRANSPORT		0x01
+#define AVDTP_REPORTING			0x02
+#define AVDTP_RECOVERY			0x03
+#define AVDTP_CONTENT_PROTECTION	0x04
+#define AVDTP_HEADER_COMPRESSION	0x05
+#define AVDTP_MULTIPLEXING		0x06
+#define AVDTP_MEDIA_CODEC		0x07
+#define AVDTP_DELAY_REPORTING		0x08
+
+struct avdtp_frame {
+	uint8_t hdr;
+	uint8_t sig_id;
+	struct l2cap_frame l2cap_frame;
+};
+
+static inline bool is_configuration_sig_id(uint8_t sig_id)
+{
+	return (sig_id == AVDTP_SET_CONFIGURATION) ||
+			(sig_id == AVDTP_GET_CONFIGURATION) ||
+			(sig_id == AVDTP_RECONFIGURE);
+}
+
+static const char *msgtype2str(uint8_t msgtype)
+{
+	switch (msgtype) {
+	case 0:
+		return "Command";
+	case 1:
+		return "General Reject";
+	case 2:
+		return "Response Accept";
+	case 3:
+		return "Response Reject";
+	}
+
+	return "";
+}
+
+static const char *sigid2str(uint8_t sigid)
+{
+	switch (sigid) {
+	case AVDTP_DISCOVER:
+		return "Discover";
+	case AVDTP_GET_CAPABILITIES:
+		return "Get Capabilities";
+	case AVDTP_SET_CONFIGURATION:
+		return "Set Configuration";
+	case AVDTP_GET_CONFIGURATION:
+		return "Get Configuration";
+	case AVDTP_RECONFIGURE:
+		return "Reconfigure";
+	case AVDTP_OPEN:
+		return "Open";
+	case AVDTP_START:
+		return "Start";
+	case AVDTP_CLOSE:
+		return "Close";
+	case AVDTP_SUSPEND:
+		return "Suspend";
+	case AVDTP_ABORT:
+		return "Abort";
+	case AVDTP_SECURITY_CONTROL:
+		return "Security Control";
+	case AVDTP_GET_ALL_CAPABILITIES:
+		return "Get All Capabilities";
+	case AVDTP_DELAYREPORT:
+		return "Delay Report";
+	default:
+		return "Reserved";
+	}
+}
+
+static const char *error2str(uint8_t error)
+{
+	switch (error) {
+	case 0x01:
+		return "BAD_HEADER_FORMAT";
+	case 0x11:
+		return "BAD_LENGTH";
+	case 0x12:
+		return "BAD_ACP_SEID";
+	case 0x13:
+		return "SEP_IN_USE";
+	case 0x14:
+		return "SEP_NOT_IN_USER";
+	case 0x17:
+		return "BAD_SERV_CATEGORY";
+	case 0x18:
+		return "BAD_PAYLOAD_FORMAT";
+	case 0x19:
+		return "NOT_SUPPORTED_COMMAND";
+	case 0x1a:
+		return "INVALID_CAPABILITIES";
+	case 0x22:
+		return "BAD_RECOVERY_TYPE";
+	case 0x23:
+		return "BAD_MEDIA_TRANSPORT_FORMAT";
+	case 0x25:
+		return "BAD_RECOVERY_FORMAT";
+	case 0x26:
+		return "BAD_ROHC_FORMAT";
+	case 0x27:
+		return "BAD_CP_FORMAT";
+	case 0x28:
+		return "BAD_MULTIPLEXING_FORMAT";
+	case 0x29:
+		return "UNSUPPORTED_CONFIGURATION";
+	case 0x31:
+		return "BAD_STATE";
+	default:
+		return "Unknown";
+	}
+}
+
+static const char *mediatype2str(uint8_t media_type)
+{
+	switch (media_type) {
+	case 0x00:
+		return "Audio";
+	case 0x01:
+		return "Video";
+	case 0x02:
+		return "Multimedia";
+	default:
+		return "Reserved";
+	}
+}
+
+static const char *mediacodec2str(uint8_t codec)
+{
+	switch (codec) {
+	case 0x00:
+		return "SBC";
+	case 0x01:
+		return "MPEG-1,2 Audio";
+	case 0x02:
+		return "MPEG-2,4 AAC";
+	case 0x04:
+		return "ATRAC Family";
+	case 0xff:
+		return "Non-A2DP";
+	default:
+		return "Reserved";
+	}
+}
+
+static const char *cptype2str(uint8_t cp)
+{
+	switch (cp) {
+	case 0x0001:
+		return "DTCP";
+	case 0x0002:
+		return "SCMS-T";
+	default:
+		return "Reserved";
+	}
+}
+
+static const char *servicecat2str(uint8_t service_cat)
+{
+	switch (service_cat) {
+	case AVDTP_MEDIA_TRANSPORT:
+		return "Media Transport";
+	case AVDTP_REPORTING:
+		return "Reporting";
+	case AVDTP_RECOVERY:
+		return "Recovery";
+	case AVDTP_CONTENT_PROTECTION:
+		return "Content Protection";
+	case AVDTP_HEADER_COMPRESSION:
+		return "Header Compression";
+	case AVDTP_MULTIPLEXING:
+		return "Multiplexing";
+	case AVDTP_MEDIA_CODEC:
+		return "Media Codec";
+	case AVDTP_DELAY_REPORTING:
+		return "Delay Reporting";
+	default:
+		return "Reserved";
+	}
+}
+
+static bool avdtp_reject_common(struct avdtp_frame *avdtp_frame)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	uint8_t error;
+
+	if (!l2cap_frame_get_u8(frame, &error))
+		return false;
+
+	print_field("Error code: %s (0x%02x)", error2str(error), error);
+
+	return true;
+}
+
+static bool service_content_protection(struct avdtp_frame *avdtp_frame,
+								uint8_t losc)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	uint16_t type = 0;
+
+	if (losc < 2)
+		return false;
+
+	if (!l2cap_frame_get_le16(frame, &type))
+		return false;
+
+	losc -= 2;
+
+	print_field("%*cContent Protection Type: %s (0x%04x)", 2, ' ',
+							cptype2str(type), type);
+
+	/* TODO: decode protection specific information */
+	packet_hexdump(frame->data, losc);
+
+	l2cap_frame_pull(frame, frame, losc);
+
+	return true;
+}
+
+static bool service_media_codec(struct avdtp_frame *avdtp_frame, uint8_t losc)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	uint8_t type = 0;
+	uint8_t codec = 0;
+
+	if (losc < 2)
+		return false;
+
+	l2cap_frame_get_u8(frame, &type);
+	l2cap_frame_get_u8(frame, &codec);
+
+	losc -= 2;
+
+	print_field("%*cMedia Type: %s (0x%02x)", 2, ' ',
+					mediatype2str(type >> 4), type >> 4);
+
+	print_field("%*cMedia Codec: %s (0x%02x)", 2, ' ',
+					mediacodec2str(codec), codec);
+
+	if (is_configuration_sig_id(avdtp_frame->sig_id))
+		return a2dp_codec_cfg(codec, losc, frame);
+	else
+		return a2dp_codec_cap(codec, losc, frame);
+}
+
+static bool decode_capabilities(struct avdtp_frame *avdtp_frame)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	uint8_t service_cat;
+	uint8_t losc;
+
+	while (l2cap_frame_get_u8(frame, &service_cat)) {
+		print_field("Service Category: %s (0x%02x)",
+				servicecat2str(service_cat), service_cat);
+
+		if (!l2cap_frame_get_u8(frame, &losc))
+			return false;
+
+		if (frame->size < losc)
+			return false;
+
+		switch (service_cat) {
+		case AVDTP_CONTENT_PROTECTION:
+			if (!service_content_protection(avdtp_frame, losc))
+				return false;
+			break;
+		case AVDTP_MEDIA_CODEC:
+			if (!service_media_codec(avdtp_frame, losc))
+				return false;
+			break;
+		case AVDTP_MEDIA_TRANSPORT:
+		case AVDTP_REPORTING:
+		case AVDTP_RECOVERY:
+		case AVDTP_HEADER_COMPRESSION:
+		case AVDTP_MULTIPLEXING:
+		case AVDTP_DELAY_REPORTING:
+		default:
+			packet_hexdump(frame->data, losc);
+			l2cap_frame_pull(frame, frame, losc);
+		}
+
+	}
+
+	return true;
+}
+
+static bool avdtp_discover(struct avdtp_frame *avdtp_frame)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	uint8_t type = avdtp_frame->hdr & 0x03;
+	uint8_t seid;
+	uint8_t info;
+
+	switch (type) {
+	case AVDTP_MSG_TYPE_COMMAND:
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+		while (l2cap_frame_get_u8(frame, &seid)) {
+			print_field("ACP SEID: %d", seid >> 2);
+
+			if (!l2cap_frame_get_u8(frame, &info))
+				return false;
+
+			print_field("%*cMedia Type: %s (0x%02x)", 2, ' ',
+					mediatype2str(info >> 4), info >> 4);
+			print_field("%*cSEP Type: %s (0x%02x)", 2, ' ',
+						info & 0x04 ? "SNK" : "SRC",
+						(info >> 3) & 0x01);
+			print_field("%*cIn use: %s", 2, ' ',
+						seid & 0x02 ? "Yes" : "No");
+		}
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+		return avdtp_reject_common(avdtp_frame);
+	}
+
+	return false;
+}
+
+static bool avdtp_get_capabilities(struct avdtp_frame *avdtp_frame)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	uint8_t type = avdtp_frame->hdr & 0x03;
+	uint8_t seid;
+
+	switch (type) {
+	case AVDTP_MSG_TYPE_COMMAND:
+		if (!l2cap_frame_get_u8(frame, &seid))
+			return false;
+
+		print_field("ACP SEID: %d", seid >> 2);
+
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+		return decode_capabilities(avdtp_frame);
+	case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+		return avdtp_reject_common(avdtp_frame);
+	}
+
+	return false;
+}
+
+static bool avdtp_set_configuration(struct avdtp_frame *avdtp_frame)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	uint8_t type = avdtp_frame->hdr & 0x03;
+	uint8_t acp_seid, int_seid;
+	uint8_t service_cat;
+
+	switch (type) {
+	case AVDTP_MSG_TYPE_COMMAND:
+		if (!l2cap_frame_get_u8(frame, &acp_seid))
+			return false;
+
+		print_field("ACP SEID: %d", acp_seid >> 2);
+
+		if (!l2cap_frame_get_u8(frame, &int_seid))
+			return false;
+
+		print_field("INT SEID: %d", int_seid >> 2);
+
+		return decode_capabilities(avdtp_frame);
+	case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+		if (!l2cap_frame_get_u8(frame, &service_cat))
+			return false;
+
+		print_field("Service Category: %s (0x%02x)",
+				servicecat2str(service_cat), service_cat);
+
+		return avdtp_reject_common(avdtp_frame);
+	}
+
+	return false;
+}
+
+static bool avdtp_get_configuration(struct avdtp_frame *avdtp_frame)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	uint8_t type = avdtp_frame->hdr & 0x03;
+	uint8_t seid;
+
+	switch (type) {
+	case AVDTP_MSG_TYPE_COMMAND:
+		if (!l2cap_frame_get_u8(frame, &seid))
+			return false;
+
+		print_field("ACP SEID: %d", seid >> 2);
+
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+		return decode_capabilities(avdtp_frame);
+	case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+		return avdtp_reject_common(avdtp_frame);
+	}
+
+	return false;
+}
+
+static bool avdtp_reconfigure(struct avdtp_frame *avdtp_frame)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	uint8_t type = avdtp_frame->hdr & 0x03;
+	uint8_t seid;
+	uint8_t service_cat;
+
+	switch (type) {
+	case AVDTP_MSG_TYPE_COMMAND:
+		if (!l2cap_frame_get_u8(frame, &seid))
+			return false;
+
+		print_field("ACP SEID: %d", seid >> 2);
+
+		return decode_capabilities(avdtp_frame);
+	case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+		if (!l2cap_frame_get_u8(frame, &service_cat))
+			return false;
+
+		print_field("Service Category: %s (0x%02x)",
+				servicecat2str(service_cat), service_cat);
+
+		return avdtp_reject_common(avdtp_frame);
+	}
+
+	return false;
+}
+
+static bool avdtp_open(struct avdtp_frame *avdtp_frame)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	uint8_t type = avdtp_frame->hdr & 0x03;
+	uint8_t seid;
+
+	switch (type) {
+	case AVDTP_MSG_TYPE_COMMAND:
+		if (!l2cap_frame_get_u8(frame, &seid))
+			return false;
+
+		print_field("ACP SEID: %d", seid >> 2);
+
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+		return avdtp_reject_common(avdtp_frame);
+	}
+
+	return false;
+}
+
+static bool avdtp_start(struct avdtp_frame *avdtp_frame)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	uint8_t type = avdtp_frame->hdr & 0x03;
+	uint8_t seid;
+
+	switch (type) {
+	case AVDTP_MSG_TYPE_COMMAND:
+		if (!l2cap_frame_get_u8(frame, &seid))
+			return false;
+
+		print_field("ACP SEID: %d", seid >> 2);
+
+		while (l2cap_frame_get_u8(frame, &seid))
+			print_field("ACP SEID: %d", seid >> 2);
+
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+		if (!l2cap_frame_get_u8(frame, &seid))
+			return false;
+
+		print_field("ACP SEID: %d", seid >> 2);
+
+		return avdtp_reject_common(avdtp_frame);
+	}
+
+	return false;
+}
+
+static bool avdtp_close(struct avdtp_frame *avdtp_frame)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	uint8_t type = avdtp_frame->hdr & 0x03;
+	uint8_t seid;
+
+	switch (type) {
+	case AVDTP_MSG_TYPE_COMMAND:
+		if (!l2cap_frame_get_u8(frame, &seid))
+			return false;
+
+		print_field("ACP SEID: %d", seid >> 2);
+
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+		return avdtp_reject_common(avdtp_frame);
+	}
+
+	return false;
+}
+
+static bool avdtp_suspend(struct avdtp_frame *avdtp_frame)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	uint8_t type = avdtp_frame->hdr & 0x03;
+	uint8_t seid;
+
+	switch (type) {
+	case AVDTP_MSG_TYPE_COMMAND:
+		if (!l2cap_frame_get_u8(frame, &seid))
+			return false;
+
+		print_field("ACP SEID: %d", seid >> 2);
+
+		while (l2cap_frame_get_u8(frame, &seid))
+			print_field("ACP SEID: %d", seid >> 2);
+
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+		if (!l2cap_frame_get_u8(frame, &seid))
+			return false;
+
+		print_field("ACP SEID: %d", seid >> 2);
+
+		return avdtp_reject_common(avdtp_frame);
+	}
+
+	return false;
+}
+
+static bool avdtp_abort(struct avdtp_frame *avdtp_frame)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	uint8_t type = avdtp_frame->hdr & 0x03;
+	uint8_t seid;
+
+	switch (type) {
+	case AVDTP_MSG_TYPE_COMMAND:
+		if (!l2cap_frame_get_u8(frame, &seid))
+			return false;
+
+		print_field("ACP SEID: %d", seid >> 2);
+
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+		return true;
+	}
+
+	return false;
+}
+
+static bool avdtp_security_control(struct avdtp_frame *avdtp_frame)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	uint8_t type = avdtp_frame->hdr & 0x03;
+	uint8_t seid;
+
+	switch (type) {
+	case AVDTP_MSG_TYPE_COMMAND:
+		if (!l2cap_frame_get_u8(frame, &seid))
+			return false;
+
+		print_field("ACP SEID: %d", seid >> 2);
+
+		/* TODO: decode more information */
+		packet_hexdump(frame->data, frame->size);
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+		/* TODO: decode more information */
+		packet_hexdump(frame->data, frame->size);
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+		return avdtp_reject_common(avdtp_frame);
+	}
+
+	return false;
+}
+
+static bool avdtp_delayreport(struct avdtp_frame *avdtp_frame)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	uint8_t type = avdtp_frame->hdr & 0x03;
+	uint8_t seid;
+	uint16_t delay;
+
+	switch (type) {
+	case AVDTP_MSG_TYPE_COMMAND:
+		if (!l2cap_frame_get_u8(frame, &seid))
+			return false;
+
+		print_field("ACP SEID: %d", seid >> 2);
+
+		if (!l2cap_frame_get_be16(frame, &delay))
+			return false;
+
+		print_field("Delay: %d.%dms", delay / 10, delay % 10);
+
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+		return true;
+	case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+		return avdtp_reject_common(avdtp_frame);
+	}
+
+	return false;
+}
+
+static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
+{
+	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+	const char *pdu_color;
+	uint8_t hdr;
+	uint8_t sig_id;
+	uint8_t nosp = 0;
+
+	if (frame->in)
+		pdu_color = COLOR_MAGENTA;
+	else
+		pdu_color = COLOR_BLUE;
+
+	if (!l2cap_frame_get_u8(frame, &hdr))
+		return false;
+
+	avdtp_frame->hdr = hdr;
+
+	/* Continue Packet || End Packet */
+	if (((hdr & 0x0c) == 0x08) || ((hdr & 0x0c) == 0x0c)) {
+		/* TODO: handle fragmentation */
+		packet_hexdump(frame->data, frame->size);
+		return true;
+	}
+
+	/* Start Packet */
+	if ((hdr & 0x0c) == 0x04) {
+		if (!l2cap_frame_get_u8(frame, &nosp))
+			return false;
+	}
+
+	if (!l2cap_frame_get_u8(frame, &sig_id))
+		return false;
+
+	sig_id &= 0x3f;
+
+	avdtp_frame->sig_id = sig_id;
+
+	print_indent(6, pdu_color, "AVDTP: ", sigid2str(sig_id), COLOR_OFF,
+			" (0x%02x) %s (0x%02x) type 0x%02x label %d nosp %d",
+			sig_id, msgtype2str(hdr & 0x03), hdr & 0x03,
+			hdr & 0x0c, hdr >> 4, nosp);
+
+	/* Start Packet */
+	if ((hdr & 0x0c) == 0x04) {
+		/* TODO: handle fragmentation */
+		packet_hexdump(frame->data, frame->size);
+		return true;
+	}
+
+	/* General Reject */
+	if ((hdr & 0x03) == 0x03)
+		return true;
+
+	switch (sig_id) {
+	case AVDTP_DISCOVER:
+		return avdtp_discover(avdtp_frame);
+	case AVDTP_GET_CAPABILITIES:
+	case AVDTP_GET_ALL_CAPABILITIES:
+		return avdtp_get_capabilities(avdtp_frame);
+	case AVDTP_SET_CONFIGURATION:
+		return avdtp_set_configuration(avdtp_frame);
+	case AVDTP_GET_CONFIGURATION:
+		return avdtp_get_configuration(avdtp_frame);
+	case AVDTP_RECONFIGURE:
+		return avdtp_reconfigure(avdtp_frame);
+	case AVDTP_OPEN:
+		return avdtp_open(avdtp_frame);
+	case AVDTP_START:
+		return avdtp_start(avdtp_frame);
+	case AVDTP_CLOSE:
+		return avdtp_close(avdtp_frame);
+	case AVDTP_SUSPEND:
+		return avdtp_suspend(avdtp_frame);
+	case AVDTP_ABORT:
+		return avdtp_abort(avdtp_frame);
+	case AVDTP_SECURITY_CONTROL:
+		return avdtp_security_control(avdtp_frame);
+	case AVDTP_DELAYREPORT:
+		return avdtp_delayreport(avdtp_frame);
+	}
+
+	packet_hexdump(frame->data, frame->size);
+
+	return true;
+}
+
+void avdtp_packet(const struct l2cap_frame *frame)
+{
+	struct avdtp_frame avdtp_frame;
+	bool ret;
+
+	l2cap_frame_pull(&avdtp_frame.l2cap_frame, frame, 0);
+
+	switch (frame->seq_num) {
+	case 1:
+		ret = avdtp_signalling_packet(&avdtp_frame);
+		break;
+	default:
+		packet_hexdump(frame->data, frame->size);
+		return;
+	}
+
+	if (!ret) {
+		print_text(COLOR_ERROR, "PDU malformed");
+		packet_hexdump(frame->data, frame->size);
+	}
+}
diff --git a/monitor/avdtp.h b/monitor/avdtp.h
new file mode 100644
index 0000000..f77d82e
--- /dev/null
+++ b/monitor/avdtp.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+void avdtp_packet(const struct l2cap_frame *frame);
diff --git a/monitor/control.c b/monitor/control.c
index 00a60bc..b3fc93d 100644
--- a/monitor/control.c
+++ b/monitor/control.c
@@ -1159,7 +1159,7 @@
 
 bool control_writer(const char *path)
 {
-	btsnoop_file = btsnoop_create(path, BTSNOOP_TYPE_MONITOR);
+	btsnoop_file = btsnoop_create(path, BTSNOOP_FORMAT_MONITOR);
 
 	return !!btsnoop_file;
 }
@@ -1168,33 +1168,33 @@
 {
 	unsigned char buf[BTSNOOP_MAX_PACKET_SIZE];
 	uint16_t pktlen;
-	uint32_t type;
+	uint32_t format;
 	struct timeval tv;
 
 	btsnoop_file = btsnoop_open(path, BTSNOOP_FLAG_PKLG_SUPPORT);
 	if (!btsnoop_file)
 		return;
 
-	type = btsnoop_get_type(btsnoop_file);
+	format = btsnoop_get_format(btsnoop_file);
 
-	switch (type) {
-	case BTSNOOP_TYPE_HCI:
-	case BTSNOOP_TYPE_UART:
-	case BTSNOOP_TYPE_SIMULATOR:
+	switch (format) {
+	case BTSNOOP_FORMAT_HCI:
+	case BTSNOOP_FORMAT_UART:
+	case BTSNOOP_FORMAT_SIMULATOR:
 		packet_del_filter(PACKET_FILTER_SHOW_INDEX);
 		break;
 
-	case BTSNOOP_TYPE_MONITOR:
+	case BTSNOOP_FORMAT_MONITOR:
 		packet_add_filter(PACKET_FILTER_SHOW_INDEX);
 		break;
 	}
 
 	open_pager();
 
-	switch (type) {
-	case BTSNOOP_TYPE_HCI:
-	case BTSNOOP_TYPE_UART:
-	case BTSNOOP_TYPE_MONITOR:
+	switch (format) {
+	case BTSNOOP_FORMAT_HCI:
+	case BTSNOOP_FORMAT_UART:
+	case BTSNOOP_FORMAT_MONITOR:
 		while (1) {
 			uint16_t index, opcode;
 
@@ -1210,7 +1210,7 @@
 		}
 		break;
 
-	case BTSNOOP_TYPE_SIMULATOR:
+	case BTSNOOP_FORMAT_SIMULATOR:
 		while (1) {
 			uint16_t frequency;
 
diff --git a/monitor/display.h b/monitor/display.h
index 4ce5d35..36e189a 100644
--- a/monitor/display.h
+++ b/monitor/display.h
@@ -38,8 +38,10 @@
 #define COLOR_WHITE_BG	"\x1B[0;47;30m"
 #define COLOR_HIGHLIGHT	"\x1B[1;39m"
 
-#define COLOR_WARN	"\x1B[1;30m"
 #define COLOR_ERROR	"\x1B[1;31m"
+#define COLOR_WARN	"\x1B[1m"
+#define COLOR_INFO	COLOR_OFF
+#define COLOR_DEBUG	COLOR_WHITE
 
 #define FALLBACK_TERMINAL_WIDTH 80
 
diff --git a/monitor/intel.c b/monitor/intel.c
index ac09dc6..1ca9a95 100644
--- a/monitor/intel.c
+++ b/monitor/intel.c
@@ -499,6 +499,10 @@
 	return NULL;
 }
 
+static void startup_evt(const void *data, uint8_t size)
+{
+}
+
 static void fatal_exception_evt(const void *data, uint8_t size)
 {
 	uint16_t line = get_le16(data);
@@ -882,6 +886,8 @@
 }
 
 static const struct vendor_evt vendor_evt_table[] = {
+	{ 0x00, "Startup",
+			startup_evt, 0, true },
 	{ 0x01, "Fatal Exception",
 			fatal_exception_evt, 4, true },
 	{ 0x02, "Bootup",
diff --git a/monitor/l2cap.c b/monitor/l2cap.c
index 118fc24..c1f2bc5 100644
--- a/monitor/l2cap.c
+++ b/monitor/l2cap.c
@@ -42,6 +42,7 @@
 #include "keys.h"
 #include "sdp.h"
 #include "avctp.h"
+#include "avdtp.h"
 #include "rfcomm.h"
 #include "bnep.h"
 
@@ -99,6 +100,7 @@
 	uint8_t  ctrlid;
 	uint8_t  mode;
 	uint8_t  ext_ctrl;
+	uint8_t  seq_num;
 };
 
 static struct chan_data chan_list[MAX_CHAN];
@@ -107,10 +109,13 @@
 				uint16_t scid, uint16_t psm, uint8_t ctrlid)
 {
 	int i, n = -1;
+	uint8_t seq_num = 1;
 
 	for (i = 0; i < MAX_CHAN; i++) {
-		if (n < 0 && chan_list[i].handle == 0x0000)
+		if (n < 0 && chan_list[i].handle == 0x0000) {
 			n = i;
+			continue;
+		}
 
 		if (chan_list[i].index != frame->index)
 			continue;
@@ -118,16 +123,18 @@
 		if (chan_list[i].handle != frame->handle)
 			continue;
 
+		if (chan_list[i].psm == psm)
+			seq_num++;
+
+		/* Don't break on match - we still need to go through all
+		 * channels to find proper seq_num.
+		 */
 		if (frame->in) {
-			if (chan_list[i].dcid == scid) {
+			if (chan_list[i].dcid == scid)
 				n = i;
-				break;
-			}
 		} else {
-			if (chan_list[i].scid == scid) {
+			if (chan_list[i].scid == scid)
 				n = i;
-				break;
-			}
 		}
 	}
 
@@ -147,6 +154,8 @@
 	chan_list[n].psm = psm;
 	chan_list[n].ctrlid = ctrlid;
 	chan_list[n].mode = 0;
+
+	chan_list[n].seq_num = seq_num;
 }
 
 static void release_scid(const struct l2cap_frame *frame, uint16_t scid)
@@ -301,6 +310,16 @@
 	return i;
 }
 
+static uint8_t get_seq_num(const struct l2cap_frame *frame)
+{
+	int i = get_chan_data_index(frame);
+
+	if (i < 0)
+		return 0;
+
+	return chan_list[i].seq_num;
+}
+
 static void assign_ext_ctrl(const struct l2cap_frame *frame,
 					uint8_t ext_ctrl, uint16_t dcid)
 {
@@ -511,11 +530,88 @@
 	case 0x0004:
 		str = "Connection refused - no resources available";
 		break;
+	case 0x0006:
+		str = "Connection refused - Invalid Source CID";
+		break;
+	case 0x0007:
+		str = "Connection refused - Source CID already allocated";
+		break;
+	default:
+		str = "Reserved";
+		break;
+	}
+
+	print_field("Result: %s (0x%4.4x)", str, le16_to_cpu(result));
+}
+
+static void print_le_conn_result(uint16_t result)
+{
+	const char *str;
+
+	switch (le16_to_cpu(result)) {
+	case 0x0000:
+		str = "Connection successful";
+		break;
+	case 0x0002:
+		str = "Connection refused - PSM not supported";
+		break;
+	case 0x0004:
+		str = "Connection refused - no resources available";
+		break;
 	case 0x0005:
-		str = "Insufficient Authentication";
+		str = "Connection refused - insufficient authentication";
 		break;
 	case 0x0006:
-		str = "Insufficient Authorization";
+		str = "Connection refused - insufficient authorization";
+		break;
+	case 0x0007:
+		str = "Connection refused - insufficient encryption key size";
+		break;
+	case 0x0008:
+		str = "Connection refused - insufficient encryption";
+		break;
+	case 0x0009:
+		str = "Connection refused - Invalid Source CID";
+		break;
+	case 0x0010:
+		str = "Connection refused - Source CID already allocated";
+		break;
+	default:
+		str = "Reserved";
+		break;
+	}
+
+	print_field("Result: %s (0x%4.4x)", str, le16_to_cpu(result));
+}
+
+static void print_create_chan_result(uint16_t result)
+{
+	const char *str;
+
+	switch (le16_to_cpu(result)) {
+	case 0x0000:
+		str = "Connection successful";
+		break;
+	case 0x0001:
+		str = "Connection pending";
+		break;
+	case 0x0002:
+		str = "Connection refused - PSM not supported";
+		break;
+	case 0x0003:
+		str = "Connection refused - security block";
+		break;
+	case 0x0004:
+		str = "Connection refused - no resources available";
+		break;
+	case 0x0005:
+		str = "Connection refused - Controller ID not supported";
+		break;
+	case 0x0006:
+		str = "Connection refused - Invalid Source CID";
+		break;
+	case 0x0007:
+		str = "Connection refused - Source CID already allocated";
 		break;
 	default:
 		str = "Reserved";
@@ -1149,7 +1245,7 @@
 
 	print_cid("Destination", pdu->dcid);
 	print_cid("Source", pdu->scid);
-	print_conn_result(pdu->result);
+	print_create_chan_result(pdu->result);
 	print_conn_status(pdu->status);
 
 	assign_dcid(frame, le16_to_cpu(pdu->dcid), le16_to_cpu(pdu->scid));
@@ -1224,7 +1320,7 @@
 	print_field("MTU: %u", le16_to_cpu(pdu->mtu));
 	print_field("MPS: %u", le16_to_cpu(pdu->mps));
 	print_field("Credits: %u", le16_to_cpu(pdu->credits));
-	print_conn_result(pdu->result);
+	print_le_conn_result(pdu->result);
 
 	assign_dcid(frame, le16_to_cpu(pdu->dcid), 0);
 }
@@ -1307,16 +1403,17 @@
 				uint16_t handle, uint8_t ident,
 				uint16_t cid, const void *data, uint16_t size)
 {
-	frame->index  = index;
-	frame->in     = in;
-	frame->handle = handle;
-	frame->ident  = ident;
-	frame->cid    = cid;
-	frame->data   = data;
-	frame->size   = size;
-	frame->psm    = get_psm(frame);
-	frame->mode   = get_mode(frame);
-	frame->chan   = get_chan(frame);
+	frame->index   = index;
+	frame->in      = in;
+	frame->handle  = handle;
+	frame->ident   = ident;
+	frame->cid     = cid;
+	frame->data    = data;
+	frame->size    = size;
+	frame->psm     = get_psm(frame);
+	frame->mode    = get_mode(frame);
+	frame->chan    = get_chan(frame);
+	frame->seq_num = get_seq_num(frame);
 }
 
 static void bredr_sig_packet(uint16_t index, bool in, uint16_t handle,
@@ -3003,6 +3100,9 @@
 		case 0x001B:
 			avctp_packet(&frame);
 			break;
+		case 0x0019:
+			avdtp_packet(&frame);
+			break;
 		default:
 			/* limit amount of data to log */
 			if (size > 32) size = 32;
diff --git a/monitor/l2cap.h b/monitor/l2cap.h
index 0364454..813c793 100644
--- a/monitor/l2cap.h
+++ b/monitor/l2cap.h
@@ -34,6 +34,7 @@
 	uint16_t psm;
 	uint16_t chan;
 	uint8_t mode;
+	uint8_t seq_num;
 	const void *data;
 	uint16_t size;
 };
diff --git a/monitor/main.c b/monitor/main.c
index a81ff56..4bf7ca1 100644
--- a/monitor/main.c
+++ b/monitor/main.c
@@ -61,6 +61,7 @@
 		"\t-w, --write <file>     Save traces in btsnoop format\n"
 		"\t-a, --analyze <file>   Analyze traces in btsnoop format\n"
 		"\t-s, --server <socket>  Start monitor server socket\n"
+		"\t-p, --priority <level> Show only priority or lower\n"
 		"\t-i, --index <num>      Show only specified controller\n"
 		"\t-t, --time             Show time instead of time offset\n"
 		"\t-T, --date             Show time and date information\n"
@@ -74,6 +75,7 @@
 	{ "write",   required_argument, NULL, 'w' },
 	{ "analyze", required_argument, NULL, 'a' },
 	{ "server",  required_argument, NULL, 's' },
+	{ "priority",required_argument, NULL, 'p' },
 	{ "index",   required_argument, NULL, 'i' },
 	{ "time",    no_argument,       NULL, 't' },
 	{ "date",    no_argument,       NULL, 'T' },
@@ -105,7 +107,7 @@
 	for (;;) {
 		int opt;
 
-		opt = getopt_long(argc, argv, "r:w:a:s:i:tTSE:vh",
+		opt = getopt_long(argc, argv, "r:w:a:s:p:i:tTSE:vh",
 						main_options, NULL);
 		if (opt < 0)
 			break;
@@ -123,6 +125,9 @@
 		case 's':
 			control_server(optarg);
 			break;
+		case 'p':
+			packet_set_priority(optarg);
+			break;
 		case 'i':
 			if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
 				str = optarg + 3;
diff --git a/monitor/packet.c b/monitor/packet.c
index 385e57f..0b21121 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -87,6 +87,7 @@
 #define COLOR_PHY_PACKET		COLOR_BLUE
 
 static time_t time_offset = ((time_t) -1);
+static int priority_level = BTSNOOP_PRIORITY_INFO;
 static unsigned long filter_mask = 0;
 static bool index_filter = false;
 static uint16_t index_number = 0;
@@ -159,6 +160,17 @@
 	filter_mask &= ~filter;
 }
 
+void packet_set_priority(const char *priority)
+{
+	if (!priority)
+		return;
+
+	if (!strcasecmp(priority, "debug"))
+		priority_level = BTSNOOP_PRIORITY_DEBUG;
+	else
+		priority_level = atoi(priority);
+}
+
 void packet_select_index(uint16_t index)
 {
 	filter_mask &= ~PACKET_FILTER_SHOW_INDEX;
@@ -245,7 +257,7 @@
 			pos += n;
 	}
 
-	n = sprintf(line + pos, "%c %s", ident, label);
+	n = sprintf(line + pos, "%c %s", ident, label ? label : "");
 	if (n > 0) {
 		pos += n;
 		len += n;
@@ -255,7 +267,8 @@
 		int extra_len = extra ? strlen(extra) : 0;
 		int max_len = col - len - extra_len - ts_len - 3;
 
-		n = snprintf(line + pos, max_len + 1, ": %s", text);
+		n = snprintf(line + pos, max_len + 1, "%s%s",
+						label ? ": " : "", text);
 		if (n > max_len) {
 			line[pos + max_len - 1] = '.';
 			line[pos + max_len - 2] = '.';
@@ -3689,8 +3702,10 @@
 {
 	const struct btsnoop_opcode_new_index *ni;
 	const struct btsnoop_opcode_index_info *ii;
+	const struct btsnoop_opcode_user_logging *ul;
 	char str[18], extra_str[24];
 	uint16_t manufacturer;
+	const char *ident;
 
 	if (index_filter && index_number != index)
 		return;
@@ -3775,6 +3790,16 @@
 
 		packet_vendor_diag(tv, index, manufacturer, data, size);
 		break;
+	case BTSNOOP_OPCODE_SYSTEM_NOTE:
+		packet_system_note(tv, cred, index, data);
+		break;
+	case BTSNOOP_OPCODE_USER_LOGGING:
+		ul = data;
+		ident = ul->ident_len ? data + sizeof(*ul) : NULL;
+
+		packet_user_logging(tv, cred, index, ul->priority, ident,
+					data + sizeof(*ul) + ul->ident_len);
+		break;
 	default:
 		sprintf(extra_str, "(code %d len %d)", opcode, size);
 		print_packet(tv, cred, index, '*', COLOR_ERROR,
@@ -8350,23 +8375,17 @@
 static void print_subevent(const struct subevent_data *subevent_data,
 					const void *data, uint8_t size)
 {
-	const char *subevent_color, *subevent_str;
+	const char *subevent_color;
 
-	if (subevent_data) {
-		if (subevent_data->func)
-			subevent_color = COLOR_HCI_EVENT;
-		else
-			subevent_color = COLOR_HCI_EVENT_UNKNOWN;
-		subevent_str = subevent_data->str;
-	} else {
+	if (subevent_data->func)
+		subevent_color = COLOR_HCI_EVENT;
+	else
 		subevent_color = COLOR_HCI_EVENT_UNKNOWN;
-		subevent_str = "Unknown";
-	}
 
-	print_indent(6, subevent_color, "", subevent_str, COLOR_OFF,
+	print_indent(6, subevent_color, "", subevent_data->str, COLOR_OFF,
 					" (0x%2.2x)", subevent_data->subevent);
 
-	if (!subevent_data || !subevent_data->func) {
+	if (!subevent_data->func) {
 		packet_hexdump(data, size);
 		return;
 	}
@@ -8417,9 +8436,16 @@
 static void le_meta_event_evt(const void *data, uint8_t size)
 {
 	uint8_t subevent = *((const uint8_t *) data);
-	const struct subevent_data *subevent_data = NULL;
+	struct subevent_data unknown;
+	const struct subevent_data *subevent_data = &unknown;
 	int i;
 
+	unknown.subevent = subevent;
+	unknown.str = "Unknown";
+	unknown.func = NULL;
+	unknown.size = 0;
+	unknown.fixed = true;
+
 	for (i = 0; le_meta_event_table[i].str; i++) {
 		if (le_meta_event_table[i].subevent == subevent) {
 			subevent_data = &le_meta_event_table[i];
@@ -8446,6 +8472,7 @@
 			vendor_data.str = vendor_str;
 		} else
 			vendor_data.str = vnd->str;
+		vendor_data.subevent = subevent;
 		vendor_data.func = vnd->evt_func;
 		vendor_data.size = vnd->evt_size;
 		vendor_data.fixed = vnd->evt_fixed;
@@ -8688,6 +8715,72 @@
 	}
 }
 
+void packet_system_note(struct timeval *tv, struct ucred *cred,
+					uint16_t index, const void *message)
+{
+	print_packet(tv, cred, index, '=', COLOR_INFO, "Note", message, NULL);
+}
+
+void packet_user_logging(struct timeval *tv, struct ucred *cred,
+					uint16_t index, uint8_t priority,
+					const char *ident, const char *message)
+{
+	char pid_str[128];
+	const char *label;
+	const char *color;
+
+	if (priority > priority_level)
+		return;
+
+	switch (priority) {
+	case BTSNOOP_PRIORITY_ERR:
+		color = COLOR_ERROR;
+		break;
+	case BTSNOOP_PRIORITY_WARNING:
+		color = COLOR_WARN;
+		break;
+	case BTSNOOP_PRIORITY_INFO:
+		color = COLOR_INFO;
+		break;
+	case BTSNOOP_PRIORITY_DEBUG:
+		color = COLOR_DEBUG;
+		break;
+	default:
+		color = COLOR_WHITE_BG;
+		break;
+	}
+
+	if (cred) {
+		char *path = alloca(24);
+		char line[128];
+		FILE *fp;
+
+		snprintf(path, 23, "/proc/%u/comm", cred->pid);
+
+		fp = fopen(path, "re");
+		if (fp) {
+			if (fgets(line, sizeof(line), fp)) {
+				line[strcspn(line, "\r\n")] = '\0';
+				snprintf(pid_str, sizeof(pid_str), "%s[%u]",
+							line, cred->pid);
+			} else
+				snprintf(pid_str, sizeof(pid_str), "%u",
+								cred->pid);
+			fclose(fp);
+		} else
+			snprintf(pid_str, sizeof(pid_str), "%u", cred->pid);
+
+		label = pid_str;
+        } else {
+		if (ident)
+			label = ident;
+		else
+			label = "Message";
+	}
+
+	print_packet(tv, cred, index, '=', color, label, message, NULL);
+}
+
 void packet_hci_command(struct timeval *tv, struct ucred *cred, uint16_t index,
 					const void *data, uint16_t size)
 {
diff --git a/monitor/packet.h b/monitor/packet.h
index 59da5af..322f101 100644
--- a/monitor/packet.h
+++ b/monitor/packet.h
@@ -38,6 +38,7 @@
 void packet_add_filter(unsigned long filter);
 void packet_del_filter(unsigned long filter);
 
+void packet_set_priority(const char *priority);
 void packet_select_index(uint16_t index);
 
 void packet_hexdump(const unsigned char *buf, uint16_t len);
@@ -73,6 +74,11 @@
 void packet_vendor_diag(struct timeval *tv, uint16_t index,
 					uint16_t manufacturer,
 					const void *data, uint16_t size);
+void packet_system_note(struct timeval *tv, struct ucred *cred,
+					uint16_t index, const void *message);
+void packet_user_logging(struct timeval *tv, struct ucred *cred,
+					uint16_t index, uint8_t priority,
+					const char *ident, const char *message);
 
 void packet_hci_command(struct timeval *tv, struct ucred *cred, uint16_t index,
 					const void *data, uint16_t size);
diff --git a/monitor/rfcomm.c b/monitor/rfcomm.c
index bdf4000..b32ad40 100644
--- a/monitor/rfcomm.c
+++ b/monitor/rfcomm.c
@@ -367,7 +367,7 @@
 	else
 		type_str = "Unknown";
 
-	print_field("%*cMCC Message type: %s %s(0x%2.2x)", indent, ' ',
+	print_field("%*cMCC Message type: %s %s (0x%2.2x)", indent, ' ',
 				type_str, CR_STR(mcc.type), type);
 
 	print_field("%*cLength: %d", indent+2, ' ', mcc.length);
@@ -421,7 +421,7 @@
 };
 
 static const struct rfcomm_data rfcomm_table[] = {
-	{ 0x2f, "Set Async Balance Mode (SABM) " },
+	{ 0x2f, "Set Async Balance Mode (SABM)" },
 	{ 0x63, "Unnumbered Ack (UA)" },
 	{ 0x0f, "Disconnect Mode (DM)" },
 	{ 0x43, "Disconnect (DISC)" },
@@ -493,7 +493,7 @@
 	}
 
 	print_indent(6, frame_color, "RFCOMM: ", frame_str, COLOR_OFF,
-						"(0x%2.2x)", ctype);
+						" (0x%2.2x)", ctype);
 
 	rfcomm_frame.hdr = hdr;
 	print_rfcomm_hdr(&rfcomm_frame, indent);
diff --git a/monitor/uuid.c b/monitor/uuid.c
index fe79f3f..b123ebe 100644
--- a/monitor/uuid.c
+++ b/monitor/uuid.c
@@ -161,7 +161,15 @@
 	{ 0x181b, "Body Composition"				},
 	{ 0x181c, "User Data"					},
 	{ 0x181d, "Weight Scale"				},
-	/* 0x181e to 0x27ff undefined */
+	{ 0x181e, "Bond Management"				},
+	{ 0x181f, "Continuous Glucose Monitoring"		},
+	{ 0x1820, "Internet Protocol Support"			},
+	{ 0x1821, "Indoor Positioning"				},
+	{ 0x1822, "Pulse Oximeter"				},
+	{ 0x1823, "HTTP Proxy"					},
+	{ 0x1824, "Transport Discovery"				},
+	{ 0x1825, "Object Transfer"				},
+	/* 0x1824 to 0x27ff undefined */
 	{ 0x2800, "Primary Service"				},
 	{ 0x2801, "Secondary Service"				},
 	{ 0x2802, "Include"					},
@@ -334,6 +342,43 @@
 	{ 0x2aa1, "Magnetic Flux Density - 3D"			},
 	{ 0x2aa2, "Language"					},
 	{ 0x2aa3, "Barometric Pressure Trend"			},
+	{ 0x2aa4, "Bond Management Control Point"		},
+	{ 0x2aa5, "Bond Management Feature"			},
+	{ 0x2aa6, "Central Address Resolution"			},
+	{ 0x2aa7, "CGM Measurement"				},
+	{ 0x2aa8, "CGM Feature"					},
+	{ 0x2aa9, "CGM Status"					},
+	{ 0x2aaa, "CGM Session Start Time"			},
+	{ 0x2aab, "CGM Session Run Time"			},
+	{ 0x2aac, "CGM Specific Ops Control Point"		},
+	{ 0x2aad, "Indoor Positioning Configuration"		},
+	{ 0x2aae, "Latitude"					},
+	{ 0x2aaf, "Longitude"					},
+	{ 0x2ab0, "Local North Coordinate"			},
+	{ 0x2ab1, "Local East Coordinate"			},
+	{ 0x2ab2, "Floor Number"				},
+	{ 0x2ab3, "Altitude"					},
+	{ 0x2ab4, "Uncertainty"					},
+	{ 0x2ab5, "Location Name"				},
+	{ 0x2ab6, "URI"						},
+	{ 0x2ab7, "HTTP Headers"				},
+	{ 0x2ab8, "HTTP Status Code"				},
+	{ 0x2ab9, "HTTP Entity Body"				},
+	{ 0x2aba, "HTTP Control Point"				},
+	{ 0x2abb, "HTTPS Security"				},
+	{ 0x2abc, "TDS Control Point"				},
+	{ 0x2abd, "OTS Feature"					},
+	{ 0x2abe, "Object Name"					},
+	{ 0x2abf, "Object Type"					},
+	{ 0x2ac0, "Object Size"					},
+	{ 0x2ac1, "Object First-Created"			},
+	{ 0x2ac2, "Object Last-Modified"			},
+	{ 0x2ac3, "Object ID"					},
+	{ 0x2ac4, "Object Properties"				},
+	{ 0x2ac5, "Object Action Control Point"			},
+	{ 0x2ac6, "Object List Control Point"			},
+	{ 0x2ac7, "Object List Filter"				},
+	{ 0x2ac8, "Object Changed"				},
 	/* vendor defined */
 	{ 0xfeff, "GN Netcom"					},
 	{ 0xfefe, "GN ReSound A/S"				},
@@ -455,6 +500,19 @@
 	{ 0xfe8a, "Apple, Inc."					},
 	{ 0xfe89, "B&O Play A/S"				},
 	{ 0xfe88, "SALTO SYSTEMS S.L."				},
+	{ 0xfe87, "Qingdao Yeelink Information Technology Co., Ltd. ( 青岛亿联客信息技术有限公司 )"	},
+	{ 0xfe86, "HUAWEI Technologies Co., Ltd. ( 华为技术有限公司 )"					},
+	{ 0xfe85, "RF Digital Corp"				},
+	{ 0xfe84, "RF Digital Corp"				},
+	{ 0xfe83, "Blue Bite"					},
+	{ 0xfe82, "Medtronic Inc."				},
+	{ 0xfe81, "Medtronic Inc."				},
+	{ 0xfe80, "Doppler Lab"					},
+	{ 0xfe7f, "Doppler Lab"					},
+	{ 0xfe7e, "Awear Solutions Ltd"				},
+	{ 0xfe7d, "Aterica Health Inc."				},
+	{ 0xfe7c, "Stollmann E+V GmbH"				},
+	{ 0xfe7b, "Orion Labs, Inc."				},
 	/* SDO defined */
 	{ 0xfffe, "Alliance for Wireless Power (A4WP)"		},
 	{ 0xfffd, "Fast IDentity Online Alliance (FIDO)"	},
diff --git a/obexd/client/session.c b/obexd/client/session.c
index 7248768..ef998f9 100644
--- a/obexd/client/session.c
+++ b/obexd/client/session.c
@@ -62,6 +62,7 @@
 
 struct callback_data {
 	struct obc_session *session;
+	guint id;
 	session_callback_t func;
 	void *data;
 };
@@ -308,6 +309,9 @@
 {
 	struct obc_session *session = callback->session;
 
+	if (callback->id > 0)
+		g_obex_cancel_req(session->obex, callback->id, TRUE);
+
 	callback->func(session, NULL, err, callback->data);
 	g_free(callback);
 	session->callback = NULL;
@@ -321,6 +325,8 @@
 	GError *gerr = NULL;
 	uint8_t rsp_code;
 
+	callback->id = 0;
+
 	if (err != NULL) {
 		error("connect_cb: %s", err->message);
 		gerr = g_error_copy(err);
@@ -392,24 +398,26 @@
 
 		len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
 		if (driver->target)
-			g_obex_connect(obex, connect_cb, callback, &err,
+			callback->id = g_obex_connect(obex, connect_cb,
+					callback, &err,
 					G_OBEX_HDR_TARGET,
 					driver->target, driver->target_len,
 					G_OBEX_HDR_APPARAM,
 					buf, len,
 					G_OBEX_HDR_INVALID);
 		else
-			g_obex_connect(obex, connect_cb, callback, &err,
+			callback->id = g_obex_connect(obex, connect_cb,
+					callback, &err,
 					G_OBEX_HDR_APPARAM, buf, len,
 					G_OBEX_HDR_INVALID);
 		g_obex_apparam_free(apparam);
 	} else if (driver->target)
-		g_obex_connect(obex, connect_cb, callback, &err,
+		callback->id = g_obex_connect(obex, connect_cb, callback, &err,
 			G_OBEX_HDR_TARGET, driver->target, driver->target_len,
 			G_OBEX_HDR_INVALID);
 	else
-		g_obex_connect(obex, connect_cb, callback, &err,
-							G_OBEX_HDR_INVALID);
+		callback->id = g_obex_connect(obex, connect_cb, callback,
+						&err, G_OBEX_HDR_INVALID);
 
 	if (err != NULL) {
 		error("%s", err->message);
diff --git a/obexd/src/log.c b/obexd/src/log.c
index ace7ab6..f259728 100644
--- a/obexd/src/log.c
+++ b/obexd/src/log.c
@@ -125,7 +125,7 @@
 
 	openlog("obexd", option, LOG_DAEMON);
 
-	syslog(LOG_INFO, "OBEX daemon %s", VERSION);
+	info("OBEX daemon %s", VERSION);
 }
 
 void __obex_log_cleanup(void)
diff --git a/profiles/audio/a2dp-codecs.h b/profiles/audio/a2dp-codecs.h
index 4d2584d..e9da0bf 100644
--- a/profiles/audio/a2dp-codecs.h
+++ b/profiles/audio/a2dp-codecs.h
@@ -141,6 +141,9 @@
 #define APTX_SAMPLING_FREQ_44100	0x02
 #define APTX_SAMPLING_FREQ_48000	0x01
 
+#define LDAC_VENDOR_ID			0x0000012d
+#define LDAC_CODEC_ID			0x00aa
+
 typedef struct {
 	uint32_t vendor_id;
 	uint16_t codec_id;
@@ -186,6 +189,11 @@
 	uint8_t frequency:4;
 } __attribute__ ((packed)) a2dp_aptx_t;
 
+typedef struct {
+	a2dp_vendor_codec_t info;
+	uint8_t unknown[2];
+} __attribute__ ((packed)) a2dp_ldac_t;
+
 #elif __BYTE_ORDER == __BIG_ENDIAN
 
 typedef struct {
diff --git a/android/bas.c b/profiles/battery/bas.c
similarity index 88%
rename from android/bas.c
rename to profiles/battery/bas.c
index dcbf9de..de369fd 100644
--- a/android/bas.c
+++ b/profiles/battery/bas.c
@@ -43,7 +43,7 @@
 #include "attrib/att.h"
 #include "attrib/gatt.h"
 
-#include "android/bas.h"
+#include "profiles/battery/bas.h"
 
 #define ATT_NOTIFICATION_HEADER_SIZE 3
 #define ATT_READ_RESPONSE_HEADER_SIZE 1
@@ -77,22 +77,15 @@
 
 	g_free(bas->primary);
 	queue_destroy(bas->gatt_op, (void *) destroy_gatt_req);
-	g_free(bas);
+	free(bas);
 }
 
 struct bt_bas *bt_bas_new(void *primary)
 {
 	struct bt_bas *bas;
 
-	bas = g_try_new0(struct bt_bas, 1);
-	if (!bas)
-		return NULL;
-
+	bas = new0(struct bt_bas, 1);
 	bas->gatt_op = queue_new();
-	if (!bas->gatt_op) {
-		bas_free(bas);
-		return NULL;
-	}
 
 	if (primary)
 		bas->primary = g_memdup(primary, sizeof(*bas->primary));
@@ -127,21 +120,18 @@
 	struct gatt_request *req;
 
 	req = new0(struct gatt_request, 1);
-	if (!req)
-		return NULL;
-
 	req->user_data = user_data;
 	req->bas = bt_bas_ref(bas);
 
 	return req;
 }
 
-static bool set_and_store_gatt_req(struct bt_bas *bas,
+static void set_and_store_gatt_req(struct bt_bas *bas,
 						struct gatt_request *req,
 						unsigned int id)
 {
 	req->id = id;
-	return queue_push_head(bas->gatt_op, req);
+	queue_push_head(bas->gatt_op, req);
 }
 
 static void write_char(struct bt_bas *bas, GAttrib *attrib, uint16_t handle,
@@ -153,18 +143,10 @@
 	unsigned int id;
 
 	req = create_request(bas, user_data);
-	if (!req)
-		return;
 
 	id = gatt_write_char(attrib, handle, value, vlen, func, req);
 
-	if (set_and_store_gatt_req(bas, req, id))
-		return;
-
-	error("bas: Could not write characteristic");
-	g_attrib_cancel(attrib, id);
-	free(req);
-
+	set_and_store_gatt_req(bas, req, id);
 }
 
 static void read_char(struct bt_bas *bas, GAttrib *attrib, uint16_t handle,
@@ -174,17 +156,10 @@
 	unsigned int id;
 
 	req = create_request(bas, user_data);
-	if (!req)
-		return;
 
 	id = gatt_read_char(attrib, handle, func, req);
 
-	if (set_and_store_gatt_req(bas, req, id))
-		return;
-
-	error("bas: Could not read characteristic");
-	g_attrib_cancel(attrib, id);
-	free(req);
+	set_and_store_gatt_req(bas, req, id);
 }
 
 static void discover_char(struct bt_bas *bas, GAttrib *attrib,
@@ -196,17 +171,10 @@
 	unsigned int id;
 
 	req = create_request(bas, user_data);
-	if (!req)
-		return;
 
 	id = gatt_discover_char(attrib, start, end, uuid, func, req);
 
-	if (set_and_store_gatt_req(bas, req, id))
-		return;
-
-	error("bas: Could not discover characteristic");
-	g_attrib_cancel(attrib, id);
-	free(req);
+	set_and_store_gatt_req(bas, req, id);
 }
 
 static void discover_desc(struct bt_bas *bas, GAttrib *attrib,
@@ -217,16 +185,9 @@
 	unsigned int id;
 
 	req = create_request(bas, user_data);
-	if (!req)
-		return;
 
 	id = gatt_discover_desc(attrib, start, end, uuid, func, req);
-	if (set_and_store_gatt_req(bas, req, id))
-		return;
-
-	error("bas: Could not discover descriptor");
-	g_attrib_cancel(attrib, id);
-	free(req);
+	set_and_store_gatt_req(bas, req, id);
 }
 
 static void notification_cb(const guint8 *pdu, guint16 len, gpointer user_data)
diff --git a/android/bas.h b/profiles/battery/bas.h
similarity index 100%
rename from android/bas.h
rename to profiles/battery/bas.h
diff --git a/android/dis.c b/profiles/deviceinfo/dis.c
similarity index 97%
rename from android/dis.c
rename to profiles/deviceinfo/dis.c
index 75dbe3d..91c5d39 100644
--- a/android/dis.c
+++ b/profiles/deviceinfo/dis.c
@@ -42,7 +42,7 @@
 #include "attrib/att.h"
 #include "attrib/gatt.h"
 
-#include "android/dis.h"
+#include "profiles/deviceinfo/dis.h"
 
 #define PNP_ID_SIZE	7
 
@@ -96,10 +96,6 @@
 		return NULL;
 
 	dis->gatt_op = queue_new();
-	if (!dis->gatt_op) {
-		dis_free(dis);
-		return NULL;
-	}
 
 	if (primary)
 		dis->primary = g_memdup(primary, sizeof(*dis->primary));
@@ -134,9 +130,6 @@
 	struct gatt_request *req;
 
 	req = new0(struct gatt_request, 1);
-	if (!req)
-		return NULL;
-
 	req->user_data = user_data;
 	req->dis = bt_dis_ref(dis);
 
@@ -197,8 +190,6 @@
 	unsigned int id;
 
 	req = create_request(dis, user_data);
-	if (!req)
-		return;
 
 	id = gatt_read_char(attrib, handle, func, req);
 
@@ -219,8 +210,6 @@
 	unsigned int id;
 
 	req = create_request(dis, user_data);
-	if (!req)
-		return;
 
 	id = gatt_discover_char(attrib, start, end, uuid, func, req);
 
diff --git a/android/dis.h b/profiles/deviceinfo/dis.h
similarity index 100%
rename from android/dis.h
rename to profiles/deviceinfo/dis.h
diff --git a/android/hog.c b/profiles/input/hog-lib.c
similarity index 95%
rename from android/hog.c
rename to profiles/input/hog-lib.c
index ff77bb3..1df1799 100644
--- a/android/hog.c
+++ b/profiles/input/hog-lib.c
@@ -53,10 +53,10 @@
 
 #include "btio/btio.h"
 
-#include "android/scpp.h"
-#include "android/dis.h"
-#include "android/bas.h"
-#include "android/hog.h"
+#include "profiles/scanparam/scpp.h"
+#include "profiles/deviceinfo/dis.h"
+#include "profiles/battery/bas.h"
+#include "profiles/input/hog-lib.h"
 
 #define HOG_UUID		"00001812-0000-1000-8000-00805f9b34fb"
 
@@ -88,6 +88,7 @@
 	GSList			*reports;
 	struct bt_uhid		*uhid;
 	int			uhid_fd;
+	bool			uhid_created;
 	gboolean		has_report_id;
 	uint16_t		bcdhid;
 	uint8_t			bcountrycode;
@@ -368,6 +369,20 @@
 	write_ccc(report->hog, report->hog->attrib, report->ccc_handle, report);
 }
 
+static const char *type_to_string(uint8_t type)
+{
+	switch (type) {
+	case HOG_REPORT_TYPE_INPUT:
+		return "input";
+	case HOG_REPORT_TYPE_OUTPUT:
+		return "output";
+	case HOG_REPORT_TYPE_FEATURE:
+		return "feature";
+	}
+
+	return NULL;
+}
+
 static void report_reference_cb(guint8 status, const guint8 *pdu,
 					guint16 plen, gpointer user_data)
 {
@@ -389,7 +404,9 @@
 
 	report->id = pdu[1];
 	report->type = pdu[2];
-	DBG("Report ID: 0x%02x Report type: 0x%02x", pdu[1], pdu[2]);
+
+	DBG("Report 0x%04x: id 0x%02x type %s", report->decl->value_handle,
+				report->id, type_to_string(report->type));
 
 	/* Enable notifications only for Input Reports */
 	if (report->type == HOG_REPORT_TYPE_INPUT)
@@ -496,9 +513,23 @@
 	report->len = len;
 }
 
+static int report_chrc_cmp(const void *data, const void *user_data)
+{
+	const struct report *report = data;
+	const struct gatt_char *decl = user_data;
+
+	return report->decl->handle - decl->handle;
+}
+
 static struct report *report_new(struct bt_hog *hog, struct gatt_char *chr)
 {
 	struct report *report;
+	GSList *l;
+
+	/* Skip if report already exists */
+	l = g_slist_find_custom(hog->reports, chr, report_chrc_cmp);
+	if (l)
+		return l->data;
 
 	report = g_new0(struct report, 1);
 	report->hog = hog;
@@ -939,6 +970,8 @@
 
 	destroy_gatt_req(req);
 
+	DBG("HoG inspecting report map");
+
 	if (status != 0) {
 		error("Report Map read failed: %s", att_ecode2str(status));
 		return;
@@ -1006,6 +1039,10 @@
 	bt_uhid_register(hog->uhid, UHID_FEATURE, get_feature, hog);
 	bt_uhid_register(hog->uhid, UHID_GET_REPORT, get_report, hog);
 	bt_uhid_register(hog->uhid, UHID_SET_REPORT, set_report, hog);
+
+	hog->uhid_created = true;
+
+	DBG("HoG created uHID device");
 }
 
 static void info_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
@@ -1084,6 +1121,8 @@
 
 	destroy_gatt_req(req);
 
+	DBG("HoG inspecting characteristics");
+
 	if (status != 0) {
 		const char *str = att_ecode2str(status);
 		DBG("Discover all characteristics failed: %s", str);
@@ -1116,6 +1155,7 @@
 			report = report_new(hog, chr);
 			discover_report(hog, hog->attrib, start, end, report);
 		} else if (bt_uuid_cmp(&uuid, &report_map_uuid) == 0) {
+			DBG("HoG discovering report map");
 			read_char(hog, hog->attrib, chr->value_handle,
 						report_map_read_cb, hog);
 			discover_external(hog, hog->attrib, start, end, hog);
@@ -1299,8 +1339,6 @@
 	struct bt_bas *instance;
 
 	instance = bt_bas_new(primary);
-	if (!instance)
-		return;
 
 	bt_bas_attach(instance, hog->attrib);
 	queue_push_head(hog->bas, instance);
@@ -1406,7 +1444,8 @@
 		bt_hog_attach(instance, gatt);
 	}
 
-	if (hog->reports == NULL) {
+	if (!hog->uhid_created) {
+		DBG("HoG discovering characteristics");
 		discover_char(hog, hog->attrib, primary->range.start,
 						primary->range.end, NULL,
 						char_discovered_cb, hog);
diff --git a/android/hog.h b/profiles/input/hog-lib.h
similarity index 100%
rename from android/hog.h
rename to profiles/input/hog-lib.h
diff --git a/profiles/input/hog.c b/profiles/input/hog.c
index 475c0e4..9b4b5c2 100644
--- a/profiles/input/hog.c
+++ b/profiles/input/hog.c
@@ -48,6 +48,7 @@
 #include "src/service.h"
 #include "src/shared/util.h"
 #include "src/shared/uhid.h"
+#include "src/shared/queue.h"
 #include "src/plugin.h"
 
 #include "suspend.h"
@@ -55,947 +56,99 @@
 #include "attrib/gattrib.h"
 #include "src/attio.h"
 #include "attrib/gatt.h"
+#include "hog-lib.h"
 
 #define HOG_UUID		"00001812-0000-1000-8000-00805f9b34fb"
 
-#define HOG_INFO_UUID		0x2A4A
-#define HOG_REPORT_MAP_UUID	0x2A4B
-#define HOG_REPORT_UUID		0x2A4D
-#define HOG_PROTO_MODE_UUID	0x2A4E
-#define HOG_CONTROL_POINT_UUID	0x2A4C
-
-#define HOG_REPORT_TYPE_INPUT	1
-#define HOG_REPORT_TYPE_OUTPUT	2
-#define HOG_REPORT_TYPE_FEATURE	3
-
-#define HOG_PROTO_MODE_BOOT    0
-#define HOG_PROTO_MODE_REPORT  1
-
-#define HOG_REPORT_MAP_MAX_SIZE        512
-#define HID_INFO_SIZE			4
-#define ATT_NOTIFICATION_HEADER_SIZE	3
-
 struct hog_device {
-	uint16_t		id;
-	struct btd_device	*device;
-	GAttrib			*attrib;
 	guint			attioid;
-	struct gatt_primary	*hog_primary;
-	GSList			*reports;
-	struct bt_uhid		*uhid;
-	gboolean		uhid_created;
-	gboolean		has_report_id;
-	uint16_t		bcdhid;
-	uint8_t			bcountrycode;
-	uint16_t		proto_mode_handle;
-	uint16_t		ctrlpt_handle;
-	uint8_t			flags;
-	guint			getrep_att;
-	uint16_t		getrep_id;
-	guint			setrep_att;
-	uint16_t		setrep_id;
-};
-
-struct report {
-	uint8_t			id;
-	uint8_t			type;
-	uint16_t		ccc_handle;
-	guint			notifyid;
-	struct gatt_char	*decl;
-	struct hog_device	*hogdev;
+	struct btd_device	*device;
+	struct bt_hog		*hog;
 };
 
 static gboolean suspend_supported = FALSE;
-static GSList *devices = NULL;
-
-static void report_value_cb(const guint8 *pdu, guint16 len, gpointer user_data)
-{
-	struct report *report = user_data;
-	struct hog_device *hogdev = report->hogdev;
-	struct uhid_event ev;
-	uint8_t *buf;
-	int err;
-
-	if (len < ATT_NOTIFICATION_HEADER_SIZE) {
-		error("Malformed ATT notification");
-		return;
-	}
-
-	pdu += ATT_NOTIFICATION_HEADER_SIZE;
-	len -= ATT_NOTIFICATION_HEADER_SIZE;
-
-	memset(&ev, 0, sizeof(ev));
-	ev.type = UHID_INPUT;
-	buf = ev.u.input.data;
-
-	if (hogdev->has_report_id) {
-		buf[0] = report->id;
-		len = MIN(len, sizeof(ev.u.input.data) - 1);
-		memcpy(buf + 1, pdu, len);
-		ev.u.input.size = ++len;
-	} else {
-		len = MIN(len, sizeof(ev.u.input.data));
-		memcpy(buf, pdu, len);
-		ev.u.input.size = len;
-	}
-
-	err = bt_uhid_send(hogdev->uhid, &ev);
-	if (err < 0) {
-		error("bt_uhid_send: %s (%d)", strerror(-err), -err);
-		return;
-	}
-
-	DBG("HoG report (%u bytes)", ev.u.input.size);
-}
-
-static void report_ccc_written_cb(guint8 status, const guint8 *pdu,
-					guint16 plen, gpointer user_data)
-{
-	struct report *report = user_data;
-
-	if (status != 0) {
-		error("Report 0x%04x CCC write failed: %s",
-				report->decl->handle, att_ecode2str(status));
-		return;
-	}
-
-	DBG("Report 0x%04x CCC written: notifications enabled",
-							report->decl->handle);
-}
-
-static void enable_report_notifications(struct report *report,
-							bool enable_on_device)
-{
-	struct hog_device *hogdev = report->hogdev;
-	uint8_t value[2];
-
-	if (!hogdev->uhid_created)
-		return;
-
-	if (!report->ccc_handle)
-		return;
-
-	/* Register callback for HoG report notifications */
-	report->notifyid = g_attrib_register(hogdev->attrib,
-					ATT_OP_HANDLE_NOTIFY,
-					report->decl->value_handle,
-					report_value_cb, report, NULL);
-
-	if (!enable_on_device)
-		return;
-
-	/* Enable HoG report notifications on the HoG device */
-	put_le16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
-	gatt_write_char(hogdev->attrib, report->ccc_handle, value,
-				sizeof(value), report_ccc_written_cb, report);
-}
-
-static void report_reference_cb(guint8 status, const guint8 *pdu,
-					guint16 plen, gpointer user_data)
-{
-	struct report *report = user_data;
-
-	if (status != 0) {
-		error("Read Report Reference descriptor failed: %s",
-							att_ecode2str(status));
-		return;
-	}
-
-	if (plen != 3) {
-		error("Malformed ATT read response");
-		return;
-	}
-
-	report->id = pdu[1];
-	report->type = pdu[2];
-	DBG("Report ID: 0x%02x Report type: 0x%02x", pdu[1], pdu[2]);
-}
-
-static void external_report_reference_cb(guint8 status, const guint8 *pdu,
-					guint16 plen, gpointer user_data);
-
-
-static void discover_descriptor_cb(uint8_t status, GSList *descs,
-								void *user_data)
-{
-	struct report *report;
-	struct hog_device *hogdev;
-	GAttrib *attrib = NULL;
-
-	if (status != 0) {
-		error("Discover all descriptors failed: %s",
-							att_ecode2str(status));
-		return;
-	}
-
-	for ( ; descs; descs = descs->next) {
-		struct gatt_desc *desc = descs->data;
-
-		switch (desc->uuid16) {
-		case GATT_CLIENT_CHARAC_CFG_UUID:
-			report = user_data;
-			report->ccc_handle = desc->handle;
-			enable_report_notifications(report, true);
-			break;
-		case GATT_REPORT_REFERENCE:
-			report = user_data;
-			attrib = report->hogdev->attrib;
-			gatt_read_char(attrib, desc->handle,
-						report_reference_cb, report);
-			break;
-		case GATT_EXTERNAL_REPORT_REFERENCE:
-			hogdev = user_data;
-			attrib = hogdev->attrib;
-			gatt_read_char(attrib, desc->handle,
-					external_report_reference_cb, hogdev);
-			break;
-		}
-	}
-}
-
-static void discover_descriptor(GAttrib *attrib, uint16_t start, uint16_t end,
-							gpointer user_data)
-{
-	if (start > end)
-		return;
-
-	gatt_discover_desc(attrib, start, end, NULL,
-					discover_descriptor_cb, user_data);
-}
-
-static void external_service_char_cb(uint8_t status, GSList *chars,
-								void *user_data)
-{
-	struct hog_device *hogdev = user_data;
-	struct gatt_primary *prim = hogdev->hog_primary;
-	struct report *report;
-	GSList *l;
-
-	if (status != 0) {
-		const char *str = att_ecode2str(status);
-		DBG("Discover external service characteristic failed: %s", str);
-		return;
-	}
-
-	for (l = chars; l; l = g_slist_next(l)) {
-		struct gatt_char *chr, *next;
-		uint16_t start, end;
-
-		chr = l->data;
-		next = l->next ? l->next->data : NULL;
-
-		DBG("0x%04x UUID: %s properties: %02x",
-				chr->handle, chr->uuid, chr->properties);
-
-		report = g_new0(struct report, 1);
-		report->hogdev = hogdev;
-		report->decl = g_memdup(chr, sizeof(*chr));
-		hogdev->reports = g_slist_append(hogdev->reports, report);
-		start = chr->value_handle + 1;
-		end = (next ? next->handle - 1 : prim->range.end);
-		discover_descriptor(hogdev->attrib, start, end, report);
-	}
-}
-
-static void external_report_reference_cb(guint8 status, const guint8 *pdu,
-					guint16 plen, gpointer user_data)
-{
-	struct hog_device *hogdev = user_data;
-	uint16_t uuid16;
-	bt_uuid_t uuid;
-
-	if (status != 0) {
-		error("Read External Report Reference descriptor failed: %s",
-							att_ecode2str(status));
-		return;
-	}
-
-	if (plen != 3) {
-		error("Malformed ATT read response");
-		return;
-	}
-
-	uuid16 = get_le16(&pdu[1]);
-	DBG("External report reference read, external report characteristic "
-						"UUID: 0x%04x", uuid16);
-	bt_uuid16_create(&uuid, uuid16);
-
-	// GFRM200 advertises battery service in its external report reference
-	// descriptor. However, the code below does not discover that service
-	// correctly and causes BlueZ to crash. Battery service is handled
-	// anyway in profiles/battery, so there is no need for HoG code to try
-	// to re-discover it. Comment this out.
-	//
-	//gatt_discover_char(hogdev->attrib, 0x0001, 0xffff, &uuid,
-	//				external_service_char_cb, hogdev);
-}
-
-static int report_cmp(gconstpointer a, gconstpointer b)
-{
-	const struct report *ra = a, *rb = b;
-
-	/* sort by type first.. */
-	if (ra->type != rb->type)
-		return ra->type - rb->type;
-
-	/* ..then by id */
-	return ra->id - rb->id;
-}
-
-static void output_written_cb(guint8 status, const guint8 *pdu,
-					guint16 plen, gpointer user_data)
-{
-	if (status != 0) {
-		error("Write output report failed: %s", att_ecode2str(status));
-		return;
-	}
-}
-
-static struct report *find_report(struct hog_device *hogdev, uint8_t type, uint8_t id)
-{
-	struct report cmp;
-	GSList *l;
-
-	switch (type) {
-	case UHID_FEATURE_REPORT:
-		cmp.type = HOG_REPORT_TYPE_FEATURE;
-		break;
-	case UHID_OUTPUT_REPORT:
-		cmp.type = HOG_REPORT_TYPE_OUTPUT;
-		break;
-	case UHID_INPUT_REPORT:
-		cmp.type = HOG_REPORT_TYPE_INPUT;
-		break;
-	default:
-		return NULL;
-	}
-
-	cmp.id = hogdev->has_report_id ? id : 0;
-
-	l = g_slist_find_custom(hogdev->reports, &cmp, report_cmp);
-
-	return l ? l->data : NULL;
-}
-
-static void forward_report(struct uhid_event *ev, void *user_data)
-{
-	struct hog_device *hogdev = user_data;
-	struct report *report;
-	void *data;
-	int size;
-
-	report = find_report(hogdev, ev->u.output.rtype, ev->u.output.data[0]);
-	if (!report)
-		return;
-
-	data = ev->u.output.data;
-	size = ev->u.output.size;
-	if (hogdev->has_report_id && size > 0) {
-		data++;
-		--size;
-	}
-
-	DBG("Sending report type %d ID %d to handle 0x%X", report->type,
-				report->id, report->decl->value_handle);
-
-	if (hogdev->attrib == NULL)
-		return;
-
-	if (report->decl->properties & GATT_CHR_PROP_WRITE)
-		gatt_write_char(hogdev->attrib, report->decl->value_handle,
-				data, size, output_written_cb, hogdev);
-	else if (report->decl->properties & GATT_CHR_PROP_WRITE_WITHOUT_RESP)
-		gatt_write_cmd(hogdev->attrib, report->decl->value_handle,
-						data, size, NULL, NULL);
-}
-
-static void set_report_cb(guint8 status, const guint8 *pdu,
-					guint16 plen, gpointer user_data)
-{
-	struct hog_device *hogdev = user_data;
-	struct uhid_event rsp;
-	int err;
-
-	hogdev->setrep_att = 0;
-
-	memset(&rsp, 0, sizeof(rsp));
-	rsp.type = UHID_SET_REPORT_REPLY;
-	rsp.u.set_report_reply.id = hogdev->setrep_id;
-	rsp.u.set_report_reply.err = status;
-
-	if (status != 0)
-		error("Error setting Report value: %s", att_ecode2str(status));
-
-	err = bt_uhid_send(hogdev->uhid, &rsp);
-	if (err < 0)
-		error("bt_uhid_send: %s", strerror(-err));
-}
-
-static void set_report(struct uhid_event *ev, void *user_data)
-{
-	struct hog_device *hogdev = user_data;
-	struct report *report;
-	void *data;
-	int size;
-	int err;
-
-	/* uhid never sends reqs in parallel; if there's a req, it timed out */
-	if (hogdev->setrep_att) {
-		g_attrib_cancel(hogdev->attrib, hogdev->setrep_att);
-		hogdev->setrep_att = 0;
-	}
-
-	hogdev->setrep_id = ev->u.set_report.id;
-
-	report = find_report(hogdev, ev->u.set_report.rtype,
-							ev->u.set_report.rnum);
-	if (!report) {
-		err = ENOTSUP;
-		goto fail;
-	}
-
-	data = ev->u.set_report.data;
-	size = ev->u.set_report.size;
-	if (hogdev->has_report_id && size > 0) {
-		data++;
-		--size;
-	}
-
-	DBG("Sending report type %d ID %d to handle 0x%X", report->type,
-				report->id, report->decl->value_handle);
-
-	if (hogdev->attrib == NULL)
-		return;
-
-	hogdev->setrep_att = gatt_write_char(hogdev->attrib,
-						report->decl->value_handle,
-						data, size, set_report_cb,
-						hogdev);
-	if (!hogdev->setrep_att) {
-		err = ENOMEM;
-		goto fail;
-	}
-
-	return;
-fail:
-	/* cancel the request on failure */
-	set_report_cb(err, NULL, 0, hogdev);
-}
-
-static void get_report_cb(guint8 status, const guint8 *pdu, guint16 len,
-							gpointer user_data)
-{
-	struct hog_device *hogdev = user_data;
-	struct uhid_event rsp;
-	int err;
-
-	hogdev->getrep_att = 0;
-
-	memset(&rsp, 0, sizeof(rsp));
-	rsp.type = UHID_GET_REPORT_REPLY;
-	rsp.u.get_report_reply.id = hogdev->getrep_id;
-
-	if (status != 0) {
-		error("Error reading Report value: %s", att_ecode2str(status));
-		goto exit;
-	}
-
-	if (len == 0) {
-		error("Error reading Report, length %d", len);
-		status = EIO;
-		goto exit;
-	}
-
-	if (pdu[0] != 0x0b) {
-		error("Error reading Report, invalid response: %02x", pdu[0]);
-		status = EPROTO;
-		goto exit;
-	}
-
-	--len;
-	++pdu;
-	if (hogdev->has_report_id && len > 0) {
-		--len;
-		++pdu;
-	}
-
-	rsp.u.get_report_reply.size = len;
-	memcpy(rsp.u.get_report_reply.data, pdu, len);
-
-exit:
-	rsp.u.get_report_reply.err = status;
-	err = bt_uhid_send(hogdev->uhid, &rsp);
-	if (err < 0)
-		error("bt_uhid_send: %s", strerror(-err));
-}
-
-static void get_report(struct uhid_event *ev, void *user_data)
-{
-	struct hog_device *hogdev = user_data;
-	struct report *report;
-	guint8 err;
-
-	/* uhid never sends reqs in parallel; if there's a req, it timed out */
-	if (hogdev->getrep_att) {
-		g_attrib_cancel(hogdev->attrib, hogdev->getrep_att);
-		hogdev->getrep_att = 0;
-	}
-
-	hogdev->getrep_id = ev->u.get_report.id;
-
-	report = find_report(hogdev, ev->u.get_report.rtype,
-							ev->u.get_report.rnum);
-	if (!report) {
-		err = ENOTSUP;
-		goto fail;
-	}
-
-	hogdev->getrep_att = gatt_read_char(hogdev->attrib,
-						report->decl->value_handle,
-						get_report_cb, hogdev);
-	if (!hogdev->getrep_att) {
-		err = ENOMEM;
-		goto fail;
-	}
-
-	return;
-
-fail:
-	/* cancel the request on failure */
-	get_report_cb(err, NULL, 0, hogdev);
-}
-
-static bool get_descriptor_item_info(uint8_t *buf, ssize_t blen, ssize_t *len,
-								bool *is_long)
-{
-	if (!blen)
-		return false;
-
-	*is_long = (buf[0] == 0xfe);
-
-	if (*is_long) {
-		if (blen < 3)
-			return false;
-
-		/*
-		 * long item:
-		 * byte 0 -> 0xFE
-		 * byte 1 -> data size
-		 * byte 2 -> tag
-		 * + data
-		 */
-
-		*len = buf[1] + 3;
-	} else {
-		uint8_t b_size;
-
-		/*
-		 * short item:
-		 * byte 0[1..0] -> data size (=0, 1, 2, 4)
-		 * byte 0[3..2] -> type
-		 * byte 0[7..4] -> tag
-		 * + data
-		 */
-
-		b_size = buf[0] & 0x03;
-		*len = (b_size ? 1 << (b_size - 1) : 0) + 1;
-	}
-
-	/* item length should be no more than input buffer length */
-	return *len <= blen;
-}
-
-static char *item2string(char *str, uint8_t *buf, uint8_t len)
-{
-	char *p = str;
-	int i;
-
-	/*
-	 * Since long item tags are not defined except for vendor ones, we
-	 * just ensure that short items are printed properly (up to 5 bytes).
-	 */
-	for (i = 0; i < 6 && i < len; i++)
-		p += sprintf(p, " %02x", buf[i]);
-
-	/*
-	 * If there are some data left, just add continuation mark to indicate
-	 * this.
-	 */
-	if (i < len)
-		sprintf(p, " ...");
-
-	return str;
-}
-
-static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
-							gpointer user_data)
-{
-	struct hog_device *hogdev = user_data;
-	struct btd_adapter *adapter = device_get_adapter(hogdev->device);
-	uint8_t value[HOG_REPORT_MAP_MAX_SIZE];
-	struct uhid_event ev;
-	uint16_t vendor_src, vendor, product, version;
-	ssize_t vlen;
-	char itemstr[20]; /* 5x3 (data) + 4 (continuation) + 1 (null) */
-	int i, err;
-	GSList *l;
-
-	DBG("HoG inspecting report map");
-
-	if (status != 0) {
-		error("Report Map read failed: %s", att_ecode2str(status));
-		return;
-	}
-
-	vlen = dec_read_resp(pdu, plen, value, sizeof(value));
-	if (vlen < 0) {
-		error("ATT protocol error");
-		return;
-	}
-
-	DBG("Report MAP:");
-	for (i = 0; i < vlen;) {
-		ssize_t ilen = 0;
-		bool long_item = false;
-
-		if (get_descriptor_item_info(&value[i], vlen - i, &ilen,
-								&long_item)) {
-			/* Report ID is short item with prefix 100001xx */
-			if (!long_item && (value[i] & 0xfc) == 0x84)
-				hogdev->has_report_id = TRUE;
-
-			DBG("\t%s", item2string(itemstr, &value[i], ilen));
-
-			i += ilen;
-		} else {
-			error("Report Map parsing failed at %d", i);
-
-			/* Just print remaining items at once and break */
-			DBG("\t%s", item2string(itemstr, &value[i], vlen - i));
-			break;
-		}
-	}
-
-	vendor_src = btd_device_get_vendor_src(hogdev->device);
-	vendor = btd_device_get_vendor(hogdev->device);
-	product = btd_device_get_product(hogdev->device);
-	version = btd_device_get_version(hogdev->device);
-	DBG("DIS information: vendor_src=0x%X, vendor=0x%X, product=0x%X, "
-			"version=0x%X",	vendor_src, vendor, product, version);
-
-	/* create uHID device */
-	memset(&ev, 0, sizeof(ev));
-	ev.type = UHID_CREATE;
-	if (device_name_known(hogdev->device))
-		device_get_name(hogdev->device, (char *) ev.u.create.name,
-						sizeof(ev.u.create.name));
-	else
-		strcpy((char *) ev.u.create.name, "bluez-hog-device");
-	ba2str(btd_adapter_get_address(adapter), (char *) ev.u.create.phys);
-	ba2str(device_get_address(hogdev->device), (char *) ev.u.create.uniq);
-	ev.u.create.vendor = vendor;
-	ev.u.create.product = product;
-	ev.u.create.version = version;
-	ev.u.create.country = hogdev->bcountrycode;
-	ev.u.create.bus = BUS_BLUETOOTH;
-	ev.u.create.rd_data = value;
-	ev.u.create.rd_size = vlen;
-
-	err = bt_uhid_send(hogdev->uhid, &ev);
-	if (err < 0) {
-		error("bt_uhid_send: %s", strerror(-err));
-		return;
-	}
-
-	bt_uhid_register(hogdev->uhid, UHID_OUTPUT, forward_report, hogdev);
-	bt_uhid_register(hogdev->uhid, UHID_SET_REPORT, set_report, hogdev);
-	bt_uhid_register(hogdev->uhid, UHID_GET_REPORT, get_report, hogdev);
-
-	hogdev->uhid_created = TRUE;
-	DBG("HoG created uHID device");
-
-	for (l = hogdev->reports; l; l = l->next) {
-		struct report *r = l->data;
-
-		enable_report_notifications(r, true);
-	}
-}
-
-static void info_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
-							gpointer user_data)
-{
-	struct hog_device *hogdev = user_data;
-	uint8_t value[HID_INFO_SIZE];
-	ssize_t vlen;
-
-	if (status != 0) {
-		error("HID Information read failed: %s",
-						att_ecode2str(status));
-		return;
-	}
-
-	vlen = dec_read_resp(pdu, plen, value, sizeof(value));
-	if (vlen != 4) {
-		error("ATT protocol error");
-		return;
-	}
-
-	hogdev->bcdhid = get_le16(&value[0]);
-	hogdev->bcountrycode = value[2];
-	hogdev->flags = value[3];
-
-	DBG("bcdHID: 0x%04X bCountryCode: 0x%02X Flags: 0x%02X",
-			hogdev->bcdhid, hogdev->bcountrycode, hogdev->flags);
-}
-
-static void proto_mode_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
-							gpointer user_data)
-{
-	struct hog_device *hogdev = user_data;
-	uint8_t value;
-	ssize_t vlen;
-
-	if (status != 0) {
-		error("Protocol Mode characteristic read failed: %s",
-							att_ecode2str(status));
-		return;
-	}
-
-	vlen = dec_read_resp(pdu, plen, &value, sizeof(value));
-	if (vlen < 0) {
-		error("ATT protocol error");
-		return;
-	}
-
-	if (value == HOG_PROTO_MODE_BOOT) {
-		uint8_t nval = HOG_PROTO_MODE_REPORT;
-
-		DBG("HoG device 0x%04X is operating in Boot Procotol Mode",
-								hogdev->id);
-
-		gatt_write_cmd(hogdev->attrib, hogdev->proto_mode_handle, &nval,
-						sizeof(nval), NULL, NULL);
-	} else if (value == HOG_PROTO_MODE_REPORT)
-		DBG("HoG device 0x%04X is operating in Report Protocol Mode",
-								hogdev->id);
-}
-
-static void char_discovered_cb(uint8_t status, GSList *chars, void *user_data)
-{
-	struct hog_device *hogdev = user_data;
-	struct gatt_primary *prim = hogdev->hog_primary;
-	bt_uuid_t report_uuid, report_map_uuid, info_uuid;
-	bt_uuid_t proto_mode_uuid, ctrlpt_uuid;
-	struct report *report;
-	GSList *l;
-	uint16_t info_handle = 0, proto_mode_handle = 0;
-
-	DBG("HoG inspecting characteristics");
-
-	if (status != 0) {
-		const char *str = att_ecode2str(status);
-		DBG("Discover all characteristics failed: %s", str);
-		return;
-	}
-
-	bt_uuid16_create(&report_uuid, HOG_REPORT_UUID);
-	bt_uuid16_create(&report_map_uuid, HOG_REPORT_MAP_UUID);
-	bt_uuid16_create(&info_uuid, HOG_INFO_UUID);
-	bt_uuid16_create(&proto_mode_uuid, HOG_PROTO_MODE_UUID);
-	bt_uuid16_create(&ctrlpt_uuid, HOG_CONTROL_POINT_UUID);
-
-	for (l = chars; l; l = g_slist_next(l)) {
-		struct gatt_char *chr, *next;
-		bt_uuid_t uuid;
-		uint16_t start, end;
-
-		chr = l->data;
-		next = l->next ? l->next->data : NULL;
-
-		DBG("0x%04x UUID: %s properties: %02x",
-				chr->handle, chr->uuid, chr->properties);
-
-		bt_string_to_uuid(&uuid, chr->uuid);
-
-		start = chr->value_handle + 1;
-		end = (next ? next->handle - 1 : prim->range.end);
-
-		if (bt_uuid_cmp(&uuid, &report_uuid) == 0) {
-			report = g_new0(struct report, 1);
-			report->hogdev = hogdev;
-			report->decl = g_memdup(chr, sizeof(*chr));
-			hogdev->reports = g_slist_append(hogdev->reports,
-								report);
-			discover_descriptor(hogdev->attrib, start, end, report);
-		} else if (bt_uuid_cmp(&uuid, &report_map_uuid) == 0) {
-			DBG("HoG discovering report map");
-			gatt_read_char(hogdev->attrib, chr->value_handle,
-						report_map_read_cb, hogdev);
-			discover_descriptor(hogdev->attrib, start, end, hogdev);
-		} else if (bt_uuid_cmp(&uuid, &info_uuid) == 0)
-			info_handle = chr->value_handle;
-		else if (bt_uuid_cmp(&uuid, &proto_mode_uuid) == 0)
-			proto_mode_handle = chr->value_handle;
-		else if (bt_uuid_cmp(&uuid, &ctrlpt_uuid) == 0)
-			hogdev->ctrlpt_handle = chr->value_handle;
-	}
-
-	if (proto_mode_handle) {
-		hogdev->proto_mode_handle = proto_mode_handle;
-		gatt_read_char(hogdev->attrib, proto_mode_handle,
-						proto_mode_read_cb, hogdev);
-	}
-
-	if (info_handle)
-		gatt_read_char(hogdev->attrib, info_handle, info_read_cb,
-									hogdev);
-}
-
-static void report_free(void *data)
-{
-	struct report *report = data;
-	struct hog_device *hogdev = report->hogdev;
-
-	if (hogdev->attrib)
-		g_attrib_unregister(hogdev->attrib, report->notifyid);
-
-	g_free(report->decl);
-	g_free(report);
-}
+static struct queue *devices = NULL;
 
 static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
 {
-	struct hog_device *hogdev = user_data;
-	struct gatt_primary *prim = hogdev->hog_primary;
-	GSList *l;
+	struct hog_device *dev = user_data;
 
 	DBG("HoG connected");
 
-	if (!hogdev->uhid_created && hogdev->reports) {
-		DBG("HoG init failed previously, preparing for re-init");
-		g_slist_free_full(hogdev->reports, report_free);
-		hogdev->reports = NULL;
-	}
-
-	hogdev->attrib = g_attrib_ref(attrib);
-
-	if (hogdev->reports == NULL) {
-		DBG("HoG discovering characteristics");
-		gatt_discover_char(hogdev->attrib, prim->range.start,
-						prim->range.end, NULL,
-						char_discovered_cb, hogdev);
-		return;
-	}
-
-	for (l = hogdev->reports; l; l = l->next) {
-		struct report *r = l->data;
-
-		// GFRM200: Re-enable HoG report notifications on HoG reconnect
-		enable_report_notifications(r, true);
-	}
+	bt_hog_attach(dev->hog, attrib);
 }
 
 static void attio_disconnected_cb(gpointer user_data)
 {
-	struct hog_device *hogdev = user_data;
-	GSList *l;
+	struct hog_device *dev = user_data;
 
 	DBG("HoG disconnected");
 
-	for (l = hogdev->reports; l; l = l->next) {
-		struct report *r = l->data;
-
-		g_attrib_unregister(hogdev->attrib, r->notifyid);
-	}
-
-	g_attrib_unref(hogdev->attrib);
-	hogdev->attrib = NULL;
+	bt_hog_detach(dev->hog);
 }
 
-static struct hog_device *hog_new_device(struct btd_device *device,
-								uint16_t id)
-{
-	struct hog_device *hogdev;
-
-	hogdev = g_try_new0(struct hog_device, 1);
-	if (!hogdev)
-		return NULL;
-
-	hogdev->id = id;
-	hogdev->device = btd_device_ref(device);
-
-	return hogdev;
-}
-
-static void hog_free_device(struct hog_device *hogdev)
-{
-	btd_device_unref(hogdev->device);
-	g_slist_free_full(hogdev->reports, report_free);
-	g_attrib_unref(hogdev->attrib);
-	g_free(hogdev->hog_primary);
-	g_free(hogdev);
-}
-
-static struct hog_device *hog_register_device(struct btd_device *device,
+static struct hog_device *hog_device_new(struct btd_device *device,
 						struct gatt_primary *prim)
 {
-	struct hog_device *hogdev;
+	struct hog_device *dev;
+	char name[248];
+	uint16_t vendor, product, version;
 
-	hogdev = hog_new_device(device, prim->range.start);
-	if (!hogdev)
-		return NULL;
+	if (device_name_known(device))
+		device_get_name(device, name, sizeof(name));
+	else
+		strcpy(name, "bluez-hog-device");
 
-	hogdev->uhid = bt_uhid_new_default();
-	if (!hogdev->uhid) {
-		error("bt_uhid_new_default: failed");
-		hog_free_device(hogdev);
-		return NULL;
-	}
+	vendor = btd_device_get_vendor(device);
+	product = btd_device_get_product(device);
+	version = btd_device_get_version(device);
 
-	hogdev->hog_primary = g_memdup(prim, sizeof(*prim));
+	DBG("name=%s vendor=0x%X, product=0x%X, version=0x%X", name, vendor,
+							product, version);
 
-	hogdev->attioid = btd_device_add_attio_callback(device,
+	dev = new0(struct hog_device, 1);
+	dev->device = btd_device_ref(device);
+	dev->hog = bt_hog_new_default(name, vendor, product, version, prim);
+
+	/*
+	 * TODO: Remove attio callback and use .accept once using
+	 * bt_gatt_client.
+	 */
+	dev->attioid = btd_device_add_attio_callback(device,
 							attio_connected_cb,
 							attio_disconnected_cb,
-							hogdev);
+							dev);
 
-	return hogdev;
+	if (!devices)
+		devices = queue_new();
+
+	queue_push_tail(devices, dev);
+
+	return dev;
 }
 
-static int hog_unregister_device(struct hog_device *hogdev)
+static void hog_device_free(void *data)
 {
-	btd_device_remove_attio_callback(hogdev->device, hogdev->attioid);
-	bt_uhid_unref(hogdev->uhid);
-	hog_free_device(hogdev);
+	struct hog_device *dev = data;
 
-	return 0;
-}
+	queue_remove(devices, dev);
+	if (queue_isempty(devices)) {
+		queue_destroy(devices, NULL);
+		devices = NULL;
+	}
 
-static int set_control_point(struct hog_device *hogdev, gboolean suspend)
-{
-	uint8_t value = suspend ? 0x00 : 0x01;
-
-	if (hogdev->attrib == NULL)
-		return -ENOTCONN;
-
-	DBG("0x%4X HID Control Point: %s", hogdev->id, suspend ?
-						"Suspend" : "Exit Suspend");
-
-	if (hogdev->ctrlpt_handle == 0)
-		return -ENOTSUP;
-
-	gatt_write_cmd(hogdev->attrib, hogdev->ctrlpt_handle, &value,
-					sizeof(value), NULL, NULL);
-
-	return 0;
+	btd_device_remove_attio_callback(dev->device, dev->attioid);
+	btd_device_unref(dev->device);
+	bt_hog_unref(dev->hog);
+	free(dev);
 }
 
 static void set_suspend(gpointer data, gpointer user_data)
 {
-	struct hog_device *hogdev = data;
+	struct hog_device *dev = data;
 	gboolean suspend = GPOINTER_TO_INT(user_data);
 
-	set_control_point(hogdev, suspend);
+	bt_hog_set_control_point(dev->hog, suspend);
 }
 
 static void suspend_callback(void)
@@ -1004,7 +157,7 @@
 
 	DBG("Suspending ...");
 
-	g_slist_foreach(devices, set_suspend, GINT_TO_POINTER(suspend));
+	queue_foreach(devices, set_suspend, GINT_TO_POINTER(suspend));
 }
 
 static void resume_callback(void)
@@ -1013,7 +166,7 @@
 
 	DBG("Resuming ...");
 
-	g_slist_foreach(devices, set_suspend, GINT_TO_POINTER(suspend));
+	queue_foreach(devices, set_suspend, GINT_TO_POINTER(suspend));
 }
 
 static int hog_probe(struct btd_service *service)
@@ -1030,41 +183,28 @@
 
 	for (l = primaries; l; l = g_slist_next(l)) {
 		struct gatt_primary *prim = l->data;
-		struct hog_device *hogdev;
+		struct hog_device *dev;
 
 		if (strcmp(prim->uuid, HOG_UUID) != 0)
 			continue;
 
-		hogdev = hog_register_device(device, prim);
-		if (hogdev == NULL)
-			continue;
-
-		devices = g_slist_append(devices, hogdev);
+		dev = hog_device_new(device, prim);
+		btd_service_set_user_data(service, dev);
+		return 0;
 	}
 
-	return 0;
-}
-
-static void remove_device(gpointer a, gpointer b)
-{
-	struct hog_device *hogdev = a;
-	struct btd_device *device = b;
-
-	if (hogdev->device != device)
-		return;
-
-	devices = g_slist_remove(devices, hogdev);
-	hog_unregister_device(hogdev);
+	return -EINVAL;
 }
 
 static void hog_remove(struct btd_service *service)
 {
+	struct hog_device *dev = btd_service_get_user_data(service);
 	struct btd_device *device = btd_service_get_device(service);
 	const char *path = device_get_path(device);
 
 	DBG("path %s", path);
 
-	g_slist_foreach(devices, remove_device, device);
+	hog_device_free(dev);
 }
 
 static struct btd_profile hog_profile = {
diff --git a/android/scpp.c b/profiles/scanparam/scpp.c
similarity index 93%
rename from android/scpp.c
rename to profiles/scanparam/scpp.c
index f8f81f3..df65d2c 100644
--- a/android/scpp.c
+++ b/profiles/scanparam/scpp.c
@@ -44,7 +44,7 @@
 #include "attrib/gattrib.h"
 #include "attrib/gatt.h"
 
-#include "android/scpp.h"
+#include "profiles/scanparam/scpp.h"
 
 #define SCAN_INTERVAL_WIN_UUID		0x2A4F
 #define SCAN_REFRESH_UUID		0x2A31
@@ -74,11 +74,7 @@
 
 	id = gatt_discover_char(attrib, start, end, uuid, func, user_data);
 
-	if (queue_push_head(scpp->gatt_op, UINT_TO_PTR(id)))
-		return;
-
-	error("scpp: Could not discover characteristic");
-	g_attrib_cancel(attrib, id);
+	queue_push_head(scpp->gatt_op, UINT_TO_PTR(id));
 }
 
 static void discover_desc(struct bt_scpp *scpp, GAttrib *attrib,
@@ -89,11 +85,7 @@
 
 	id = gatt_discover_desc(attrib, start, end, uuid, func, user_data);
 
-	if (queue_push_head(scpp->gatt_op, UINT_TO_PTR(id)))
-		return;
-
-	error("scpp: Could not discover descriptor");
-	g_attrib_cancel(attrib, id);
+	queue_push_head(scpp->gatt_op, UINT_TO_PTR(id));
 }
 
 static void write_char(struct bt_scpp *scan, GAttrib *attrib, uint16_t handle,
@@ -105,11 +97,7 @@
 
 	id = gatt_write_char(attrib, handle, value, vlen, func, user_data);
 
-	if (queue_push_head(scan->gatt_op, UINT_TO_PTR(id)))
-		return;
-
-	error("scpp: Could not read char");
-	g_attrib_cancel(attrib, id);
+	queue_push_head(scan->gatt_op, UINT_TO_PTR(id));
 }
 
 static void scpp_free(struct bt_scpp *scan)
@@ -133,10 +121,6 @@
 	scan->window = SCAN_WINDOW;
 
 	scan->gatt_op = queue_new();
-	if (!scan->gatt_op) {
-		scpp_free(scan);
-		return NULL;
-	}
 
 	if (primary)
 		scan->primary = g_memdup(primary, sizeof(*scan->primary));
diff --git a/android/scpp.h b/profiles/scanparam/scpp.h
similarity index 100%
rename from android/scpp.h
rename to profiles/scanparam/scpp.h
diff --git a/src/adapter.c b/src/adapter.c
index 9c5122a..fcc7a09 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -318,7 +318,8 @@
 	uint32_t dev_class;
 
 	if (length < sizeof(*rp)) {
-		error("Wrong size of class of device changed parameters");
+		btd_error(adapter->dev_id,
+			"Wrong size of class of device changed parameters");
 		return;
 	}
 
@@ -341,7 +342,8 @@
 	struct btd_adapter *adapter = user_data;
 
 	if (status != MGMT_STATUS_SUCCESS) {
-		error("Failed to set device class: %s (0x%02x)",
+		btd_error(adapter->dev_id,
+				"Failed to set device class: %s (0x%02x)",
 						mgmt_errstr(status), status);
 		return;
 	}
@@ -390,7 +392,8 @@
 				set_dev_class_complete, adapter, NULL) > 0)
 		return;
 
-	error("Failed to set class of device for index %u", adapter->dev_id);
+	btd_error(adapter->dev_id,
+		"Failed to set class of device for index %u", adapter->dev_id);
 }
 
 void btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
@@ -530,7 +533,8 @@
 	uint32_t settings;
 
 	if (length < sizeof(settings)) {
-		error("Wrong size of new settings parameters");
+		btd_error(adapter->dev_id,
+				"Wrong size of new settings parameters");
 		return;
 	}
 
@@ -550,7 +554,7 @@
 	struct btd_adapter *adapter = user_data;
 
 	if (status != MGMT_STATUS_SUCCESS) {
-		error("Failed to set mode: %s (0x%02x)",
+		btd_error(adapter->dev_id, "Failed to set mode: %s (0x%02x)",
 						mgmt_errstr(status), status);
 		return;
 	}
@@ -578,7 +582,8 @@
 				set_mode_complete, adapter, NULL) > 0)
 		return true;
 
-	error("Failed to set mode for index %u", adapter->dev_id);
+	btd_error(adapter->dev_id, "Failed to set mode for index %u",
+							adapter->dev_id);
 
 	return false;
 }
@@ -608,7 +613,8 @@
 				set_mode_complete, adapter, NULL) > 0)
 		return true;
 
-	error("Failed to set mode for index %u", adapter->dev_id);
+	btd_error(adapter->dev_id, "Failed to set mode for index %u",
+							adapter->dev_id);
 
 	return false;
 }
@@ -646,7 +652,8 @@
 	const struct mgmt_cp_set_local_name *rp = param;
 
 	if (length < sizeof(*rp)) {
-		error("Wrong size of local name changed parameters");
+		btd_error(adapter->dev_id,
+				"Wrong size of local name changed parameters");
 		return;
 	}
 
@@ -700,7 +707,8 @@
 	struct btd_adapter *adapter = user_data;
 
 	if (status != MGMT_STATUS_SUCCESS) {
-		error("Failed to set local name: %s (0x%02x)",
+		btd_error(adapter->dev_id,
+				"Failed to set local name: %s (0x%02x)",
 						mgmt_errstr(status), status);
 		return;
 	}
@@ -722,7 +730,8 @@
 	strncpy(maxname, name, MAX_NAME_LENGTH);
 
 	if (!g_utf8_validate(maxname, -1, NULL)) {
-		error("Name change failed: supplied name isn't valid UTF-8");
+		btd_error(adapter->dev_id,
+			"Name change failed: supplied name isn't valid UTF-8");
 		return -EINVAL;
 	}
 
@@ -736,7 +745,8 @@
 				set_local_name_complete, adapter, NULL) > 0)
 		return 0;
 
-	error("Failed to set local name for index %u", adapter->dev_id);
+	btd_error(adapter->dev_id, "Failed to set local name for index %u",
+							adapter->dev_id);
 
 	return -EIO;
 }
@@ -835,7 +845,7 @@
 	struct btd_adapter *adapter = user_data;
 
 	if (status != MGMT_STATUS_SUCCESS) {
-		error("Failed to add UUID: %s (0x%02x)",
+		btd_error(adapter->dev_id, "Failed to add UUID: %s (0x%02x)",
 						mgmt_errstr(status), status);
 		return;
 	}
@@ -859,7 +869,8 @@
 	uint128_t uint128;
 
 	if (!is_supported_uuid(uuid)) {
-		warn("Ignoring unsupported UUID for addition");
+		btd_warn(adapter->dev_id,
+				"Ignoring unsupported UUID for addition");
 		return 0;
 	}
 
@@ -876,7 +887,8 @@
 				add_uuid_complete, adapter, NULL) > 0)
 		return 0;
 
-	error("Failed to add UUID for index %u", adapter->dev_id);
+	btd_error(adapter->dev_id, "Failed to add UUID for index %u",
+							adapter->dev_id);
 
 	return -EIO;
 }
@@ -887,7 +899,7 @@
 	struct btd_adapter *adapter = user_data;
 
 	if (status != MGMT_STATUS_SUCCESS) {
-		error("Failed to remove UUID: %s (0x%02x)",
+		btd_error(adapter->dev_id, "Failed to remove UUID: %s (0x%02x)",
 						mgmt_errstr(status), status);
 		return;
 	}
@@ -911,7 +923,8 @@
 	uint128_t uint128;
 
 	if (!is_supported_uuid(uuid)) {
-		warn("Ignoring unsupported UUID for removal");
+		btd_warn(adapter->dev_id,
+				"Ignoring unsupported UUID for removal");
 		return 0;
 	}
 
@@ -927,7 +940,8 @@
 				remove_uuid_complete, adapter, NULL) > 0)
 		return 0;
 
-	error("Failed to remove UUID for index %u", adapter->dev_id);
+	btd_error(adapter->dev_id, "Failed to remove UUID for index %u",
+							adapter->dev_id);
 
 	return -EIO;
 }
@@ -938,7 +952,7 @@
 	struct btd_adapter *adapter = user_data;
 
 	if (status != MGMT_STATUS_SUCCESS) {
-		error("Failed to clear UUIDs: %s (0x%02x)",
+		btd_error(adapter->dev_id, "Failed to clear UUIDs: %s (0x%02x)",
 						mgmt_errstr(status), status);
 		return;
 	}
@@ -964,7 +978,8 @@
 				clear_uuids_complete, adapter, NULL) > 0)
 		return 0;
 
-	error("Failed to clear UUIDs for index %u", adapter->dev_id);
+	btd_error(adapter->dev_id, "Failed to clear UUIDs for index %u",
+							adapter->dev_id);
 
 	return -EIO;
 }
@@ -1195,7 +1210,8 @@
 	DBG("status 0x%02x", status);
 
 	if (length < sizeof(*rp)) {
-		error("Wrong size of start scanning return parameters");
+		btd_error(adapter->dev_id,
+			"Wrong size of start scanning return parameters");
 		return;
 	}
 
@@ -1298,7 +1314,7 @@
 	 * around the time we called stop_passive_scanning().
 	 */
 	if (status != MGMT_STATUS_SUCCESS && status != MGMT_STATUS_REJECTED) {
-		error("Stopping passive scanning failed: %s",
+		btd_error(adapter->dev_id, "Stopping passive scanning failed: %s",
 							mgmt_errstr(status));
 		return;
 	}
@@ -1314,8 +1330,8 @@
 
 	err = device_connect_le(dev);
 	if (err < 0) {
-		error("LE auto connection failed: %s (%d)",
-						strerror(-err), -err);
+		btd_error(adapter->dev_id, "LE auto connection failed: %s (%d)",
+							strerror(-err), -err);
 		trigger_passive_scanning(adapter);
 	}
 }
@@ -1389,7 +1405,8 @@
 	DBG("status 0x%02x", status);
 
 	if (length < sizeof(*rp)) {
-		error("Wrong size of start discovery return parameters");
+		btd_error(adapter->dev_id,
+			"Wrong size of start discovery return parameters");
 		return;
 	}
 
@@ -1605,7 +1622,7 @@
 	struct btd_adapter *adapter = user_data;
 
 	if (length < sizeof(*ev)) {
-		error("Too small discovering event");
+		btd_error(adapter->dev_id, "Too small discovering event");
 		return;
 	}
 
@@ -1902,7 +1919,8 @@
 	DBG("");
 
 	if (discovery_filter_to_mgmt_cp(adapter, &sd_cp)) {
-		error("discovery_filter_to_mgmt_cp returned error");
+		btd_error(adapter->dev_id,
+				"discovery_filter_to_mgmt_cp returned error");
 		return;
 	}
 
@@ -2517,7 +2535,7 @@
 	if (status != MGMT_STATUS_SUCCESS) {
 		const char *dbus_err;
 
-		error("Failed to set mode: %s (0x%02x)",
+		btd_error(adapter->dev_id, "Failed to set mode: %s (0x%02x)",
 						mgmt_errstr(status), status);
 
 		if (status == MGMT_STATUS_RFKILLED)
@@ -2619,7 +2637,8 @@
 	g_free(data);
 
 failed:
-	error("Failed to set mode for index %u", adapter->dev_id);
+	btd_error(adapter->dev_id, "Failed to set mode for index %u",
+							adapter->dev_id);
 
 	g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed", NULL);
 }
@@ -3125,7 +3144,8 @@
 	struct btd_adapter *adapter = user_data;
 
 	if (status != MGMT_STATUS_SUCCESS) {
-		error("Failed to load link keys for hci%u: %s (0x%02x)",
+		btd_error(adapter->dev_id,
+			"Failed to load link keys for hci%u: %s (0x%02x)",
 				adapter->dev_id, mgmt_errstr(status), status);
 		return;
 	}
@@ -3161,7 +3181,8 @@
 
 	cp = g_try_malloc0(cp_size);
 	if (cp == NULL) {
-		error("No memory for link keys for hci%u", adapter->dev_id);
+		btd_error(adapter->dev_id, "No memory for link keys for hci%u",
+							adapter->dev_id);
 		return;
 	}
 
@@ -3193,14 +3214,16 @@
 	g_free(cp);
 
 	if (id == 0)
-		error("Failed to load link keys for hci%u", adapter->dev_id);
+		btd_error(adapter->dev_id, "Failed to load link keys for hci%u",
+							adapter->dev_id);
 }
 
 static gboolean load_ltks_timeout(gpointer user_data)
 {
 	struct btd_adapter *adapter = user_data;
 
-	error("Loading LTKs timed out for hci%u", adapter->dev_id);
+	btd_error(adapter->dev_id, "Loading LTKs timed out for hci%u",
+							adapter->dev_id);
 
 	adapter->load_ltks_timeout = 0;
 
@@ -3216,7 +3239,8 @@
 	struct btd_adapter *adapter = user_data;
 
 	if (status != MGMT_STATUS_SUCCESS) {
-		error("Failed to load LTKs for hci%u: %s (0x%02x)",
+		btd_error(adapter->dev_id,
+				"Failed to load LTKs for hci%u: %s (0x%02x)",
 				adapter->dev_id, mgmt_errstr(status), status);
 	}
 
@@ -3256,7 +3280,8 @@
 
 	cp = g_try_malloc0(cp_size);
 	if (cp == NULL) {
-		error("No memory for LTKs for hci%u", adapter->dev_id);
+		btd_error(adapter->dev_id, "No memory for LTKs for hci%u",
+							adapter->dev_id);
 		return;
 	}
 
@@ -3288,7 +3313,8 @@
 	g_free(cp);
 
 	if (adapter->load_ltks_id == 0) {
-		error("Failed to load LTKs for hci%u", adapter->dev_id);
+		btd_error(adapter->dev_id, "Failed to load LTKs for hci%u",
+							adapter->dev_id);
 		return;
 	}
 
@@ -3307,12 +3333,14 @@
 	struct btd_adapter *adapter = user_data;
 
 	if (status == MGMT_STATUS_UNKNOWN_COMMAND) {
-		info("Load IRKs failed: Kernel doesn't support LE Privacy");
+		btd_info(adapter->dev_id,
+			"Load IRKs failed: Kernel doesn't support LE Privacy");
 		return;
 	}
 
 	if (status != MGMT_STATUS_SUCCESS) {
-		error("Failed to load IRKs for hci%u: %s (0x%02x)",
+		btd_error(adapter->dev_id,
+				"Failed to load IRKs for hci%u: %s (0x%02x)",
 				adapter->dev_id, mgmt_errstr(status), status);
 		return;
 	}
@@ -3344,7 +3372,8 @@
 
 	cp = g_try_malloc0(cp_size);
 	if (cp == NULL) {
-		error("No memory for IRKs for hci%u", adapter->dev_id);
+		btd_error(adapter->dev_id, "No memory for IRKs for hci%u",
+							adapter->dev_id);
 		return;
 	}
 
@@ -3369,7 +3398,8 @@
 	g_free(cp);
 
 	if (id == 0)
-		error("Failed to IRKs for hci%u", adapter->dev_id);
+		btd_error(adapter->dev_id, "Failed to IRKs for hci%u",
+							adapter->dev_id);
 }
 
 static void load_conn_params_complete(uint8_t status, uint16_t length,
@@ -3378,7 +3408,8 @@
 	struct btd_adapter *adapter = user_data;
 
 	if (status != MGMT_STATUS_SUCCESS) {
-		error("hci%u Load Connection Parameters failed: %s (0x%02x)",
+		btd_error(adapter->dev_id,
+			"hci%u Load Connection Parameters failed: %s (0x%02x)",
 				adapter->dev_id, mgmt_errstr(status), status);
 		return;
 	}
@@ -3410,7 +3441,8 @@
 
 	cp = g_try_malloc0(cp_size);
 	if (cp == NULL) {
-		error("Failed to allocate memory for connection parameters");
+		btd_error(adapter->dev_id,
+			"Failed to allocate memory for connection parameters");
 		return;
 	}
 
@@ -3433,7 +3465,7 @@
 	g_free(cp);
 
 	if (id == 0)
-		error("Load connection parameters failed");
+		btd_error(adapter->dev_id, "Load connection parameters failed");
 }
 
 static uint8_t get_le_addr_type(GKeyFile *keyfile)
@@ -3482,7 +3514,9 @@
 
 	dir = opendir(dirname);
 	if (!dir) {
-		error("Unable to open adapter storage directory: %s", dirname);
+		btd_error(adapter->dev_id,
+				"Unable to open adapter storage directory: %s",
+								dirname);
 		return;
 	}
 
@@ -3631,7 +3665,8 @@
 
 	err = driver->probe(adapter);
 	if (err < 0) {
-		error("%s: %s (%d)", driver->name, strerror(-err), -err);
+		btd_error(adapter->dev_id, "%s: %s (%d)", driver->name,
+							strerror(-err), -err);
 		return;
 	}
 
@@ -3656,7 +3691,8 @@
 
 	err = profile->adapter_probe(profile, adapter);
 	if (err < 0) {
-		error("%s: %s (%d)", profile->name, strerror(-err), -err);
+		btd_error(adapter->dev_id, "%s: %s (%d)", profile->name,
+							strerror(-err), -err);
 		return;
 	}
 
@@ -3698,7 +3734,8 @@
 	device_add_connection(device, bdaddr_type);
 
 	if (g_slist_find(adapter->connections, device)) {
-		error("Device is already marked as connected");
+		btd_error(adapter->dev_id,
+				"Device is already marked as connected");
 		return;
 	}
 
@@ -3713,13 +3750,15 @@
 	uint16_t i, conn_count;
 
 	if (status != MGMT_STATUS_SUCCESS) {
-		error("Failed to get connections: %s (0x%02x)",
+		btd_error(adapter->dev_id,
+				"Failed to get connections: %s (0x%02x)",
 						mgmt_errstr(status), status);
 		return;
 	}
 
 	if (length < sizeof(*rp)) {
-		error("Wrong size of get connections response");
+		btd_error(adapter->dev_id,
+				"Wrong size of get connections response");
 		return;
 	}
 
@@ -3729,7 +3768,8 @@
 
 	if (conn_count * sizeof(struct mgmt_addr_info) +
 						sizeof(*rp) != length) {
-		error("Incorrect packet size for get connections response");
+		btd_error(adapter->dev_id,
+			"Incorrect packet size for get connections response");
 		return;
 	}
 
@@ -3757,7 +3797,8 @@
 				get_connections_complete, adapter, NULL) > 0)
 		return;
 
-	error("Failed to get connections for index %u", adapter->dev_id);
+	btd_error(adapter->dev_id, "Failed to get connections for index %u",
+							adapter->dev_id);
 }
 
 bool btd_adapter_get_pairable(struct btd_adapter *adapter)
@@ -3834,7 +3875,8 @@
 	}
 
 	if (!(adapter->supported_settings & MGMT_SETTING_LE)) {
-		error("Can't add %s to non-LE capable adapter connect list",
+		btd_error(adapter->dev_id,
+			"Can't add %s to non-LE capable adapter connect list",
 						device_get_path(device));
 		return -ENOTSUP;
 	}
@@ -3896,7 +3938,8 @@
 	char addr[18];
 
 	if (length < sizeof(*rp)) {
-		error("Too small Add Device complete event");
+		btd_error(adapter->dev_id,
+				"Too small Add Device complete event");
 		return;
 	}
 
@@ -3905,12 +3948,14 @@
 	dev = btd_adapter_find_device(adapter, &rp->addr.bdaddr,
 							rp->addr.type);
 	if (!dev) {
-		error("Add Device complete for unknown device %s", addr);
+		btd_error(adapter->dev_id,
+			"Add Device complete for unknown device %s", addr);
 		return;
 	}
 
 	if (status != MGMT_STATUS_SUCCESS) {
-		error("Failed to add device %s: %s (0x%02x)",
+		btd_error(adapter->dev_id,
+					"Failed to add device %s: %s (0x%02x)",
 					addr, mgmt_errstr(status), status);
 		return;
 	}
@@ -3982,7 +4027,8 @@
 	char addr[18];
 
 	if (length < sizeof(*rp)) {
-		error("Too small Add Device complete event");
+		btd_error(adapter->dev_id,
+				"Too small Add Device complete event");
 		return;
 	}
 
@@ -3991,12 +4037,14 @@
 	dev = btd_adapter_find_device(adapter, &rp->addr.bdaddr,
 							rp->addr.type);
 	if (!dev) {
-		error("Add Device complete for unknown device %s", addr);
+		btd_error(adapter->dev_id,
+			"Add Device complete for unknown device %s", addr);
 		return;
 	}
 
 	if (status != MGMT_STATUS_SUCCESS) {
-		error("Failed to add device %s (%u): %s (0x%02x)",
+		btd_error(adapter->dev_id,
+			"Failed to add device %s (%u): %s (0x%02x)",
 			addr, rp->addr.type, mgmt_errstr(status), status);
 		adapter->connect_list = g_slist_remove(adapter->connect_list,
 									dev);
@@ -5223,7 +5271,8 @@
 {
 	struct btd_adapter *adapter = user_data;
 
-	error("Confirm name timed out for hci%u", adapter->dev_id);
+	btd_error(adapter->dev_id, "Confirm name timed out for hci%u",
+							adapter->dev_id);
 
 	adapter->confirm_name_timeout = 0;
 
@@ -5239,7 +5288,8 @@
 	struct btd_adapter *adapter = user_data;
 
 	if (status != MGMT_STATUS_SUCCESS) {
-		error("Failed to confirm name for hci%u: %s (0x%02x)",
+		btd_error(adapter->dev_id,
+				"Failed to confirm name for hci%u: %s (0x%02x)",
 				adapter->dev_id, mgmt_errstr(status), status);
 	}
 
@@ -5269,7 +5319,9 @@
 	 * cancel it to be safe here.
 	 */
 	if (adapter->confirm_name_id > 0) {
-		warn("Found pending confirm name for hci%u", adapter->dev_id);
+		btd_warn(adapter->dev_id,
+				"Found pending confirm name for hci%u",
+							adapter->dev_id);
 		mgmt_cancel(adapter->mgmt, adapter->confirm_name_id);
 	}
 
@@ -5289,7 +5341,8 @@
 					confirm_name_complete, adapter, NULL);
 
 	if (adapter->confirm_name_id == 0) {
-		error("Failed to confirm name for hci%u", adapter->dev_id);
+		btd_error(adapter->dev_id, "Failed to confirm name for hci%u",
+							adapter->dev_id);
 		return;
 	}
 
@@ -5417,7 +5470,8 @@
 	}
 
 	if (!dev) {
-		error("Unable to create object for found device %s", addr);
+		btd_error(adapter->dev_id,
+			"Unable to create object for found device %s", addr);
 		eir_data_free(&eir_data);
 		return;
 	}
@@ -5559,13 +5613,15 @@
 	char addr[18];
 
 	if (length < sizeof(*ev)) {
-		error("Too short device found event (%u bytes)", length);
+		btd_error(adapter->dev_id,
+			"Too short device found event (%u bytes)", length);
 		return;
 	}
 
 	eir_len = btohs(ev->eir_len);
 	if (length != sizeof(*ev) + eir_len) {
-		error("Device found event size mismatch (%u != %zu)",
+		btd_error(adapter->dev_id,
+				"Device found event size mismatch (%u != %zu)",
 					length, sizeof(*ev) + eir_len);
 		return;
 	}
@@ -5602,7 +5658,7 @@
 	DBG("");
 
 	if (!g_slist_find(adapter->connections, device)) {
-		error("No matching connection for device");
+		btd_error(adapter->dev_id, "No matching connection for device");
 		return;
 	}
 
@@ -5779,7 +5835,8 @@
 
 		auth->agent = agent_get(NULL);
 		if (auth->agent == NULL) {
-			warn("Authentication attempt without agent");
+			btd_warn(adapter->dev_id,
+					"Authentication attempt without agent");
 			auth->cb(&err, auth->user_data);
 			goto next;
 		}
@@ -5840,7 +5897,8 @@
 
 	/* Device connected? */
 	if (!g_slist_find(adapter->connections, device))
-		error("Authorization request for non-connected device!?");
+		btd_error(adapter->dev_id,
+			"Authorization request for non-connected device!?");
 
 	auth = g_try_new0(struct service_auth, 1);
 	if (!auth)
@@ -6100,7 +6158,8 @@
 	int err;
 
 	if (length < sizeof(*ev)) {
-		error("Too small user confirm request event");
+		btd_error(adapter->dev_id,
+				"Too small user confirm request event");
 		return;
 	}
 
@@ -6110,14 +6169,16 @@
 	device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
 								ev->addr.type);
 	if (!device) {
-		error("Unable to get device object for %s", addr);
+		btd_error(adapter->dev_id,
+				"Unable to get device object for %s", addr);
 		return;
 	}
 
 	err = device_confirm_passkey(device, btohl(ev->value),
 							ev->confirm_hint);
 	if (err < 0) {
-		error("device_confirm_passkey: %s", strerror(-err));
+		btd_error(adapter->dev_id,
+				"device_confirm_passkey: %s", strerror(-err));
 		btd_adapter_confirm_reply(adapter, &ev->addr.bdaddr,
 							ev->addr.type, FALSE);
 	}
@@ -6172,7 +6233,7 @@
 	int err;
 
 	if (length < sizeof(*ev)) {
-		error("Too small passkey request event");
+		btd_error(adapter->dev_id, "Too small passkey request event");
 		return;
 	}
 
@@ -6182,13 +6243,15 @@
 	device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
 								ev->addr.type);
 	if (!device) {
-		error("Unable to get device object for %s", addr);
+		btd_error(adapter->dev_id,
+				"Unable to get device object for %s", addr);
 		return;
 	}
 
 	err = device_request_passkey(device);
 	if (err < 0) {
-		error("device_request_passkey: %s", strerror(-err));
+		btd_error(adapter->dev_id,
+				"device_request_passkey: %s", strerror(-err));
 		btd_adapter_passkey_reply(adapter, &ev->addr.bdaddr,
 					ev->addr.type, INVALID_PASSKEY);
 	}
@@ -6205,7 +6268,7 @@
 	int err;
 
 	if (length < sizeof(*ev)) {
-		error("Too small passkey notify event");
+		btd_error(adapter->dev_id, "Too small passkey notify event");
 		return;
 	}
 
@@ -6215,7 +6278,8 @@
 	device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
 								ev->addr.type);
 	if (!device) {
-		error("Unable to get device object for %s", addr);
+		btd_error(adapter->dev_id,
+				"Unable to get device object for %s", addr);
 		return;
 	}
 
@@ -6225,7 +6289,8 @@
 
 	err = device_notify_passkey(device, passkey, ev->entered);
 	if (err < 0)
-		error("device_notify_passkey: %s", strerror(-err));
+		btd_error(adapter->dev_id,
+				"device_notify_passkey: %s", strerror(-err));
 }
 
 struct btd_adapter_pin_cb_iter *btd_adapter_pin_cb_iter_new(
@@ -6287,7 +6352,7 @@
 	struct btd_adapter_pin_cb_iter *iter;
 
 	if (length < sizeof(*ev)) {
-		error("Too small PIN code request event");
+		btd_error(adapter->dev_id, "Too small PIN code request event");
 		return;
 	}
 
@@ -6298,7 +6363,8 @@
 	device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
 								ev->addr.type);
 	if (!device) {
-		error("Unable to get device object for %s", addr);
+		btd_error(adapter->dev_id,
+				"Unable to get device object for %s", addr);
 		return;
 	}
 
@@ -6318,7 +6384,9 @@
 		if (display && device_is_bonding(device, NULL)) {
 			err = device_notify_pincode(device, ev->secure, pin);
 			if (err < 0) {
-				error("device_notify_pin: %s", strerror(-err));
+				btd_error(adapter->dev_id,
+						"device_notify_pin: %s",
+							strerror(-err));
 				btd_adapter_pincode_reply(adapter,
 							&ev->addr.bdaddr,
 							NULL, 0);
@@ -6332,7 +6400,8 @@
 
 	err = device_request_pincode(device, ev->secure);
 	if (err < 0) {
-		error("device_request_pin: %s", strerror(-err));
+		btd_error(adapter->dev_id, "device_request_pin: %s",
+							strerror(-err));
 		btd_adapter_pincode_reply(adapter, &ev->addr.bdaddr, NULL, 0);
 	}
 }
@@ -6447,7 +6516,8 @@
 	struct pair_device_data *data = user_data;
 	struct btd_adapter *adapter = data->adapter;
 
-	error("Pair device timed out for hci%u", adapter->dev_id);
+	btd_error(adapter->dev_id, "Pair device timed out for hci%u",
+							adapter->dev_id);
 
 	adapter->pair_device_timeout = 0;
 	adapter->pair_device_id = 0;
@@ -6480,7 +6550,7 @@
 	 * powered.
 	 */
 	if (status != MGMT_STATUS_SUCCESS && length < sizeof(*rp)) {
-		error("Pair device failed: %s (0x%02x)",
+		btd_error(adapter->dev_id, "Pair device failed: %s (0x%02x)",
 						mgmt_errstr(status), status);
 
 		bonding_attempt_complete(adapter, &data->bdaddr,
@@ -6489,7 +6559,7 @@
 	}
 
 	if (length < sizeof(*rp)) {
-		error("Too small pair device response");
+		btd_error(adapter->dev_id, "Too small pair device response");
 		return;
 	}
 
@@ -6501,7 +6571,8 @@
 					uint8_t addr_type, uint8_t io_cap)
 {
 	if (adapter->pair_device_id > 0) {
-		error("Unable pair since another pairing is in progress");
+		btd_error(adapter->dev_id,
+			"Unable pair since another pairing is in progress");
 		return -EBUSY;
 	}
 
@@ -6542,7 +6613,8 @@
 				free_pair_device_data);
 
 	if (id == 0) {
-		error("Failed to pair %s for hci%u", addr, adapter->dev_id);
+		btd_error(adapter->dev_id, "Failed to pair %s for hci%u",
+							addr, adapter->dev_id);
 		free_pair_device_data(data);
 		return -EIO;
 	}
@@ -6607,15 +6679,18 @@
 	struct btd_adapter *adapter = user_data;
 
 	if (status == MGMT_STATUS_NOT_CONNECTED) {
-		warn("Disconnecting failed: already disconnected");
+		btd_warn(adapter->dev_id,
+				"Disconnecting failed: already disconnected");
 	} else if (status != MGMT_STATUS_SUCCESS) {
-		error("Failed to disconnect device: %s (0x%02x)",
+		btd_error(adapter->dev_id,
+				"Failed to disconnect device: %s (0x%02x)",
 						mgmt_errstr(status), status);
 		return;
 	}
 
 	if (length < sizeof(*rp)) {
-		error("Too small device disconnect response");
+		btd_error(adapter->dev_id,
+				"Too small device disconnect response");
 		return;
 	}
 
@@ -6648,7 +6723,7 @@
 	struct btd_adapter *adapter = user_data;
 
 	if (length < sizeof(*ev)) {
-		error("Too small auth failed mgmt event");
+		btd_error(adapter->dev_id, "Too small auth failed mgmt event");
 		return;
 	}
 
@@ -6704,7 +6779,7 @@
 	char dst[18];
 
 	if (length < sizeof(*ev)) {
-		error("Too small new link key event");
+		btd_error(adapter->dev_id, "Too small new link key event");
 		return;
 	}
 
@@ -6715,14 +6790,16 @@
 		ev->store_hint);
 
 	if (ev->key.pin_len > 16) {
-		error("Invalid PIN length (%u) in new_key event",
+		btd_error(adapter->dev_id,
+				"Invalid PIN length (%u) in new_key event",
 							ev->key.pin_len);
 		return;
 	}
 
 	device = btd_adapter_get_device(adapter, &addr->bdaddr, addr->type);
 	if (!device) {
-		error("Unable to get device object for %s", dst);
+		btd_error(adapter->dev_id,
+				"Unable to get device object for %s", dst);
 		return;
 	}
 
@@ -6802,7 +6879,7 @@
 	char dst[18];
 
 	if (length < sizeof(*ev)) {
-		error("Too small long term key event");
+		btd_error(adapter->dev_id, "Too small long term key event");
 		return;
 	}
 
@@ -6813,7 +6890,8 @@
 
 	device = btd_adapter_get_device(adapter, &addr->bdaddr, addr->type);
 	if (!device) {
-		error("Unable to get device object for %s", dst);
+		btd_error(adapter->dev_id,
+				"Unable to get device object for %s", dst);
 		return;
 	}
 
@@ -6927,7 +7005,7 @@
 	char dst[18];
 
 	if (length < sizeof(*ev)) {
-		error("Too small CSRK event");
+		btd_error(adapter->dev_id, "Too small CSRK event");
 		return;
 	}
 
@@ -6938,7 +7016,8 @@
 
 	device = btd_adapter_get_device(adapter, &addr->bdaddr, addr->type);
 	if (!device) {
-		error("Unable to get device object for %s", dst);
+		btd_error(adapter->dev_id,
+				"Unable to get device object for %s", dst);
 		return;
 	}
 
@@ -6997,7 +7076,7 @@
 	char dst[18], rpa[18];
 
 	if (length < sizeof(*ev)) {
-		error("Too small New IRK event");
+		btd_error(adapter->dev_id, "Too small New IRK event");
 		return;
 	}
 
@@ -7020,7 +7099,8 @@
 	}
 
 	if (!device) {
-		error("Unable to get device object for %s", dst);
+		btd_error(adapter->dev_id,
+				"Unable to get device object for %s", dst);
 		return;
 	}
 
@@ -7089,7 +7169,8 @@
 
 
 	if (length < sizeof(*ev)) {
-		error("Too small New Connection Parameter event");
+		btd_error(adapter->dev_id,
+				"Too small New Connection Parameter event");
 		return;
 	}
 
@@ -7105,7 +7186,8 @@
 
 	dev = btd_adapter_get_device(adapter, &ev->addr.bdaddr, ev->addr.type);
 	if (!dev) {
-		error("Unable to get device object for %s", dst);
+		btd_error(adapter->dev_id,
+				"Unable to get device object for %s", dst);
 		return;
 	}
 
@@ -7204,12 +7286,14 @@
 	const uint8_t *hash, *randomizer;
 
 	if (status != MGMT_STATUS_SUCCESS) {
-		error("Read local OOB data failed: %s (0x%02x)",
+		btd_error(adapter->dev_id,
+				"Read local OOB data failed: %s (0x%02x)",
 						mgmt_errstr(status), status);
 		hash = NULL;
 		randomizer = NULL;
 	} else if (length < sizeof(*rp)) {
-		error("Too small read local OOB data response");
+		btd_error(adapter->dev_id,
+				"Too small read local OOB data response");
 		return;
 	} else {
 		hash = rp->hash192;
@@ -7335,7 +7419,8 @@
 					adapter_methods, NULL,
 					adapter_properties, adapter,
 					adapter_free)) {
-		error("Adapter interface init failed on path %s",
+		btd_error(adapter->dev_id,
+				"Adapter interface init failed on path %s",
 							adapter->path);
 		g_free(adapter->path);
 		adapter->path = NULL;
@@ -7356,7 +7441,8 @@
 
 	adapter->database = btd_gatt_database_new(adapter);
 	if (!adapter->database) {
-		error("Failed to create GATT database for adapter");
+		btd_error(adapter->dev_id,
+				"Failed to create GATT database for adapter");
 		adapters = g_slist_remove(adapters, adapter);
 		return -EINVAL;
 	}
@@ -7367,7 +7453,8 @@
 			adapter->adv_manager =
 					btd_advertising_manager_new(adapter);
 		} else {
-			info("LEAdvertisingManager skipped, LE unavailable");
+			btd_info(adapter->dev_id,
+				"LEAdvertisingManager skipped, LE unavailable");
 		}
 	}
 
@@ -7435,7 +7522,8 @@
 	uint8_t reason;
 
 	if (length < sizeof(struct mgmt_addr_info)) {
-		error("Too small device disconnected event");
+		btd_error(adapter->dev_id,
+				"Too small device disconnected event");
 		return;
 	}
 
@@ -7459,13 +7547,13 @@
 	bool name_known;
 
 	if (length < sizeof(*ev)) {
-		error("Too small device connected event");
+		btd_error(adapter->dev_id, "Too small device connected event");
 		return;
 	}
 
 	eir_len = btohs(ev->eir_len);
 	if (length < sizeof(*ev) + eir_len) {
-		error("Too small device connected event");
+		btd_error(adapter->dev_id, "Too small device connected event");
 		return;
 	}
 
@@ -7476,7 +7564,8 @@
 	device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
 								ev->addr.type);
 	if (!device) {
-		error("Unable to get device object for %s", addr);
+		btd_error(adapter->dev_id,
+				"Unable to get device object for %s", addr);
 		return;
 	}
 
@@ -7511,7 +7600,7 @@
 	char addr[18];
 
 	if (length < sizeof(*ev)) {
-		error("Too small device blocked event");
+		btd_error(adapter->dev_id, "Too small device blocked event");
 		return;
 	}
 
@@ -7533,7 +7622,7 @@
 	char addr[18];
 
 	if (length < sizeof(*ev)) {
-		error("Too small device unblocked event");
+		btd_error(adapter->dev_id, "Too small device unblocked event");
 		return;
 	}
 
@@ -7575,7 +7664,7 @@
 	char addr[18];
 
 	if (length < sizeof(*ev)) {
-		error("Too small connect failed event");
+		btd_error(adapter->dev_id, "Too small connect failed event");
 		return;
 	}
 
@@ -7658,7 +7747,7 @@
 	char addr[18];
 
 	if (length < sizeof(*ev)) {
-		error("Too small device unpaired event");
+		btd_error(adapter->dev_id, "Too small device unpaired event");
 		return;
 	}
 
@@ -7669,7 +7758,8 @@
 	device = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
 								ev->addr.type);
 	if (!device) {
-		warn("No device object for unpaired device %s", addr);
+		btd_warn(adapter->dev_id,
+			"No device object for unpaired device %s", addr);
 		return;
 	}
 
@@ -7703,7 +7793,8 @@
 				clear_devices_complete, adapter, NULL) > 0)
 		return 0;
 
-	error("Failed to clear devices for index %u", adapter->dev_id);
+	btd_error(adapter->dev_id, "Failed to clear devices for index %u",
+							adapter->dev_id);
 
 	return -EIO;
 }
@@ -7719,18 +7810,21 @@
 	DBG("index %u status 0x%02x", adapter->dev_id, status);
 
 	if (status != MGMT_STATUS_SUCCESS) {
-		error("Failed to read info for index %u: %s (0x%02x)",
+		btd_error(adapter->dev_id,
+				"Failed to read info for index %u: %s (0x%02x)",
 				adapter->dev_id, mgmt_errstr(status), status);
 		goto failed;
 	}
 
 	if (length < sizeof(*rp)) {
-		error("Too small read info complete response");
+		btd_error(adapter->dev_id,
+				"Too small read info complete response");
 		goto failed;
 	}
 
 	if (bacmp(&rp->bdaddr, BDADDR_ANY) == 0) {
-		error("No Bluetooth address for index %u", adapter->dev_id);
+		btd_error(adapter->dev_id, "No Bluetooth address for index %u",
+							adapter->dev_id);
 		goto failed;
 	}
 
@@ -7768,7 +7862,8 @@
 		break;
 	case BT_MODE_BREDR:
 		if (!(adapter->supported_settings & MGMT_SETTING_BREDR)) {
-			error("Ignoring adapter withouth BR/EDR support");
+			btd_error(adapter->dev_id,
+				"Ignoring adapter withouth BR/EDR support");
 			goto failed;
 		}
 
@@ -7781,7 +7876,8 @@
 		break;
 	case BT_MODE_LE:
 		if (!(adapter->supported_settings & MGMT_SETTING_LE)) {
-			error("Ignoring adapter withouth LE support");
+			btd_error(adapter->dev_id,
+				"Ignoring adapter withouth LE support");
 			goto failed;
 		}
 
@@ -7801,7 +7897,7 @@
 
 	err = adapter_register(adapter);
 	if (err < 0) {
-		error("Unable to register new adapter");
+		btd_error(adapter->dev_id, "Unable to register new adapter");
 		goto failed;
 	}
 
@@ -7962,7 +8058,8 @@
 
 	adapter = btd_adapter_lookup(index);
 	if (adapter) {
-		warn("Ignoring index added for an already existing adapter");
+		btd_warn(adapter->dev_id,
+			"Ignoring index added for an already existing adapter");
 		return;
 	}
 
@@ -7978,7 +8075,8 @@
 
 	adapter = btd_adapter_new(index);
 	if (!adapter) {
-		error("Unable to create new adapter for index %u", index);
+		btd_error(adapter->dev_id,
+			"Unable to create new adapter for index %u", index);
 		return;
 	}
 
@@ -8001,7 +8099,8 @@
 					read_info_complete, adapter, NULL) > 0)
 		return;
 
-	error("Failed to read controller info for index %u", index);
+	btd_error(adapter->dev_id,
+			"Failed to read controller info for index %u", index);
 
 	adapter_list = g_list_remove(adapter_list, adapter);
 
diff --git a/src/advertising.c b/src/advertising.c
index a148625..59c8c3d 100644
--- a/src/advertising.c
+++ b/src/advertising.c
@@ -591,9 +591,6 @@
 		return NULL;
 
 	ad = new0(struct advertisement, 1);
-	if (!ad)
-		return NULL;
-
 	ad->client = g_dbus_client_new_full(conn, sender, path, path);
 	if (!ad->client)
 		goto fail;
@@ -765,9 +762,6 @@
 	struct btd_advertising *manager;
 
 	manager = new0(struct btd_advertising, 1);
-	if (!manager)
-		return NULL;
-
 	manager->adapter = adapter;
 
 	manager->mgmt = mgmt_new_default();
diff --git a/src/agent.c b/src/agent.c
index 12e369a..ff44d57 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -924,7 +924,7 @@
 static uint8_t parse_io_capability(const char *capability)
 {
 	if (g_str_equal(capability, ""))
-		return IO_CAPABILITY_DISPLAYYESNO;
+		return IO_CAPABILITY_KEYBOARDDISPLAY;
 	if (g_str_equal(capability, "DisplayOnly"))
 		return IO_CAPABILITY_DISPLAYONLY;
 	if (g_str_equal(capability, "DisplayYesNo"))
diff --git a/src/attrib-server.c b/src/attrib-server.c
index 8b0b7f6..658db55 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -41,6 +41,7 @@
 
 #include "btio/btio.h"
 #include "log.h"
+#include "backtrace.h"
 #include "adapter.h"
 #include "device.h"
 #include "src/shared/util.h"
@@ -1524,7 +1525,7 @@
 uint16_t attrib_db_find_avail(struct btd_adapter *adapter, bt_uuid_t *svc_uuid,
 								uint16_t nitems)
 {
-	g_assert(nitems > 0);
+	btd_assert(nitems > 0);
 
 	if (svc_uuid->type == BT_UUID16)
 		return find_uuid16_avail(adapter, nitems);
diff --git a/src/backtrace.c b/src/backtrace.c
new file mode 100644
index 0000000..c438733
--- /dev/null
+++ b/src/backtrace.c
@@ -0,0 +1,135 @@
+/*
+ *
+ *  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 <unistd.h>
+#include <inttypes.h>
+
+#ifdef HAVE_BACKTRACE_SUPPORT
+#include <execinfo.h>
+#include <elfutils/libdwfl.h>
+#endif
+
+#include "src/log.h"
+#include "src/backtrace.h"
+
+void btd_backtrace_init(void)
+{
+#ifdef HAVE_BACKTRACE_SUPPORT
+	void *frames[1];
+
+	/*
+	 * initialize the backtracer, since the ctor calls dlopen(), which
+	 * calls malloc(), which isn't signal-safe.
+	 */
+	backtrace(frames, 1);
+#endif
+}
+
+void btd_backtrace(uint16_t index)
+{
+#ifdef HAVE_BACKTRACE_SUPPORT
+	char *debuginfo_path = NULL;
+	const Dwfl_Callbacks callbacks = {
+		.find_debuginfo = dwfl_standard_find_debuginfo,
+		.find_elf = dwfl_linux_proc_find_elf,
+		.debuginfo_path = &debuginfo_path,
+	};
+	Dwfl *dwfl;
+	void *frames[48];
+	int n, n_ptrs;
+
+	dwfl = dwfl_begin(&callbacks);
+
+	if (dwfl_linux_proc_report(dwfl, getpid()))
+		goto done;
+
+	dwfl_report_end(dwfl, NULL, NULL);
+
+	n_ptrs = backtrace(frames, 48);
+	if (n_ptrs < 1)
+		goto done;
+
+	btd_error(index, "++++++++ backtrace ++++++++");
+
+	for (n = 1; n < n_ptrs; n++) {
+		GElf_Addr addr = (uintptr_t) frames[n];
+		GElf_Sym sym;
+		GElf_Word shndx;
+		Dwfl_Module *module = dwfl_addrmodule(dwfl, addr);
+		Dwfl_Line *line;
+		const char *name, *modname;
+
+		if (!module) {
+			btd_error(index, "#%-2u ?? [%#" PRIx64 "]", n, addr);
+			continue;
+		}
+
+		name = dwfl_module_addrsym(module, addr, &sym, &shndx);
+		if (!name) {
+			modname = dwfl_module_info(module, NULL, NULL, NULL,
+							NULL, NULL, NULL, NULL);
+			btd_error(index, "#%-2u ?? (%s) [%#" PRIx64 "]",
+							n, modname, addr);
+			continue;
+		}
+
+		line = dwfl_module_getsrc(module, addr);
+		if (line) {
+			int lineno;
+			const char *src = dwfl_lineinfo(line, NULL, &lineno,
+							NULL, NULL, NULL);
+
+			if (src) {
+				btd_error(index, "#%-2u %s+%#" PRIx64 " "
+						"(%s:%d) [%#" PRIx64 "]",
+						n, name, addr - sym.st_value,
+							src, lineno, addr);
+				continue;
+			}
+		}
+
+		modname = dwfl_module_info(module, NULL, NULL, NULL,
+						NULL, NULL, NULL, NULL);
+		btd_error(index, "#%-2u %s+%#" PRIx64 " (%s) [%#" PRIx64 "]",
+						n, name, addr - sym.st_value,
+								modname, addr);
+	}
+
+	btd_error(index, "+++++++++++++++++++++++++++");
+
+done:
+	dwfl_end(dwfl);
+#endif
+}
+
+void btd_assertion_message_expr(const char *file, int line,
+					const char *func, const char *expr)
+{
+	btd_error(0xffff, "Assertion failed: (%s) %s:%d in %s",
+						expr, file, line, func);
+	btd_backtrace(0xffff);
+}
diff --git a/src/backtrace.h b/src/backtrace.h
new file mode 100644
index 0000000..b3eef6d
--- /dev/null
+++ b/src/backtrace.h
@@ -0,0 +1,35 @@
+/*
+ *
+ *  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
+ *
+ */
+
+#include <stdint.h>
+
+void btd_backtrace_init(void);
+void btd_backtrace(uint16_t index);
+
+void btd_assertion_message_expr(const char *file, int line,
+					const char *func, const char *expr);
+
+#define btd_assert(expr) do { \
+	if (expr) ; else \
+		btd_assertion_message_expr(__FILE__, __LINE__, __func__, #expr); \
+	} while (0)
diff --git a/src/device.c b/src/device.c
index d708e06..d31604a 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1521,7 +1521,8 @@
 	while (dev->pending) {
 		service = dev->pending->data;
 
-		if (btd_service_connect(service) == 0)
+		err = btd_service_connect(service);
+		if (!err)
 			return 0;
 
 		dev->pending = g_slist_delete_link(dev->pending, dev->pending);
@@ -1542,7 +1543,7 @@
 		btd_device_set_temporary(dev, false);
 
 	if (dev->pending == NULL)
-		return;
+		goto done;
 
 	if (!btd_device_is_connected(dev)) {
 		switch (-err) {
@@ -1776,8 +1777,11 @@
 	}
 
 	err = connect_next(dev);
-	if (err < 0)
+	if (err < 0) {
+		if (err == -EALREADY)
+			return dbus_message_new_method_return(msg);
 		return btd_error_failed(msg, strerror(-err));
+	}
 
 	dev->connect = dbus_message_ref(msg);
 
@@ -4770,12 +4774,12 @@
 	dst = device_get_address(dev);
 	ba2str(dst, dstaddr);
 
-	if (gatt_db_isempty(dev->db))
-		load_gatt_db(dev, srcaddr, dstaddr);
-
 	gatt_client_init(dev);
 	gatt_server_init(dev, btd_gatt_database_get_db(database));
 
+	if (gatt_db_isempty(dev->db))
+		load_gatt_db(dev, srcaddr, dstaddr);
+
 	/*
 	 * Remove the device from the connect_list and give the passive
 	 * scanning another chance to be restarted in case there are
diff --git a/src/gatt-client.c b/src/gatt-client.c
index 4e52c5d..39f6646 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
@@ -407,9 +407,6 @@
 		return btd_error_in_progress(msg);
 
 	op = new0(struct async_dbus_op, 1);
-	if (!op)
-		return btd_error_failed(msg, "Failed to initialize request");
-
 	op->msg = dbus_message_ref(msg);
 	op->data = desc;
 
@@ -472,9 +469,6 @@
 	unsigned int id;
 
 	op = new0(struct async_dbus_op, 1);
-	if (!op)
-		return false;
-
 	op->msg = dbus_message_ref(msg);
 	op->data = data;
 	op->complete = complete;
@@ -500,9 +494,6 @@
 	unsigned int id;
 
 	op = new0(struct async_dbus_op, 1);
-	if (!op)
-		return false;
-
 	op->msg = dbus_message_ref(msg);
 	op->data = data;
 	op->complete = complete;
@@ -610,9 +601,6 @@
 	struct descriptor *desc;
 
 	desc = new0(struct descriptor, 1);
-	if (!desc)
-		return NULL;
-
 	desc->chrc = chrc;
 	desc->attr = attr;
 	desc->handle = gatt_db_attribute_get_handle(attr);
@@ -852,9 +840,6 @@
 		return btd_error_in_progress(msg);
 
 	op = new0(struct async_dbus_op, 1);
-	if (!op)
-		return btd_error_failed(msg, "Failed to initialize request");
-
 	op->msg = dbus_message_ref(msg);
 	op->data = chrc;
 
@@ -1045,9 +1030,6 @@
 	struct notify_client *client;
 
 	client = new0(struct notify_client, 1);
-	if (!client)
-		return NULL;
-
 	client->chrc = chrc;
 	client->owner = strdup(owner);
 	if (!client->owner) {
@@ -1193,9 +1175,6 @@
 	}
 
 	op = new0(struct async_dbus_op, 1);
-	if (!op)
-		goto fail;
-
 	op->data = client;
 	op->msg = dbus_message_ref(msg);
 
@@ -1320,22 +1299,8 @@
 	bt_uuid_t uuid;
 
 	chrc = new0(struct characteristic, 1);
-	if (!chrc)
-		return NULL;
-
 	chrc->descs = queue_new();
-	if (!chrc->descs) {
-		free(chrc);
-		return NULL;
-	}
-
 	chrc->notify_clients = queue_new();
-	if (!chrc->notify_clients) {
-		queue_destroy(chrc->descs, NULL);
-		free(chrc);
-		return NULL;
-	}
-
 	chrc->service = service;
 
 	gatt_db_attribute_get_char_data(attr, &chrc->handle,
@@ -1494,22 +1459,8 @@
 	bt_uuid_t uuid;
 
 	service = new0(struct service, 1);
-	if (!service)
-		return NULL;
-
 	service->chrcs = queue_new();
-	if (!service->chrcs) {
-		free(service);
-		return NULL;
-	}
-
 	service->pending_ext_props = queue_new();
-	if (!service->pending_ext_props) {
-		queue_destroy(service->chrcs, NULL);
-		free(service);
-		return NULL;
-	}
-
 	service->client = client;
 
 	gatt_db_attribute_get_service_data(attr, &service->start_handle,
@@ -1703,6 +1654,7 @@
 {
 	struct service *service = user_data;
 
+	service->idle_id = 0;
 	notify_chrcs(service);
 
 	return FALSE;
@@ -1757,22 +1709,8 @@
 		return NULL;
 
 	client = new0(struct btd_gatt_client, 1);
-	if (!client)
-		return NULL;
-
 	client->services = queue_new();
-	if (!client->services) {
-		free(client);
-		return NULL;
-	}
-
 	client->all_notify_clients = queue_new();
-	if (!client->all_notify_clients) {
-		queue_destroy(client->services, NULL);
-		free(client);
-		return NULL;
-	}
-
 	client->device = device;
 	ba2str(device_get_address(device), client->devaddr);
 
@@ -1802,9 +1740,6 @@
 	DBG("Re-register subscribed notification client");
 
 	op = new0(struct async_dbus_op, 1);
-	if (!op)
-		goto fail;
-
 	op->data = notify_client;
 
 	notify_client->notify_id = bt_gatt_client_register_notify(client->gatt,
@@ -1816,7 +1751,6 @@
 
 	async_dbus_op_free(op);
 
-fail:
 	DBG("Failed to re-register notification client");
 
 	queue_remove(notify_client->chrc->notify_clients, client);
diff --git a/src/gatt-database.c b/src/gatt-database.c
index 774b19e..e8ce7d5 100644
--- a/src/gatt-database.c
+++ b/src/gatt-database.c
@@ -231,15 +231,7 @@
 	struct device_state *dev_state;
 
 	dev_state = new0(struct device_state, 1);
-	if (!dev_state)
-		return NULL;
-
 	dev_state->ccc_states = queue_new();
-	if (!dev_state->ccc_states) {
-		free(dev_state);
-		return NULL;
-	}
-
 	bacpy(&dev_state->bdaddr, bdaddr);
 	dev_state->bdaddr_type = bdaddr_type;
 
@@ -261,8 +253,6 @@
 		return dev_state;
 
 	dev_state = device_state_create(bdaddr, bdaddr_type);
-	if (!dev_state)
-		return NULL;
 
 	queue_push_tail(database->device_states, dev_state);
 
@@ -278,17 +268,12 @@
 	struct ccc_state *ccc;
 
 	dev_state = get_device_state(database, bdaddr, bdaddr_type);
-	if (!dev_state)
-		return NULL;
 
 	ccc = find_ccc_state(dev_state, handle);
 	if (ccc)
 		return ccc;
 
 	ccc = new0(struct ccc_state, 1);
-	if (!ccc)
-		return NULL;
-
 	ccc->handle = handle;
 	queue_push_tail(dev_state->ccc_states, ccc);
 
@@ -727,10 +712,6 @@
 	}
 
 	ccc = get_ccc_state(database, &bdaddr, bdaddr_type, handle);
-	if (!ccc) {
-		ecode = BT_ATT_ERROR_UNLIKELY;
-		goto done;
-	}
 
 	len = 2 - offset;
 	value = len ? &ccc->value[offset] : NULL;
@@ -773,10 +754,6 @@
 	}
 
 	ccc = get_ccc_state(database, &bdaddr, bdaddr_type, handle);
-	if (!ccc) {
-		ecode = BT_ATT_ERROR_UNLIKELY;
-		goto done;
-	}
 
 	ccc_cb = queue_find(database->ccc_callbacks, ccc_cb_match_handle,
 			UINT_TO_PTR(gatt_db_attribute_get_handle(attrib)));
@@ -813,10 +790,6 @@
 	bt_uuid_t uuid;
 
 	ccc_cb = new0(struct ccc_cb_data, 1);
-	if (!ccc_cb) {
-		error("Could not allocate memory for callback data");
-		return NULL;
-	}
 
 	bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
 	ccc = gatt_db_service_add_descriptor(service, &uuid,
@@ -1102,21 +1075,8 @@
 	struct external_chrc *chrc;
 
 	chrc = new0(struct external_chrc, 1);
-	if (!chrc)
-		return NULL;
-
 	chrc->pending_reads = queue_new();
-	if (!chrc->pending_reads) {
-		free(chrc);
-		return NULL;
-	}
-
 	chrc->pending_writes = queue_new();
-	if (!chrc->pending_writes) {
-		queue_destroy(chrc->pending_reads, NULL);
-		free(chrc);
-		return NULL;
-	}
 
 	chrc->path = g_strdup(path);
 	if (!chrc->path) {
@@ -1139,21 +1099,8 @@
 	struct external_desc *desc;
 
 	desc = new0(struct external_desc, 1);
-	if (!desc)
-		return NULL;
-
 	desc->pending_reads = queue_new();
-	if (!desc->pending_reads) {
-		free(desc);
-		return NULL;
-	}
-
 	desc->pending_writes = queue_new();
-	if (!desc->pending_writes) {
-		queue_destroy(desc->pending_reads, NULL);
-		free(desc);
-		return NULL;
-	}
 
 	desc->chrc_path = g_strdup(chrc_path);
 	if (!desc->chrc_path) {
@@ -1600,8 +1547,6 @@
 	struct pending_op *op;
 
 	op = new0(struct pending_op, 1);
-	if (!op)
-		return NULL;
 
 	op->owner_queue = owner_queue;
 	op->attrib = attrib;
@@ -1619,11 +1564,6 @@
 	uint8_t ecode = BT_ATT_ERROR_UNLIKELY;
 
 	op = pending_read_new(owner_queue, attrib, id);
-	if (!op) {
-		error("Failed to allocate memory for pending read call");
-		ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
-		goto error;
-	}
 
 	if (g_dbus_proxy_method_call(proxy, "ReadValue", NULL, read_reply_cb,
 						op, pending_op_free) == TRUE)
@@ -1631,7 +1571,6 @@
 
 	pending_op_free(op);
 
-error:
 	gatt_db_attribute_read_result(attrib, id, ecode, NULL, 0);
 }
 
@@ -1691,8 +1630,6 @@
 	struct pending_op *op;
 
 	op = new0(struct pending_op, 1);
-	if (!op)
-		return NULL;
 
 	op->data.iov_base = (uint8_t *) value;
 	op->data.iov_len = len;
@@ -1714,11 +1651,6 @@
 	uint8_t ecode = BT_ATT_ERROR_UNLIKELY;
 
 	op = pending_write_new(owner_queue, attrib, id, value, len);
-	if (!op) {
-		error("Failed to allocate memory for pending read call");
-		ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
-		goto error;
-	}
 
 	if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup_cb,
 						write_reply_cb, op,
@@ -1727,7 +1659,6 @@
 
 	pending_op_free(op);
 
-error:
 	gatt_db_attribute_write_result(attrib, id, ecode);
 }
 
@@ -2156,8 +2087,6 @@
 		return NULL;
 
 	service = new0(struct external_service, 1);
-	if (!service)
-		return NULL;
 
 	service->client = g_dbus_client_new_full(conn, sender, path, path);
 	if (!service->client)
@@ -2172,12 +2101,7 @@
 		goto fail;
 
 	service->chrcs = queue_new();
-	if (!service->chrcs)
-		goto fail;
-
 	service->descs = queue_new();
-	if (!service->descs)
-		goto fail;
 
 	service->reg = dbus_message_ref(msg);
 
@@ -2301,8 +2225,6 @@
 	struct btd_profile *p;
 
 	p = new0(struct btd_profile, 1);
-	if (!p)
-		return -ENOMEM;
 
 	/* Assign directly to avoid having extra fields */
 	p->name = (const void *) g_strdup_printf("%s%s/%s", profile->owner,
@@ -2351,8 +2273,6 @@
 		return -EINVAL;
 
 	profile = new0(struct external_profile, 1);
-	if (!profile)
-		return -ENOMEM;
 
 	profile->owner = g_strdup(sender);
 	if (!profile->owner)
@@ -2363,9 +2283,6 @@
 		goto fail;
 
 	profile->profiles = queue_new();
-	if (!profile->profiles)
-		goto fail;
-
 	profile->database = database;
 	profile->id = g_dbus_add_disconnect_watch(conn, sender, profile_exited,
 								profile, NULL);
@@ -2498,29 +2415,12 @@
 		return NULL;
 
 	database = new0(struct btd_gatt_database, 1);
-	if (!database)
-		return NULL;
-
 	database->adapter = btd_adapter_ref(adapter);
 	database->db = gatt_db_new();
-	if (!database->db)
-		goto fail;
-
 	database->device_states = queue_new();
-	if (!database->device_states)
-		goto fail;
-
 	database->services = queue_new();
-	if (!database->services)
-		goto fail;
-
 	database->profiles = queue_new();
-	if (!database->profiles)
-		goto fail;
-
 	database->ccc_callbacks = queue_new();
-	if (!database->ccc_callbacks)
-		goto fail;
 
 	database->db_id = gatt_db_register(database->db, gatt_db_service_added,
 							gatt_db_service_removed,
diff --git a/src/log.c b/src/log.c
index ca783f3..d2a20de 100644
--- a/src/log.c
+++ b/src/log.c
@@ -26,21 +26,125 @@
 #endif
 
 #include <stdio.h>
-#include <stdarg.h>
+#include <errno.h>
 #include <syslog.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
 
 #include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+
+#include "src/shared/util.h"
 #include "log.h"
 
-void info(const char *format, ...)
+#define LOG_IDENT "bluetoothd"
+#define LOG_IDENT_LEN sizeof(LOG_IDENT)
+
+struct log_hdr {
+	uint16_t opcode;
+	uint16_t index;
+	uint16_t len;
+	uint8_t  priority;
+	uint8_t  ident_len;
+} __attribute__((packed));
+
+static int logging_fd = -1;
+
+static void logging_open(void)
+{
+	struct sockaddr_hci addr;
+	int fd;
+
+	if (logging_fd >= 0)
+		return;
+
+	fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+	if (fd < 0)
+		return;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.hci_family = AF_BLUETOOTH;
+	addr.hci_dev = HCI_DEV_NONE;
+	addr.hci_channel = HCI_CHANNEL_LOGGING;
+
+	if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		close(fd);
+		return;
+	}
+
+	logging_fd = fd;
+}
+
+static void logging_close(void)
+{
+	if (logging_fd >= 0) {
+		close(logging_fd);
+		logging_fd = -1;
+	}
+}
+
+static void logging_log(uint16_t index, int priority,
+					const char *format, va_list ap)
+{
+	struct log_hdr hdr;
+	struct msghdr msg;
+	struct iovec iov[3];
+	uint16_t len;
+	char *str;
+
+	if (vasprintf(&str, format, ap) < 0)
+		return;
+
+	len = strlen(str) + 1;
+
+	hdr.opcode = cpu_to_le16(0x0000);
+	hdr.index = cpu_to_le16(index);
+	hdr.len = cpu_to_le16(2 + LOG_IDENT_LEN + len);
+	hdr.priority = priority;
+	hdr.ident_len = LOG_IDENT_LEN;
+
+	iov[0].iov_base = &hdr;
+	iov[0].iov_len = sizeof(hdr);
+
+	iov[1].iov_base = LOG_IDENT;
+	iov[1].iov_len = LOG_IDENT_LEN;
+
+	iov[2].iov_base = str;
+	iov[2].iov_len = len;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 3;
+
+	if (sendmsg(logging_fd, &msg, 0) < 0) {
+		if (errno != ENODEV) {
+			close(logging_fd);
+			logging_fd = -1;
+		}
+	}
+
+	free(str);
+}
+
+void error(const char *format, ...)
 {
 	va_list ap;
 
 	va_start(ap, format);
+	vsyslog(LOG_ERR, format, ap);
+	va_end(ap);
 
-	vsyslog(LOG_INFO, format, ap);
+	if (logging_fd < 0)
+		return;
 
+	va_start(ap, format);
+	logging_log(HCI_DEV_NONE, LOG_ERR, format, ap);
 	va_end(ap);
 }
 
@@ -49,31 +153,110 @@
 	va_list ap;
 
 	va_start(ap, format);
-
 	vsyslog(LOG_WARNING, format, ap);
+	va_end(ap);
 
+	if (logging_fd < 0)
+		return;
+
+	va_start(ap, format);
+	logging_log(HCI_DEV_NONE, LOG_WARNING, format, ap);
 	va_end(ap);
 }
 
-void error(const char *format, ...)
+void info(const char *format, ...)
 {
 	va_list ap;
 
 	va_start(ap, format);
+	vsyslog(LOG_INFO, format, ap);
+	va_end(ap);
 
+	if (logging_fd < 0)
+		return;
+
+	va_start(ap, format);
+	logging_log(HCI_DEV_NONE, LOG_INFO, format, ap);
+	va_end(ap);
+}
+
+void btd_log(uint16_t index, int priority, const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+	vsyslog(priority, format, ap);
+	va_end(ap);
+
+	if (logging_fd < 0)
+		return;
+
+	va_start(ap, format);
+	logging_log(index, priority, format, ap);
+	va_end(ap);
+}
+
+void btd_error(uint16_t index, const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
 	vsyslog(LOG_ERR, format, ap);
+	va_end(ap);
 
+	if (logging_fd < 0)
+		return;
+
+	va_start(ap, format);
+	logging_log(index, LOG_ERR, format, ap);
 	va_end(ap);
 }
 
-void btd_debug(const char *format, ...)
+void btd_warn(uint16_t index, const char *format, ...)
 {
 	va_list ap;
 
 	va_start(ap, format);
+	vsyslog(LOG_WARNING, format, ap);
+	va_end(ap);
 
+	if (logging_fd < 0)
+		return;
+
+	va_start(ap, format);
+	logging_log(index, LOG_WARNING, format, ap);
+	va_end(ap);
+}
+
+void btd_info(uint16_t index, const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+	vsyslog(LOG_INFO, format, ap);
+	va_end(ap);
+
+	if (logging_fd < 0)
+		return;
+
+	va_start(ap, format);
+	logging_log(index, LOG_INFO, format, ap);
+	va_end(ap);
+}
+
+void btd_debug(uint16_t index, const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
 	vsyslog(LOG_DEBUG, format, ap);
+	va_end(ap);
 
+	if (logging_fd < 0)
+		return;
+
+	va_start(ap, format);
+	logging_log(index, LOG_DEBUG, format, ap);
 	va_end(ap);
 }
 
@@ -128,17 +311,21 @@
 
 	__btd_enable_debug(__start___debug, __stop___debug);
 
+	logging_open();
+
 	if (!detach)
 		option |= LOG_PERROR;
 
-	openlog("bluetoothd", option, LOG_DAEMON);
+	openlog(LOG_IDENT, option, LOG_DAEMON);
 
-	syslog(LOG_INFO, "Bluetooth daemon %s", VERSION);
+	info("Bluetooth daemon %s", VERSION);
 }
 
 void __btd_log_cleanup(void)
 {
 	closelog();
 
+	logging_close();
+
 	g_strfreev(enabled);
 }
diff --git a/src/log.h b/src/log.h
index bf9eac2..0d243ce 100644
--- a/src/log.h
+++ b/src/log.h
@@ -21,11 +21,23 @@
  *
  */
 
-void info(const char *format, ...) __attribute__((format(printf, 1, 2)));
-void warn(const char *format, ...) __attribute__((format(printf, 1, 2)));
-void error(const char *format, ...) __attribute__((format(printf, 1, 2)));
+#include <stdint.h>
 
-void btd_debug(const char *format, ...) __attribute__((format(printf, 1, 2)));
+void error(const char *format, ...) __attribute__((format(printf, 1, 2)));
+void warn(const char *format, ...) __attribute__((format(printf, 1, 2)));
+void info(const char *format, ...) __attribute__((format(printf, 1, 2)));
+
+void btd_log(uint16_t index, int priority, const char *format, ...)
+					__attribute__((format(printf, 3, 4)));
+
+void btd_error(uint16_t index, const char *format, ...)
+					__attribute__((format(printf, 2, 3)));
+void btd_warn(uint16_t index, const char *format, ...)
+					__attribute__((format(printf, 2, 3)));
+void btd_info(uint16_t index, const char *format, ...)
+					__attribute__((format(printf, 2, 3)));
+void btd_debug(uint16_t index, const char *format, ...)
+					__attribute__((format(printf, 2, 3)));
 
 void __btd_log_init(const char *debug, int detach);
 void __btd_log_cleanup(void);
@@ -49,11 +61,13 @@
  * Simple macro around btd_debug() which also include the function
  * name it is called in.
  */
-#define DBG(fmt, arg...) do { \
+#define DBG_IDX(idx, fmt, arg...) do { \
 	static struct btd_debug_desc __btd_debug_desc \
 	__attribute__((used, section("__debug"), aligned(8))) = { \
 		.file = __FILE__, .flags = BTD_DEBUG_FLAG_DEFAULT, \
 	}; \
 	if (__btd_debug_desc.flags & BTD_DEBUG_FLAG_PRINT) \
-		btd_debug("%s:%s() " fmt,  __FILE__, __func__ , ## arg); \
+		btd_debug(idx, "%s:%s() " fmt, __FILE__, __func__ , ## arg); \
 } while (0)
+
+#define DBG(fmt, arg...) DBG_IDX(0xffff, fmt, ## arg)
diff --git a/src/main.c b/src/main.c
index ae8cddb..c85bf19 100644
--- a/src/main.c
+++ b/src/main.c
@@ -48,6 +48,7 @@
 #include "gdbus/gdbus.h"
 
 #include "log.h"
+#include "backtrace.h"
 
 #include "lib/uuid.h"
 #include "hcid.h"
@@ -360,6 +361,21 @@
 	main_opts.did_version = (major << 8 | minor);
 }
 
+static void log_handler(const gchar *log_domain, GLogLevelFlags log_level,
+				const gchar *message, gpointer user_data)
+{
+	int priority;
+
+	if (log_level & (G_LOG_LEVEL_ERROR |
+				G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING))
+		priority = 0x03;
+	else
+		priority = 0x06;
+
+	btd_log(0xffff, priority, "GLib: %s", message);
+	btd_backtrace(0xffff);
+}
+
 static GMainLoop *event_loop;
 
 void btd_exit(void)
@@ -586,12 +602,18 @@
 
 	umask(0077);
 
+	btd_backtrace_init();
+
 	event_loop = g_main_loop_new(NULL, FALSE);
 
 	signal = setup_signalfd();
 
 	__btd_log_init(option_debug, option_detach);
 
+	g_log_set_handler("GLib", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL |
+							G_LOG_FLAG_RECURSION,
+							log_handler, NULL);
+
 	sd_notify(0, "STATUS=Starting up");
 
 	main_conf = load_config(CONFIGDIR "/main.conf");
@@ -617,14 +639,18 @@
 	btd_agent_init();
 	btd_profile_init();
 
-	if (option_compat == TRUE)
-		sdp_flags |= SDP_SERVER_COMPAT;
+	if (main_opts.mode != BT_MODE_LE) {
+		if (option_compat == TRUE)
+			sdp_flags |= SDP_SERVER_COMPAT;
 
-	start_sdp_server(sdp_mtu, sdp_flags);
+		start_sdp_server(sdp_mtu, sdp_flags);
 
-	if (main_opts.did_source > 0)
-		register_device_id(main_opts.did_source, main_opts.did_vendor,
-				main_opts.did_product, main_opts.did_version);
+		if (main_opts.did_source > 0)
+			register_device_id(main_opts.did_source,
+						main_opts.did_vendor,
+						main_opts.did_product,
+						main_opts.did_version);
+	}
 
 	if (mps != MPS_OFF)
 		register_mps(mps == MPS_MULTIPLE);
@@ -675,7 +701,8 @@
 
 	rfkill_exit();
 
-	stop_sdp_server();
+	if (main_opts.mode != BT_MODE_LE)
+		stop_sdp_server();
 
 	g_main_loop_unref(event_loop);
 
diff --git a/src/profile.c b/src/profile.c
index 49445d7..5a4f09c 100644
--- a/src/profile.c
+++ b/src/profile.c
@@ -719,19 +719,13 @@
 
 int btd_profile_register(struct btd_profile *profile)
 {
-	if (profile->external)
-		ext_profiles = g_slist_append(ext_profiles, profile);
-	else
-		profiles = g_slist_append(profiles, profile);
+	profiles = g_slist_append(profiles, profile);
 	return 0;
 }
 
 void btd_profile_unregister(struct btd_profile *profile)
 {
-	if (profile->external)
-		ext_profiles = g_slist_remove(ext_profiles, profile);
-	else
-		profiles = g_slist_remove(profiles, profile);
+	profiles = g_slist_remove(profiles, profile);
 }
 
 static struct ext_profile *find_ext_profile(const char *owner,
@@ -742,10 +736,6 @@
 	for (l = ext_profiles; l != NULL; l = g_slist_next(l)) {
 		struct ext_profile *ext = l->data;
 
-		/*
-		 * Owner and path can be NULL if profile was registered by a
-		 * plugin using external flag.
-		 */
 		if (g_strcmp0(ext->owner, owner))
 			continue;
 
diff --git a/src/sdpd-server.c b/src/sdpd-server.c
index e6b611a..c863508 100644
--- a/src/sdpd-server.c
+++ b/src/sdpd-server.c
@@ -46,8 +46,7 @@
 #include "sdpd.h"
 
 static guint l2cap_id = 0, unix_id = 0;
-
-static int l2cap_sock, unix_sock;
+static int l2cap_sock = -1, unix_sock = -1;
 
 /*
  * SDP server initialization on startup includes creating the
diff --git a/src/service.c b/src/service.c
index 2ed72fb..f7912f5 100644
--- a/src/service.c
+++ b/src/service.c
@@ -27,7 +27,6 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <assert.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <stdbool.h>
@@ -41,6 +40,7 @@
 #include "lib/sdp.h"
 
 #include "log.h"
+#include "backtrace.h"
 
 #include "adapter.h"
 #include "device.h"
@@ -92,8 +92,8 @@
 	if (state == old)
 		return;
 
-	assert(service->device != NULL);
-	assert(service->profile != NULL);
+	btd_assert(service->device != NULL);
+	btd_assert(service->profile != NULL);
 
 	service->state = state;
 	service->err = err;
@@ -155,7 +155,7 @@
 	char addr[18];
 	int err;
 
-	assert(service->state == BTD_SERVICE_STATE_UNAVAILABLE);
+	btd_assert(service->state == BTD_SERVICE_STATE_UNAVAILABLE);
 
 	err = service->profile->device_probe(service);
 	if (err == 0) {
@@ -191,7 +191,7 @@
 		break;
 	case BTD_SERVICE_STATE_CONNECTING:
 	case BTD_SERVICE_STATE_CONNECTED:
-		return -EALREADY;
+		return 0;
 	case BTD_SERVICE_STATE_DISCONNECTING:
 		return -EBUSY;
 	}
@@ -228,6 +228,7 @@
 	case BTD_SERVICE_STATE_DISCONNECTED:
 		break;
 	case BTD_SERVICE_STATE_CONNECTING:
+		return 0;
 	case BTD_SERVICE_STATE_CONNECTED:
 		return -EALREADY;
 	case BTD_SERVICE_STATE_DISCONNECTING:
@@ -299,7 +300,7 @@
 
 void btd_service_set_user_data(struct btd_service *service, void *user_data)
 {
-	assert(service->state == BTD_SERVICE_STATE_UNAVAILABLE);
+	btd_assert(service->state == BTD_SERVICE_STATE_UNAVAILABLE);
 	service->user_data = user_data;
 }
 
diff --git a/src/shared/ad.c b/src/shared/ad.c
index 6259eb9..1bf013d 100644
--- a/src/shared/ad.c
+++ b/src/shared/ad.c
@@ -42,36 +42,12 @@
 	struct bt_ad *ad;
 
 	ad = new0(struct bt_ad, 1);
-	if (!ad)
-		return NULL;
-
 	ad->service_uuids = queue_new();
-	if (!ad->service_uuids)
-		goto fail;
-
 	ad->manufacturer_data = queue_new();
-	if (!ad->manufacturer_data)
-		goto fail;
-
 	ad->solicit_uuids = queue_new();
-	if (!ad->solicit_uuids)
-		goto fail;
-
 	ad->service_data = queue_new();
-	if (!ad->service_data)
-		goto fail;
 
 	return bt_ad_ref(ad);
-
-fail:
-	queue_destroy(ad->service_uuids, NULL);
-	queue_destroy(ad->manufacturer_data, NULL);
-	queue_destroy(ad->solicit_uuids, NULL);
-	queue_destroy(ad->service_data, NULL);
-
-	free(ad);
-
-	return NULL;
 }
 
 struct bt_ad *bt_ad_ref(struct bt_ad *ad)
@@ -373,8 +349,6 @@
 		return false;
 
 	new_uuid = new0(bt_uuid_t, 1);
-	if (!new_uuid)
-		return false;
 
 	*new_uuid = *uuid;
 
@@ -466,9 +440,6 @@
 	}
 
 	new_data = new0(struct bt_ad_manufacturer_data, 1);
-	if (!new_data)
-		return false;
-
 	new_data->manufacturer_id = manufacturer_id;
 
 	new_data->data = malloc(len);
@@ -605,8 +576,6 @@
 	}
 
 	new_data = new0(struct bt_ad_service_data, 1);
-	if (!new_data)
-		return false;
 
 	new_data->uuid = *uuid;
 
diff --git a/src/shared/att-types.h b/src/shared/att-types.h
index d474495..c3062c0 100644
--- a/src/shared/att-types.h
+++ b/src/shared/att-types.h
@@ -42,8 +42,8 @@
 #define BT_ATT_OP_MTU_RSP			0x03
 #define BT_ATT_OP_FIND_INFO_REQ			0x04
 #define BT_ATT_OP_FIND_INFO_RSP			0x05
-#define BT_ATT_OP_FIND_BY_TYPE_VAL_REQ		0x06
-#define BT_ATT_OP_FIND_BY_TYPE_VAL_RSP		0x07
+#define BT_ATT_OP_FIND_BY_TYPE_REQ		0x06
+#define BT_ATT_OP_FIND_BY_TYPE_RSP		0x07
 #define BT_ATT_OP_READ_BY_TYPE_REQ		0x08
 #define BT_ATT_OP_READ_BY_TYPE_RSP		0x09
 #define BT_ATT_OP_READ_REQ			0x0a
diff --git a/src/shared/att.c b/src/shared/att.c
index d88169e..3a84783 100644
--- a/src/shared/att.c
+++ b/src/shared/att.c
@@ -112,8 +112,8 @@
 	{ BT_ATT_OP_MTU_RSP,			ATT_OP_TYPE_RSP },
 	{ BT_ATT_OP_FIND_INFO_REQ,		ATT_OP_TYPE_REQ },
 	{ BT_ATT_OP_FIND_INFO_RSP,		ATT_OP_TYPE_RSP },
-	{ BT_ATT_OP_FIND_BY_TYPE_VAL_REQ,	ATT_OP_TYPE_REQ },
-	{ BT_ATT_OP_FIND_BY_TYPE_VAL_RSP,	ATT_OP_TYPE_RSP },
+	{ BT_ATT_OP_FIND_BY_TYPE_REQ,		ATT_OP_TYPE_REQ },
+	{ BT_ATT_OP_FIND_BY_TYPE_RSP,		ATT_OP_TYPE_RSP },
 	{ BT_ATT_OP_READ_BY_TYPE_REQ,		ATT_OP_TYPE_REQ },
 	{ BT_ATT_OP_READ_BY_TYPE_RSP,		ATT_OP_TYPE_RSP },
 	{ BT_ATT_OP_READ_REQ,			ATT_OP_TYPE_REQ },
@@ -156,7 +156,7 @@
 } att_req_rsp_mapping_table[] = {
 	{ BT_ATT_OP_MTU_REQ,			BT_ATT_OP_MTU_RSP },
 	{ BT_ATT_OP_FIND_INFO_REQ,		BT_ATT_OP_FIND_INFO_RSP},
-	{ BT_ATT_OP_FIND_BY_TYPE_VAL_REQ,	BT_ATT_OP_FIND_BY_TYPE_VAL_RSP },
+	{ BT_ATT_OP_FIND_BY_TYPE_REQ,		BT_ATT_OP_FIND_BY_TYPE_RSP },
 	{ BT_ATT_OP_READ_BY_TYPE_REQ,		BT_ATT_OP_READ_BY_TYPE_RSP },
 	{ BT_ATT_OP_READ_REQ,			BT_ATT_OP_READ_RSP },
 	{ BT_ATT_OP_READ_BLOB_REQ,		BT_ATT_OP_READ_BLOB_RSP },
@@ -320,33 +320,30 @@
 						bt_att_destroy_func_t destroy)
 {
 	struct att_send_op *op;
-	enum att_op_type op_type;
+	enum att_op_type type;
 
 	if (length && !pdu)
 		return NULL;
 
-	op_type = get_op_type(opcode);
-	if (op_type == ATT_OP_TYPE_UNKNOWN)
+	type = get_op_type(opcode);
+	if (type == ATT_OP_TYPE_UNKNOWN)
 		return NULL;
 
 	/* If the opcode corresponds to an operation type that does not elicit a
 	 * response from the remote end, then no callback should have been
 	 * provided, since it will never be called.
 	 */
-	if (callback && op_type != ATT_OP_TYPE_REQ && op_type != ATT_OP_TYPE_IND)
+	if (callback && type != ATT_OP_TYPE_REQ && type != ATT_OP_TYPE_IND)
 		return NULL;
 
 	/* Similarly, if the operation does elicit a response then a callback
 	 * must be provided.
 	 */
-	if (!callback && (op_type == ATT_OP_TYPE_REQ || op_type == ATT_OP_TYPE_IND))
+	if (!callback && (type == ATT_OP_TYPE_REQ || type == ATT_OP_TYPE_IND))
 		return NULL;
 
 	op = new0(struct att_send_op, 1);
-	if (!op)
-		return NULL;
-
-	op->type = op_type;
+	op->type = type;
 	op->opcode = opcode;
 	op->callback = callback;
 	op->destroy = destroy;
@@ -496,9 +493,6 @@
 	}
 
 	timeout = new0(struct timeout_data, 1);
-	if (!timeout)
-		return true;
-
 	timeout->att = att;
 	timeout->id = op->id;
 	op->timeout_id = timeout_add(ATT_TIMEOUT_INTERVAL, timeout_cb,
@@ -957,9 +951,6 @@
 		return NULL;
 
 	att = new0(struct bt_att, 1);
-	if (!att)
-		return NULL;
-
 	att->fd = fd;
 	att->mtu = BT_ATT_DEFAULT_LE_MTU;
 	att->buf = malloc(att->mtu);
@@ -975,24 +966,10 @@
 		att->crypto = bt_crypto_new();
 
 	att->req_queue = queue_new();
-	if (!att->req_queue)
-		goto fail;
-
 	att->ind_queue = queue_new();
-	if (!att->ind_queue)
-		goto fail;
-
 	att->write_queue = queue_new();
-	if (!att->write_queue)
-		goto fail;
-
 	att->notify_list = queue_new();
-	if (!att->notify_list)
-		goto fail;
-
 	att->disconn_list = queue_new();
-	if (!att->disconn_list)
-		goto fail;
 
 	if (!io_set_read_handler(att->io, can_read_data, att, NULL))
 		goto fail;
@@ -1126,9 +1103,6 @@
 		return 0;
 
 	disconn = new0(struct att_disconn, 1);
-	if (!disconn)
-		return 0;
-
 	disconn->callback = callback;
 	disconn->destroy = destroy;
 	disconn->user_data = user_data;
@@ -1342,9 +1316,6 @@
 		return 0;
 
 	notify = new0(struct att_notify, 1);
-	if (!notify)
-		return 0;
-
 	notify->opcode = opcode;
 	notify->callback = callback;
 	notify->destroy = destroy;
@@ -1435,11 +1406,8 @@
 static bool sign_set_key(struct sign_info **sign, uint8_t key[16],
 				bt_att_counter_func_t func, void *user_data)
 {
-	if (!(*sign)) {
+	if (!(*sign))
 		*sign = new0(struct sign_info, 1);
-		if (!(*sign))
-			return false;
-	}
 
 	(*sign)->counter = func;
 	(*sign)->user_data = user_data;
diff --git a/src/shared/btsnoop.c b/src/shared/btsnoop.c
index 212cbf7..cec1b21 100644
--- a/src/shared/btsnoop.c
+++ b/src/shared/btsnoop.c
@@ -68,7 +68,7 @@
 	int ref_count;
 	int fd;
 	unsigned long flags;
-	uint32_t type;
+	uint32_t format;
 	uint16_t index;
 	bool aborted;
 	bool pklg_format;
@@ -102,7 +102,7 @@
 		if (be32toh(hdr.version) != btsnoop_version)
 			goto failed;
 
-		btsnoop->type = be32toh(hdr.type);
+		btsnoop->format = be32toh(hdr.type);
 		btsnoop->index = 0xffff;
 	} else {
 		if (!(btsnoop->flags & BTSNOOP_FLAG_PKLG_SUPPORT))
@@ -113,7 +113,7 @@
 				(hdr.id[1] != 0x00 && hdr.id[1] != 0x01))
 			goto failed;
 
-		btsnoop->type = BTSNOOP_TYPE_MONITOR;
+		btsnoop->format = BTSNOOP_FORMAT_MONITOR;
 		btsnoop->index = 0xffff;
 		btsnoop->pklg_format = true;
 		btsnoop->pklg_v2 = (hdr.id[1] == 0x01);
@@ -131,7 +131,7 @@
 	return NULL;
 }
 
-struct btsnoop *btsnoop_create(const char *path, uint32_t type)
+struct btsnoop *btsnoop_create(const char *path, uint32_t format)
 {
 	struct btsnoop *btsnoop;
 	struct btsnoop_hdr hdr;
@@ -148,12 +148,12 @@
 		return NULL;
 	}
 
-	btsnoop->type = type;
+	btsnoop->format = format;
 	btsnoop->index = 0xffff;
 
 	memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
 	hdr.version = htobe32(btsnoop_version);
-	hdr.type = htobe32(btsnoop->type);
+	hdr.type = htobe32(btsnoop->format);
 
 	written = write(btsnoop->fd, &hdr, BTSNOOP_HDR_SIZE);
 	if (written < 0) {
@@ -189,12 +189,12 @@
 	free(btsnoop);
 }
 
-uint32_t btsnoop_get_type(struct btsnoop *btsnoop)
+uint32_t btsnoop_get_format(struct btsnoop *btsnoop)
 {
 	if (!btsnoop)
-		return BTSNOOP_TYPE_INVALID;
+		return BTSNOOP_FORMAT_INVALID;
 
-	return btsnoop->type;
+	return btsnoop->format;
 }
 
 bool btsnoop_write(struct btsnoop *btsnoop, struct timeval *tv,
@@ -262,8 +262,8 @@
 	if (!btsnoop)
 		return false;
 
-	switch (btsnoop->type) {
-	case BTSNOOP_TYPE_HCI:
+	switch (btsnoop->format) {
+	case BTSNOOP_FORMAT_HCI:
 		if (btsnoop->index == 0xffff)
 			btsnoop->index = index;
 
@@ -275,7 +275,7 @@
 			return false;
 		break;
 
-	case BTSNOOP_TYPE_MONITOR:
+	case BTSNOOP_FORMAT_MONITOR:
 		flags = (index << 16) | opcode;
 		break;
 
@@ -294,8 +294,8 @@
 	if (!btsnoop)
 		return false;
 
-	switch (btsnoop->type) {
-	case BTSNOOP_TYPE_SIMULATOR:
+	switch (btsnoop->format) {
+	case BTSNOOP_FORMAT_SIMULATOR:
 		flags = (1 << 16) | frequency;
 		break;
 
@@ -306,22 +306,6 @@
 	return btsnoop_write(btsnoop, tv, flags, data, size);
 }
 
-static uint16_t get_opcode_from_pklg(uint8_t type)
-{
-	switch (type) {
-	case 0x00:
-		return BTSNOOP_OPCODE_COMMAND_PKT;
-	case 0x01:
-		return BTSNOOP_OPCODE_EVENT_PKT;
-	case 0x02:
-		return BTSNOOP_OPCODE_ACL_TX_PKT;
-	case 0x03:
-		return BTSNOOP_OPCODE_ACL_RX_PKT;
-	}
-
-	return 0xffff;
-}
-
 static bool pklg_read_hci(struct btsnoop *btsnoop, struct timeval *tv,
 					uint16_t *index, uint16_t *opcode,
 					void *data, uint16_t *size)
@@ -354,8 +338,36 @@
 		tv->tv_usec = ts & 0xffffffff;
 	}
 
-	*index = 0;
-	*opcode = get_opcode_from_pklg(pkt.type);
+	switch (pkt.type) {
+	case 0x00:
+		*index = 0x0000;
+		*opcode = BTSNOOP_OPCODE_COMMAND_PKT;
+		break;
+	case 0x01:
+		*index = 0x0000;
+		*opcode = BTSNOOP_OPCODE_EVENT_PKT;
+		break;
+	case 0x02:
+		*index = 0x0000;
+		*opcode = BTSNOOP_OPCODE_ACL_TX_PKT;
+		break;
+	case 0x03:
+		*index = 0x0000;
+		*opcode = BTSNOOP_OPCODE_ACL_RX_PKT;
+		break;
+	case 0x0b:
+		*index = 0x0000;
+		*opcode = BTSNOOP_OPCODE_VENDOR_DIAG;
+		break;
+	case 0xfc:
+		*index = 0xffff;
+		*opcode = BTSNOOP_OPCODE_SYSTEM_NOTE;
+		break;
+	default:
+		*index = 0xffff;
+		*opcode = 0xffff;
+		break;
+	}
 
 	len = read(btsnoop->fd, data, toread);
 	if (len < 0) {
@@ -440,13 +452,13 @@
 	tv->tv_sec = (ts / 1000000ll) + 946684800ll;
 	tv->tv_usec = ts % 1000000ll;
 
-	switch (btsnoop->type) {
-	case BTSNOOP_TYPE_HCI:
+	switch (btsnoop->format) {
+	case BTSNOOP_FORMAT_HCI:
 		*index = 0;
 		*opcode = get_opcode_from_flags(0xff, flags);
 		break;
 
-	case BTSNOOP_TYPE_UART:
+	case BTSNOOP_FORMAT_UART:
 		len = read(btsnoop->fd, &pkt_type, 1);
 		if (len < 0) {
 			btsnoop->aborted = true;
@@ -458,7 +470,7 @@
 		*opcode = get_opcode_from_flags(pkt_type, flags);
 		break;
 
-	case BTSNOOP_TYPE_MONITOR:
+	case BTSNOOP_FORMAT_MONITOR:
 		*index = flags >> 16;
 		*opcode = flags & 0xffff;
 		break;
diff --git a/src/shared/btsnoop.h b/src/shared/btsnoop.h
index a0157ff..d94dbae 100644
--- a/src/shared/btsnoop.h
+++ b/src/shared/btsnoop.h
@@ -25,13 +25,13 @@
 #include <stdbool.h>
 #include <sys/time.h>
 
-#define BTSNOOP_TYPE_INVALID		0
-#define BTSNOOP_TYPE_HCI		1001
-#define BTSNOOP_TYPE_UART		1002
-#define BTSNOOP_TYPE_BCSP		1003
-#define BTSNOOP_TYPE_3WIRE		1004
-#define BTSNOOP_TYPE_MONITOR		2001
-#define BTSNOOP_TYPE_SIMULATOR		2002
+#define BTSNOOP_FORMAT_INVALID		0
+#define BTSNOOP_FORMAT_HCI		1001
+#define BTSNOOP_FORMAT_UART		1002
+#define BTSNOOP_FORMAT_BCSP		1003
+#define BTSNOOP_FORMAT_3WIRE		1004
+#define BTSNOOP_FORMAT_MONITOR		2001
+#define BTSNOOP_FORMAT_SIMULATOR	2002
 
 #define BTSNOOP_FLAG_PKLG_SUPPORT	(1 << 0)
 
@@ -47,9 +47,22 @@
 #define BTSNOOP_OPCODE_CLOSE_INDEX	9
 #define BTSNOOP_OPCODE_INDEX_INFO	10
 #define BTSNOOP_OPCODE_VENDOR_DIAG	11
+#define BTSNOOP_OPCODE_SYSTEM_NOTE	12
+#define BTSNOOP_OPCODE_USER_LOGGING	13
 
 #define BTSNOOP_MAX_PACKET_SIZE		(1486 + 4)
 
+#define BTSNOOP_TYPE_PRIMARY	0
+#define BTSNOOP_TYPE_AMP	1
+
+#define BTSNOOP_BUS_VIRTUAL	0
+#define BTSNOOP_BUS_USB		1
+#define BTSNOOP_BUS_PCCARD	2
+#define BTSNOOP_BUS_UART	3
+#define BTSNOOP_BUS_RS232	4
+#define BTSNOOP_BUS_PCI		5
+#define BTSNOOP_BUS_SDIO	6
+
 struct btsnoop_opcode_new_index {
 	uint8_t  type;
 	uint8_t  bus;
@@ -62,15 +75,29 @@
 	uint16_t manufacturer;
 } __attribute__((packed));
 
+#define BTSNOOP_PRIORITY_EMERG		0
+#define BTSNOOP_PRIORITY_ALERT		1
+#define BTSNOOP_PRIORITY_CRIT		2
+#define BTSNOOP_PRIORITY_ERR		3
+#define BTSNOOP_PRIORITY_WARNING	4
+#define BTSNOOP_PRIORITY_NOTICE		5
+#define BTSNOOP_PRIORITY_INFO		6
+#define BTSNOOP_PRIORITY_DEBUG		7
+
+struct btsnoop_opcode_user_logging {
+	uint8_t  priority;
+	uint8_t  ident_len;
+} __attribute__((packed));
+
 struct btsnoop;
 
 struct btsnoop *btsnoop_open(const char *path, unsigned long flags);
-struct btsnoop *btsnoop_create(const char *path, uint32_t type);
+struct btsnoop *btsnoop_create(const char *path, uint32_t format);
 
 struct btsnoop *btsnoop_ref(struct btsnoop *btsnoop);
 void btsnoop_unref(struct btsnoop *btsnoop);
 
-uint32_t btsnoop_get_type(struct btsnoop *btsnoop);
+uint32_t btsnoop_get_format(struct btsnoop *btsnoop);
 
 bool btsnoop_write(struct btsnoop *btsnoop, struct timeval *tv,
 			uint32_t flags, const void *data, uint16_t size);
diff --git a/src/shared/crypto.c b/src/shared/crypto.c
index d5cd915..aa66dac 100644
--- a/src/shared/crypto.c
+++ b/src/shared/crypto.c
@@ -142,8 +142,6 @@
 	struct bt_crypto *crypto;
 
 	crypto = new0(struct bt_crypto, 1);
-	if (!crypto)
-		return NULL;
 
 	crypto->ecb_aes = ecb_aes_setup();
 	if (crypto->ecb_aes < 0) {
diff --git a/src/shared/gap.c b/src/shared/gap.c
index cc48a02..4a21e5d 100644
--- a/src/shared/gap.c
+++ b/src/shared/gap.c
@@ -162,9 +162,6 @@
 		return NULL;
 
 	gap = new0(struct bt_gap, 1);
-	if (!gap)
-		return NULL;
-
 	gap->index = index;
 
 	gap->mgmt = mgmt_new_default();
@@ -174,7 +171,6 @@
 	}
 
 	gap->irk_list = queue_new();
-
 	gap->mgmt_ready = false;
 
 	if (!mgmt_send(gap->mgmt, MGMT_OP_READ_VERSION,
@@ -269,9 +265,6 @@
 		return false;
 
 	irk = new0(struct irk_entry, 1);
-	if (!irk)
-		return false;
-
 	irk->addr_type = addr_type;
 	memcpy(irk->addr, addr, 6);
 	memcpy(irk->key, key, 16);
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index d3e17e1..06ac763 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -21,6 +21,10 @@
  *
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include "src/shared/att.h"
 #include "lib/bluetooth.h"
 #include "lib/uuid.h"
@@ -131,8 +135,6 @@
 	struct request *req;
 
 	req = new0(struct request, 1);
-	if (!req)
-		return NULL;
 
 	if (client->next_request_id < 1)
 		client->next_request_id = 1;
@@ -243,8 +245,6 @@
 			return NULL;
 
 	chrc = new0(struct notify_chrc, 1);
-	if (!chrc)
-		return NULL;
 
 	chrc->reg_notify_queue = queue_new();
 	if (!chrc->reg_notify_queue) {
@@ -310,6 +310,16 @@
 					chrc->value_handle <= range->end;
 }
 
+static void notify_data_cleanup(void *data)
+{
+	struct notify_data *notify_data = data;
+
+	if (notify_data->att_id)
+		bt_att_cancel(notify_data->client->att, notify_data->att_id);
+
+	notify_data_unref(notify_data);
+}
+
 static void gatt_client_remove_all_notify_in_range(
 				struct bt_gatt_client *client,
 				uint16_t start_handle, uint16_t end_handle)
@@ -320,7 +330,7 @@
 	range.end = end_handle;
 
 	queue_remove_all(client->notify_list, match_notify_data_handle_range,
-						&range, notify_data_unref);
+						&range, notify_data_cleanup);
 }
 
 static void gatt_client_remove_notify_chrcs_in_range(
@@ -373,21 +383,9 @@
 	struct discovery_op *op;
 
 	op = new0(struct discovery_op, 1);
-	if (!op)
-		return NULL;
-
 	op->pending_svcs = queue_new();
-	if (!op->pending_svcs)
-		goto fail;
-
 	op->pending_chrcs = queue_new();
-	if (!op->pending_chrcs)
-		goto fail;
-
 	op->tmp_queue = queue_new();
-	if (!op->tmp_queue)
-		goto fail;
-
 	op->client = client;
 	op->complete_func = complete_func;
 	op->failure_func = failure_func;
@@ -395,10 +393,6 @@
 	op->end = end;
 
 	return op;
-
-fail:
-	discovery_op_free(op);
-	return NULL;
 }
 
 static struct discovery_op *discovery_op_ref(struct discovery_op *op)
@@ -787,8 +781,6 @@
 				start, end, value, properties, uuid_str);
 
 		chrc_data = new0(struct chrc, 1);
-		if (!chrc_data)
-			goto failed;
 
 		chrc_data->start_handle = start;
 		chrc_data->end_handle = end;
@@ -1255,9 +1247,6 @@
 		return 0;
 
 	notify_data = new0(struct notify_data, 1);
-	if (!notify_data)
-		return 0;
-
 	notify_data->client = client;
 	notify_data->ref_count = 1;
 	notify_data->chrc = chrc;
@@ -1417,6 +1406,10 @@
 {
 	struct discovery_op *op;
 
+	/* On full database reset just re-run attribute discovery */
+	if (start_handle == 0x0001 && end_handle == 0xffff)
+		goto discover;
+
 	/* Invalidate and remove all effected notify callbacks */
 	gatt_client_remove_all_notify_in_range(client, start_handle,
 								end_handle);
@@ -1428,6 +1421,7 @@
 	 */
 	gatt_db_clear_range(client->db, start_handle, end_handle);
 
+discover:
 	op = discovery_op_create(client, start_handle, end_handle,
 						service_changed_complete,
 						service_changed_failure);
@@ -1481,8 +1475,6 @@
 	}
 
 	op = new0(struct service_changed_op, 1);
-	if (!op)
-		return;
 
 	op->start_handle = start;
 	op->end_handle = end;
@@ -1647,16 +1639,6 @@
 	bt_gatt_client_unref(client);
 }
 
-static void notify_data_cleanup(void *data)
-{
-	struct notify_data *notify_data = data;
-
-	if (notify_data->att_id)
-		bt_att_cancel(notify_data->client->att, notify_data->att_id);
-
-	notify_data_unref(notify_data);
-}
-
 static void bt_gatt_client_free(struct bt_gatt_client *client)
 {
 	bt_gatt_client_cancel_all(client);
@@ -1713,33 +1695,16 @@
 		return NULL;
 
 	client = new0(struct bt_gatt_client, 1);
-	if (!client)
-		return NULL;
-
 	client->disc_id = bt_att_register_disconnect(att, att_disconnect_cb,
 								client, NULL);
 	if (!client->disc_id)
 		goto fail;
 
 	client->long_write_queue = queue_new();
-	if (!client->long_write_queue)
-		goto fail;
-
 	client->svc_chngd_queue = queue_new();
-	if (!client->svc_chngd_queue)
-		goto fail;
-
 	client->notify_list = queue_new();
-	if (!client->notify_list)
-		goto fail;
-
 	client->notify_chrcs = queue_new();
-	if (!client->notify_chrcs)
-		goto fail;
-
 	client->pending_requests = queue_new();
-	if (!client->pending_requests)
-		goto fail;
 
 	client->notify_id = bt_att_register(att, BT_ATT_OP_HANDLE_VAL_NOT,
 						notify_cb, client, NULL);
@@ -2025,8 +1990,6 @@
 		return 0;
 
 	op = new0(struct read_op, 1);
-	if (!op)
-		return 0;
 
 	req = request_create(client);
 	if (!req) {
@@ -2104,8 +2067,6 @@
 		return 0;
 
 	op = new0(struct read_op, 1);
-	if (!op)
-		return 0;
 
 	req = request_create(client);
 	if (!req) {
@@ -2254,8 +2215,6 @@
 		return 0;
 
 	op = new0(struct read_long_op, 1);
-	if (!op)
-		return 0;
 
 	req = request_create(client);
 	if (!req) {
@@ -2381,8 +2340,6 @@
 		return 0;
 
 	op = new0(struct write_op, 1);
-	if (!op)
-		return 0;
 
 	req = request_create(client);
 	if (!req) {
@@ -2656,9 +2613,6 @@
 		return 0;
 
 	op = new0(struct long_write_op, 1);
-	if (!op)
-		return 0;
-
 	op->value = malloc(length);
 	if (!op->value) {
 		free(op);
@@ -2787,8 +2741,6 @@
 	struct prep_write_op *op;
 
 	op = new0(struct prep_write_op, 1);
-	if (!op)
-		return NULL;
 
 	/* Following prepare writes */
 	if (id != 0)
@@ -2947,8 +2899,6 @@
 		return 0;
 
 	op = new0(struct write_op, 1);
-	if (!op)
-		return 0;
 
 	req = queue_find(client->pending_requests, match_req_id,
 							UINT_TO_PTR(id));
diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 7f863ef..cc49458 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -21,6 +21,10 @@
  *
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include <stdbool.h>
 #include <errno.h>
 
@@ -166,8 +170,6 @@
 	struct gatt_db_attribute *attribute;
 
 	attribute = new0(struct gatt_db_attribute, 1);
-	if (!attribute)
-		return NULL;
 
 	attribute->service = service;
 	attribute->handle = handle;
@@ -182,12 +184,7 @@
 	}
 
 	attribute->pending_reads = queue_new();
-	if (!attribute->pending_reads)
-		goto failed;
-
 	attribute->pending_writes = queue_new();
-	if (!attribute->pending_reads)
-		goto failed;
 
 	return attribute;
 
@@ -211,22 +208,8 @@
 	struct gatt_db *db;
 
 	db = new0(struct gatt_db, 1);
-	if (!db)
-		return NULL;
-
 	db->services = queue_new();
-	if (!db->services) {
-		free(db);
-		return NULL;
-	}
-
 	db->notify_list = queue_new();
-	if (!db->notify_list) {
-		queue_destroy(db->services, NULL);
-		free(db);
-		return NULL;
-	}
-
 	db->next_handle = 0x0001;
 
 	return gatt_db_ref(db);
@@ -386,14 +369,7 @@
 		return NULL;
 
 	service = new0(struct gatt_db_service, 1);
-	if (!service)
-		return NULL;
-
 	service->attributes = new0(struct gatt_db_attribute *, num_handles);
-	if (!service->attributes) {
-		free(service);
-		return NULL;
-	}
 
 	if (primary)
 		type = &primary_service_uuid;
@@ -605,9 +581,6 @@
 		return 0;
 
 	notify = new0(struct notify, 1);
-	if (!notify)
-		return 0;
-
 	notify->service_added = service_added;
 	notify->service_removed = service_removed;
 	notify->destroy = destroy;
@@ -1591,9 +1564,6 @@
 		struct pending_read *p;
 
 		p = new0(struct pending_read, 1);
-		if (!p)
-			return false;
-
 		p->attrib = attrib;
 		p->id = ++attrib->read_id;
 		p->timeout_id = timeout_add(ATTRIBUTE_TIMEOUT, read_timeout,
@@ -1675,9 +1645,6 @@
 		struct pending_write *p;
 
 		p = new0(struct pending_write, 1);
-		if (!p)
-			return false;
-
 		p->attrib = attrib;
 		p->id = ++attrib->write_id;
 		p->timeout_id = timeout_add(ATTRIBUTE_TIMEOUT, write_timeout,
diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c
index 008b8bc..a0a5b26 100644
--- a/src/shared/gatt-helpers.c
+++ b/src/shared/gatt-helpers.c
@@ -56,9 +56,6 @@
 	struct bt_gatt_result *result;
 
 	result = new0(struct bt_gatt_result, 1);
-	if (!result)
-		return NULL;
-
 	result->pdu = malloc(pdu_len);
 	if (!result->pdu) {
 		free(result);
@@ -110,7 +107,7 @@
 		return 0;
 
 	if (result->opcode != BT_ATT_OP_READ_BY_GRP_TYPE_RSP &&
-			result->opcode != BT_ATT_OP_FIND_BY_TYPE_VAL_RSP)
+			result->opcode != BT_ATT_OP_FIND_BY_TYPE_RSP)
 		return 0;
 
 	return result_element_count(result);
@@ -345,7 +342,7 @@
 		*end_handle = get_le16(pdu_ptr + 2);
 		convert_uuid_le(pdu_ptr + 4, iter->result->data_len - 4, uuid);
 		break;
-	case BT_ATT_OP_FIND_BY_TYPE_VAL_RSP:
+	case BT_ATT_OP_FIND_BY_TYPE_RSP:
 		*start_handle = get_le16(pdu_ptr);
 		*end_handle = get_le16(pdu_ptr + 2);
 
@@ -549,9 +546,6 @@
 		return false;
 
 	op = new0(struct mtu_op, 1);
-	if (!op)
-		return false;
-
 	op->att = att;
 	op->client_rx_mtu = client_rx_mtu;
 	op->callback = callback;
@@ -753,7 +747,7 @@
 	/* PDU must contain 4 bytes and it must be a multiple of 4, where each
 	 * 4 bytes contain the 16-bit attribute and group end handles.
 	 */
-	if (opcode != BT_ATT_OP_FIND_BY_TYPE_VAL_RSP || !pdu || !length ||
+	if (opcode != BT_ATT_OP_FIND_BY_TYPE_RSP || !pdu || !length ||
 								length % 4) {
 		success = false;
 		goto done;
@@ -791,7 +785,7 @@
 		put_le16(op->service_type, pdu + 4);
 		bt_uuid_to_le(&op->uuid, pdu + 6);
 
-		op->id = bt_att_send(op->att, BT_ATT_OP_FIND_BY_TYPE_VAL_REQ,
+		op->id = bt_att_send(op->att, BT_ATT_OP_FIND_BY_TYPE_REQ,
 						pdu, sizeof(pdu),
 						find_by_type_val_cb,
 						bt_gatt_request_ref(op),
@@ -823,9 +817,6 @@
 		return NULL;
 
 	op = new0(struct bt_gatt_request, 1);
-	if (!op)
-		return NULL;
-
 	op->att = att;
 	op->start_handle = start;
 	op->end_handle = end;
@@ -864,7 +855,7 @@
 		put_le16(op->service_type, pdu + 4);
 		bt_uuid_to_le(&op->uuid, pdu + 6);
 
-		op->id = bt_att_send(att, BT_ATT_OP_FIND_BY_TYPE_VAL_REQ,
+		op->id = bt_att_send(att, BT_ATT_OP_FIND_BY_TYPE_REQ,
 						pdu, sizeof(pdu),
 						find_by_type_val_cb,
 						bt_gatt_request_ref(op),
@@ -924,9 +915,6 @@
 	struct read_incl_data *data;
 
 	data = new0(struct read_incl_data, 1);
-	if (!data)
-		return NULL;
-
 	data->op = bt_gatt_request_ref(res->op);
 	data->result = res;
 
@@ -1161,9 +1149,6 @@
 		return false;
 
 	op = new0(struct bt_gatt_request, 1);
-	if (!op)
-		return false;
-
 	op->att = att;
 	op->callback = callback;
 	op->user_data = user_data;
@@ -1278,9 +1263,6 @@
 		return false;
 
 	op = new0(struct bt_gatt_request, 1);
-	if (!op)
-		return false;
-
 	op->att = att;
 	op->callback = callback;
 	op->user_data = user_data;
@@ -1388,9 +1370,6 @@
 		return false;
 
 	op = new0(struct bt_gatt_request, 1);
-	if (!op)
-		return false;
-
 	op->att = att;
 	op->callback = callback;
 	op->user_data = user_data;
@@ -1512,9 +1491,6 @@
 		return false;
 
 	op = new0(struct bt_gatt_request, 1);
-	if (!op)
-		return false;
-
 	op->att = att;
 	op->callback = callback;
 	op->user_data = user_data;
diff --git a/src/shared/gatt-server.c b/src/shared/gatt-server.c
index 6167065..ba668e3 100644
--- a/src/shared/gatt-server.c
+++ b/src/shared/gatt-server.c
@@ -21,6 +21,10 @@
  *
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include <sys/uio.h>
 #include <errno.h>
 
@@ -248,10 +252,6 @@
 	}
 
 	q = queue_new();
-	if (!q) {
-		ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
-		goto error;
-	}
 
 	start = get_le16(pdu);
 	end = get_le16(pdu + 2);
@@ -457,10 +457,6 @@
 	}
 
 	q = queue_new();
-	if (!q) {
-		ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
-		goto error;
-	}
 
 	start = get_le16(pdu);
 	end = get_le16(pdu + 2);
@@ -495,11 +491,6 @@
 	}
 
 	op = new0(struct async_read_op, 1);
-	if (!op) {
-		ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
-		goto error;
-	}
-
 	op->pdu = malloc(bt_att_get_mtu(server->att));
 	if (!op->pdu) {
 		free(op);
@@ -593,10 +584,6 @@
 	}
 
 	q = queue_new();
-	if (!q) {
-		ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
-		goto error;
-	}
 
 	start = get_le16(pdu);
 	end = get_le16(pdu + 2);
@@ -724,7 +711,7 @@
 	if (data.ecode)
 		goto error;
 
-	bt_att_send(server->att, BT_ATT_OP_FIND_BY_TYPE_VAL_RSP, data.pdu,
+	bt_att_send(server->att, BT_ATT_OP_FIND_BY_TYPE_RSP, data.pdu,
 						data.len, NULL, NULL, NULL);
 
 	return;
@@ -802,11 +789,6 @@
 	}
 
 	op = new0(struct async_write_op, 1);
-	if (!op) {
-		ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
-		goto error;
-	}
-
 	op->server = server;
 	op->opcode = opcode;
 	server->pending_write_op = op;
@@ -914,11 +896,6 @@
 	}
 
 	op = new0(struct async_read_op, 1);
-	if (!op) {
-		ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
-		goto error;
-	}
-
 	op->opcode = opcode;
 	op->server = server;
 	server->pending_read_op = op;
@@ -1088,9 +1065,6 @@
 
 	data.handles = new0(uint16_t, data.num_handles);
 
-	if (!data.handles)
-		goto error;
-
 	for (i = 0; i < data.num_handles; i++)
 		data.handles[i] = get_le16(pdu + i * 2);
 
@@ -1153,11 +1127,6 @@
 		goto error;
 
 	prep_data = new0(struct prep_write_data, 1);
-	if (!prep_data) {
-		ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
-		goto error;
-	}
-
 	prep_data->length = length - 4;
 	if (prep_data->length) {
 		prep_data->value = malloc(prep_data->length);
@@ -1347,7 +1316,7 @@
 
 	/* Find By Type Value */
 	server->find_by_type_value_id = bt_att_register(server->att,
-						BT_ATT_OP_FIND_BY_TYPE_VAL_REQ,
+						BT_ATT_OP_FIND_BY_TYPE_REQ,
 						find_by_type_val_cb,
 						server, NULL);
 
@@ -1418,19 +1387,11 @@
 		return NULL;
 
 	server = new0(struct bt_gatt_server, 1);
-	if (!server)
-		return NULL;
-
 	server->db = gatt_db_ref(db);
 	server->att = bt_att_ref(att);
 	server->mtu = MAX(mtu, BT_ATT_DEFAULT_LE_MTU);
 	server->max_prep_queue_len = DEFAULT_MAX_PREP_QUEUE_LEN;
-
 	server->prep_queue = queue_new();
-	if (!server->prep_queue) {
-		bt_gatt_server_free(server);
-		return NULL;
-	}
 
 	if (!gatt_server_register_att_handlers(server)) {
 		bt_gatt_server_free(server);
@@ -1551,10 +1512,6 @@
 		return false;
 
 	data = new0(struct ind_data, 1);
-	if (!data) {
-		free(pdu);
-		return false;
-	}
 
 	data->callback = callback;
 	data->destroy = destroy;
diff --git a/src/shared/hci-crypto.c b/src/shared/hci-crypto.c
index 8a40aa5..f750747 100644
--- a/src/shared/hci-crypto.c
+++ b/src/shared/hci-crypto.c
@@ -66,9 +66,6 @@
 	memcpy(cmd.plaintext, plaintext, 16);
 
 	data = new0(struct crypto_data, 1);
-	if (!data)
-		return false;
-
 	data->size = size;
 	data->callback = callback;
 	data->user_data = user_data;
@@ -110,9 +107,6 @@
 		return false;
 
 	data = new0(struct crypto_data, 1);
-	if (!data)
-		return false;
-
 	data->callback = callback;
 	data->user_data = user_data;
 
diff --git a/src/shared/hci.c b/src/shared/hci.c
index 0db0146..bfee4ab 100644
--- a/src/shared/hci.c
+++ b/src/shared/hci.c
@@ -290,9 +290,6 @@
 		return NULL;
 
 	hci = new0(struct bt_hci, 1);
-	if (!hci)
-		return NULL;
-
 	hci->io = io_new(fd);
 	if (!hci->io) {
 		free(hci);
@@ -306,28 +303,8 @@
 	hci->next_evt_id = 1;
 
 	hci->cmd_queue = queue_new();
-	if (!hci->cmd_queue) {
-		io_destroy(hci->io);
-		free(hci);
-		return NULL;
-	}
-
 	hci->rsp_queue = queue_new();
-	if (!hci->rsp_queue) {
-		queue_destroy(hci->cmd_queue, NULL);
-		io_destroy(hci->io);
-		free(hci);
-		return NULL;
-	}
-
 	hci->evt_list = queue_new();
-	if (!hci->evt_list) {
-		queue_destroy(hci->rsp_queue, NULL);
-		queue_destroy(hci->cmd_queue, NULL);
-		io_destroy(hci->io);
-		free(hci);
-		return NULL;
-	}
 
 	if (!io_set_read_handler(hci->io, io_read_callback, hci, NULL)) {
 		queue_destroy(hci->evt_list, NULL);
@@ -476,9 +453,6 @@
 		return 0;
 
 	cmd = new0(struct cmd, 1);
-	if (!cmd)
-		return 0;
-
 	cmd->opcode = opcode;
 	cmd->size = size;
 
@@ -568,9 +542,6 @@
 		return 0;
 
 	evt = new0(struct evt, 1);
-	if (!evt)
-		return 0;
-
 	evt->event = event;
 
 	if (hci->next_evt_id < 1)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 74ee979..d9f7659 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -575,9 +575,6 @@
 		return NULL;
 
 	hfp = new0(struct hfp_gw, 1);
-	if (!hfp)
-		return NULL;
-
 	hfp->fd = fd;
 	hfp->close_on_unref = false;
 
@@ -603,13 +600,6 @@
 	}
 
 	hfp->cmd_handlers = queue_new();
-	if (!hfp->cmd_handlers) {
-		io_destroy(hfp->io);
-		ringbuf_free(hfp->write_buf);
-		ringbuf_free(hfp->read_buf);
-		free(hfp);
-		return NULL;
-	}
 
 	if (!io_set_read_handler(hfp->io, can_read_data, hfp,
 							read_watch_destroy)) {
@@ -844,9 +834,6 @@
 	struct cmd_handler *handler;
 
 	handler = new0(struct cmd_handler, 1);
-	if (!handler)
-		return false;
-
 	handler->callback = callback;
 	handler->user_data = user_data;
 
@@ -1262,9 +1249,6 @@
 		return NULL;
 
 	hfp = new0(struct hfp_hf, 1);
-	if (!hfp)
-		return NULL;
-
 	hfp->fd = fd;
 	hfp->close_on_unref = false;
 
@@ -1290,24 +1274,7 @@
 	}
 
 	hfp->event_handlers = queue_new();
-	if (!hfp->event_handlers) {
-		io_destroy(hfp->io);
-		ringbuf_free(hfp->write_buf);
-		ringbuf_free(hfp->read_buf);
-		free(hfp);
-		return NULL;
-	}
-
 	hfp->cmd_queue = queue_new();
-	if (!hfp->cmd_queue) {
-		io_destroy(hfp->io);
-		ringbuf_free(hfp->write_buf);
-		ringbuf_free(hfp->read_buf);
-		queue_destroy(hfp->event_handlers, NULL);
-		free(hfp);
-		return NULL;
-	}
-
 	hfp->writer_active = false;
 
 	if (!io_set_read_handler(hfp->io, hf_can_read_data, hfp,
@@ -1440,10 +1407,6 @@
 		return false;
 
 	cmd = new0(struct cmd_response, 1);
-	if (!cmd) {
-		free(fmt);
-		return false;
-	}
 
 	va_start(ap, format);
 	len = ringbuf_vprintf(hfp->write_buf, fmt, ap);
@@ -1481,9 +1444,6 @@
 		return false;
 
 	handler = new0(struct event_handler, 1);
-	if (!handler)
-		return false;
-
 	handler->callback = callback;
 	handler->user_data = user_data;
 
diff --git a/src/shared/io-mainloop.c b/src/shared/io-mainloop.c
index 4923710..2306c34 100644
--- a/src/shared/io-mainloop.c
+++ b/src/shared/io-mainloop.c
@@ -160,9 +160,6 @@
 		return NULL;
 
 	io = new0(struct io, 1);
-	if (!io)
-		return NULL;
-
 	io->fd = fd;
 	io->events = 0;
 	io->close_on_destroy = false;
diff --git a/src/shared/mgmt.c b/src/shared/mgmt.c
index 1ed635d..277e361 100644
--- a/src/shared/mgmt.c
+++ b/src/shared/mgmt.c
@@ -51,6 +51,8 @@
 	struct queue *notify_list;
 	unsigned int next_request_id;
 	unsigned int next_notify_id;
+	bool need_notify_cleanup;
+	bool in_notify;
 	void *buf;
 	uint16_t len;
 	mgmt_debug_func_t debug_callback;
@@ -73,6 +75,7 @@
 	unsigned int id;
 	uint16_t event;
 	uint16_t index;
+	bool removed;
 	mgmt_notify_func_t callback;
 	mgmt_destroy_func_t destroy;
 	void *user_data;
@@ -131,6 +134,22 @@
 	return notify->index == index;
 }
 
+static bool match_notify_removed(const void *a, const void *b)
+{
+	const struct mgmt_notify *notify = a;
+
+	return notify->removed;
+}
+
+static void mark_notify_removed(void *data , void *user_data)
+{
+	struct mgmt_notify *notify = data;
+	uint16_t index = PTR_TO_UINT(user_data);
+
+	if (notify->index == index || index == MGMT_INDEX_NONE)
+		notify->removed = true;
+}
+
 static void write_watch_destroy(void *user_data)
 {
 	struct mgmt *mgmt = user_data;
@@ -260,6 +279,9 @@
 	struct mgmt_notify *notify = data;
 	struct event_index *match = user_data;
 
+	if (notify->removed)
+		return;
+
 	if (notify->event != match->event)
 		return;
 
@@ -277,7 +299,17 @@
 	struct event_index match = { .event = event, .index = index,
 					.length = length, .param = param };
 
+	mgmt->in_notify = true;
+
 	queue_foreach(mgmt->notify_list, notify_handler, &match);
+
+	mgmt->in_notify = false;
+
+	if (mgmt->need_notify_cleanup) {
+		queue_remove_all(mgmt->notify_list, match_notify_removed,
+							NULL, destroy_notify);
+		mgmt->need_notify_cleanup = false;
+	}
 }
 
 static bool can_read_data(struct io *io, void *user_data)
@@ -353,9 +385,6 @@
 		return NULL;
 
 	mgmt = new0(struct mgmt, 1);
-	if (!mgmt)
-		return NULL;
-
 	mgmt->fd = fd;
 	mgmt->close_on_unref = false;
 
@@ -374,42 +403,9 @@
 	}
 
 	mgmt->request_queue = queue_new();
-	if (!mgmt->request_queue) {
-		io_destroy(mgmt->io);
-		free(mgmt->buf);
-		free(mgmt);
-		return NULL;
-	}
-
 	mgmt->reply_queue = queue_new();
-	if (!mgmt->reply_queue) {
-		queue_destroy(mgmt->request_queue, NULL);
-		io_destroy(mgmt->io);
-		free(mgmt->buf);
-		free(mgmt);
-		return NULL;
-	}
-
 	mgmt->pending_list = queue_new();
-	if (!mgmt->pending_list) {
-		queue_destroy(mgmt->reply_queue, NULL);
-		queue_destroy(mgmt->request_queue, NULL);
-		io_destroy(mgmt->io);
-		free(mgmt->buf);
-		free(mgmt);
-		return NULL;
-	}
-
 	mgmt->notify_list = queue_new();
-	if (!mgmt->notify_list) {
-		queue_destroy(mgmt->pending_list, NULL);
-		queue_destroy(mgmt->reply_queue, NULL);
-		queue_destroy(mgmt->request_queue, NULL);
-		io_destroy(mgmt->io);
-		free(mgmt->buf);
-		free(mgmt);
-		return NULL;
-	}
 
 	if (!io_set_read_handler(mgmt->io, can_read_data, mgmt, NULL)) {
 		queue_destroy(mgmt->notify_list, NULL);
@@ -501,11 +497,12 @@
 	free(mgmt->buf);
 	mgmt->buf = NULL;
 
-	queue_destroy(mgmt->notify_list, NULL);
-	queue_destroy(mgmt->pending_list, NULL);
-	free(mgmt);
-
-	return;
+	if (!mgmt->in_notify) {
+		queue_destroy(mgmt->notify_list, NULL);
+		queue_destroy(mgmt->pending_list, NULL);
+		free(mgmt);
+		return;
+	}
 }
 
 bool mgmt_set_debug(struct mgmt *mgmt, mgmt_debug_func_t callback,
@@ -549,9 +546,6 @@
 		return NULL;
 
 	request = new0(struct mgmt_request, 1);
-	if (!request)
-		return NULL;
-
 	request->len = length + MGMT_HDR_SIZE;
 	request->buf = malloc(request->len);
 	if (!request->buf) {
@@ -732,9 +726,6 @@
 		return 0;
 
 	notify = new0(struct mgmt_notify, 1);
-	if (!notify)
-		return 0;
-
 	notify->event = event;
 	notify->index = index;
 
@@ -767,7 +758,14 @@
 	if (!notify)
 		return false;
 
-	destroy_notify(notify);
+	if (!mgmt->in_notify) {
+		destroy_notify(notify);
+		return true;
+	}
+
+	notify->removed = true;
+	mgmt->need_notify_cleanup = true;
+
 	return true;
 }
 
@@ -776,7 +774,12 @@
 	if (!mgmt)
 		return false;
 
-	queue_remove_all(mgmt->notify_list, match_notify_index,
+	if (mgmt->in_notify) {
+		queue_foreach(mgmt->notify_list, mark_notify_removed,
+							UINT_TO_PTR(index));
+		mgmt->need_notify_cleanup = true;
+	} else
+		queue_remove_all(mgmt->notify_list, match_notify_index,
 					UINT_TO_PTR(index), destroy_notify);
 
 	return true;
@@ -787,7 +790,12 @@
 	if (!mgmt)
 		return false;
 
-	queue_remove_all(mgmt->notify_list, NULL, NULL, destroy_notify);
+	if (mgmt->in_notify) {
+		queue_foreach(mgmt->notify_list, mark_notify_removed,
+						UINT_TO_PTR(MGMT_INDEX_NONE));
+		mgmt->need_notify_cleanup = true;
+	} else
+		queue_remove_all(mgmt->notify_list, NULL, NULL, destroy_notify);
 
 	return true;
 }
diff --git a/src/shared/queue.c b/src/shared/queue.c
index 3507ed1..5ddb832 100644
--- a/src/shared/queue.c
+++ b/src/shared/queue.c
@@ -58,9 +58,6 @@
 	struct queue *queue;
 
 	queue = new0(struct queue, 1);
-	if (!queue)
-		return NULL;
-
 	queue->head = NULL;
 	queue->tail = NULL;
 	queue->entries = 0;
@@ -78,35 +75,14 @@
 	queue_unref(queue);
 }
 
-static struct queue_entry *queue_entry_ref(struct queue_entry *entry)
-{
-	if (!entry)
-		return NULL;
-
-	__sync_fetch_and_add(&entry->ref_count, 1);
-
-	return entry;
-}
-
-static void queue_entry_unref(struct queue_entry *entry)
-{
-	if (__sync_sub_and_fetch(&entry->ref_count, 1))
-		return;
-
-	free(entry);
-}
-
 static struct queue_entry *queue_entry_new(void *data)
 {
 	struct queue_entry *entry;
 
 	entry = new0(struct queue_entry, 1);
-	if (!entry)
-		return NULL;
-
 	entry->data = data;
 
-	return queue_entry_ref(entry);
+	return entry;
 }
 
 bool queue_push_tail(struct queue *queue, void *data)
@@ -117,8 +93,6 @@
 		return false;
 
 	entry = queue_entry_new(data);
-	if (!entry)
-		return false;
 
 	if (queue->tail)
 		queue->tail->next = entry;
@@ -141,8 +115,6 @@
 		return false;
 
 	entry = queue_entry_new(data);
-	if (!entry)
-		return false;
 
 	entry->next = queue->head;
 
@@ -176,8 +148,6 @@
 		return false;
 
 	new_entry = queue_entry_new(data);
-	if (!new_entry)
-		return false;
 
 	new_entry->next = qentry->next;
 
@@ -208,7 +178,7 @@
 
 	data = entry->data;
 
-	queue_entry_unref(entry);
+	free(entry);
 	queue->entries--;
 
 	return data;
@@ -246,14 +216,8 @@
 	while (entry && queue->head && queue->ref_count > 1) {
 		struct queue_entry *next;
 
-		queue_entry_ref(entry);
-
-		function(entry->data, user_data);
-
 		next = entry->next;
-
-		queue_entry_unref(entry);
-
+		function(entry->data, user_data);
 		entry = next;
 	}
 	queue_unref(queue);
@@ -302,7 +266,7 @@
 		if (!entry->next)
 			queue->tail = prev;
 
-		queue_entry_unref(entry);
+		free(entry);
 		queue->entries--;
 
 		return true;
@@ -335,7 +299,7 @@
 
 			data = entry->data;
 
-			queue_entry_unref(entry);
+			free(entry);
 			queue->entries--;
 
 			return data;
@@ -386,7 +350,7 @@
 			if (destroy)
 				destroy(tmp->data);
 
-			queue_entry_unref(tmp);
+			free(tmp);
 			count++;
 		}
 	}
diff --git a/src/shared/queue.h b/src/shared/queue.h
index 3bc8d2e..8cd817c 100644
--- a/src/shared/queue.h
+++ b/src/shared/queue.h
@@ -28,7 +28,6 @@
 struct queue;
 
 struct queue_entry {
-	int ref_count;
 	void *data;
 	struct queue_entry *next;
 };
diff --git a/src/shared/ringbuf.c b/src/shared/ringbuf.c
index a11d2dc..8e7c50e 100644
--- a/src/shared/ringbuf.c
+++ b/src/shared/ringbuf.c
@@ -72,9 +72,6 @@
 	real_size = align_power2(size);
 
 	ringbuf = new0(struct ringbuf, 1);
-	if (!ringbuf)
-		return NULL;
-
 	ringbuf->buffer = malloc(real_size);
 	if (!ringbuf->buffer) {
 		free(ringbuf);
diff --git a/src/shared/tester.c b/src/shared/tester.c
index c3120fb..80d6511 100644
--- a/src/shared/tester.c
+++ b/src/shared/tester.c
@@ -215,12 +215,6 @@
 	}
 
 	test = new0(struct test_case, 1);
-	if (!test) {
-		if (destroy)
-			destroy(user_data);
-		return;
-	}
-
 	test->name = strdup(name);
 	test->result = TEST_RESULT_NOT_RUN;
 	test->stage = TEST_STAGE_INVALID;
@@ -684,9 +678,6 @@
 	test = test_current->data;
 
 	wait = new0(struct wait_data, 1);
-	if (!wait)
-		return;
-
 	wait->seconds = seconds;
 	wait->test = test;
 	wait->func = func;
diff --git a/src/shared/timeout-mainloop.c b/src/shared/timeout-mainloop.c
index f099312..971124a 100644
--- a/src/shared/timeout-mainloop.c
+++ b/src/shared/timeout-mainloop.c
@@ -58,9 +58,6 @@
 	struct timeout_data *data;
 
 	data = new0(struct timeout_data, 1);
-	if (!data)
-		return 0;
-
 	data->func = func;
 	data->user_data = user_data;
 	data->timeout = timeout;
diff --git a/src/shared/uhid.c b/src/shared/uhid.c
index f7ad0cb..1c684cd 100644
--- a/src/shared/uhid.c
+++ b/src/shared/uhid.c
@@ -125,16 +125,11 @@
 	struct bt_uhid *uhid;
 
 	uhid = new0(struct bt_uhid, 1);
-	if (!uhid)
-		return NULL;
-
 	uhid->io = io_new(fd);
 	if (!uhid->io)
 		goto failed;
 
 	uhid->notify_list = queue_new();
-	if (!uhid->notify_list)
-		goto failed;
 
 	if (!io_set_read_handler(uhid->io, uhid_read_handler, uhid, NULL))
 		goto failed;
@@ -186,9 +181,6 @@
 		return 0;
 
 	notify = new0(struct uhid_notify, 1);
-	if (!notify)
-		return 0;
-
 	notify->id = uhid->notify_id++;
 	notify->event = event;
 	notify->func = func;
diff --git a/src/shared/util.c b/src/shared/util.c
index a70c709..7878552 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -37,6 +37,22 @@
 
 #include "src/shared/util.h"
 
+void *btd_malloc(size_t size)
+{
+	if (__builtin_expect(!!size, 1)) {
+		void *ptr;
+
+		ptr = malloc(size);
+		if (ptr)
+			return ptr;
+
+		fprintf(stderr, "failed to allocate %zu bytes\n", size);
+		abort();
+	}
+
+	return NULL;
+}
+
 void util_debug(util_debug_func_t function, void *user_data,
 						const char *format, ...)
 {
diff --git a/src/shared/util.h b/src/shared/util.h
index 65f5359..ff705d0 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -25,6 +25,7 @@
 #include <stdlib.h>
 #include <alloca.h>
 #include <byteswap.h>
+#include <string.h>
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 #define le16_to_cpu(val) (val)
@@ -78,10 +79,21 @@
 #define PTR_TO_INT(p) ((int) ((intptr_t) (p)))
 #define INT_TO_PTR(u) ((void *) ((intptr_t) (u)))
 
-#define new0(t, n) ((t*) calloc((n), sizeof(t)))
+#define new0(type, count)			\
+	(type *) (__extension__ ({		\
+		size_t __n = (size_t) (count);	\
+		size_t __s = sizeof(type);	\
+		void *__p;			\
+		__p = btd_malloc(__n * __s);	\
+		memset(__p, 0, __n * __s);	\
+		__p;				\
+	}))
+
 #define newa(t, n) ((t*) alloca(sizeof(t)*(n)))
 #define malloc0(n) (calloc((n), 1))
 
+void *btd_malloc(size_t size);
+
 typedef void (*util_debug_func_t)(const char *str, void *user_data);
 
 void util_debug(util_debug_func_t function, void *user_data,
diff --git a/test/ftp-client b/test/ftp-client
index 78c32b3..4540602 100755
--- a/test/ftp-client
+++ b/test/ftp-client
@@ -77,16 +77,18 @@
 		if path != self.transfer_path:
 			return
 
-		if properties['Status'] == 'complete' or \
-				properties['Status'] == 'error':
+		if "Status" in properties and \
+				(properties['Status'] == 'complete' or \
+				properties['Status'] == 'error'):
 			if self.verbose:
 				print("Transfer %s" % properties['Status'])
 			mainloop.quit()
 			return
 
-		if properties["Transferred"] == None:
+		if "Transferred" not in properties:
 			return
 
+		value = properties["Transferred"]
 		speed = (value - self.transferred) / 1000
 		print("Transfer progress %d/%d at %d kBps" % (value,
 							self.transfer_size,
diff --git a/test/test-discovery b/test/test-discovery
index 73b8161..9a2c6b9 100755
--- a/test/test-discovery
+++ b/test/test-discovery
@@ -107,10 +107,6 @@
 	else:
 		print_normal(address, devices[path])
 
-def property_changed(name, value):
-	if (name == "Discovering" and not value):
-		mainloop.quit()
-
 if __name__ == '__main__':
 	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
@@ -141,10 +137,6 @@
 			arg0 = "org.bluez.Device1",
 			path_keyword = "path")
 
-	bus.add_signal_receiver(property_changed,
-					dbus_interface = "org.bluez.Adapter1",
-					signal_name = "PropertyChanged")
-
 	om = dbus.Interface(bus.get_object("org.bluez", "/"),
 				"org.freedesktop.DBus.ObjectManager")
 	objects = om.GetManagedObjects()
diff --git a/tools/avinfo.c b/tools/avinfo.c
index 3f406ca..31c4e10 100644
--- a/tools/avinfo.c
+++ b/tools/avinfo.c
@@ -74,6 +74,10 @@
 #define AVDTP_MEDIA_TYPE_VIDEO		0x01
 #define AVDTP_MEDIA_TYPE_MULTIMEDIA	0x02
 
+/* Content Protection types definitions */
+#define AVDTP_CONTENT_PROTECTION_TYPE_DTCP	0x0001
+#define AVDTP_CONTENT_PROTECTION_TYPE_SCMS_T	0x0002
+
 struct avdtp_service_capability {
 	uint8_t category;
 	uint8_t length;
@@ -158,6 +162,11 @@
 	uint8_t caps[0];
 } __attribute__ ((packed));
 
+struct avdtp_content_protection_capability {
+	uint16_t content_protection_type;
+	uint8_t data[0];
+} __attribute__ ((packed));
+
 static void print_aptx(a2dp_aptx_t *aptx)
 {
 	printf("\t\tVendor Specific Value (aptX)");
@@ -181,6 +190,16 @@
 	printf("\n");
 }
 
+static void print_ldac(a2dp_ldac_t *ldac)
+{
+	printf("\t\tVendor Specific Value (LDAC)");
+
+	printf("\n\t\t\tUnknown: %02x %02x", ldac->unknown[0],
+							ldac->unknown[1]);
+
+	printf("\n");
+}
+
 static void print_vendor(a2dp_vendor_codec_t *vendor)
 {
 	uint32_t vendor_id = btohl(vendor->vendor_id);
@@ -194,6 +213,8 @@
 
 	if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID)
 		print_aptx((void *) vendor);
+	else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID)
+		print_ldac((void *) vendor);
 }
 
 static void print_mpeg24(a2dp_aac_t *aac)
@@ -393,6 +414,25 @@
 	}
 }
 
+static void print_content_protection(
+				struct avdtp_content_protection_capability *cap)
+{
+	printf("\tContent Protection: ");
+
+	switch (btohs(cap->content_protection_type)) {
+	case AVDTP_CONTENT_PROTECTION_TYPE_DTCP:
+		printf("DTCP");
+		break;
+	case AVDTP_CONTENT_PROTECTION_TYPE_SCMS_T:
+		printf("SCMS-T");
+		break;
+	default:
+		printf("Unknown");
+	}
+
+	printf("\n");
+}
+
 static void print_caps(void *data, int size)
 {
 	int processed;
@@ -411,13 +451,15 @@
 		case AVDTP_MEDIA_TRANSPORT:
 		case AVDTP_REPORTING:
 		case AVDTP_RECOVERY:
-		case AVDTP_CONTENT_PROTECTION:
 		case AVDTP_MULTIPLEXING:
 			/* FIXME: Add proper functions */
 			break;
 		case AVDTP_MEDIA_CODEC:
 			print_media_codec((void *) cap->data);
 			break;
+		case AVDTP_CONTENT_PROTECTION:
+			print_content_protection((void *) cap->data);
+			break;
 		}
 
 		processed += 2 + cap->length;
diff --git a/tools/btattach.1 b/tools/btattach.1
new file mode 100644
index 0000000..ffd653d
--- /dev/null
+++ b/tools/btattach.1
@@ -0,0 +1,53 @@
+.TH "btattach" "1" "November 2015" "BlueZ" "Linux System Administration"
+.SH NAME
+btattach \- attach serial devices to BlueZ stack
+
+.SH SYNOPSIS
+.B btattach
+.RB [\| \-B
+.IR device \|]
+.RB [\| \-A
+.IR device \|]
+.RB [\| \-P
+.IR protocol \|]
+.RB [\| \-R \|]
+
+.SH DESCRIPTION
+.LP
+btattach is used to attach a serial UART to the Bluetooth stack as a
+transport interface.
+
+.SH OPTIONS
+.TP
+.BI \-B " device" , " " \--bredr " device"
+Attach a BR/EDR controller.
+.TP
+.BI \-A " device" , " " \--amp " device"
+Attach an AMP controller.
+.TP
+.BI \-P " protocol" , " " \--protocol " protocol"
+Specify the protocol type for talking to the device.
+Supported values are:
+.RS
+.IP \(bu 2
+.B h4
+.IP \(bu 2
+.B bcsp
+.IP \(bu 2
+.B 3wire
+.IP \(bu 2
+.B h4ds
+.IP \(bu 2
+.B ll
+.IP \(bu 2
+.B ath3k
+.IP \(bu 2
+.B intel
+.IP \(bu 2
+.B bcm
+.IP \(bu 2
+.B qca
+.RE
+.TP
+.B \-R
+Set the device into raw mode (the kernel and bluetoothd will ignore it).
diff --git a/tools/btmgmt.c b/tools/btmgmt.c
index a100f53..f82461e 100644
--- a/tools/btmgmt.c
+++ b/tools/btmgmt.c
@@ -3866,6 +3866,110 @@
 	}
 }
 
+static void adv_size_info_rsp(uint8_t status, uint16_t len, const void *param,
+							void *user_data)
+{
+	const struct mgmt_rp_get_adv_size_info *rp = param;
+	uint32_t flags;
+
+	if (status != 0) {
+		error("Reading adv size info failed with status 0x%02x (%s)",
+						status, mgmt_errstr(status));
+		return noninteractive_quit(EXIT_FAILURE);
+	}
+
+	if (len < sizeof(*rp)) {
+		error("Too small adv size info reply (%u bytes)", len);
+		return noninteractive_quit(EXIT_FAILURE);
+	}
+
+	flags = le32_to_cpu(rp->flags);
+	print("Instance: %u", rp->instance);
+	print("Flags: %s", adv_flags2str(flags));
+	print("Max advertising data len: %u", rp->max_adv_data_len);
+	print("Max scan response data len: %u", rp->max_scan_rsp_len);
+
+	return noninteractive_quit(EXIT_SUCCESS);
+}
+
+static void advsize_usage(void)
+{
+	print("Usage: advsize [options] <instance_id>\nOptions:\n"
+		"\t -c, --connectable         \"connectable\" flag\n"
+		"\t -g, --general-discov      \"general-discoverable\" flag\n"
+		"\t -l, --limited-discov      \"limited-discoverable\" flag\n"
+		"\t -m, --managed-flags       \"managed-flags\" flag\n"
+		"\t -p, --tx-power            \"tx-power\" flag");
+}
+
+static struct option advsize_options[] = {
+	{ "help",		0, 0, 'h' },
+	{ "connectable",	0, 0, 'c' },
+	{ "general-discov",	0, 0, 'g' },
+	{ "limited-discov",	0, 0, 'l' },
+	{ "managed-flags",	0, 0, 'm' },
+	{ "tx-power",		0, 0, 'p' },
+	{ 0, 0, 0, 0}
+};
+
+static void cmd_advsize(struct mgmt *mgmt, uint16_t index,
+						int argc, char **argv)
+{
+	struct mgmt_cp_get_adv_size_info cp;
+	uint8_t instance;
+	uint32_t flags = 0;
+	int opt;
+
+	while ((opt = getopt_long(argc, argv, "+cglmph",
+						advsize_options, NULL)) != -1) {
+		switch (opt) {
+		case 'c':
+			flags |= MGMT_ADV_FLAG_CONNECTABLE;
+			break;
+		case 'g':
+			flags |= MGMT_ADV_FLAG_DISCOV;
+			break;
+		case 'l':
+			flags |= MGMT_ADV_FLAG_LIMITED_DISCOV;
+			break;
+		case 'm':
+			flags |= MGMT_ADV_FLAG_MANAGED_FLAGS;
+			break;
+		case 'p':
+			flags |= MGMT_ADV_FLAG_TX_POWER;
+			break;
+		default:
+			advsize_usage();
+			return noninteractive_quit(EXIT_FAILURE);
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+	optind = 0;
+
+	if (argc != 1) {
+		advsize_usage();
+		return noninteractive_quit(EXIT_FAILURE);
+	}
+
+	instance = strtol(argv[0], NULL, 0);
+
+	if (index == MGMT_INDEX_NONE)
+		index = 0;
+
+	memset(&cp, 0, sizeof(cp));
+
+	cp.instance = instance;
+	cp.flags = cpu_to_le32(flags);
+
+	if (!mgmt_send(mgmt, MGMT_OP_GET_ADV_SIZE_INFO, index, sizeof(cp), &cp,
+					adv_size_info_rsp, NULL, NULL)) {
+		error("Unable to send advertising size info command");
+		return noninteractive_quit(EXIT_FAILURE);
+	}
+}
+
 static void add_adv_rsp(uint8_t status, uint16_t len, const void *param,
 								void *user_data)
 {
@@ -4245,6 +4349,7 @@
 	{ "bredr-oob",	cmd_bredr_oob,	"Local OOB data (BR/EDR)"	},
 	{ "le-oob",	cmd_le_oob,	"Local OOB data (LE)"		},
 	{ "advinfo",	cmd_advinfo,	"Show advertising features"	},
+	{ "advsize",	cmd_advsize,	"Show advertising size info"	},
 	{ "add-adv",	cmd_add_adv,	"Add advertising instance"	},
 	{ "rm-adv",	cmd_rm_adv,	"Remove advertising instance"	},
 	{ "clr-adv",	cmd_clr_adv,	"Clear advertising instances"	},
@@ -4535,6 +4640,13 @@
 	return io;
 }
 
+static void mgmt_debug(const char *str, void *user_data)
+{
+	const char *prefix = user_data;
+
+	print("%s%s", prefix, str);
+}
+
 int main(int argc, char *argv[])
 {
 	struct io *input;
@@ -4570,6 +4682,9 @@
 		return EXIT_FAILURE;
 	}
 
+	if (getenv("MGMT_DEBUG"))
+		mgmt_set_debug(mgmt, mgmt_debug, "mgmt: ", NULL);
+
 	if (argc > 0) {
 		struct cmd_info *c;
 
diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c
index 2b89045..945f82c 100644
--- a/tools/l2cap-tester.c
+++ b/tools/l2cap-tester.c
@@ -53,6 +53,8 @@
 	uint16_t handle;
 	uint16_t scid;
 	uint16_t dcid;
+	int sk;
+	int sk2;
 };
 
 struct l2cap_data {
@@ -85,6 +87,11 @@
 
 	bool addr_type_avail;
 	uint8_t addr_type;
+
+	uint8_t *client_bdaddr;
+	bool server_not_advertising;
+	bool direct_advertising;
+	bool close_one_socket;
 };
 
 static void mgmt_debug(const char *str, void *user_data)
@@ -429,6 +436,12 @@
 	.server_psm = 0x0080,
 };
 
+static const struct l2cap_data le_client_connect_adv_success_test_1 = {
+	.client_psm = 0x0080,
+	.server_psm = 0x0080,
+	.direct_advertising = true,
+};
+
 static const struct l2cap_data le_client_connect_success_test_2 = {
 	.client_psm = 0x0080,
 	.server_psm = 0x0080,
@@ -450,6 +463,30 @@
 	.addr_type = BDADDR_LE_PUBLIC,
 };
 
+static uint8_t nonexisting_bdaddr[] = {0x00, 0xAA, 0x01, 0x02, 0x03, 0x00};
+static const struct l2cap_data le_client_close_socket_test_1 = {
+	.client_psm = 0x0080,
+	.client_bdaddr = nonexisting_bdaddr,
+};
+
+static const struct l2cap_data le_client_close_socket_test_2 = {
+	.client_psm = 0x0080,
+	.server_not_advertising = true,
+};
+
+static const struct l2cap_data le_client_two_sockets_same_client = {
+	.client_psm = 0x0080,
+	.server_psm = 0x0080,
+	.server_not_advertising = true,
+};
+
+static const struct l2cap_data le_client_two_sockets_close_one = {
+	.client_psm = 0x0080,
+	.server_psm = 0x0080,
+	.server_not_advertising = true,
+	.close_one_socket = true,
+};
+
 static const struct l2cap_data le_client_connect_nval_psm_test = {
 	.client_psm = 0x0080,
 	.expect_err = ECONNREFUSED,
@@ -462,12 +499,45 @@
 						0x05, 0x00, /* Credits */
 };
 
+static const uint8_t le_connect_rsp[] = {	0x40, 0x00, /* DCID */
+						0xa0, 0x02, /* MTU */
+						0xe6, 0x00, /* MPS */
+						0x0a, 0x00, /* Credits */
+						0x00, 0x00, /* Result */
+};
+
 static const struct l2cap_data le_server_success_test = {
 	.server_psm = 0x0080,
 	.send_cmd_code = BT_L2CAP_PDU_LE_CONN_REQ,
 	.send_cmd = le_connect_req,
 	.send_cmd_len = sizeof(le_connect_req),
 	.expect_cmd_code = BT_L2CAP_PDU_LE_CONN_RSP,
+	.expect_cmd = le_connect_rsp,
+	.expect_cmd_len = sizeof(le_connect_rsp),
+};
+
+static const uint8_t nval_le_connect_req[] = {	0x80, 0x00, /* PSM */
+						0x01, 0x00, /* SCID */
+						0x20, 0x00, /* MTU */
+						0x20, 0x00, /* MPS */
+						0x05, 0x00, /* Credits */
+};
+
+static const uint8_t nval_le_connect_rsp[] = {	0x00, 0x00, /* DCID */
+						0x00, 0x00, /* MTU */
+						0x00, 0x00, /* MPS */
+						0x00, 0x00, /* Credits */
+						0x09, 0x00, /* Result */
+};
+
+static const struct l2cap_data le_server_nval_scid_test = {
+	.server_psm = 0x0080,
+	.send_cmd_code = BT_L2CAP_PDU_LE_CONN_REQ,
+	.send_cmd = nval_le_connect_req,
+	.send_cmd_len = sizeof(nval_le_connect_req),
+	.expect_cmd_code = BT_L2CAP_PDU_LE_CONN_RSP,
+	.expect_cmd = nval_le_connect_rsp,
+	.expect_cmd_len = sizeof(nval_le_connect_rsp),
 };
 
 static const struct l2cap_data le_att_client_connect_success_test_1 = {
@@ -534,6 +604,7 @@
 					const void *param, void *user_data)
 {
 	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
 	struct bthost *bthost;
 
 	if (status != MGMT_STATUS_SUCCESS) {
@@ -545,10 +616,15 @@
 
 	bthost = hciemu_client_get_host(data->hciemu);
 	bthost_set_cmd_complete_cb(bthost, client_cmd_complete, user_data);
-	if (data->hciemu_type == HCIEMU_TYPE_LE)
-		bthost_set_adv_enable(bthost, 0x01);
-	else
+
+	if (data->hciemu_type == HCIEMU_TYPE_LE) {
+		if (!l2data || !l2data->server_not_advertising)
+			bthost_set_adv_enable(bthost, 0x01);
+		else
+			tester_setup_complete();
+	} else {
 		bthost_write_scan_enable(bthost, 0x03);
+	}
 }
 
 static void setup_powered_server_callback(uint8_t status, uint16_t length,
@@ -718,6 +794,11 @@
 		bthost_set_connect_cb(bthost, send_rsp_new_conn, data);
 	}
 
+	if (test && test->direct_advertising)
+		mgmt_send(data->mgmt, MGMT_OP_SET_ADVERTISING,
+				data->mgmt_index, sizeof(param), param,
+				NULL, NULL, NULL);
+
 	mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
 			sizeof(param), param, setup_powered_client_callback,
 			NULL, NULL);
@@ -1013,33 +1094,24 @@
 	return sk;
 }
 
-static int connect_l2cap_sock(struct test_data *data, int sk, uint16_t psm,
-								uint16_t cid)
+static int connect_l2cap_impl(int sk, const uint8_t *bdaddr,
+				uint8_t bdaddr_type, uint16_t psm, uint16_t cid)
 {
-	const struct l2cap_data *l2data = data->test_data;
-	const uint8_t *client_bdaddr;
 	struct sockaddr_l2 addr;
 	int err;
 
-	client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
-	if (!client_bdaddr) {
+	if (!bdaddr) {
 		tester_warn("No client bdaddr");
 		return -ENODEV;
 	}
 
 	memset(&addr, 0, sizeof(addr));
 	addr.l2_family = AF_BLUETOOTH;
-	bacpy(&addr.l2_bdaddr, (void *) client_bdaddr);
+	bacpy(&addr.l2_bdaddr, (void *) bdaddr);
+	addr.l2_bdaddr_type = bdaddr_type;
 	addr.l2_psm = htobs(psm);
 	addr.l2_cid = htobs(cid);
 
-	if (l2data && l2data->addr_type_avail)
-		addr.l2_bdaddr_type = l2data->addr_type;
-	else if (data->hciemu_type == HCIEMU_TYPE_LE)
-		addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;
-	else
-		addr.l2_bdaddr_type = BDADDR_BREDR;
-
 	err = connect(sk, (struct sockaddr *) &addr, sizeof(addr));
 	if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) {
 		err = -errno;
@@ -1051,6 +1123,33 @@
 	return 0;
 }
 
+static int connect_l2cap_sock(struct test_data *data, int sk, uint16_t psm,
+								uint16_t cid)
+{
+	const struct l2cap_data *l2data = data->test_data;
+	const uint8_t *client_bdaddr;
+	uint8_t bdaddr_type;
+
+	if (l2data->client_bdaddr != NULL)
+		client_bdaddr = l2data->client_bdaddr;
+	else
+		client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+
+	if (!client_bdaddr) {
+		tester_warn("No client bdaddr");
+		return -ENODEV;
+	}
+
+	if (l2data && l2data->addr_type_avail)
+		bdaddr_type = l2data->addr_type;
+	else if (data->hciemu_type == HCIEMU_TYPE_LE)
+		bdaddr_type = BDADDR_LE_PUBLIC;
+	else
+		bdaddr_type = BDADDR_BREDR;
+
+	return connect_l2cap_impl(sk, client_bdaddr, bdaddr_type, psm, cid);
+}
+
 static void client_l2cap_connect_cb(uint16_t handle, uint16_t cid,
 							void *user_data)
 {
@@ -1060,6 +1159,37 @@
 	data->handle = handle;
 }
 
+static void direct_adv_cmd_complete(uint16_t opcode, const void *param,
+						uint8_t len, void *user_data)
+{
+	struct test_data *data = tester_get_data();
+	const struct bt_hci_cmd_le_set_adv_parameters *cp;
+	const uint8_t *expect_bdaddr;
+
+	if (opcode != BT_HCI_CMD_LE_SET_ADV_PARAMETERS)
+		return;
+
+	tester_print("Received advertising parameters HCI command");
+
+	cp = param;
+
+	/* Advertising as client should be direct advertising */
+	if (cp->type != 0x01) {
+		tester_warn("Invalid advertising type");
+		tester_test_failed();
+		return;
+	}
+
+	expect_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+	if (memcmp(expect_bdaddr, cp->direct_addr, 6)) {
+		tester_warn("Invalid direct address in adv params");
+		tester_test_failed();
+		return;
+	}
+
+	tester_test_passed();
+}
+
 static void test_connect(const void *test_data)
 {
 	struct test_data *data = tester_get_data();
@@ -1078,6 +1208,10 @@
 						client_l2cap_connect_cb, data);
 	}
 
+	if (l2data->direct_advertising)
+		hciemu_add_master_post_command_hook(data->hciemu,
+						direct_adv_cmd_complete, NULL);
+
 	sk = create_l2cap_sock(data, 0, l2data->cid, l2data->sec_level);
 	if (sk < 0) {
 		tester_test_failed();
@@ -1122,6 +1256,322 @@
 	close(sk);
 }
 
+static void connect_socket(const uint8_t *client_bdaddr, int *sk_holder,
+							GIOFunc connect_cb)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+	GIOChannel *io;
+	int sk;
+
+	sk = create_l2cap_sock(data, 0, l2data->cid, l2data->sec_level);
+	if (sk < 0) {
+		tester_print("Error in create_l2cap_sock");
+		tester_test_failed();
+		return;
+	}
+
+	*sk_holder = sk;
+
+	if (connect_l2cap_impl(sk, client_bdaddr, BDADDR_LE_PUBLIC,
+			l2data->client_psm, l2data->cid) < 0) {
+		tester_print("Error in connect_l2cap_sock");
+		close(sk);
+		tester_test_failed();
+		return;
+	}
+
+	if (connect_cb) {
+		io = g_io_channel_unix_new(sk);
+		g_io_channel_set_close_on_unref(io, TRUE);
+
+		data->io_id = g_io_add_watch(io, G_IO_OUT, connect_cb, NULL);
+
+		g_io_channel_unref(io);
+	}
+
+	tester_print("Connect in progress, sk = %d", sk);
+}
+
+static gboolean test_close_socket_1_part_3(gpointer arg)
+{
+	struct test_data *data = tester_get_data();
+
+	tester_print("Checking whether scan was properly stopped...");
+
+	if (data->sk != -1) {
+		tester_print("Error - scan was not enabled yet");
+		tester_test_failed();
+		return FALSE;
+	}
+
+	if (hciemu_get_master_le_scan_enable(data->hciemu)) {
+		tester_print("Delayed check whether scann is off failed");
+		tester_test_failed();
+		return FALSE;
+	}
+
+	tester_test_passed();
+	return FALSE;
+}
+
+static gboolean test_close_socket_1_part_2(gpointer args)
+{
+	struct test_data *data = tester_get_data();
+	int sk = data->sk;
+
+	tester_print("Will close socket during scan phase...");
+
+	/* We tried to conect to LE device that is not advertising. It
+	 * was added to kernel whitelist, and scan was started. We
+	 * should be still scanning.
+	 */
+	if (!hciemu_get_master_le_scan_enable(data->hciemu)) {
+		tester_print("Error - should be still scanning");
+		tester_test_failed();
+		return FALSE;
+	}
+
+	/* Calling close() should remove device from  whitelist, and stop
+	 * the scan.
+	 */
+	if (close(sk) < 0) {
+		tester_print("Error when closing socket");
+		tester_test_failed();
+		return FALSE;
+	}
+
+	data->sk = -1;
+	/* tester_test_passed will be called when scan is stopped. */
+	return FALSE;
+}
+
+static gboolean test_close_socket_2_part_3(gpointer arg)
+{
+	struct test_data *data = tester_get_data();
+	int sk = data->sk;
+	int err;
+
+	/* Scan should be already over, we're trying to create connection */
+	if (hciemu_get_master_le_scan_enable(data->hciemu)) {
+		tester_print("Error - should no longer scan");
+		tester_test_failed();
+		return FALSE;
+	}
+
+	/* Calling close() should eventually cause CMD_LE_CREATE_CONN_CANCEL */
+	err = close(sk);
+	if (err < 0) {
+		tester_print("Error when closing socket");
+		tester_test_failed();
+		return FALSE;
+	}
+
+	/* CMD_LE_CREATE_CONN_CANCEL will trigger test pass. */
+	return FALSE;
+}
+
+static bool test_close_socket_cc_hook(const void *data, uint16_t len,
+							void *user_data)
+{
+	return false;
+}
+
+static gboolean test_close_socket_2_part_2(gpointer arg)
+{
+	struct test_data *data = tester_get_data();
+	struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+
+	/* Make sure CMD_LE_CREATE_CONN will not immediately result in
+	 * BT_HCI_EVT_CONN_COMPLETE.
+	 */
+	hciemu_add_hook(data->hciemu, HCIEMU_HOOK_PRE_EVT,
+		BT_HCI_CMD_LE_CREATE_CONN, test_close_socket_cc_hook, NULL);
+
+	/* Advertise once. After that, kernel should stop scanning, and trigger
+	 * BT_HCI_CMD_LE_CREATE_CONN_CANCEL.
+	 */
+	bthost_set_adv_enable(bthost, 0x01);
+	bthost_set_adv_enable(bthost, 0x00);
+	return FALSE;
+}
+
+static void test_close_socket_scan_enabled(void)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+
+	if (l2data == &le_client_close_socket_test_1)
+		g_idle_add(test_close_socket_1_part_2, NULL);
+	else if (l2data == &le_client_close_socket_test_2)
+		g_idle_add(test_close_socket_2_part_2, NULL);
+}
+
+static void test_close_socket_scan_disabled(void)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+
+	if (l2data == &le_client_close_socket_test_1)
+		g_idle_add(test_close_socket_1_part_3, NULL);
+	else if (l2data == &le_client_close_socket_test_2)
+		g_idle_add(test_close_socket_2_part_3, NULL);
+}
+
+static void test_close_socket_conn_cancel(void)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+
+	if (l2data == &le_client_close_socket_test_2)
+		tester_test_passed();
+}
+
+static void test_close_socket_router(uint16_t opcode, const void *param,
+					uint8_t length, void *user_data)
+{
+	/* tester_print("HCI Command 0x%04x length %u", opcode, length); */
+	if (opcode == BT_HCI_CMD_LE_SET_SCAN_ENABLE) {
+		const struct bt_hci_cmd_le_set_scan_enable *scan_params = param;
+
+		if (scan_params->enable == true)
+			test_close_socket_scan_enabled();
+		else
+			test_close_socket_scan_disabled();
+	} else if (opcode == BT_HCI_CMD_LE_CREATE_CONN_CANCEL) {
+		test_close_socket_conn_cancel();
+	}
+}
+
+static void test_close_socket(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+	const uint8_t *client_bdaddr;
+
+	hciemu_add_master_post_command_hook(data->hciemu,
+					test_close_socket_router, data);
+
+	if (l2data->client_bdaddr != NULL)
+		client_bdaddr = l2data->client_bdaddr;
+	else
+		client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+
+	connect_socket(client_bdaddr, &data->sk, NULL);
+}
+
+static uint8_t test_two_sockets_connect_cb_cnt;
+static gboolean test_two_sockets_connect_cb(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+	int err, sk_err, sk;
+	socklen_t len = sizeof(sk_err);
+
+	data->io_id = 0;
+
+	sk = g_io_channel_unix_get_fd(io);
+
+	if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+		err = -errno;
+	else
+		err = -sk_err;
+
+	if (err < 0) {
+		tester_warn("Connect failed: %s (%d)", strerror(-err), -err);
+		tester_test_failed();
+		return FALSE;
+	}
+
+	tester_print("Successfully connected");
+	test_two_sockets_connect_cb_cnt++;
+
+	if (test_two_sockets_connect_cb_cnt == 2) {
+		close(data->sk);
+		close(data->sk2);
+		tester_test_passed();
+	}
+
+	if (l2data->close_one_socket && test_two_sockets_connect_cb_cnt == 1) {
+		close(data->sk2);
+		tester_test_passed();
+	}
+
+	return FALSE;
+}
+
+static gboolean enable_advertising(gpointer args)
+{
+	struct test_data *data = tester_get_data();
+	struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+
+	bthost_set_adv_enable(bthost, 0x01);
+	return FALSE;
+}
+
+static void test_connect_two_sockets_part_2(void)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+	const uint8_t *client_bdaddr;
+
+	client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+	connect_socket(client_bdaddr, &data->sk2, test_two_sockets_connect_cb);
+
+	if (l2data->close_one_socket) {
+		tester_print("Closing first socket! %d", data->sk);
+		close(data->sk);
+	}
+
+	g_idle_add(enable_advertising, NULL);
+}
+
+static uint8_t test_scan_enable_counter;
+static void test_connect_two_sockets_router(uint16_t opcode, const void *param,
+					uint8_t length, void *user_data)
+{
+	const struct bt_hci_cmd_le_set_scan_enable *scan_params = param;
+
+	tester_print("HCI Command 0x%04x length %u", opcode, length);
+	if (opcode == BT_HCI_CMD_LE_SET_SCAN_ENABLE &&
+						scan_params->enable == true) {
+		test_scan_enable_counter++;
+		if (test_scan_enable_counter == 1)
+			test_connect_two_sockets_part_2();
+		else if (test_scan_enable_counter == 2)
+			g_idle_add(enable_advertising, NULL);
+	}
+}
+
+static void test_connect_two_sockets(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+	const uint8_t *client_bdaddr;
+
+	test_two_sockets_connect_cb_cnt = 0;
+	test_scan_enable_counter = 0;
+
+	hciemu_add_master_post_command_hook(data->hciemu,
+				test_connect_two_sockets_router, data);
+
+	if (l2data->server_psm) {
+		struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+
+		if (!l2data->data_len)
+			bthost_add_l2cap_server(bthost, l2data->server_psm,
+						NULL, NULL);
+	}
+
+	client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+	if (l2data->close_one_socket)
+		connect_socket(client_bdaddr, &data->sk, NULL);
+	else
+		connect_socket(client_bdaddr, &data->sk,
+						test_two_sockets_connect_cb);
+}
+
 static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond,
 							gpointer user_data)
 {
@@ -1199,7 +1649,7 @@
 	if (code != l2data->expect_cmd_code) {
 		tester_warn("Unexpected L2CAP response code (expected 0x%02x)",
 						l2data->expect_cmd_code);
-		goto failed;
+		return;
 	}
 
 	if (code == BT_L2CAP_PDU_CONN_RSP) {
@@ -1428,6 +1878,9 @@
 	test_l2cap_le("L2CAP LE Client - Success",
 				&le_client_connect_success_test_1,
 				setup_powered_client, test_connect);
+	test_l2cap_le("L2CAP LE Client, Direct Advertising - Success",
+				&le_client_connect_adv_success_test_1,
+				setup_powered_client, test_connect);
 	test_l2cap_le("L2CAP LE Client SMP - Success",
 				&le_client_connect_success_test_2,
 				setup_powered_client, test_connect);
@@ -1437,11 +1890,34 @@
 	test_l2cap_bredr("L2CAP LE Client - Connection Reject",
 				&le_client_connect_reject_test_2,
 				setup_powered_client, test_connect_reject);
+
+	test_l2cap_le("L2CAP LE Client - Close socket 1",
+				&le_client_close_socket_test_1,
+				setup_powered_client,
+				test_close_socket);
+
+	test_l2cap_le("L2CAP LE Client - Close socket 2",
+				&le_client_close_socket_test_2,
+				setup_powered_client,
+				test_close_socket);
+
+	test_l2cap_le("L2CAP LE Client - Open two sockets",
+				&le_client_two_sockets_same_client,
+				setup_powered_client,
+				test_connect_two_sockets);
+
+	test_l2cap_le("L2CAP LE Client - Open two sockets close one",
+				&le_client_two_sockets_close_one,
+				setup_powered_client,
+				test_connect_two_sockets);
+
 	test_l2cap_le("L2CAP LE Client - Invalid PSM",
 					&le_client_connect_nval_psm_test,
 					setup_powered_client, test_connect);
 	test_l2cap_le("L2CAP LE Server - Success", &le_server_success_test,
 					setup_powered_server, test_server);
+	test_l2cap_le("L2CAP LE Server - Nval SCID", &le_server_nval_scid_test,
+					setup_powered_server, test_server);
 
 
 	test_l2cap_le("L2CAP LE ATT Client - Success",
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index 0a1a7c2..494d436 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
@@ -79,7 +79,7 @@
 	const struct mgmt_rp_read_version *rp = param;
 
 	tester_print("Read Version callback");
-	tester_print("  Status: 0x%02x", status);
+	tester_print("  Status: %s (0x%02x)", mgmt_errstr(status), status);
 
 	if (status || !param) {
 		tester_pre_setup_failed();
@@ -97,7 +97,7 @@
 					const void *param, void *user_data)
 {
 	tester_print("Read Commands callback");
-	tester_print("  Status: 0x%02x", status);
+	tester_print("  Status: %s (0x%02x)", mgmt_errstr(status), status);
 
 	if (status || !param) {
 		tester_pre_setup_failed();
@@ -116,7 +116,7 @@
 	struct bthost *bthost;
 
 	tester_print("Read Info callback");
-	tester_print("  Status: 0x%02x", status);
+	tester_print("  Status: %s (0x%02x)", mgmt_errstr(status), status);
 
 	if (status || !param) {
 		tester_pre_setup_failed();
@@ -216,7 +216,7 @@
 	struct test_data *data = tester_get_data();
 
 	tester_print("Read Index List callback");
-	tester_print("  Status: 0x%02x", status);
+	tester_print("  Status: %s (0x%02x)", mgmt_errstr(status), status);
 
 	if (status || !param) {
 		tester_pre_setup_failed();
@@ -437,8 +437,6 @@
 	uint8_t adv_data_len;
 };
 
-# define TESTER_NOOP_OPCODE 0x0000
-
 static const char dummy_data[] = { 0x00 };
 
 static const struct generic_data invalid_command_test = {
@@ -586,6 +584,22 @@
 	.expect_status = MGMT_STATUS_INVALID_INDEX,
 };
 
+static uint16_t settings_powered_advertising_privacy[] = {
+						MGMT_OP_SET_PRIVACY,
+						MGMT_OP_SET_ADVERTISING,
+						MGMT_OP_SET_POWERED, 0 };
+
+static const char set_adv_off_param[] = { 0x00 };
+
+static const struct generic_data set_powered_on_privacy_adv_test = {
+	.setup_settings = settings_powered_advertising_privacy,
+	.send_opcode = MGMT_OP_SET_ADVERTISING,
+	.send_param = set_adv_off_param,
+	.send_len = sizeof(set_adv_off_param),
+	.expect_status = MGMT_STATUS_SUCCESS,
+	.expect_ignore_param = true,
+};
+
 static const uint16_t settings_powered[] = { MGMT_OP_SET_POWERED, 0 };
 
 static const char set_powered_off_param[] = { 0x00 };
@@ -1859,7 +1873,7 @@
 };
 
 static const struct generic_data start_discovery_valid_param_power_off_1 = {
-	.setup_settings = settings_powered_le,
+	.setup_settings = settings_le,
 	.send_opcode = MGMT_OP_START_DISCOVERY,
 	.send_param = start_discovery_bredrle_param,
 	.send_len = sizeof(start_discovery_bredrle_param),
@@ -3848,16 +3862,12 @@
 	.expect_alt_ev = MGMT_EV_DEVICE_REMOVED,
 	.expect_alt_ev_param = remove_device_param_1,
 	.expect_alt_ev_len = sizeof(remove_device_param_1),
-	.expect_hci_command = BT_HCI_CMD_WRITE_SCAN_ENABLE,
-	.expect_hci_param = set_connectable_off_scan_enable_param,
-	.expect_hci_len = sizeof(set_connectable_off_scan_enable_param),
 };
 
 static const uint8_t remove_device_param_2[] =  {
 					0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc,
 					0x01,
 };
-static const uint8_t set_le_scan_off[] = { 0x00, 0x00 };
 static const struct generic_data remove_device_success_4 = {
 	.setup_settings = settings_powered,
 	.send_opcode = MGMT_OP_REMOVE_DEVICE,
@@ -3869,9 +3879,6 @@
 	.expect_alt_ev = MGMT_EV_DEVICE_REMOVED,
 	.expect_alt_ev_param = remove_device_param_2,
 	.expect_alt_ev_len = sizeof(remove_device_param_2),
-	.expect_hci_command = BT_HCI_CMD_LE_SET_SCAN_ENABLE,
-	.expect_hci_param = set_le_scan_off,
-	.expect_hci_len = sizeof(set_le_scan_off),
 };
 
 static const struct generic_data remove_device_success_5 = {
@@ -3884,9 +3891,6 @@
 	.expect_alt_ev = MGMT_EV_DEVICE_REMOVED,
 	.expect_alt_ev_param = remove_device_param_2,
 	.expect_alt_ev_len = sizeof(remove_device_param_2),
-	.expect_hci_command = BT_HCI_CMD_LE_SET_SCAN_ENABLE,
-	.expect_hci_param = set_le_scan_off,
-	.expect_hci_len = sizeof(set_le_scan_off),
 };
 
 static const struct generic_data read_adv_features_invalid_param_test = {
@@ -4365,8 +4369,6 @@
 	.expect_hci_len = sizeof(set_adv_data_txpwr),
 };
 
-static const char set_adv_off_param[] = { 0x00 };
-
 static const struct generic_data add_advertising_success_5 = {
 	.send_opcode = MGMT_OP_SET_ADVERTISING,
 	.send_param = set_adv_off_param,
@@ -4601,7 +4603,6 @@
 };
 
 static const struct generic_data add_advertising_timeout_expired = {
-	.send_opcode = TESTER_NOOP_OPCODE,
 	.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
 	.expect_alt_ev_param = advertising_instance1_param,
 	.expect_alt_ev_len = sizeof(advertising_instance1_param),
@@ -4656,7 +4657,6 @@
 };
 
 static const struct generic_data multi_advertising_switch = {
-	.send_opcode = TESTER_NOOP_OPCODE,
 	.expect_alt_ev = MGMT_EV_ADVERTISING_REMOVED,
 	.expect_alt_ev_param = advertising_instance1_param,
 	.expect_alt_ev_len = sizeof(advertising_instance1_param),
@@ -4784,14 +4784,16 @@
 	switch (opcode) {
 	case BT_HCI_CMD_WRITE_SCAN_ENABLE:
 	case BT_HCI_CMD_LE_SET_ADV_ENABLE:
-		tester_print("Client set connectable status 0x%02x", status);
+		tester_print("Client set connectable: %s (0x%02x)",
+						mgmt_errstr(status), status);
 		if (!status && test->client_enable_ssp) {
 			bthost_write_ssp_mode(bthost, 0x01);
 			return;
 		}
 		break;
 	case BT_HCI_CMD_WRITE_SIMPLE_PAIRING_MODE:
-		tester_print("Client enable SSP status 0x%02x", status);
+		tester_print("Client enable SSP: %s (0x%02x)",
+						mgmt_errstr(status), status);
 		break;
 	default:
 		return;
@@ -5103,7 +5105,7 @@
 	const unsigned char *add_param;
 	size_t add_param_len;
 
-	tester_print("Powering on controller (with added device))");
+	tester_print("Powering on controller (with added device)");
 
 	if (data->hciemu_type == HCIEMU_TYPE_LE) {
 		add_param = add_device_success_param_2;
@@ -5577,6 +5579,9 @@
 	for (cmd = test->setup_settings; *cmd; cmd++) {
 		unsigned char simple_param[] = { 0x01 };
 		unsigned char discov_param[] = { 0x01, 0x00, 0x00 };
+		unsigned char privacy_param[] = { 0x01,
+			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+			0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
 		unsigned char *param = simple_param;
 		size_t param_size = sizeof(simple_param);
 		mgmt_request_func_t func = NULL;
@@ -5595,6 +5600,11 @@
 			param = discov_param;
 		}
 
+		if (*cmd == MGMT_OP_SET_PRIVACY) {
+			param_size = sizeof(privacy_param);
+			param = privacy_param;
+		}
+
 		if (*cmd == MGMT_OP_SET_LE && test->setup_nobredr) {
 			unsigned char off[] = { 0x00 };
 			mgmt_send(data->mgmt, *cmd, data->mgmt_index,
@@ -5713,8 +5723,8 @@
 	const void *expect_param = test->expect_param;
 	uint16_t expect_len = test->expect_len;
 
-	tester_print("Command 0x%04x finished with status 0x%02x",
-						test->send_opcode, status);
+	tester_print("%s (0x%04x): %s (0x%02x)", mgmt_opstr(test->send_opcode),
+			test->send_opcode, mgmt_errstr(status), status);
 
 	if (status != test->expect_status) {
 		tester_test_failed();
@@ -5836,7 +5846,8 @@
 		return;
 	}
 
-	tester_print("Sending command 0x%04x", test->send_opcode);
+	tester_print("Sending %s (0x%04x)", mgmt_opstr(test->send_opcode),
+							test->send_opcode);
 
 	if (test->send_func)
 		send_param = test->send_func(&send_len);
@@ -5855,6 +5866,34 @@
 	test_add_condition(data);
 }
 
+static void check_scan(void *user_data)
+{
+	struct test_data *data = tester_get_data();
+
+	if (hciemu_get_master_le_scan_enable(data->hciemu)) {
+		tester_warn("LE scan still enabled");
+		tester_test_failed();
+		return;
+	}
+
+	if (hciemu_get_master_scan_enable(data->hciemu)) {
+		tester_warn("BR/EDR scan still enabled");
+		tester_test_failed();
+		return;
+	}
+
+	test_condition_complete(data);
+}
+
+static void test_remove_device(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+
+	test_command_generic(test_data);
+	tester_wait(1, check_scan, NULL);
+	test_add_condition(data);
+}
+
 static void test_device_found(const void *test_data)
 {
 	struct test_data *data = tester_get_data();
@@ -5936,7 +5975,8 @@
 	const void *send_param = test->send_param;
 	uint16_t send_len = test->send_len;
 
-	tester_print("Sending command 0x%04x", test->send_opcode);
+	tester_print("Sending %s 0x%04x", mgmt_opstr(test->send_opcode),
+							test->send_opcode);
 
 	if (test->send_func)
 		send_param = test->send_func(&send_len);
@@ -6064,6 +6104,9 @@
 	test_bredrle("Set powered on - Invalid index",
 				&set_powered_on_invalid_index_test,
 				NULL, test_command_generic);
+	test_le("Set powered on - Privacy and Advertising",
+				&set_powered_on_privacy_adv_test,
+				NULL, test_command_generic);
 
 	test_bredrle("Set powered off - Success",
 				&set_powered_off_success_test,
@@ -6787,13 +6830,13 @@
 				setup_add_device, test_command_generic);
 	test_bredrle("Remove Device - Success 3",
 				&remove_device_success_3,
-				setup_add_device, test_command_generic);
+				setup_add_device, test_remove_device);
 	test_le("Remove Device - Success 4",
 				&remove_device_success_4,
-				setup_add_device, test_command_generic);
+				setup_add_device, test_remove_device);
 	test_le("Remove Device - Success 5",
 				&remove_device_success_5,
-				setup_add_device, test_command_generic);
+				setup_add_device, test_remove_device);
 
 	test_bredrle("Read Advertising Features - Invalid parameters",
 				&read_adv_features_invalid_param_test,
diff --git a/tools/parse_companies.pl b/tools/parse_companies.pl
new file mode 100755
index 0000000..6dc358e
--- /dev/null
+++ b/tools/parse_companies.pl
@@ -0,0 +1,59 @@
+#!/usr/bin/perl
+
+# parse companies from
+# https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers
+
+use strict;
+# use URI::Encode qw(uri_decode);
+
+my %known_entities = (
+    'nbsp' => ' ',
+    'eacute' => 'é',
+    'auml' => 'ä',
+);
+
+# better to use URI::Encode if you have it
+sub uri_decode {
+    my $name = $_[0];
+    foreach my $entity (keys %known_entities) {
+        my $to = $known_entities{$entity};
+        $name =~ s/&$entity;/$to/g;
+    }
+    foreach my $entity (map { lc $_ } $name =~ /&([^;]+);/g) {
+        if ($entity ne 'amp') {
+            print "Unable to convert &$entity;, giving up\n";
+            exit 1;
+        }
+    }
+    $name =~ s/&amp;/&/ig;
+    $name =~ s/&nbsp;/ /ig;
+    return $name;
+}
+
+# never parse HTML with regex!
+# except when you should
+
+my $identifier;
+my $next_is_name = 0;
+
+while (<>) {
+    s/\xe2\x80\x8b//g; # kill zero width space
+
+    # grab identifier (in hex)
+    if (/\<td.*(0x[0-9A-F]{4})/i) {
+        $identifier = $1;
+        $next_is_name = 1;
+
+    # next <td> should be company name
+    } elsif ($next_is_name && m|\<td.*\>(.*)\</td\>|) {
+        my $name = uri_decode($1);
+        $name =~ s/^\s+//g; # kill leading
+        $name =~ s/\s+$//g; # and trailing space
+        my $id = hex($identifier);
+        if ($id != 65535) {
+            print "\tcase $id:\n";
+            print "\t\treturn \"$name\";\n";
+        }
+        $next_is_name = 0;
+    }
+}
diff --git a/tools/parser/avdtp.c b/tools/parser/avdtp.c
index f05f329..4f53553 100644
--- a/tools/parser/avdtp.c
+++ b/tools/parser/avdtp.c
@@ -154,6 +154,8 @@
 {
 	if (vendor == 0x0000004f && vndcodec == 0x0001)
 		return "aptX";
+	else if (vendor == 0x0000012d && vndcodec == 0x00aa)
+		return "LDAC";
 	return "Unknown";
 }
 
diff --git a/tools/update_compids.sh b/tools/update_compids.sh
index 95c961d..7c4cc12 100755
--- a/tools/update_compids.sh
+++ b/tools/update_compids.sh
@@ -13,45 +13,30 @@
 tmpdir=$(mktemp -d)
 trap "rm -rf $tmpdir" EXIT
 
+scriptdir=$(pwd)
+
 mkdir $tmpdir/lib
 cp lib/bluetooth.c $tmpdir/lib/bluetooth.c.orig
 cp lib/bluetooth.c $tmpdir/lib/bluetooth.c
 
 cd $tmpdir
 
-path=en-us/specification/assigned-numbers/company-identifiers
-# Use "iconv -c" to strip unwanted unicode characters
-# Fixups:
-# - strip <input> tags of type "checkbox" because html2text generates UTF-8 for
-#   them in some distros even when using -ascii (e.g. Fedora)
-# - replace "&#160;" (non-breaking space) with whitespace manually, because
-#   some versions incorrectly convert it into "\xC2\xA0"
-curl https://www.bluetooth.org/$path | iconv -c -f utf8 -t ascii | \
-    sed '/<input.*type="checkbox"/d; s/&#160;/ /g' | \
-    html2text -ascii -width 160 -o identifiers.txt >/dev/null
-
-# Some versions of html2text do not replace &amp; (e.g. Fedora)
-sed -i 's/&amp;/\&/g' identifiers.txt
-
-sed -n '/^const char \*bt_compidtostr(int compid)/,/^}/p' \
-    lib/bluetooth.c > old.c
-
 echo -e 'const char *bt_compidtostr(int compid)\n{\n\tswitch (compid) {' > new.c
-cat identifiers.txt |
-    perl -ne 'm/^(\d+)\s+0x[0-9a-f]+\s+(.*)/i &&
-        print "\tcase $1:\n\t\treturn \"$2\";\n"' >> new.c
+
+path=specifications/assigned-numbers/company-identifiers
+# Use "iconv -c" to strip unwanted unicode characters
+curl https://www.bluetooth.com/$path | \
+    $scriptdir/tools/parse_companies.pl >> new.c
+
 if ! grep -q "return \"" new.c; then
     echo "ERROR: could not parse company IDs from bluetooth.org" >&2
     exit 1
 fi
-if [ -n "$(tr -d '[:print:]\t\n' < new.c)" ]; then
-    echo -n "ERROR: invalid non-ASCII characters found while parsing" >&2
-    echo -n " company IDs. Please identify offending sequence and fix" >&2
-    echo " tools/update_compids.sh accordingly." >&2
-    exit 1
-fi
 echo -e '\tcase 65535:\n\t\treturn "internal use";' >> new.c
 echo -e '\tdefault:\n\t\treturn "not assigned";\n\t}\n}' >> new.c
 
+sed -n '/^const char \*bt_compidtostr(int compid)/,/^}/p' \
+    lib/bluetooth.c > old.c
+
 diff -Naur old.c new.c | patch -sp0 lib/bluetooth.c
 diff -Naur lib/bluetooth.c.orig lib/bluetooth.c
diff --git a/tools/valgrind.supp b/tools/valgrind.supp
index bf28bcd..9efb6f1 100644
--- a/tools/valgrind.supp
+++ b/tools/valgrind.supp
@@ -12,3 +12,16 @@
    fun:bind
    fun:cmac_aes_setup
 }
+{
+   logging_open
+   Memcheck:Param
+   socketcall.bind(my_addr.rc_bdaddr)
+   fun:bind
+   fun:logging_open
+}
+{
+   bind
+   Memcheck:Param
+   socketcall.bind(my_addr.rc_channel)
+   fun:bind
+}
diff --git a/unit/test-hog.c b/unit/test-hog.c
index 24731d7..9f026e5 100644
--- a/unit/test-hog.c
+++ b/unit/test-hog.c
@@ -37,7 +37,7 @@
 
 #include "attrib/gattrib.h"
 
-#include "android/hog.h"
+#include "profiles/input/hog-lib.h"
 
 struct test_pdu {
 	bool valid;
diff --git a/unit/test-uuid.c b/unit/test-uuid.c
index 5f45b0c..7c6789e 100644
--- a/unit/test-uuid.c
+++ b/unit/test-uuid.c
@@ -151,7 +151,7 @@
 	g_assert(bt_string_to_uuid(&uuid, test_data->str) == 0);
 
 	bt_uuid_to_string(&uuid, buf, sizeof(buf));
-	g_assert(strcasecmp(buf, str) == 0);
+	g_assert(bt_uuid_strcmp(buf, str) == 0);
 
 	switch (test_data->type) {
 	case BT_UUID16:
@@ -166,7 +166,7 @@
 	}
 
 	bt_uuid_to_string(&uuid, buf, sizeof(buf));
-	g_assert(strcasecmp(buf, str) == 0);
+	g_assert(bt_uuid_strcmp(buf, str) == 0);
 	tester_test_passed();
 }