merge -s ours from froyo-release so that upgrading to gingerbread is a git fast-forward

Change-Id: I199d5b50435f5d31038287831521a73a60abbb14
diff --git a/.gitignore b/.gitignore
index d5b85d3..7430b9c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
 *.so
 .deps
 .libs
+.dirstamp
 Makefile
 Makefile.in
 aclocal.m4
@@ -26,16 +27,22 @@
 
 ylwrap
 bluez.pc
-include/bluetooth
+lib/bluetooth
+src/builtin.h
 src/bluetoothd
+src/bluetooth.exp
+src/bluetooth.ver
 audio/telephony.c
 scripts/bluetooth.rules
+scripts/97-bluetooth.rules
+scripts/97-bluetooth-hid2hci.rules
 
 sbc/sbcdec
 sbc/sbcenc
 sbc/sbcinfo
 sbc/sbctester
 
+tracer/hcitrace
 tools/avctrl
 tools/avinfo
 tools/bccmd
@@ -48,10 +55,10 @@
 tools/hcisecfilter
 tools/hcitool
 tools/hid2hci
+tools/rfcomm
 tools/l2ping
 tools/ppporc
 tools/sdptool
-audio/ipctest
 cups/bluetooth
 test/agent
 test/bdaddr
@@ -62,14 +69,15 @@
 test/l2test
 test/rctest
 test/scotest
+test/gaptest
 test/sdptest
 test/lmptest
+test/ipctest
 test/btiotest
-rfcomm/rfcomm
+test/test-textfile
 compat/dund
 compat/hidd
 compat/pand
-common/test_textfile
 
 doc/*.bak
 doc/*.stamp
@@ -80,4 +88,3 @@
 doc/xml
 doc/html
 src/bluetoothd.8
-src/hcid.conf.5
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..2d7ce47
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,5 @@
+Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>	<luiz.dentz-von@nokia.com>
+Vinicius Costa Gomes <vinicius.gomes@openbossa.org>	<vinicius.gomes@openbossa.org>
+Elvis Pfützenreuter <epx@signove.com>			<epx@signove.com>
+Santiago Carot-Nemesio <scarot@libresoft.es>		<scarot@libresoft.es>
+José Antonio Santos Cadenas <santoscadenas@gmail.com>	<santoscadenas@gmail.com>
diff --git a/AUTHORS b/AUTHORS
index cd0189e..8e0a012 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -44,3 +44,9 @@
 Ilya Rubtsov <lusyaru@gmail.com>
 Mario Limonciello <mario_limonciello@dell.com>
 Filippo Giunchedi <filippo@esaurito.net>
+Jaikumar Ganesh <jaikumar@google.com>
+Elvis Pfutzenreuter <epx@signove.com>
+Santiago Carot-Nemesio <scarot@libresoft.es>
+José Antonio Santos Cadenas <jcaden@libresoft.es>
+Francisco Alecrim <francisco.alecrim@openbossa.org>
+Daniel Orstadius <daniel.orstadius@gmail.com>
diff --git a/ChangeLog b/ChangeLog
index e7066b8..4aa4589 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,176 @@
+ver 4.69:
+	Fix issue with calling g_option_context_free() twice.
+	Fix inconsistencies with initial LE commands and events.
+	Add support for telephony ClearLastNumber method.
+	Add support for network server interface.
+
+ver 4.68:
+	Fix initialization of adapters in RAW mode.
+	Fix signal strength for HFP in Maemo's telephony support.
+	Add support for following the radio state via Maemo's MCE.
+	Add initial set of LE commands and events definitions.
+	Add mode option for L2CAP sockets to the BtIO API.
+
+ver 4.67:
+	Fix issue with authentication reply when bonding already completed.
+	Fix issue with not canceling authentication when bonding fails.
+	Fix issue with changed combination keys and temporary storage.
+	Fix issue with sdp_get_supp_feat library function.
+	Fix issue with missing unblock on device removal.
+	Fix issue with not waiting for mode change completion.
+	Add ARMv6 optimized version of analysis filter for SBC encoder.
+
+ver 4.66:
+	Fix regression with full debug enabling via SIGUSR2.
+	Fix redundant speaker/microphone gains being sent.
+	Fix not emitting PropertyChanged for SpeakerGain/MicrophoneGain.
+	Fix issue with storage usage when a record is not found in memory.
+	Fix issue with DiscoverServices not retrieving any records.
+	Fix audio profile disconnection order to match whitepaper.
+	Fix auto-accept confirmation when local agent has NoInputNoOutput.
+	Fix remote just-works SSP when MITM protection is required.
+	Fix performing dedicated bonding without MITM requirement.
+	Add support for storing debug link keys in runtime memory.
+
+ver 4.65:
+	Fix issues with general bonding being default setting now.
+	Fix driver removal upon device removal.
+	Add new "Blocked" property to device objects.
+	Add hciconfig support for blacklisting.
+	Add support for dynamic debug feature.
+
+ver 4.64:
+	Fix invalid memory access in headset_get_nrec function.
+	Fix issue with disconnect event on higher protocol layers.
+	Fix issue with list parsing in sdp_set_supp_features function.
+	Fix device object reference counting for SDP browse requests.
+	Add missing memory checks whenever memory is allocated for SDP.
+	Add support for exporting local services via D-Bus.
+	Add more L2CAP Enhanced Retransmission test options.
+
+ver 4.63:
+	Fix avdtp_abort not canceling pending requests.
+	Fix stale connection when abort gets rejected.
+
+ver 4.62:
+	Fix accidental symbol breakage with inquiry transmit power.
+	Fix using invalid data from previous headset connection.
+	Fix double free on AVDTP Abort response.
+	Fix possible crash while verifying AVDTP version.
+	Fix missing inuse flag when AVDTP stream is configured.
+	Add support for Bluetooth controller types.
+
+ver 4.61:
+	Fix issues with Read Inquiry Response Transmit Power Level.
+	Fix possible invalid read when removing a temporary device.
+	Fix mode restoration when remember_powered is false.
+	Fix conference call releasing in telephony-maemo.
+	Fix segmentation fault with authorization during headset disconnects.
+	Add support for handling unanswered AVDTP request on disconnect.
+	Add support for handling Inquiry Response Transmit Power Level.
+	Add support for caching of remote host features.
+	Add preliminary voice dialing support for HSP.
+
+ver 4.60:
+	Fix voice mailbox number reading from SIM.
+	Fix some races with D-Bus mainloop integration.
+	Add helpers for D-Bus signal watches.
+
+ver 4.59:
+	Add values for Bluetooth 4.0 specification.
+	Add SDP functions for HDP support.
+	Add test scripts for input and audio.
+	Fix missing close on BtIO create_io function.
+	Fix sending incorrect AVDTP commands after timeout occurs.
+	Fix timer removal when device disconnects unexpectedly.
+	Fix Extended Inquiry Response record for Device ID.
+
+ver 4.58:
+	Fix crash when adapter agent exists during authentication.
+	Fix CK-20W quirks for play and pause events.
+
+ver 4.57:
+	Fix unloading of drivers for uninitialized adapters.
+	Fix debug message to use requested and not opened SEID.
+	Fix codec selection for GStreamer plugin.
+	Fix deleting of SDP records during service updates.
+	Fix deleting of SDP records when a device is removed.
+	Fix handling when the SDP record is modified on remote device.
+	Fix potential buffer overflow by using snprintf instead of sprintf.
+	Fix const declarations for some storage function parameters.
+
+ver 4.56:
+	Add missing values from Bluetooth 3.0 specification.
+	Add proper tracking of device paired status.
+	Fix tracking of devices without permanently stored link key.
+	Fix issue with link key removal after connection failures.
+	Fix legacy pairing information based on remote host features.
+	Fix off-by-one issue with AVDTP capability parsing.
+	Fix AVRCP, AVCTP, AVDTP, A2DP and HFP version numbers.
+	Fix agent canceling before calling agent_destroy.
+	Fix service record parsing with an empty UUID list.
+	Fix various SDP related memory leaks.
+
+ver 4.55:
+	Add support for POSIX capabilities dropping.
+	Add special quirk for the Nokia CK-20W car kit.
+	Fix error code handling for AVDTP SetConfiguration response.
+	Fix updating out of range list when RSSI hasn't changed.
+	Fix various memory leaks and unnecessary error checks.
+
+ver 4.54:
+	Add introspection interface to output of introspection calls.
+	Fix stream handling when media transport disconnects prematurely.
+	Fix command timeout handling when there's no stream.
+	Fix headset_suspend_stream behavior for invalid states
+	Fix issue with AVDTP ABORTING state transition.
+	Fix issue with AVDTP suspend while closing.
+
+ver 4.53:
+	Fix issue with telephony connection state notifications.
+	Fix AVDTP stream leak for invalid media transport config.
+	Fix audio connection authorization handling with timeouts.
+	Fix race condition in authorizing audio connections.
+	Fix device authorized setting for AVRCP-only connections.
+	Fix duplicate attempts from device to connect signal channel.
+
+ver 4.52:
+	Add AVCTP support to test utility.
+	Fix AVDTP Abort when transport closes before response.
+	Fix authorization when the audio profiles are slow to connect.
+	Fix potential AVDTP reference leaks.
+
+ver 4.51:
+	Add utility for basic AVDTP testing.
+	Add support for configuring L2CAP FCS option.
+	Fix discovery mode for CUPS 1.4.x and later.
+	Fix global state tracking of audio service.
+	Fix last issues with the new build system.
+
+ver 4.50:
+	Fix issue with missing manual pages in distribution.
+	Fix issue with the configuration and state directories.
+	Fix issue with creating include directory.
+	Fix dependencies of include file generation.
+
+ver 4.49:
+	Add simple test program for basic GAP testing.
+	Add support for confirmation requests to agent example.
+	Add support for full non-recursive build.
+	Add five millisecond delay for Simple Pairing auto-accept.
+	Fix Class of Device setting when InitiallyPowered=false.
+
+ver 4.48:
+	Add library function for comparing UUID values.
+	Add support for creating all plugins as builtins.
+	Add support for async handling of service class changes.
+	Add support for source interface to audio IPC.
+	Fix device name settings when device is off or down.
+	Fix issue with enabled SCO server when not necessary.
+	Fix missing D-Bus access policy for CUPS backend.
+	Fix discovery results of CUPS backend.
+	Fix initialization handling of Maemo telephony.
+
 ver 4.47:
 	Add support for RFKILL unblock handling.
 	Add support for serial proxy configurations.
diff --git a/Makefile.am b/Makefile.am
index c4c6322..f4bf87d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,16 +1,334 @@
 
-SUBDIRS = include lib sbc gdbus common plugins src client\
-			network serial input audio tools \
-			rfcomm compat cups test scripts doc
+AM_MAKEFLAGS = --no-print-directory
 
-EXTRA_DIST = bluez.m4
+lib_LTLIBRARIES =
+
+noinst_LTLIBRARIES =
+
+bin_PROGRAMS =
+
+sbin_PROGRAMS =
+
+noinst_PROGRAMS =
+
+dist_man_MANS =
+
+dist_noinst_MANS =
+
+CLEANFILES =
+
+EXTRA_DIST =
+
+includedir = @includedir@/bluetooth
+
+include_HEADERS =
+
+if CONFIGFILES
+dbusdir = $(sysconfdir)/dbus-1/system.d
+
+dbus_DATA = src/bluetooth.conf
+
+confdir = $(sysconfdir)/bluetooth
+
+conf_DATA =
+
+statedir = $(localstatedir)/lib/bluetooth
+
+state_DATA =
+endif
+
+plugindir = $(libdir)/bluetooth/plugins
+
+plugin_LTLIBRARIES =
+
+
+lib_headers = lib/bluetooth.h lib/hci.h lib/hci_lib.h \
+			lib/sco.h lib/l2cap.h lib/sdp.h lib/sdp_lib.h \
+				lib/rfcomm.h lib/bnep.h lib/cmtp.h lib/hidp.h
+local_headers = $(foreach file,$(lib_headers), lib/bluetooth/$(notdir $(file)))
+
+include_HEADERS += $(lib_headers)
+
+lib_LTLIBRARIES += lib/libbluetooth.la
+
+lib_libbluetooth_la_SOURCES = $(lib_headers) \
+					lib/bluetooth.c lib/hci.c lib/sdp.c
+lib_libbluetooth_la_LDFLAGS = -version-info 12:0:9
+lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
+
+CLEANFILES += $(local_headers)
+
+
+if SBC
+noinst_LTLIBRARIES += sbc/libsbc.la
+
+sbc_libsbc_la_SOURCES = sbc/sbc.h sbc/sbc.c sbc/sbc_math.h sbc/sbc_tables.h \
+			sbc/sbc_primitives.h sbc/sbc_primitives.c \
+			sbc/sbc_primitives_mmx.h sbc/sbc_primitives_mmx.c \
+			sbc/sbc_primitives_neon.h sbc/sbc_primitives_neon.c \
+			sbc/sbc_primitives_armv6.h sbc/sbc_primitives_armv6.c
+
+sbc_libsbc_la_CFLAGS = -finline-functions -fgcse-after-reload \
+					-funswitch-loops -funroll-loops
+
+noinst_PROGRAMS += sbc/sbcinfo sbc/sbcdec sbc/sbcenc
+
+sbc_sbcdec_SOURCES = sbc/sbcdec.c sbc/formats.h
+sbc_sbcdec_LDADD = sbc/libsbc.la
+
+sbc_sbcenc_SOURCES = sbc/sbcenc.c sbc/formats.h
+sbc_sbcenc_LDADD = sbc/libsbc.la
+
+if SNDFILE
+noinst_PROGRAMS += sbc/sbctester
+
+sbc_sbctester_LDADD = @SNDFILE_LIBS@ -lm
+sbc_sbctest_CFLAGS = @SNDFILE_CFLAGS@
+endif
+endif
+
+
+if NETLINK
+plugin_LTLIBRARIES += plugins/netlink.la
+
+plugins_netlink_la_LIBADD = @NETLINK_LIBS@
+plugins_netlink_la_LDFLAGS = -module -avoid-version -no-undefined
+plugins_netlink_la_CFLAGS = -fvisibility=hidden @DBUS_CFLAGS@ \
+					@GLIB_CFLAGS@ @NETLINK_CFLAGS@
+endif
+
+gdbus_sources = gdbus/gdbus.h gdbus/mainloop.c gdbus/object.c gdbus/watch.c
+
+builtin_modules =
+builtin_sources =
+builtin_nodist =
+
+if PNATPLUGIN
+builtin_modules += pnat
+builtin_sources += plugins/pnat.c
+endif
+
+if ECHOPLUGIN
+builtin_modules += echo
+builtin_sources += plugins/echo.c
+endif
+
+if AUDIOPLUGIN
+builtin_modules += audio
+builtin_sources += audio/main.c \
+			audio/manager.h audio/manager.c \
+			audio/gateway.h audio/gateway.c \
+			audio/headset.h audio/headset.c \
+			audio/control.h audio/control.c \
+			audio/device.h audio/device.c \
+			audio/source.h audio/source.c \
+			audio/sink.h audio/sink.c \
+			audio/a2dp.h audio/a2dp.c \
+			audio/avdtp.h audio/avdtp.c \
+			audio/ipc.h audio/ipc.c \
+			audio/unix.h audio/unix.c \
+			audio/telephony.h
+builtin_nodist += audio/telephony.c
+
+noinst_LIBRARIES = audio/libtelephony.a
+
+audio_libtelephony_a_SOURCES = audio/telephony.h audio/telephony-dummy.c \
+				audio/telephony-maemo5.c audio/telephony-ofono.c \
+				audio/telephony-maemo6.c
+endif
+
+if INPUTPLUGIN
+builtin_modules += input
+builtin_sources += input/main.c \
+			input/manager.h input/manager.c \
+			input/server.h input/server.c \
+			input/device.h input/device.c \
+			input/fakehid.c input/fakehid.h
+endif
+
+if SERIALPLUGIN
+builtin_modules += serial
+builtin_sources += serial/main.c \
+			serial/manager.h serial/manager.c \
+			serial/proxy.h serial/proxy.c \
+			serial/port.h serial/port.c
+endif
+
+if NETWORKPLUGIN
+builtin_modules += network
+builtin_sources += network/main.c \
+			network/manager.h network/manager.c \
+			network/common.h network/common.c \
+			network/server.h network/server.c \
+			network/connection.h network/connection.c
+endif
+
+if SERVICEPLUGIN
+builtin_modules += service
+builtin_sources += plugins/service.c
+endif
+
+builtin_modules += hciops
+builtin_sources += plugins/hciops.c
+
+builtin_modules += hal
+builtin_sources += plugins/hal.c
+
+builtin_modules += storage
+builtin_sources += plugins/storage.c
+
+if MAEMO6PLUGIN
+builtin_modules += maemo6
+builtin_sources += plugins/maemo6.c
+endif
+
+sbin_PROGRAMS += src/bluetoothd
+
+src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
+			src/main.c src/log.h src/log.c \
+			src/security.c src/rfkill.c src/hcid.h src/sdpd.h \
+			src/sdpd-server.c src/sdpd-request.c \
+			src/sdpd-service.c src/sdpd-database.c \
+			src/sdp-xml.h src/sdp-xml.c src/btio.h src/btio.c \
+			src/textfile.h src/textfile.c \
+			src/glib-helper.h src/glib-helper.c \
+			src/oui.h src/oui.c src/uinput.h src/ppoll.h \
+			src/plugin.h src/plugin.c \
+			src/storage.h src/storage.c \
+			src/agent.h src/agent.c \
+			src/error.h src/error.c \
+			src/manager.h src/manager.c \
+			src/adapter.h src/adapter.c \
+			src/device.h src/device.c \
+			src/dbus-common.c src/dbus-common.h \
+			src/dbus-hci.h src/dbus-hci.c
+src_bluetoothd_LDADD = lib/libbluetooth.la @GLIB_LIBS@ @DBUS_LIBS@ \
+							@CAPNG_LIBS@ -ldl
+src_bluetoothd_LDFLAGS = -Wl,--export-dynamic \
+					-Wl,--version-script=src/bluetooth.ver
+src_bluetoothd_DEPENDENCIES = src/bluetooth.ver lib/libbluetooth.la
+
+builtin_files = src/builtin.h $(builtin_nodist)
+
+nodist_src_bluetoothd_SOURCES = $(builtin_files)
+
+CLEANFILES += src/bluetooth.ver src/bluetooth.exp $(builtin_files)
+
+man_MANS = src/bluetoothd.8
+
+if CONFIGFILES
+conf_DATA += src/main.conf
+endif
+
+EXTRA_DIST += src/genbuiltin src/bluetooth.conf \
+			src/main.conf network/network.conf \
+			input/input.conf serial/serial.conf \
+			audio/audio.conf audio/telephony-dummy.c \
+			audio/telephony-maemo5.c audio/telephony-ofono.c \
+			audio/telephony-maemo6.c
+
+
+if ALSA
+alsadir = $(libdir)/alsa-lib
+
+alsa_LTLIBRARIES = audio/libasound_module_pcm_bluetooth.la \
+				audio/libasound_module_ctl_bluetooth.la
+
+audio_libasound_module_pcm_bluetooth_la_SOURCES = audio/pcm_bluetooth.c \
+					audio/rtp.h audio/ipc.h audio/ipc.c
+audio_libasound_module_pcm_bluetooth_la_LDFLAGS = -module -avoid-version #-export-symbols-regex [_]*snd_pcm_.*
+audio_libasound_module_pcm_bluetooth_la_LIBADD = sbc/libsbc.la \
+						lib/libbluetooth.la @ALSA_LIBS@
+audio_libasound_module_pcm_bluetooth_la_CFLAGS = @ALSA_CFLAGS@
+
+audio_libasound_module_ctl_bluetooth_la_SOURCES = audio/ctl_bluetooth.c \
+					audio/rtp.h audio/ipc.h audio/ipc.c
+audio_libasound_module_ctl_bluetooth_la_LDFLAGS = -module -avoid-version #-export-symbols-regex [_]*snd_ctl_.*
+audio_libasound_module_ctl_bluetooth_la_LIBADD = lib/libbluetooth.la @ALSA_LIBS@
+audio_libasound_module_ctl_bluetooth_la_CFLAGS = @ALSA_CFLAGS@
+
+if CONFIGFILES
+alsaconfdir = $(sysconfdir)/alsa
+
+alsaconf_DATA = audio/bluetooth.conf
+endif
+endif
+
+if AUDIOPLUGIN
+if GSTREAMER
+gstreamerdir = $(libdir)/gstreamer-0.10
+
+gstreamer_LTLIBRARIES = audio/libgstbluetooth.la
+
+audio_libgstbluetooth_la_SOURCES = audio/gstbluetooth.c audio/gstpragma.h \
+				audio/gstsbcenc.h audio/gstsbcenc.c \
+				audio/gstsbcdec.h audio/gstsbcdec.c \
+				audio/gstsbcparse.h audio/gstsbcparse.c \
+				audio/gstavdtpsink.h audio/gstavdtpsink.c \
+				audio/gsta2dpsink.h audio/gsta2dpsink.c \
+				audio/gstsbcutil.h audio/gstsbcutil.c \
+				audio/gstrtpsbcpay.h audio/gstrtpsbcpay.c \
+				audio/rtp.h audio/ipc.h audio/ipc.c
+audio_libgstbluetooth_la_LDFLAGS = -module -avoid-version
+audio_libgstbluetooth_la_LIBADD = sbc/libsbc.la lib/libbluetooth.la \
+				@GSTREAMER_LIBS@ -lgstaudio-0.10 -lgstrtp-0.10
+audio_libgstbluetooth_la_CFLAGS = -fvisibility=hidden -fno-strict-aliasing \
+						$(AM_CFLAGS) @GSTREAMER_CFLAGS@
+endif
+endif
+
+EXTRA_DIST += audio/bluetooth.conf
+
+
+include Makefile.tools
+
+if UDEVRULES
+rulesdir = @UDEV_DATADIR@
+
+udev_files = scripts/bluetooth.rules
+
+if HID2HCI
+udev_files += scripts/bluetooth-hid2hci.rules
+endif
+
+if PCMCIA
+udev_files += scripts/bluetooth-serial.rules
+endif
+
+rules_DATA = $(foreach file,$(udev_files), scripts/97-$(notdir $(file)))
+endif
+
+CLEANFILES += $(rules_DATA)
+
+EXTRA_DIST += scripts/bluetooth.rules \
+		scripts/bluetooth-hid2hci.rules scripts/bluetooth-serial.rules
+
+if PCMCIA
+udevdir = $(libexecdir)/udev
+
+dist_udev_SCRIPTS = scripts/bluetooth_serial
+endif
+
+EXTRA_DIST += doc/manager-api.txt \
+		doc/adapter-api.txt doc/device-api.txt \
+		doc/service-api.txt doc/agent-api.txt doc/attribute-api.txt \
+		doc/serial-api.txt doc/network-api.txt \
+		doc/input-api.txt doc/audio-api.txt doc/control-api.txt
+
+AM_YFLAGS = -d
+
+AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @CAPNG_CFLAGS@ \
+		-DBLUETOOTH_PLUGIN_BUILTIN -DPLUGINDIR=\""$(plugindir)"\"
+
+INCLUDES = -I$(builddir)/lib -I$(builddir)/src -I$(srcdir)/src \
+			-I$(srcdir)/audio -I$(srcdir)/sbc -I$(srcdir)/gdbus
+
 
 pkgconfigdir = $(libdir)/pkgconfig
 
 pkgconfig_DATA = bluez.pc
 
-DISTCHECK_CONFIGURE_FLAGS = --disable-gtk-doc \
-				--disable-udevrules
+DISTCHECK_CONFIGURE_FLAGS = --disable-udevrules
 
 DISTCLEANFILES = $(pkgconfig_DATA)
 
@@ -18,3 +336,34 @@
 	aclocal.m4 configure config.h.in config.sub config.guess \
 	ltmain.sh depcomp compile missing install-sh mkinstalldirs ylwrap
 
+src/plugin.$(OBJEXT): src/builtin.h
+
+src/builtin.h: src/genbuiltin $(builtin_sources)
+	$(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
+
+src/bluetooth.exp: $(src_bluetoothd_OBJECTS)
+	$(AM_V_GEN)$(NM) $^ | $(AWK) '{ print $$3 }' | sort -u | \
+				$(EGREP) -e '^btd_' -e '^g_dbus_' > $@
+	$(AM_V_at)echo -e "info" >> $@
+	$(AM_V_at)echo -e "error" >> $@
+	$(AM_V_at)echo -e "debug" >> $@
+
+src/bluetooth.ver: src/bluetooth.exp
+	$(AM_V_at)echo "{ global:" > $@
+	$(AM_V_GEN)$(SED) -e "s/\(.*\)/\1;/" $< >> $@
+	$(AM_V_at)echo "local: *; };" >> $@
+
+audio/telephony.c: audio/@TELEPHONY_DRIVER@
+	$(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
+
+scripts/%.rules:
+	$(AM_V_GEN)cp $(subst 97-,,$@) $@
+
+$(lib_libbluetooth_la_OBJECTS): $(local_headers)
+
+lib/bluetooth/%.h: lib/%.h
+	$(AM_V_at)$(MKDIR_P) lib/bluetooth
+	$(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
+
+clean-local: lib/bluetooth
+	@$(RM) -r $<
diff --git a/Makefile.tools b/Makefile.tools
new file mode 100644
index 0000000..2dbf925
--- /dev/null
+++ b/Makefile.tools
@@ -0,0 +1,230 @@
+
+if TOOLS
+if CONFIGFILES
+conf_DATA += tools/rfcomm.conf
+endif
+
+bin_PROGRAMS += tools/rfcomm tools/l2ping \
+				tools/hcitool tools/sdptool tools/ciptool
+
+sbin_PROGRAMS += tools/hciattach tools/hciconfig
+
+noinst_PROGRAMS += tools/avinfo tools/ppporc \
+				tools/hcieventmask tools/hcisecfilter
+
+tools_rfcomm_SOURCES = tools/main.c tools/parser.y tools/lexer.l \
+					tools/kword.h tools/kword.c
+EXTRA_tools_rfcomm_SOURCES = tools/parser.h tools/parser.c \
+							tools/lexer.c
+tools_rfcomm_LDADD = lib/libbluetooth.la
+
+tools_l2ping_LDADD = lib/libbluetooth.la
+
+tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
+						tools/hciattach_st.c \
+						tools/hciattach_ti.c \
+						tools/hciattach_tialt.c
+tools_hciattach_LDADD = lib/libbluetooth.la
+
+tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c \
+						src/textfile.h src/textfile.c
+tools_hciconfig_LDADD = lib/libbluetooth.la
+
+tools_hcitool_SOURCES = tools/hcitool.c src/oui.h src/oui.c \
+						src/textfile.h src/textfile.c
+tools_hcitool_LDADD = lib/libbluetooth.la
+
+tools_sdptool_SOURCES = tools/sdptool.c src/sdp-xml.h src/sdp-xml.c
+tools_sdptool_LDADD = lib/libbluetooth.la
+
+tools_ciptool_LDADD = lib/libbluetooth.la
+
+tools_avinfo_LDADD = lib/libbluetooth.la
+
+tools_ppporc_LDADD = lib/libbluetooth.la
+
+tools_hcieventmask_LDADD = lib/libbluetooth.la
+
+dist_man_MANS += tools/rfcomm.1 tools/l2ping.8 \
+			tools/hciattach.8 tools/hciconfig.8 \
+			tools/hcitool.1 tools/sdptool.1 tools/ciptool.1
+else
+EXTRA_DIST += tools/rfcomm.1 tools/l2ping.8 \
+			tools/hciattach.8 tools/hciconfig.8 \
+			tools/hcitool.1 tools/sdptool.1 tools/ciptool.1
+endif
+
+CLEANFILES += tools/lexer.c tools/parser.c tools/parser.h
+
+EXTRA_DIST += tools/rfcomm.conf
+
+if TRACER
+sbin_PROGRAMS += tracer/hcitrace
+
+tracer_hcitrace_SOURCES = tracer/main.c
+tracer_hcitrace_LDADD = lib/libbluetooth.la \
+				@GLIB_LIBS@ @DBUS_LIBS@ @CAPNG_LIBS@
+tracer_hcitrace_DEPENDENCIES = lib/libbluetooth.la
+endif
+
+if BCCMD
+sbin_PROGRAMS += tools/bccmd
+
+tools_bccmd_SOURCES = tools/bccmd.c tools/csr.h tools/csr.c \
+			tools/csr_hci.c tools/csr_h4.c tools/csr_3wire.c \
+			tools/csr_bcsp.c tools/ubcsp.h tools/ubcsp.c
+tools_bccmd_LDADD = lib/libbluetooth.la
+
+if USB
+tools_bccmd_SOURCES += tools/csr_usb.c
+tools_bccmd_LDADD += @USB_LIBS@
+endif
+
+dist_man_MANS += tools/bccmd.8
+else
+EXTRA_DIST += tools/bccmd.8
+endif
+
+if HID2HCI
+sbin_PROGRAMS += tools/hid2hci
+
+tools_hid2hci_LDADD = @USB_LIBS@
+
+dist_man_MANS += tools/hid2hci.8
+else
+EXTRA_DIST += tools/hid2hci.8
+endif
+
+if DFUTOOL
+bin_PROGRAMS += tools/dfutool
+
+tools_dfutool_SOURCES = tools/dfutool.c tools/dfu.h tools/dfu.c
+tools_dfutool_LDADD = @USB_LIBS@
+
+dist_man_MANS += tools/dfutool.1
+else
+EXTRA_DIST += tools/dfutool.1
+endif
+
+
+if USB
+noinst_PROGRAMS += tools/dfubabel tools/avctrl
+
+tools_dfubabel_LDADD = @USB_LIBS@
+
+tools_avctrl_LDADD = @USB_LIBS@
+endif
+
+EXTRA_DIST += tools/dfubabel.1 tools/avctrl.8
+
+
+if CUPS
+cupsdir = $(libdir)/cups/backend
+
+cups_PROGRAMS = cups/bluetooth
+
+cups_bluetooth_SOURCES = $(gdbus_sources) cups/main.c cups/cups.h \
+					cups/sdp.c cups/spp.c cups/hcrp.c
+
+cups_bluetooth_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ lib/libbluetooth.la
+endif
+
+
+if TEST
+sbin_PROGRAMS += test/hciemu
+
+bin_PROGRAMS += test/l2test test/rctest
+
+noinst_PROGRAMS += test/gaptest test/sdptest test/scotest \
+			test/attest test/hstest test/avtest test/ipctest \
+					test/lmptest test/bdaddr test/agent \
+					test/btiotest test/test-textfile
+
+test_hciemu_LDADD = @GLIB_LIBS@ lib/libbluetooth.la
+
+test_l2test_LDADD = lib/libbluetooth.la
+
+test_rctest_LDADD = lib/libbluetooth.la
+
+test_gaptest_LDADD = @DBUS_LIBS@
+
+test_sdptest_LDADD = lib/libbluetooth.la
+
+test_scotest_LDADD = lib/libbluetooth.la
+
+test_attest_LDADD = lib/libbluetooth.la
+
+test_hstest_LDADD = lib/libbluetooth.la
+
+test_avtest_LDADD = lib/libbluetooth.la
+
+test_lmptest_LDADD = lib/libbluetooth.la
+
+test_ipctest_SOURCES = test/ipctest.c audio/ipc.h audio/ipc.c
+test_ipctest_LDADD= @GLIB_LIBS@ sbc/libsbc.la
+
+test_bdaddr_SOURCES = test/bdaddr.c src/oui.h src/oui.c
+test_bdaddr_LDADD = lib/libbluetooth.la
+
+test_agent_LDADD = @DBUS_LIBS@
+
+test_btiotest_SOURCES = test/btiotest.c src/btio.h src/btio.c
+test_btiotest_LDADD = @GLIB_LIBS@ lib/libbluetooth.la
+
+test_test_textfile_SOURCES = test/test-textfile.c src/textfile.h src/textfile.c
+
+dist_man_MANS += test/rctest.1 test/hciemu.1
+
+EXTRA_DIST += test/bdaddr.8
+else
+EXTRA_DIST += test/rctest.1 test/hciemu.1 test/bdaddr.8
+endif
+
+EXTRA_DIST += test/apitest test/hsplay test/hsmicro test/dbusdef.py \
+		test/monitor-bluetooth test/list-devices test/test-discovery \
+		test/test-manager test/test-adapter test/test-device \
+		test/test-service test/test-serial test/test-telephony \
+		test/test-network test/simple-agent test/simple-service \
+		test/test-audio test/test-input \
+		test/service-record.dtd test/service-did.xml \
+		test/service-spp.xml test/service-opp.xml test/service-ftp.xml
+
+
+if HIDD
+bin_PROGRAMS += compat/hidd
+
+compat_hidd_SOURCES = compat/hidd.c compat/hidd.h src/uinput.h \
+				compat/sdp.h compat/sdp.c compat/fakehid.c \
+						src/textfile.h src/textfile.c
+compat_hidd_LDADD = -lm lib/libbluetooth.la
+
+dist_man_MANS += compat/hidd.1
+else
+EXTRA_DIST += compat/hidd.1
+endif
+
+if PAND
+bin_PROGRAMS += compat/pand
+
+compat_pand_SOURCES = compat/pand.c compat/pand.h \
+				compat/bnep.c compat/sdp.h compat/sdp.c \
+						src/textfile.h src/textfile.c
+compat_pand_LDADD = lib/libbluetooth.la
+
+dist_man_MANS += compat/pand.1
+else
+EXTRA_DIST += compat/pand.1
+endif
+
+if DUND
+bin_PROGRAMS += compat/dund
+
+compat_dund_SOURCES = compat/dund.c compat/dund.h compat/lib.h \
+			compat/sdp.h compat/sdp.c compat/dun.c compat/msdun.c \
+						src/textfile.h src/textfile.c
+compat_dund_LDADD = lib/libbluetooth.la
+
+dist_man_MANS += compat/dund.1
+else
+EXTRA_DIST += compat/dund.1
+endif
diff --git a/README b/README
index 3cc6547..77778e0 100644
--- a/README
+++ b/README
@@ -3,7 +3,7 @@
 
 Copyright (C) 2000-2001  Qualcomm Incorporated
 Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
-Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
 
 
 Compilation and installation
diff --git a/ThirdPartyProject.prop b/ThirdPartyProject.prop
new file mode 100644
index 0000000..b6bef4a
--- /dev/null
+++ b/ThirdPartyProject.prop
@@ -0,0 +1,10 @@
+# Copyright 2010 Google Inc. All Rights Reserved.
+#Fri Jul 16 10:03:08 PDT 2010
+currentVersion=Unknown
+version=4.69
+isNative=true
+feedurl=ChangeLog
+name=bluez-utils
+keywords=bluez-utils
+onDevice=true
+homepage=www.bluez.org
diff --git a/acinclude.m4 b/acinclude.m4
index 248fed3..f5fdd66 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -25,34 +25,6 @@
 	fi
 ])
 
-AC_DEFUN([GTK_DOC_CHECK], [
-	AC_ARG_WITH([html-dir],
-		AS_HELP_STRING([--with-html-dir=PATH], [path to installed docs]),,
-					[with_html_dir='${datadir}/gtk-doc/html'])
-	HTML_DIR="$with_html_dir"
-	AC_SUBST([HTML_DIR])
-
-	AC_ARG_ENABLE([gtk-doc],
-		AS_HELP_STRING([--enable-gtk-doc], [use gtk-doc to build documentation [[default=no]]]),,
-					[enable_gtk_doc=no])
-
-	if test x$enable_gtk_doc = xyes; then
-		ifelse([$1],[],
-			[PKG_CHECK_EXISTS([gtk-doc],,
-				AC_MSG_ERROR([gtk-doc not installed and --enable-gtk-doc requested]))],
-			[PKG_CHECK_EXISTS([gtk-doc >= $1],,
-				AC_MSG_ERROR([You need to have gtk-doc >= $1 installed to build gtk-doc]))])
-	fi
-
-	AC_MSG_CHECKING([whether to build gtk-doc documentation])
-	AC_MSG_RESULT($enable_gtk_doc)
-
-	AC_PATH_PROGS(GTKDOC_CHECK,gtkdoc-check,)
-
-	AM_CONDITIONAL([ENABLE_GTK_DOC], [test x$enable_gtk_doc = xyes])
-	AM_CONDITIONAL([GTK_DOC_USE_LIBTOOL], [test -n "$LIBTOOL"])
-])
-
 AC_DEFUN([AC_FUNC_PPOLL], [
 	AC_CHECK_FUNC(ppoll, dummy=yes, AC_DEFINE(NEED_PPOLL, 1,
 			[Define to 1 if you need the ppoll() function.]))
@@ -126,6 +98,10 @@
 	AC_CHECK_LIB(dbus-1, dbus_watch_get_unix_fd, dummy=yes,
 		AC_DEFINE(NEED_DBUS_WATCH_GET_UNIX_FD, 1,
 			[Define to 1 if you need the dbus_watch_get_unix_fd() function.]))
+	AC_CHECK_LIB(dbus-1, dbus_connection_can_send_type, dummy=yes,
+		AC_DEFINE(NEED_DBUS_CONNECTION_CAN_SEND_TYPE, 1,
+			[Define to 1 if you need the dbus_connection_can_send_type() function.]
+))
 	AC_SUBST(DBUS_CFLAGS)
 	AC_SUBST(DBUS_LIBS)
 ])
@@ -170,12 +146,6 @@
 			[Define to 1 if you need the usb_interrupt_read() function.]))
 ])
 
-AC_DEFUN([AC_PATH_NETLINK], [
-	PKG_CHECK_MODULES(NETLINK, libnl-1, netlink_found=yes, netlink_found=no)
-	AC_SUBST(NETLINK_CFLAGS)
-	AC_SUBST(NETLINK_LIBS)
-])
-
 AC_DEFUN([AC_PATH_SNDFILE], [
 	PKG_CHECK_MODULES(SNDFILE, sndfile, sndfile_found=yes, sndfile_found=no)
 	AC_SUBST(SNDFILE_CFLAGS)
@@ -188,7 +158,6 @@
 	fortify_enable=yes
 	pie_enable=yes
 	sndfile_enable=${sndfile_found}
-	netlink_enable=no
 	hal_enable=${hal_found}
 	usb_enable=${usb_found}
 	alsa_enable=${alsa_found}
@@ -198,6 +167,8 @@
 	serial_enable=yes
 	network_enable=yes
 	service_enable=yes
+	pnat_enable=no
+	tracer_enable=no
 	tools_enable=yes
 	hidd_enable=no
 	pand_enable=no
@@ -208,10 +179,10 @@
 	pcmcia_enable=no
 	hid2hci_enable=no
 	dfutool_enable=no
-	manpages_enable=yes
 	udevrules_enable=yes
 	configfiles_enable=yes
 	telephony_driver=dummy
+	maemo6_enable=no
 
 	AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization], [disable code optimization]), [
 		optimization_enable=${enableval}
@@ -245,6 +216,10 @@
 		service_enable=${enableval}
 	])
 
+	AC_ARG_ENABLE(pnat, AC_HELP_STRING([--enable-pnat], [enable pnat plugin]), [
+		pnat_enable=${enableval}
+	])
+
 	AC_ARG_ENABLE(gstreamer, AC_HELP_STRING([--enable-gstreamer], [enable GStreamer support]), [
 		gstreamer_enable=${enableval}
 	])
@@ -257,8 +232,8 @@
 		usb_enable=${enableval}
 	])
 
-	AC_ARG_ENABLE(netlink, AC_HELP_STRING([--enable-netlink], [enable NETLINK support]), [
-		netlink_enable=${enableval}
+	AC_ARG_ENABLE(tracer, AC_HELP_STRING([--enable-tracer], [install Tracing daemon]), [
+		tracer_enable=${enableval}
 	])
 
 	AC_ARG_ENABLE(tools, AC_HELP_STRING([--enable-tools], [install Bluetooth utilities]), [
@@ -301,10 +276,6 @@
 		test_enable=${enableval}
 	])
 
-	AC_ARG_ENABLE(manpages, AC_HELP_STRING([--enable-manpages], [install Bluetooth manual pages]), [
-		manpages_enable=${enableval}
-	])
-
 	AC_ARG_ENABLE(udevrules, AC_HELP_STRING([--enable-udevrules], [install Bluetooth udev rules]), [
 		udevrules_enable=${enableval}
 	])
@@ -323,6 +294,10 @@
 
 	AC_SUBST([TELEPHONY_DRIVER], [telephony-${telephony_driver}.c])
 
+	AC_ARG_ENABLE(maemo6, AC_HELP_STRING([--enable-maemo6], [compile with maemo6 plugin]), [
+		maemo6_enable=${enableval}
+	])
+
 	if (test "${fortify_enable}" = "yes"); then
 		CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2"
 	fi
@@ -344,19 +319,10 @@
 		AC_DEFINE(HAVE_LIBUSB, 1, [Define to 1 if you have USB library.])
 	fi
 
-	AC_SUBST([BLUEZ_CFLAGS], ['-I$(top_builddir)/include'])
-	AC_SUBST([BLUEZ_LIBS], ['$(top_builddir)/lib/libbluetooth.la'])
-
-	AC_SUBST([GDBUS_CFLAGS], ['-I$(top_srcdir)/gdbus'])
-	AC_SUBST([GDBUS_LIBS], ['$(top_builddir)/gdbus/libgdbus.la'])
-
-	AC_SUBST([SBC_CFLAGS], ['-I$(top_srcdir)/sbc'])
-	AC_SUBST([SBC_LIBS], ['$(top_builddir)/sbc/libsbc.la'])
-
 	AM_CONDITIONAL(SNDFILE, test "${sndfile_enable}" = "yes" && test "${sndfile_found}" = "yes")
-	AM_CONDITIONAL(NETLINK, test "${netlink_enable}" = "yes" && test "${netlink_found}" = "yes")
 	AM_CONDITIONAL(USB, test "${usb_enable}" = "yes" && test "${usb_found}" = "yes")
-	AM_CONDITIONAL(SBC, test "${alsa_enable}" = "yes" || test "${gstreamer_enable}" = "yes")
+	AM_CONDITIONAL(SBC, test "${alsa_enable}" = "yes" || test "${gstreamer_enable}" = "yes" ||
+									test "${test_enable}" = "yes")
 	AM_CONDITIONAL(ALSA, test "${alsa_enable}" = "yes" && test "${alsa_found}" = "yes")
 	AM_CONDITIONAL(GSTREAMER, test "${gstreamer_enable}" = "yes" && test "${gstreamer_found}" = "yes")
 	AM_CONDITIONAL(AUDIOPLUGIN, test "${audio_enable}" = "yes")
@@ -364,6 +330,9 @@
 	AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes")
 	AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes")
 	AM_CONDITIONAL(SERVICEPLUGIN, test "${service_enable}" = "yes")
+	AM_CONDITIONAL(ECHOPLUGIN, test "no" = "yes")
+	AM_CONDITIONAL(PNATPLUGIN, test "${pnat_enable}" = "yes")
+	AM_CONDITIONAL(TRACER, test "${tracer_enable}" = "yes")
 	AM_CONDITIONAL(HIDD, test "${hidd_enable}" = "yes")
 	AM_CONDITIONAL(PAND, test "${pand_enable}" = "yes")
 	AM_CONDITIONAL(DUND, test "${dund_enable}" = "yes")
@@ -374,7 +343,7 @@
 	AM_CONDITIONAL(PCMCIA, test "${pcmcia_enable}" = "yes")
 	AM_CONDITIONAL(HID2HCI, test "${hid2hci_enable}" = "yes" && test "${usb_found}" = "yes")
 	AM_CONDITIONAL(DFUTOOL, test "${dfutool_enable}" = "yes" && test "${usb_found}" = "yes")
-	AM_CONDITIONAL(MANPAGES, test "${manpages_enable}" = "yes")
 	AM_CONDITIONAL(UDEVRULES, test "${udevrules_enable}" = "yes")
 	AM_CONDITIONAL(CONFIGFILES, test "${configfiles_enable}" = "yes")
+	AM_CONDITIONAL(MAEMO6PLUGIN, test "${maemo6_enable}" = "yes")
 ])
diff --git a/audio/Android.mk b/audio/Android.mk
index cc93441..483db12 100755
--- a/audio/Android.mk
+++ b/audio/Android.mk
@@ -21,15 +21,14 @@
 	unix.c
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\" \
+	-DVERSION=\"4.69\" \
 	-DSTORAGEDIR=\"/data/misc/bluetoothd\" \
 	-DCONFIGDIR=\"/etc/bluetooth\" \
 	-DANDROID \
 	-D__S_IFREG=0100000  # missing from bionic stat.h
 
 LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common \
+	$(LOCAL_PATH)/../lib \
 	$(LOCAL_PATH)/../gdbus \
 	$(LOCAL_PATH)/../src \
 	$(call include-path-for, glib) \
diff --git a/audio/Makefile.am b/audio/Makefile.am
deleted file mode 100644
index 52ad212..0000000
--- a/audio/Makefile.am
+++ /dev/null
@@ -1,87 +0,0 @@
-
-BUILT_SOURCES = telephony.c
-
-if AUDIOPLUGIN
-plugindir = $(libdir)/bluetooth/plugins
-
-plugin_LTLIBRARIES = audio.la
-
-audio_la_SOURCES = main.c \
-	ipc.h ipc.c unix.h unix.c manager.h manager.c telephony.h \
-	device.h device.c headset.h headset.c gateway.h gateway.c \
-	avdtp.h avdtp.c a2dp.h a2dp.c sink.h sink.c source.h source.c \
-	control.h control.c
-
-nodist_audio_la_SOURCES = $(BUILT_SOURCES)
-
-audio_la_LDFLAGS = -module -avoid-version -no-undefined
-
-LDADD = $(top_builddir)/common/libhelper.a \
-		@GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
-
-if ALSA
-alsadir = $(libdir)/alsa-lib
-
-alsa_LTLIBRARIES = libasound_module_pcm_bluetooth.la libasound_module_ctl_bluetooth.la
-
-libasound_module_pcm_bluetooth_la_SOURCES = pcm_bluetooth.c rtp.h ipc.h ipc.c
-libasound_module_pcm_bluetooth_la_LDFLAGS = -module -avoid-version #-export-symbols-regex [_]*snd_pcm_.*
-libasound_module_pcm_bluetooth_la_LIBADD = @SBC_LIBS@ @BLUEZ_LIBS@ @ALSA_LIBS@
-libasound_module_pcm_bluetooth_la_CFLAGS = @ALSA_CFLAGS@ @BLUEZ_CFLAGS@ @SBC_CFLAGS@
-
-libasound_module_ctl_bluetooth_la_SOURCES = ctl_bluetooth.c rtp.h ipc.h ipc.c
-libasound_module_ctl_bluetooth_la_LDFLAGS = -module -avoid-version #-export-symbols-regex [_]*snd_ctl_.*
-libasound_module_ctl_bluetooth_la_LIBADD = @BLUEZ_LIBS@ @ALSA_LIBS@
-libasound_module_ctl_bluetooth_la_CFLAGS = @ALSA_CFLAGS@ @BLUEZ_CFLAGS@
-
-if CONFIGFILES
-alsaconfdir = $(sysconfdir)/alsa
-
-alsaconf_DATA = bluetooth.conf
-endif
-endif
-
-if GSTREAMER
-gstreamerdir = $(libdir)/gstreamer-0.10
-
-gstreamer_LTLIBRARIES = libgstbluetooth.la
-
-libgstbluetooth_la_SOURCES = gstbluetooth.c \
-				gstsbcenc.h gstsbcenc.c \
-				gstsbcdec.h gstsbcdec.c \
-				gstsbcparse.h gstsbcparse.c \
-				gstavdtpsink.h gstavdtpsink.c \
-				gsta2dpsink.h gsta2dpsink.c \
-				gstsbcutil.h gstsbcutil.c \
-				gstrtpsbcpay.h gstrtpsbcpay.c \
-				rtp.h ipc.h ipc.c
-libgstbluetooth_la_LDFLAGS = -module -avoid-version
-libgstbluetooth_la_LIBADD = @SBC_LIBS@ @BLUEZ_LIBS@ @GSTREAMER_LIBS@ \
-						-lgstaudio-0.10 -lgstrtp-0.10
-libgstbluetooth_la_CFLAGS = -fvisibility=hidden -fno-strict-aliasing \
-			 @GSTREAMER_CFLAGS@ @BLUEZ_CFLAGS@ @SBC_CFLAGS@
-endif
-endif
-
-noinst_LTLIBRARIES = libipc.la
-
-libipc_la_SOURCES = ipc.h ipc.c
-
-noinst_PROGRAMS = ipctest
-
-ipctest_LDADD= libipc.la @SBC_LIBS@ @GLIB_LIBS@
-
-AM_CFLAGS = -fvisibility=hidden @SBC_CFLAGS@ \
-		@BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
-
-CLEANFILES = $(BUILT_SOURCES)
-
-INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/src
-
-EXTRA_DIST = audio.conf telephony-dummy.c telephony-maemo.c telephony-ofono.c \
-		bluetooth.conf
-
-MAINTAINERCLEANFILES = Makefile.in
-
-telephony.c: @TELEPHONY_DRIVER@
-	@if [ ! -e $@ ] ; then $(LN_S) $< $@ ; fi
diff --git a/audio/a2dp.c b/audio/a2dp.c
index 45be5d4..7b39c3d 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -36,12 +36,13 @@
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
-#include "logging.h"
+#include "log.h"
 #include "device.h"
 #include "manager.h"
 #include "avdtp.h"
 #include "sink.h"
 #include "source.h"
+#include "unix.h"
 #include "a2dp.h"
 #include "sdpd.h"
 
@@ -65,6 +66,7 @@
 	struct avdtp *session;
 	struct avdtp_stream *stream;
 	guint suspend_timer;
+	gboolean delay_reporting;
 	gboolean locked;
 	gboolean suspending;
 	gboolean starting;
@@ -86,7 +88,6 @@
 	struct avdtp_error *err;
 	GSList *client_caps;
 	gboolean reconfigure;
-	gboolean canceled;
 	gboolean start;
 	GSList *cb;
 	int ref;
@@ -100,6 +101,7 @@
 	GSList *sources;
 	uint32_t source_record_id;
 	uint32_t sink_record_id;
+	uint16_t version;
 };
 
 static GSList *servers = NULL;
@@ -110,14 +112,14 @@
 {
 	setup->ref++;
 
-	debug("setup_ref(%p): ref=%d", setup, setup->ref);
+	DBG("%p: ref=%d", setup, setup->ref);
 
 	return setup;
 }
 
 static void setup_free(struct a2dp_setup *s)
 {
-	debug("setup_free(%p)", s);
+	DBG("%p", s);
 	setups = g_slist_remove(setups, s);
 	if (s->session)
 		avdtp_unref(s->session);
@@ -130,7 +132,7 @@
 {
 	setup->ref--;
 
-	debug("setup_unref(%p): ref=%d", setup, setup->ref);
+	DBG("%p: ref=%d", setup, setup->ref);
 
 	if (setup->ref <= 0)
 		setup_free(setup);
@@ -286,14 +288,11 @@
 {
 	struct a2dp_sep *a2dp_sep = user_data;
 	struct audio_device *dev;
-	struct avdtp_service_capability *cap;
-	struct avdtp_media_codec_capability *codec_cap;
-	struct sbc_codec_cap *sbc_cap;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Set_Configuration_Ind", sep);
+		DBG("Sink %p: Set_Configuration_Ind", sep);
 	else
-		debug("Source %p: Set_Configuration_Ind", sep);
+		DBG("Source %p: Set_Configuration_Ind", sep);
 
 	dev = a2dp_get_dev(session);
 	if (!dev) {
@@ -302,9 +301,19 @@
 		return FALSE;
 	}
 
-	/* Check bipool range */
-	for (codec_cap = NULL; caps; caps = g_slist_next(caps)) {
-		cap = caps->data;
+	/* Check valid settings */
+	for (; caps != NULL; caps = g_slist_next(caps)) {
+		struct avdtp_service_capability *cap = caps->data;
+		struct avdtp_media_codec_capability *codec_cap;
+		struct sbc_codec_cap *sbc_cap;
+
+		if (cap->category == AVDTP_DELAY_REPORTING &&
+					!a2dp_sep->delay_reporting) {
+			*err = AVDTP_UNSUPPORTED_CONFIGURATION;
+			*category = AVDTP_DELAY_REPORTING;
+			return FALSE;
+		}
+
 		if (cap->category != AVDTP_MEDIA_CODEC)
 			continue;
 
@@ -324,8 +333,6 @@
 			*category = AVDTP_MEDIA_CODEC;
 			return FALSE;
 		}
-
-		break;
 	}
 
 	avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep);
@@ -338,16 +345,17 @@
 }
 
 static gboolean sbc_getcap_ind(struct avdtp *session, struct avdtp_local_sep *sep,
-				GSList **caps, uint8_t *err, void *user_data)
+				gboolean get_all, GSList **caps, uint8_t *err,
+				void *user_data)
 {
 	struct a2dp_sep *a2dp_sep = user_data;
 	struct avdtp_service_capability *media_transport, *media_codec;
 	struct sbc_codec_cap sbc_cap;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Get_Capability_Ind", sep);
+		DBG("Sink %p: Get_Capability_Ind", sep);
 	else
-		debug("Source %p: Get_Capability_Ind", sep);
+		DBG("Source %p: Get_Capability_Ind", sep);
 
 	*caps = NULL;
 
@@ -393,6 +401,13 @@
 
 	*caps = g_slist_append(*caps, media_codec);
 
+	if (get_all) {
+		struct avdtp_service_capability *delay_reporting;
+		delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
+								NULL, 0);
+		*caps = g_slist_append(*caps, delay_reporting);
+	}
+
 	return TRUE;
 }
 
@@ -406,9 +421,9 @@
 	struct audio_device *dev;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Set_Configuration_Ind", sep);
+		DBG("Sink %p: Set_Configuration_Ind", sep);
 	else
-		debug("Source %p: Set_Configuration_Ind", sep);
+		DBG("Source %p: Set_Configuration_Ind", sep);
 
 	dev = a2dp_get_dev(session);
 	if (!dev) {
@@ -417,6 +432,17 @@
 		return FALSE;
 	}
 
+	for (; caps != NULL; caps = g_slist_next(caps)) {
+		struct avdtp_service_capability *cap = caps->data;
+
+		if (cap->category == AVDTP_DELAY_REPORTING &&
+					!a2dp_sep->delay_reporting) {
+			*err = AVDTP_UNSUPPORTED_CONFIGURATION;
+			*category = AVDTP_DELAY_REPORTING;
+			return FALSE;
+		}
+	}
+
 	avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep);
 	a2dp_sep->stream = stream;
 
@@ -428,6 +454,7 @@
 
 static gboolean mpeg_getcap_ind(struct avdtp *session,
 				struct avdtp_local_sep *sep,
+				gboolean get_all,
 				GSList **caps, uint8_t *err, void *user_data)
 {
 	struct a2dp_sep *a2dp_sep = user_data;
@@ -435,9 +462,9 @@
 	struct mpeg_codec_cap mpeg_cap;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Get_Capability_Ind", sep);
+		DBG("Sink %p: Get_Capability_Ind", sep);
 	else
-		debug("Source %p: Get_Capability_Ind", sep);
+		DBG("Source %p: Get_Capability_Ind", sep);
 
 	*caps = NULL;
 
@@ -472,6 +499,13 @@
 
 	*caps = g_slist_append(*caps, media_codec);
 
+	if (get_all) {
+		struct avdtp_service_capability *delay_reporting;
+		delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
+								NULL, 0);
+		*caps = g_slist_append(*caps, delay_reporting);
+	}
+
 	return TRUE;
 }
 
@@ -485,9 +519,9 @@
 	int ret;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Set_Configuration_Cfm", sep);
+		DBG("Sink %p: Set_Configuration_Cfm", sep);
 	else
-		debug("Source %p: Set_Configuration_Cfm", sep);
+		DBG("Source %p: Set_Configuration_Cfm", sep);
 
 	setup = find_setup_by_session(session);
 
@@ -527,9 +561,9 @@
 	struct a2dp_sep *a2dp_sep = user_data;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Get_Configuration_Ind", sep);
+		DBG("Sink %p: Get_Configuration_Ind", sep);
 	else
-		debug("Source %p: Get_Configuration_Ind", sep);
+		DBG("Source %p: Get_Configuration_Ind", sep);
 	return TRUE;
 }
 
@@ -540,9 +574,9 @@
 	struct a2dp_sep *a2dp_sep = user_data;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Set_Configuration_Cfm", sep);
+		DBG("Sink %p: Set_Configuration_Cfm", sep);
 	else
-		debug("Source %p: Set_Configuration_Cfm", sep);
+		DBG("Source %p: Set_Configuration_Cfm", sep);
 }
 
 static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep,
@@ -552,9 +586,9 @@
 	struct a2dp_sep *a2dp_sep = user_data;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Open_Ind", sep);
+		DBG("Sink %p: Open_Ind", sep);
 	else
-		debug("Source %p: Open_Ind", sep);
+		DBG("Source %p: Open_Ind", sep);
 	return TRUE;
 }
 
@@ -566,21 +600,14 @@
 	struct a2dp_setup *setup;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Open_Cfm", sep);
+		DBG("Sink %p: Open_Cfm", sep);
 	else
-		debug("Source %p: Open_Cfm", sep);
+		DBG("Source %p: Open_Cfm", sep);
 
 	setup = find_setup_by_session(session);
 	if (!setup)
 		return;
 
-	if (setup->canceled) {
-		if (!err)
-			avdtp_close(session, stream);
-		setup_unref(setup);
-		return;
-	}
-
 	if (setup->reconfigure)
 		setup->reconfigure = FALSE;
 
@@ -613,17 +640,13 @@
 	struct a2dp_setup *setup;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Start_Ind", sep);
+		DBG("Sink %p: Start_Ind", sep);
 	else
-		debug("Source %p: Start_Ind", sep);
+		DBG("Source %p: Start_Ind", sep);
 
 	setup = find_setup_by_session(session);
-	if (setup) {
-		if (setup->canceled)
-			setup_unref(setup);
-		else
-			finalize_resume(setup);
-	}
+	if (setup)
+		finalize_resume(setup);
 
 	if (!a2dp_sep->locked) {
 		a2dp_sep->session = avdtp_ref(session);
@@ -643,21 +666,14 @@
 	struct a2dp_setup *setup;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Start_Cfm", sep);
+		DBG("Sink %p: Start_Cfm", sep);
 	else
-		debug("Source %p: Start_Cfm", sep);
+		DBG("Source %p: Start_Cfm", sep);
 
 	setup = find_setup_by_session(session);
 	if (!setup)
 		return;
 
-	if (setup->canceled) {
-		if (!err)
-			avdtp_close(session, stream);
-		setup_unref(setup);
-		return;
-	}
-
 	if (err) {
 		setup->stream = NULL;
 		setup->err = err;
@@ -673,9 +689,9 @@
 	struct a2dp_sep *a2dp_sep = user_data;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Suspend_Ind", sep);
+		DBG("Sink %p: Suspend_Ind", sep);
 	else
-		debug("Source %p: Suspend_Ind", sep);
+		DBG("Source %p: Suspend_Ind", sep);
 
 	if (a2dp_sep->suspend_timer) {
 		g_source_remove(a2dp_sep->suspend_timer);
@@ -696,9 +712,9 @@
 	gboolean start;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Suspend_Cfm", sep);
+		DBG("Sink %p: Suspend_Cfm", sep);
 	else
-		debug("Source %p: Suspend_Cfm", sep);
+		DBG("Source %p: Suspend_Cfm", sep);
 
 	a2dp_sep->suspending = FALSE;
 
@@ -739,9 +755,9 @@
 	struct a2dp_sep *a2dp_sep = user_data;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Close_Ind", sep);
+		DBG("Sink %p: Close_Ind", sep);
 	else
-		debug("Source %p: Close_Ind", sep);
+		DBG("Source %p: Close_Ind", sep);
 
 	return TRUE;
 }
@@ -804,19 +820,14 @@
 	struct a2dp_setup *setup;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Close_Cfm", sep);
+		DBG("Sink %p: Close_Cfm", sep);
 	else
-		debug("Source %p: Close_Cfm", sep);
+		DBG("Source %p: Close_Cfm", sep);
 
 	setup = find_setup_by_session(session);
 	if (!setup)
 		return;
 
-	if (setup->canceled) {
-		setup_unref(setup);
-		return;
-	}
-
 	if (err) {
 		setup->stream = NULL;
 		setup->err = err;
@@ -835,9 +846,9 @@
 	struct a2dp_sep *a2dp_sep = user_data;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Abort_Ind", sep);
+		DBG("Sink %p: Abort_Ind", sep);
 	else
-		debug("Source %p: Abort_Ind", sep);
+		DBG("Source %p: Abort_Ind", sep);
 
 	a2dp_sep->stream = NULL;
 
@@ -852,9 +863,9 @@
 	struct a2dp_setup *setup;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: Abort_Cfm", sep);
+		DBG("Sink %p: Abort_Cfm", sep);
 	else
-		debug("Source %p: Abort_Cfm", sep);
+		DBG("Source %p: Abort_Cfm", sep);
 
 	setup = find_setup_by_session(session);
 	if (!setup)
@@ -869,9 +880,28 @@
 	struct a2dp_sep *a2dp_sep = user_data;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: ReConfigure_Ind", sep);
+		DBG("Sink %p: ReConfigure_Ind", sep);
 	else
-		debug("Source %p: ReConfigure_Ind", sep);
+		DBG("Source %p: ReConfigure_Ind", sep);
+
+	return TRUE;
+}
+
+static gboolean delayreport_ind(struct avdtp *session,
+				struct avdtp_local_sep *sep,
+				uint8_t rseid, uint16_t delay,
+				uint8_t *err, void *user_data)
+{
+	struct a2dp_sep *a2dp_sep = user_data;
+	struct audio_device *dev = a2dp_get_dev(session);
+
+	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: DelayReport_Ind", sep);
+	else
+		DBG("Source %p: DelayReport_Ind", sep);
+
+	unix_delay_report(dev, rseid, delay);
+
 	return TRUE;
 }
 
@@ -883,21 +913,14 @@
 	struct a2dp_setup *setup;
 
 	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-		debug("Sink %p: ReConfigure_Cfm", sep);
+		DBG("Sink %p: ReConfigure_Cfm", sep);
 	else
-		debug("Source %p: ReConfigure_Cfm", sep);
+		DBG("Source %p: ReConfigure_Cfm", sep);
 
 	setup = find_setup_by_session(session);
 	if (!setup)
 		return;
 
-	if (setup->canceled) {
-		if (!err)
-			avdtp_close(session, stream);
-		setup_unref(setup);
-		return;
-	}
-
 	if (err) {
 		setup->stream = NULL;
 		setup->err = err;
@@ -906,6 +929,18 @@
 	finalize_config(setup);
 }
 
+static void delay_report_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
+				struct avdtp_stream *stream,
+				struct avdtp_error *err, void *user_data)
+{
+	struct a2dp_sep *a2dp_sep = user_data;
+
+	if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
+		DBG("Sink %p: DelayReport_Cfm", sep);
+	else
+		DBG("Source %p: DelayReport_Cfm", sep);
+}
+
 static struct avdtp_sep_cfm cfm = {
 	.set_configuration	= setconf_cfm,
 	.get_configuration	= getconf_cfm,
@@ -914,7 +949,8 @@
 	.suspend		= suspend_cfm,
 	.close			= close_cfm,
 	.abort			= abort_cfm,
-	.reconfigure		= reconf_cfm
+	.reconfigure		= reconf_cfm,
+	.delay_report		= delay_report_cfm,
 };
 
 static struct avdtp_sep_ind sbc_ind = {
@@ -926,7 +962,8 @@
 	.suspend		= suspend_ind,
 	.close			= close_ind,
 	.abort			= abort_ind,
-	.reconfigure		= reconf_ind
+	.reconfigure		= reconf_ind,
+	.delayreport		= delayreport_ind,
 };
 
 static struct avdtp_sep_ind mpeg_ind = {
@@ -938,10 +975,11 @@
 	.suspend		= suspend_ind,
 	.close			= close_ind,
 	.abort			= abort_ind,
-	.reconfigure		= reconf_ind
+	.reconfigure		= reconf_ind,
+	.delayreport		= delayreport_ind,
 };
 
-static sdp_record_t *a2dp_record(uint8_t type)
+static sdp_record_t *a2dp_record(uint8_t type, uint16_t avdtp_ver)
 {
 	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
 	uuid_t root_uuid, l2cap_uuid, avdtp_uuid, a2dp_uuid;
@@ -949,7 +987,8 @@
 	sdp_list_t *aproto, *proto[2];
 	sdp_record_t *record;
 	sdp_data_t *psm, *version, *features;
-	uint16_t lp = AVDTP_UUID, ver = 0x0100, feat = 0x000F;
+	uint16_t lp = AVDTP_UUID;
+	uint16_t a2dp_ver = 0x0102, feat = 0x000f;
 
 	record = sdp_record_alloc();
 	if (!record)
@@ -967,7 +1006,7 @@
 	sdp_set_service_classes(record, svclass_id);
 
 	sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
-	profile[0].version = 0x0100;
+	profile[0].version = a2dp_ver;
 	pfseq = sdp_list_append(0, &profile[0]);
 	sdp_set_profile_descs(record, pfseq);
 
@@ -979,7 +1018,7 @@
 
 	sdp_uuid16_create(&avdtp_uuid, AVDTP_UUID);
 	proto[1] = sdp_list_append(0, &avdtp_uuid);
-	version = sdp_data_alloc(SDP_UINT16, &ver);
+	version = sdp_data_alloc(SDP_UINT16, &avdtp_ver);
 	proto[1] = sdp_list_append(proto[1], version);
 	apseq = sdp_list_append(apseq, proto[1]);
 
@@ -1008,7 +1047,7 @@
 }
 
 static struct a2dp_sep *a2dp_add_sep(struct a2dp_server *server, uint8_t type,
-					uint8_t codec)
+					uint8_t codec, gboolean delay_reporting)
 {
 	struct a2dp_sep *sep;
 	GSList **l;
@@ -1020,8 +1059,8 @@
 
 	ind = (codec == A2DP_CODEC_MPEG12) ? &mpeg_ind : &sbc_ind;
 	sep->sep = avdtp_register_sep(&server->src, type,
-					AVDTP_MEDIA_TYPE_AUDIO, codec, ind,
-					&cfm, sep);
+					AVDTP_MEDIA_TYPE_AUDIO, codec,
+					delay_reporting, ind, &cfm, sep);
 	if (sep->sep == NULL) {
 		g_free(sep);
 		return NULL;
@@ -1029,6 +1068,7 @@
 
 	sep->codec = codec;
 	sep->type = type;
+	sep->delay_reporting = delay_reporting;
 
 	if (type == AVDTP_SEP_TYPE_SOURCE) {
 		l = &server->sources;
@@ -1041,7 +1081,7 @@
 	if (*record_id != 0)
 		goto add;
 
-	record = a2dp_record(type);
+	record = a2dp_record(type, server->version);
 	if (!record) {
 		error("Unable to allocate new service record");
 		avdtp_unregister_sep(sep->sep);
@@ -1082,7 +1122,7 @@
 {
 	int sbc_srcs = 1, sbc_sinks = 1;
 	int mpeg12_srcs = 0, mpeg12_sinks = 0;
-	gboolean source = TRUE, sink = FALSE;
+	gboolean source = TRUE, sink = FALSE, delay_reporting;
 	char *str;
 	GError *err = NULL;
 	int i;
@@ -1094,7 +1134,7 @@
 	str = g_key_file_get_string(config, "General", "Enable", &err);
 
 	if (err) {
-		debug("audio.conf: %s", err->message);
+		DBG("audio.conf: %s", err->message);
 		g_clear_error(&err);
 	} else {
 		if (strstr(str, "Sink"))
@@ -1107,7 +1147,7 @@
 	str = g_key_file_get_string(config, "General", "Disable", &err);
 
 	if (err) {
-		debug("audio.conf: %s", err->message);
+		DBG("audio.conf: %s", err->message);
 		g_clear_error(&err);
 	} else {
 		if (strstr(str, "Sink"))
@@ -1119,7 +1159,7 @@
 
 	str = g_key_file_get_string(config, "A2DP", "SBCSources", &err);
 	if (err) {
-		debug("audio.conf: %s", err->message);
+		DBG("audio.conf: %s", err->message);
 		g_clear_error(&err);
 	} else {
 		sbc_srcs = atoi(str);
@@ -1128,7 +1168,7 @@
 
 	str = g_key_file_get_string(config, "A2DP", "MPEG12Sources", &err);
 	if (err) {
-		debug("audio.conf: %s", err->message);
+		DBG("audio.conf: %s", err->message);
 		g_clear_error(&err);
 	} else {
 		mpeg12_srcs = atoi(str);
@@ -1137,7 +1177,7 @@
 
 	str = g_key_file_get_string(config, "A2DP", "SBCSinks", &err);
 	if (err) {
-		debug("audio.conf: %s", err->message);
+		DBG("audio.conf: %s", err->message);
 		g_clear_error(&err);
 	} else {
 		sbc_sinks = atoi(str);
@@ -1146,7 +1186,7 @@
 
 	str = g_key_file_get_string(config, "A2DP", "MPEG12Sinks", &err);
 	if (err) {
-		debug("audio.conf: %s", err->message);
+		DBG("audio.conf: %s", err->message);
 		g_clear_error(&err);
 	} else {
 		mpeg12_sinks = atoi(str);
@@ -1165,32 +1205,41 @@
 		if (!server)
 			return -ENOMEM;
 
-		av_err = avdtp_init(src, config);
-		if (av_err < 0)
+		av_err = avdtp_init(src, config, &server->version);
+		if (av_err < 0) {
+			g_free(server);
 			return av_err;
+		}
 
 		bacpy(&server->src, src);
 		servers = g_slist_append(servers, server);
 	}
 
+	delay_reporting = g_key_file_get_boolean(config, "A2DP",
+						"DelayReporting", NULL);
+	if (delay_reporting)
+		server->version = 0x0103;
+	else
+		server->version = 0x0102;
+
 	if (source) {
 		for (i = 0; i < sbc_srcs; i++)
 			a2dp_add_sep(server, AVDTP_SEP_TYPE_SOURCE,
-					A2DP_CODEC_SBC);
+					A2DP_CODEC_SBC, delay_reporting);
 
 		for (i = 0; i < mpeg12_srcs; i++)
 			a2dp_add_sep(server, AVDTP_SEP_TYPE_SOURCE,
-					A2DP_CODEC_MPEG12);
+					A2DP_CODEC_MPEG12, delay_reporting);
 	}
 
 	if (sink) {
 		for (i = 0; i < sbc_sinks; i++)
 			a2dp_add_sep(server, AVDTP_SEP_TYPE_SINK,
-					A2DP_CODEC_SBC);
+					A2DP_CODEC_SBC, delay_reporting);
 
 		for (i = 0; i < mpeg12_sinks; i++)
 			a2dp_add_sep(server, AVDTP_SEP_TYPE_SINK,
-					A2DP_CODEC_MPEG12);
+					A2DP_CODEC_MPEG12, delay_reporting);
 	}
 
 	return 0;
@@ -1310,7 +1359,7 @@
 	if (sep->codec != codec_cap->media_codec_type)
 		return 0;
 
-	debug("a2dp_config: selected SEP %p", sep->sep);
+	DBG("a2dp_config: selected SEP %p", sep->sep);
 
 	cb_data = g_new0(struct a2dp_setup_cb, 1);
 	cb_data->config_cb = cb;
@@ -1349,7 +1398,7 @@
 
 		if (l != NULL) {
 			setup->reconfigure = TRUE;
-			if (avdtp_close(session, tmp->stream) < 0) {
+			if (avdtp_close(session, tmp->stream, FALSE) < 0) {
 				error("avdtp_close failed");
 				goto failed;
 			}
@@ -1375,11 +1424,11 @@
 	case AVDTP_STATE_OPEN:
 	case AVDTP_STATE_STREAMING:
 		if (avdtp_stream_has_capabilities(setup->stream, caps)) {
-			debug("Configuration match: resuming");
+			DBG("Configuration match: resuming");
 			g_idle_add((GSourceFunc) finalize_config, setup);
 		} else if (!setup->reconfigure) {
 			setup->reconfigure = TRUE;
-			if (avdtp_close(session, sep->stream) < 0) {
+			if (avdtp_close(session, sep->stream, FALSE) < 0) {
 				error("avdtp_close failed");
 				goto failed;
 			}
@@ -1514,7 +1563,7 @@
 	struct a2dp_setup *setup;
 	GSList *l;
 
-	debug("a2dp_cancel()");
+	DBG("a2dp_cancel()");
 
 	setup = find_setup_by_dev(dev);
 	if (!setup)
@@ -1535,10 +1584,10 @@
 	setup->cb = g_slist_remove(setup->cb, cb_data);
 	g_free(cb_data);
 
-	if (!setup->cb) {
-		setup->canceled = TRUE;
-		setup->sep = NULL;
-	}
+	if (setup->cb)
+		return TRUE;
+
+	avdtp_abort(setup->session, setup->stream);
 
 	return TRUE;
 }
@@ -1548,7 +1597,7 @@
 	if (sep->locked)
 		return FALSE;
 
-	debug("SEP %p locked", sep->sep);
+	DBG("SEP %p locked", sep->sep);
 	sep->locked = TRUE;
 
 	return TRUE;
@@ -1562,7 +1611,7 @@
 
 	sep->locked = FALSE;
 
-	debug("SEP %p unlocked", sep->sep);
+	DBG("SEP %p unlocked", sep->sep);
 
 	if (!sep->stream || state == AVDTP_STATE_IDLE)
 		return TRUE;
diff --git a/audio/a2dp.h b/audio/a2dp.h
index f08c643..fa81776 100644
--- a/audio/a2dp.h
+++ b/audio/a2dp.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/audio/avdtp.c b/audio/avdtp.c
index 939db10..cf07f6c 100644
--- a/audio/avdtp.c
+++ b/audio/avdtp.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,7 @@
 #include <config.h>
 #endif
 
+#include <stdlib.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <errno.h>
@@ -36,12 +37,14 @@
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
 
-#include "logging.h"
+#include "log.h"
 
+#include "../src/manager.h"
 #include "../src/adapter.h"
 #include "../src/device.h"
 
@@ -71,6 +74,8 @@
 #define AVDTP_SUSPEND				0x09
 #define AVDTP_ABORT				0x0A
 #define AVDTP_SECURITY_CONTROL			0x0B
+#define AVDTP_GET_ALL_CAPABILITIES		0x0C
+#define AVDTP_DELAY_REPORT			0x0D
 
 #define AVDTP_PKT_TYPE_SINGLE			0x00
 #define AVDTP_PKT_TYPE_START			0x01
@@ -78,10 +83,12 @@
 #define AVDTP_PKT_TYPE_END			0x03
 
 #define AVDTP_MSG_TYPE_COMMAND			0x00
+#define AVDTP_MSG_TYPE_GEN_REJECT		0x01
 #define AVDTP_MSG_TYPE_ACCEPT			0x02
 #define AVDTP_MSG_TYPE_REJECT			0x03
 
 #define REQ_TIMEOUT 4
+#define ABORT_TIMEOUT 2
 #define DISCONNECT_TIMEOUT 1
 #define STREAM_TIMEOUT 20
 
@@ -240,6 +247,12 @@
 	uint8_t caps[0];
 } __attribute__ ((packed));
 
+struct delay_req {
+	uint8_t rfa0:2;
+	uint8_t acp_seid:6;
+	uint16_t delay;
+} __attribute__ ((packed));
+
 #elif __BYTE_ORDER == __BIG_ENDIAN
 
 struct seid_req {
@@ -272,6 +285,12 @@
 	uint8_t caps[0];
 } __attribute__ ((packed));
 
+struct delay_req {
+	uint8_t acp_seid:6;
+	uint8_t rfa0:2;
+	uint16_t delay;
+} __attribute__ ((packed));
+
 #else
 #error "Unknown byte order"
 #endif
@@ -300,12 +319,14 @@
 	uint8_t type;
 	uint8_t media_type;
 	struct avdtp_service_capability *codec;
+	gboolean delay_reporting;
 	GSList *caps; /* of type struct avdtp_service_capability */
 	struct avdtp_stream *stream;
 };
 
 struct avdtp_server {
 	bdaddr_t src;
+	uint16_t version;
 	GIOChannel *io;
 	GSList *seps;
 	GSList *sessions;
@@ -316,6 +337,7 @@
 	struct avdtp_stream *stream;
 	struct seid_info info;
 	uint8_t codec;
+	gboolean delay_reporting;
 	GSList *caps;
 	struct avdtp_sep_ind *ind;
 	struct avdtp_sep_cfm *cfm;
@@ -352,6 +374,8 @@
 	gboolean close_int;	/* If we are in INT role for Close */
 	gboolean abort_int;	/* If we are in INT role for Abort */
 	guint idle_timer;
+	gboolean delay_reporting;
+	uint16_t delay;		/* AVDTP 1.3 Delay Reporting feature */
 };
 
 /* Structure describing an AVDTP connection between two devices */
@@ -360,6 +384,8 @@
 	int ref;
 	int free_lock;
 
+	uint16_t version;
+
 	struct avdtp_server *server;
 	bdaddr_t dst;
 
@@ -422,6 +448,7 @@
 static void avdtp_sep_set_state(struct avdtp *session,
 				struct avdtp_local_sep *sep,
 				avdtp_state_t state);
+static void auth_cb(DBusError *derr, void *user_data);
 
 static struct avdtp_server *find_server(GSList *list, const bdaddr_t *src)
 {
@@ -514,8 +541,7 @@
 	cont_fragments = (len - (session->omtu - sizeof(start))) /
 					(session->omtu - sizeof(cont)) + 1;
 
-	debug("avdtp_send: %zu bytes split into %d fragments", len,
-							cont_fragments + 1);
+	DBG("%zu bytes split into %d fragments", len, cont_fragments + 1);
 
 	/* Send the start packet */
 	memset(&start, 0, sizeof(start));
@@ -532,8 +558,7 @@
 	if (!try_send(sock, session->buf, session->omtu))
 		return FALSE;
 
-	debug("avdtp_send: first packet with %zu bytes sent",
-						session->omtu - sizeof(start));
+	DBG("first packet with %zu bytes sent", session->omtu - sizeof(start));
 
 	sent = session->omtu - sizeof(start);
 
@@ -545,13 +570,11 @@
 		if (left + sizeof(cont) > session->omtu) {
 			cont.packet_type = AVDTP_PKT_TYPE_CONTINUE;
 			to_copy = session->omtu - sizeof(cont);
-			debug("avdtp_send: sending continue with %d bytes",
-								to_copy);
+			DBG("sending continue with %d bytes", to_copy);
 		} else {
 			cont.packet_type = AVDTP_PKT_TYPE_END;
 			to_copy = left;
-			debug("avdtp_send: sending end with %d bytes",
-								to_copy);
+			DBG("sending end with %d bytes", to_copy);
 		}
 
 		cont.transaction = transaction;
@@ -598,7 +621,7 @@
 {
 	struct avdtp_stream *stream = user_data;
 
-	debug("Timed out waiting for peer to close the transport channel");
+	DBG("Timed out waiting for peer to close the transport channel");
 
 	stream->timer = 0;
 
@@ -611,7 +634,7 @@
 {
 	struct avdtp_stream *stream = user_data;
 
-	debug("Timed out waiting for peer to open the transport channel");
+	DBG("Timed out waiting for peer to open the transport channel");
 
 	stream->timer = 0;
 
@@ -777,7 +800,8 @@
 	struct avdtp_stream *stream = user_data;
 	struct avdtp *session = stream->session;
 
-	avdtp_close(session, stream);
+	if (avdtp_close(session, stream, FALSE) < 0)
+		error("stream_timeout: closing AVDTP stream failed");
 
 	stream->idle_timer = 0;
 
@@ -872,6 +896,68 @@
 	}
 }
 
+static void handle_unanswered_req(struct avdtp *session,
+						struct avdtp_stream *stream)
+{
+	struct pending_req *req;
+	struct avdtp_local_sep *lsep;
+	struct avdtp_error err;
+
+	if (session->req->signal_id == AVDTP_ABORT) {
+		/* Avoid freeing the Abort request here */
+		DBG("handle_unanswered_req: Abort req, returning");
+		session->req->stream = NULL;
+		return;
+	}
+
+	req = session->req;
+	session->req = NULL;
+
+	avdtp_error_init(&err, AVDTP_ERROR_ERRNO, EIO);
+
+	lsep = stream->lsep;
+
+	switch (req->signal_id) {
+	case AVDTP_RECONFIGURE:
+		error("No reply to Reconfigure request");
+		if (lsep && lsep->cfm && lsep->cfm->reconfigure)
+			lsep->cfm->reconfigure(session, lsep, stream, &err,
+						lsep->user_data);
+		break;
+	case AVDTP_OPEN:
+		error("No reply to Open request");
+		if (lsep && lsep->cfm && lsep->cfm->open)
+			lsep->cfm->open(session, lsep, stream, &err,
+					lsep->user_data);
+		break;
+	case AVDTP_START:
+		error("No reply to Start request");
+		if (lsep && lsep->cfm && lsep->cfm->start)
+			lsep->cfm->start(session, lsep, stream, &err,
+						lsep->user_data);
+		break;
+	case AVDTP_SUSPEND:
+		error("No reply to Suspend request");
+		if (lsep && lsep->cfm && lsep->cfm->suspend)
+			lsep->cfm->suspend(session, lsep, stream, &err,
+						lsep->user_data);
+		break;
+	case AVDTP_CLOSE:
+		error("No reply to Close request");
+		if (lsep && lsep->cfm && lsep->cfm->close)
+			lsep->cfm->close(session, lsep, stream, &err,
+						lsep->user_data);
+		break;
+	case AVDTP_SET_CONFIGURATION:
+		error("No reply to SetConfiguration request");
+		if (lsep && lsep->cfm && lsep->cfm->set_configuration)
+			lsep->cfm->set_configuration(session, lsep, stream,
+							&err, lsep->user_data);
+	}
+
+	pending_req_free(req);
+}
+
 static void avdtp_sep_set_state(struct avdtp *session,
 				struct avdtp_local_sep *sep,
 				avdtp_state_t state)
@@ -888,11 +974,11 @@
 
 	if (sep->state == state) {
 		avdtp_error_init(&err, AVDTP_ERROR_ERRNO, EIO);
-		debug("stream state change failed: %s", avdtp_strerror(&err));
+		DBG("stream state change failed: %s", avdtp_strerror(&err));
 		err_ptr = &err;
 	} else {
 		err_ptr = NULL;
-		debug("stream state changed: %s -> %s",
+		DBG("stream state changed: %s -> %s",
 				avdtp_statestr(sep->state),
 				avdtp_statestr(state));
 	}
@@ -906,6 +992,10 @@
 	}
 
 	switch (state) {
+	case AVDTP_STATE_CONFIGURED:
+		if (sep->info.type == AVDTP_SEP_TYPE_SINK)
+			avdtp_delay_report(session, stream, stream->delay);
+		break;
 	case AVDTP_STATE_OPEN:
 		if (old_state > AVDTP_STATE_OPEN && session->auto_dc)
 			stream->idle_timer = g_timeout_add_seconds(STREAM_TIMEOUT,
@@ -929,7 +1019,7 @@
 		if (session->pending_open == stream)
 			handle_transport_connect(session, NULL, 0, 0);
 		if (session->req && session->req->stream == stream)
-			session->req->stream = NULL;
+			handle_unanswered_req(session, stream);
 		/* Remove pending commands for this stream from the queue */
 		cleanup_queue(session, stream);
 		stream_free(stream);
@@ -973,12 +1063,16 @@
 static void connection_lost(struct avdtp *session, int err)
 {
 	char address[18];
+	struct audio_device *dev;
 
 	ba2str(&session->dst, address);
-	debug("Disconnected from %s", address);
+	DBG("Disconnected from %s", address);
 
-	if (session->state == AVDTP_SESSION_STATE_CONNECTING && err != EACCES)
-		btd_cancel_authorization(&session->server->src, &session->dst);
+	dev = manager_get_device(&session->server->src, &session->dst, FALSE);
+
+	if (dev != NULL && session->state == AVDTP_SESSION_STATE_CONNECTING &&
+								err != EACCES)
+		audio_device_cancel_authorization(dev, auth_cb, session);
 
 	session->free_lock = 1;
 
@@ -1022,13 +1116,16 @@
 
 	session->ref--;
 
-	debug("avdtp_unref(%p): ref=%d", session, session->ref);
+	DBG("%p: ref=%d", session, session->ref);
 
 	if (session->ref == 1) {
 		if (session->state == AVDTP_SESSION_STATE_CONNECTING &&
 								session->io) {
-			btd_cancel_authorization(&session->server->src,
-							&session->dst);
+			struct audio_device *dev;
+			dev = manager_get_device(&session->server->src,
+							&session->dst, FALSE);
+			audio_device_cancel_authorization(dev, auth_cb,
+								session);
 			g_io_channel_shutdown(session->io, TRUE, NULL);
 			g_io_channel_unref(session->io);
 			session->io = NULL;
@@ -1046,8 +1143,7 @@
 
 	server = session->server;
 
-	debug("avdtp_unref(%p): freeing session and removing from list",
-			session);
+	DBG("%p: freeing session and removing from list", session);
 
 	if (session->dc_timer)
 		remove_disconnect_timer(session);
@@ -1068,7 +1164,7 @@
 struct avdtp *avdtp_ref(struct avdtp *session)
 {
 	session->ref++;
-	debug("avdtp_ref(%p): ref=%d", session, session->ref);
+	DBG("%p: ref=%d", session, session->ref);
 	if (session->dc_timer)
 		remove_disconnect_timer(session);
 	return session;
@@ -1112,12 +1208,16 @@
 }
 
 static GSList *caps_to_list(uint8_t *data, int size,
-				struct avdtp_service_capability **codec)
+				struct avdtp_service_capability **codec,
+				gboolean *delay_reporting)
 {
 	GSList *caps;
 	int processed;
 
-	for (processed = 0, caps = NULL; processed + 2 < size;) {
+	if (delay_reporting)
+		*delay_reporting = FALSE;
+
+	for (processed = 0, caps = NULL; processed + 2 <= size;) {
 		struct avdtp_service_capability *cap;
 		uint8_t length, category;
 
@@ -1142,16 +1242,18 @@
 				length >=
 				sizeof(struct avdtp_media_codec_capability))
 			*codec = cap;
+		else if (category == AVDTP_DELAY_REPORTING && delay_reporting)
+			*delay_reporting = TRUE;
 	}
 
 	return caps;
 }
 
 static gboolean avdtp_unknown_cmd(struct avdtp *session, uint8_t transaction,
-							void *buf, int size)
+							uint8_t signal_id)
 {
-	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
-								0, NULL, 0);
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_GEN_REJECT,
+							signal_id, NULL, 0);
 }
 
 static gboolean avdtp_discover_cmd(struct avdtp *session, uint8_t transaction,
@@ -1188,12 +1290,16 @@
 }
 
 static gboolean avdtp_getcap_cmd(struct avdtp *session, uint8_t transaction,
-					struct seid_req *req, unsigned int size)
+					struct seid_req *req, unsigned int size,
+					gboolean get_all)
 {
 	GSList *l, *caps;
 	struct avdtp_local_sep *sep = NULL;
 	unsigned int rsp_size;
 	uint8_t err, buf[1024], *ptr = buf;
+	uint8_t cmd;
+
+	cmd = get_all ? AVDTP_GET_ALL_CAPABILITIES : AVDTP_GET_CAPABILITIES;
 
 	if (size < sizeof(struct seid_req)) {
 		err = AVDTP_BAD_LENGTH;
@@ -1206,8 +1312,11 @@
 		goto failed;
 	}
 
-	if (!sep->ind->get_capability(session, sep, &caps, &err,
-					sep->user_data))
+	if (get_all && session->server->version < 0x0103)
+		return avdtp_unknown_cmd(session, transaction, cmd);
+
+	if (!sep->ind->get_capability(session, sep, get_all, &caps,
+							&err, sep->user_data))
 		goto failed;
 
 	for (l = caps, rsp_size = 0; l != NULL; l = g_slist_next(l)) {
@@ -1225,12 +1334,12 @@
 
 	g_slist_free(caps);
 
-	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
-				AVDTP_GET_CAPABILITIES, buf, rsp_size);
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT, cmd,
+								buf, rsp_size);
 
 failed:
-	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
-				AVDTP_GET_CAPABILITIES, &err, sizeof(err));
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT, cmd,
+							&err, sizeof(err));
 }
 
 static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction,
@@ -1264,6 +1373,7 @@
 	dev = manager_get_device(&src, &dst, FALSE);
 	if (!dev) {
 		error("Unable to get a audio device object");
+		err = AVDTP_BAD_STATE;
 		goto failed;
 	}
 
@@ -1273,6 +1383,7 @@
 			btd_device_add_uuid(dev->btd_dev, A2DP_SINK_UUID);
 			if (!dev->sink) {
 				error("Unable to get a audio sink object");
+				err = AVDTP_BAD_STATE;
 				goto failed;
 			}
 		}
@@ -1288,7 +1399,8 @@
 	stream->rseid = req->int_seid;
 	stream->caps = caps_to_list(req->caps,
 					size - sizeof(struct setconf_req),
-					&stream->codec);
+					&stream->codec,
+					&stream->delay_reporting);
 
 	/* Verify that the Media Transport capability's length = 0. Reject otherwise */
 	for (l = stream->caps; l != NULL; l = g_slist_next(l)) {
@@ -1300,6 +1412,9 @@
 		}
 	}
 
+	if (stream->delay_reporting && session->version < 0x0103)
+		session->version = 0x0103;
+
 	if (sep->ind && sep->ind->set_configuration) {
 		if (!sep->ind->set_configuration(session, sep, stream,
 							stream->caps, &err,
@@ -1315,6 +1430,7 @@
 	}
 
 	sep->stream = stream;
+	sep->info.inuse = 1;
 	session->streams = g_slist_append(session->streams, stream);
 
 	avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);
@@ -1379,7 +1495,7 @@
 static gboolean avdtp_reconf_cmd(struct avdtp *session, uint8_t transaction,
 					struct seid_req *req, int size)
 {
-	return avdtp_unknown_cmd(session, transaction, (void *) req, size);
+	return avdtp_unknown_cmd(session, transaction, AVDTP_RECONFIGURE);
 }
 
 static gboolean avdtp_open_cmd(struct avdtp *session, uint8_t transaction,
@@ -1630,7 +1746,52 @@
 static gboolean avdtp_secctl_cmd(struct avdtp *session, uint8_t transaction,
 					struct seid_req *req, int size)
 {
-	return avdtp_unknown_cmd(session, transaction, (void *) req, size);
+	return avdtp_unknown_cmd(session, transaction, AVDTP_SECURITY_CONTROL);
+}
+
+static gboolean avdtp_delayreport_cmd(struct avdtp *session,
+					uint8_t transaction,
+					struct delay_req *req,
+					unsigned int size)
+{
+	struct avdtp_local_sep *sep;
+	struct avdtp_stream *stream;
+	uint8_t err;
+
+	if (size < sizeof(struct delay_req)) {
+		error("Too short delay report request");
+		return FALSE;
+	}
+
+	sep = find_local_sep_by_seid(session->server, req->acp_seid);
+	if (!sep || !sep->stream) {
+		err = AVDTP_BAD_ACP_SEID;
+		goto failed;
+	}
+
+	stream = sep->stream;
+
+	if (sep->state != AVDTP_STATE_CONFIGURED &&
+					sep->state != AVDTP_STATE_STREAMING) {
+		err = AVDTP_BAD_STATE;
+		goto failed;
+	}
+
+	stream->delay = ntohs(req->delay);
+
+	if (sep->ind && sep->ind->delayreport) {
+		if (!sep->ind->delayreport(session, sep, stream->rseid,
+						stream->delay, &err,
+						sep->user_data))
+			goto failed;
+	}
+
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
+						AVDTP_DELAY_REPORT, NULL, 0);
+
+failed:
+	return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+					AVDTP_DELAY_REPORT, &err, sizeof(err));
 }
 
 static gboolean avdtp_parse_cmd(struct avdtp *session, uint8_t transaction,
@@ -1638,41 +1799,48 @@
 {
 	switch (signal_id) {
 	case AVDTP_DISCOVER:
-		debug("Received DISCOVER_CMD");
+		DBG("Received DISCOVER_CMD");
 		return avdtp_discover_cmd(session, transaction, buf, size);
 	case AVDTP_GET_CAPABILITIES:
-		debug("Received  GET_CAPABILITIES_CMD");
-		return avdtp_getcap_cmd(session, transaction, buf, size);
+		DBG("Received  GET_CAPABILITIES_CMD");
+		return avdtp_getcap_cmd(session, transaction, buf, size,
+									FALSE);
+	case AVDTP_GET_ALL_CAPABILITIES:
+		DBG("Received  GET_ALL_CAPABILITIES_CMD");
+		return avdtp_getcap_cmd(session, transaction, buf, size, TRUE);
 	case AVDTP_SET_CONFIGURATION:
-		debug("Received SET_CONFIGURATION_CMD");
+		DBG("Received SET_CONFIGURATION_CMD");
 		return avdtp_setconf_cmd(session, transaction, buf, size);
 	case AVDTP_GET_CONFIGURATION:
-		debug("Received GET_CONFIGURATION_CMD");
+		DBG("Received GET_CONFIGURATION_CMD");
 		return avdtp_getconf_cmd(session, transaction, buf, size);
 	case AVDTP_RECONFIGURE:
-		debug("Received RECONFIGURE_CMD");
+		DBG("Received RECONFIGURE_CMD");
 		return avdtp_reconf_cmd(session, transaction, buf, size);
 	case AVDTP_OPEN:
-		debug("Received OPEN_CMD");
+		DBG("Received OPEN_CMD");
 		return avdtp_open_cmd(session, transaction, buf, size);
 	case AVDTP_START:
-		debug("Received START_CMD");
+		DBG("Received START_CMD");
 		return avdtp_start_cmd(session, transaction, buf, size);
 	case AVDTP_CLOSE:
-		debug("Received CLOSE_CMD");
+		DBG("Received CLOSE_CMD");
 		return avdtp_close_cmd(session, transaction, buf, size);
 	case AVDTP_SUSPEND:
-		debug("Received SUSPEND_CMD");
+		DBG("Received SUSPEND_CMD");
 		return avdtp_suspend_cmd(session, transaction, buf, size);
 	case AVDTP_ABORT:
-		debug("Received ABORT_CMD");
+		DBG("Received ABORT_CMD");
 		return avdtp_abort_cmd(session, transaction, buf, size);
 	case AVDTP_SECURITY_CONTROL:
-		debug("Received SECURITY_CONTROL_CMD");
+		DBG("Received SECURITY_CONTROL_CMD");
 		return avdtp_secctl_cmd(session, transaction, buf, size);
+	case AVDTP_DELAY_REPORT:
+		DBG("Received DELAY_REPORT_CMD");
+		return avdtp_delayreport_cmd(session, transaction, buf, size);
 	default:
-		debug("Received unknown request id %u", signal_id);
-		return avdtp_unknown_cmd(session, transaction, buf, size);
+		DBG("Received unknown request id %u", signal_id);
+		return avdtp_unknown_cmd(session, transaction, signal_id);
 	}
 }
 
@@ -1791,7 +1959,7 @@
 
 	if (session->in.no_of_packets > 1) {
 		session->in.no_of_packets--;
-		debug("Received AVDTP fragment. %d to go",
+		DBG("Received AVDTP fragment. %d to go",
 						session->in.no_of_packets);
 		return PARSE_FRAGMENT;
 	}
@@ -1808,7 +1976,7 @@
 	struct avdtp_common_header *header;
 	gsize size;
 
-	debug("session_cb");
+	DBG("");
 
 	if (cond & G_IO_NVAL)
 		return FALSE;
@@ -1895,6 +2063,9 @@
 			goto failed;
 		}
 		break;
+	case AVDTP_MSG_TYPE_GEN_REJECT:
+		error("Received a General Reject message");
+		break;
 	default:
 		error("Unknown message type 0x%02X", header->message_type);
 		break;
@@ -1929,6 +2100,46 @@
 	return NULL;
 }
 
+static uint16_t get_version(struct avdtp *session)
+{
+	struct btd_adapter *adapter;
+	struct btd_device *device;
+	const sdp_record_t *rec;
+	sdp_list_t *protos;
+	sdp_data_t *proto_desc;
+	char addr[18];
+	uint16_t ver = 0x0100;
+
+	adapter = manager_find_adapter(&session->server->src);
+	if (!adapter)
+		goto done;
+
+	ba2str(&session->dst, addr);
+	device = adapter_find_device(adapter, addr);
+	if (!device)
+		goto done;
+
+	rec = btd_device_get_record(device, A2DP_SINK_UUID);
+	if (!rec)
+		rec = btd_device_get_record(device, A2DP_SOURCE_UUID);
+
+	if (!rec)
+		goto done;
+
+	if (sdp_get_access_protos(rec, &protos) < 0)
+		goto done;
+
+	proto_desc = sdp_get_proto_desc(protos, AVDTP_UUID);
+	if (proto_desc && proto_desc->dtd == SDP_UINT16)
+		ver = proto_desc->val.uint16;
+
+	sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+	sdp_list_free(protos, NULL);
+
+done:
+	return ver;
+}
+
 static struct avdtp *avdtp_get_internal(const bdaddr_t *src, const bdaddr_t *dst)
 {
 	struct avdtp_server *server;
@@ -1959,6 +2170,8 @@
 	session->state = AVDTP_SESSION_STATE_DISCONNECTED;
 	session->auto_dc = TRUE;
 
+	session->version = get_version(session);
+
 	server->sessions = g_slist_append(server->sessions, session);
 
 	return session;
@@ -2001,12 +2214,12 @@
 	}
 
 	ba2str(&session->dst, address);
-	debug("AVDTP: connected %s channel to %s",
+	DBG("AVDTP: connected %s channel to %s",
 			session->pending_open ? "transport" : "signaling",
 			address);
 
 	if (session->state == AVDTP_SESSION_STATE_CONNECTING) {
-		debug("AVDTP imtu=%u, omtu=%u", session->imtu, session->omtu);
+		DBG("AVDTP imtu=%u, omtu=%u", session->imtu, session->omtu);
 
 		session->buf = g_malloc0(session->imtu);
 		avdtp_set_state(session, AVDTP_SESSION_STATE_CONNECTED);
@@ -2053,8 +2266,6 @@
 						AVDTP_STATE_IDLE);
 	} else
 		connection_lost(session, EIO);
-
-	return;
 }
 
 static void auth_cb(DBusError *derr, void *user_data)
@@ -2101,7 +2312,7 @@
 		goto drop;
 	}
 
-	debug("AVDTP: incoming connect from %s", address);
+	DBG("AVDTP: incoming connect from %s", address);
 
 	session = avdtp_get_internal(&src, &dst);
 	if (!session)
@@ -2114,8 +2325,7 @@
 	 * Abort the device's channel in favor of our own.
 	 */
 	if (session->state == AVDTP_SESSION_STATE_CONNECTING) {
-		debug("avdtp_confirm_cb: connect already in progress"
-						" (XCASE connect:connect)");
+		DBG("connect already in progress (XCASE connect:connect)");
 		goto drop;
 	}
 
@@ -2201,20 +2411,19 @@
 	return ((struct seid_req *) (req->data))->acp_seid;
 }
 
-static gboolean request_timeout(gpointer user_data)
+static int cancel_request(struct avdtp *session, int err)
 {
-	struct avdtp *session = user_data;
 	struct pending_req *req;
 	struct seid_req sreq;
 	struct avdtp_local_sep *lsep;
 	struct avdtp_stream *stream;
 	uint8_t seid;
-	struct avdtp_error err;
+	struct avdtp_error averr;
 
 	req = session->req;
 	session->req = NULL;
 
-	avdtp_error_init(&err, AVDTP_ERROR_ERRNO, ETIMEDOUT);
+	avdtp_error_init(&averr, AVDTP_ERROR_ERRNO, err);
 
 	seid = req_get_seid(req);
 	if (seid)
@@ -2222,59 +2431,60 @@
 	else
 		stream = NULL;
 
-	if (stream)
+	if (stream) {
+		stream->abort_int = TRUE;
 		lsep = stream->lsep;
-	else
+	} else
 		lsep = NULL;
 
 	switch (req->signal_id) {
 	case AVDTP_RECONFIGURE:
-		error("Reconfigure request timed out");
+		error("Reconfigure: %s (%d)", strerror(err), err);
 		if (lsep && lsep->cfm && lsep->cfm->reconfigure)
-			lsep->cfm->reconfigure(session, lsep, stream, &err,
+			lsep->cfm->reconfigure(session, lsep, stream, &averr,
 						lsep->user_data);
 		break;
 	case AVDTP_OPEN:
-		error("Open request timed out");
+		error("Open: %s (%d)", strerror(err), err);
 		if (lsep && lsep->cfm && lsep->cfm->open)
-			lsep->cfm->open(session, lsep, stream, &err,
+			lsep->cfm->open(session, lsep, stream, &averr,
 					lsep->user_data);
 		break;
 	case AVDTP_START:
-		error("Start request timed out");
+		error("Start: %s (%d)", strerror(err), err);
 		if (lsep && lsep->cfm && lsep->cfm->start)
-			lsep->cfm->start(session, lsep, stream, &err,
+			lsep->cfm->start(session, lsep, stream, &averr,
 						lsep->user_data);
 		break;
 	case AVDTP_SUSPEND:
-		error("Suspend request timed out");
+		error("Suspend: %s (%d)", strerror(err), err);
 		if (lsep && lsep->cfm && lsep->cfm->suspend)
-			lsep->cfm->suspend(session, lsep, stream, &err,
+			lsep->cfm->suspend(session, lsep, stream, &averr,
 						lsep->user_data);
 		break;
 	case AVDTP_CLOSE:
-		error("Close request timed out");
+		error("Close: %s (%d)", strerror(err), err);
 		if (lsep && lsep->cfm && lsep->cfm->close) {
-			lsep->cfm->close(session, lsep, stream, &err,
+			lsep->cfm->close(session, lsep, stream, &averr,
 						lsep->user_data);
 			if (stream)
 				stream->close_int = FALSE;
 		}
 		break;
 	case AVDTP_SET_CONFIGURATION:
-		error("SetConfiguration request timed out");
+		error("SetConfiguration: %s (%d)", strerror(err), err);
 		if (lsep && lsep->cfm && lsep->cfm->set_configuration)
 			lsep->cfm->set_configuration(session, lsep, stream,
-							&err, lsep->user_data);
+							&averr, lsep->user_data);
 		goto failed;
 	case AVDTP_DISCOVER:
-		error("Discover request timed out");
+		error("Discover: %s (%d)", strerror(err), err);
 		goto failed;
 	case AVDTP_GET_CAPABILITIES:
-		error("GetCapabilities request timed out");
+		error("GetCapabilities: %s (%d)", strerror(err), err);
 		goto failed;
 	case AVDTP_ABORT:
-		error("Abort request timed out");
+		error("Abort: %s (%d)", strerror(err), err);
 		goto failed;
 	}
 
@@ -2284,20 +2494,28 @@
 	memset(&sreq, 0, sizeof(sreq));
 	sreq.acp_seid = seid;
 
-	if (send_request(session, TRUE, stream, AVDTP_ABORT,
-						&sreq, sizeof(sreq)) < 0) {
+	err = send_request(session, TRUE, stream, AVDTP_ABORT, &sreq,
+				sizeof(sreq));
+	if (err < 0) {
 		error("Unable to send abort request");
 		goto failed;
 	}
 
-	stream->abort_int = TRUE;
-
 	goto done;
 
 failed:
-	connection_lost(session, ETIMEDOUT);
+	connection_lost(session, err);
 done:
 	pending_req_free(req);
+	return err;
+}
+
+static gboolean request_timeout(gpointer user_data)
+{
+	struct avdtp *session = user_data;
+
+	cancel_request(session, ETIMEDOUT);
+
 	return FALSE;
 }
 
@@ -2334,7 +2552,8 @@
 
 	session->req = req;
 
-	req->timeout = g_timeout_add_seconds(REQ_TIMEOUT,
+	req->timeout = g_timeout_add_seconds(req->signal_id == AVDTP_ABORT ?
+					ABORT_TIMEOUT : REQ_TIMEOUT,
 					request_timeout,
 					session);
 	return 0;
@@ -2351,6 +2570,9 @@
 {
 	struct pending_req *req;
 
+	if (stream && stream->abort_int && signal_id != AVDTP_ABORT)
+		return -EINVAL;
+
 	req = g_new0(struct pending_req, 1);
 	req->signal_id = signal_id;
 	req->data = g_malloc(size);
@@ -2365,6 +2587,12 @@
 					struct discover_resp *resp, int size)
 {
 	int sep_count, i;
+	uint8_t getcap_cmd;
+
+	if (session->version >= 0x0103 && session->server->version >= 0x0103)
+		getcap_cmd = AVDTP_GET_ALL_CAPABILITIES;
+	else
+		getcap_cmd = AVDTP_GET_CAPABILITIES;
 
 	sep_count = size / sizeof(struct seid_info);
 
@@ -2374,7 +2602,7 @@
 		struct seid_req req;
 		int ret;
 
-		debug("seid %d type %d media %d in use %d",
+		DBG("seid %d type %d media %d in use %d",
 				resp->seps[i].seid, resp->seps[i].type,
 				resp->seps[i].media_type, resp->seps[i].inuse);
 
@@ -2396,9 +2624,8 @@
 		memset(&req, 0, sizeof(req));
 		req.acp_seid = sep->seid;
 
-		ret = send_request(session, TRUE, NULL,
-					AVDTP_GET_CAPABILITIES,
-					&req, sizeof(req));
+		ret = send_request(session, TRUE, NULL, getcap_cmd,
+							&req, sizeof(req));
 		if (ret < 0) {
 			finalize_discovery(session, -ret);
 			break;
@@ -2431,7 +2658,7 @@
 
 	sep = find_remote_sep(session->seps, seid);
 
-	debug("seid %d type %d media %d", sep->seid,
+	DBG("seid %d type %d media %d", sep->seid,
 					sep->type, sep->media_type);
 
 	if (sep->caps) {
@@ -2439,10 +2666,11 @@
 		g_slist_free(sep->caps);
 		sep->caps = NULL;
 		sep->codec = NULL;
+		sep->delay_reporting = FALSE;
 	}
 
 	sep->caps = caps_to_list(resp->caps, size - sizeof(struct getcap_resp),
-					&sep->codec);
+					&sep->codec, &sep->delay_reporting);
 
 	return TRUE;
 }
@@ -2545,12 +2773,25 @@
 	return TRUE;
 }
 
+static gboolean avdtp_delay_report_resp(struct avdtp *session,
+					struct avdtp_stream *stream,
+					void *data, int size)
+{
+	struct avdtp_local_sep *sep = stream->lsep;
+
+	if (sep->cfm && sep->cfm->delay_report)
+		sep->cfm->delay_report(session, sep, stream, NULL, sep->user_data);
+
+	return TRUE;
+}
+
 static gboolean avdtp_parse_resp(struct avdtp *session,
 					struct avdtp_stream *stream,
 					uint8_t transaction, uint8_t signal_id,
 					void *buf, int size)
 {
 	struct pending_req *next;
+	const char *get_all = "";
 
 	if (session->prio_queue)
 		next = session->prio_queue->data;
@@ -2561,13 +2802,16 @@
 
 	switch (signal_id) {
 	case AVDTP_DISCOVER:
-		debug("DISCOVER request succeeded");
+		DBG("DISCOVER request succeeded");
 		return avdtp_discover_resp(session, buf, size);
+	case AVDTP_GET_ALL_CAPABILITIES:
+		get_all = "ALL_";
 	case AVDTP_GET_CAPABILITIES:
-		debug("GET_CAPABILITIES request succeeded");
+		DBG("GET_%sCAPABILITIES request succeeded", get_all);
 		if (!avdtp_get_capabilities_resp(session, buf, size))
 			return FALSE;
-		if (!(next && next->signal_id == AVDTP_GET_CAPABILITIES))
+		if (!(next && (next->signal_id == AVDTP_GET_CAPABILITIES ||
+				next->signal_id == AVDTP_GET_ALL_CAPABILITIES)))
 			finalize_discovery(session, 0);
 		return TRUE;
 	}
@@ -2575,33 +2819,36 @@
 	/* The remaining commands require an existing stream so bail out
 	 * here if the stream got unexpectedly disconnected */
 	if (!stream) {
-		debug("AVDTP: stream was closed while waiting for reply");
+		DBG("AVDTP: stream was closed while waiting for reply");
 		return TRUE;
 	}
 
 	switch (signal_id) {
 	case AVDTP_SET_CONFIGURATION:
-		debug("SET_CONFIGURATION request succeeded");
+		DBG("SET_CONFIGURATION request succeeded");
 		return avdtp_set_configuration_resp(session, stream,
 								buf, size);
 	case AVDTP_RECONFIGURE:
-		debug("RECONFIGURE request succeeded");
+		DBG("RECONFIGURE request succeeded");
 		return avdtp_reconfigure_resp(session, stream, buf, size);
 	case AVDTP_OPEN:
-		debug("OPEN request succeeded");
+		DBG("OPEN request succeeded");
 		return avdtp_open_resp(session, stream, buf, size);
 	case AVDTP_SUSPEND:
-		debug("SUSPEND request succeeded");
+		DBG("SUSPEND request succeeded");
 		return avdtp_suspend_resp(session, stream, buf, size);
 	case AVDTP_START:
-		debug("START request succeeded");
+		DBG("START request succeeded");
 		return avdtp_start_resp(session, stream, buf, size);
 	case AVDTP_CLOSE:
-		debug("CLOSE request succeeded");
+		DBG("CLOSE request succeeded");
 		return avdtp_close_resp(session, stream, buf, size);
 	case AVDTP_ABORT:
-		debug("ABORT request succeeded");
+		DBG("ABORT request succeeded");
 		return avdtp_abort_resp(session, stream, buf, size);
+	case AVDTP_DELAY_REPORT:
+		DBG("DELAY_REPORT request succeeded");
+		return avdtp_delay_report_resp(session, stream, buf, size);
 	}
 
 	error("Unknown signal id in accept response: %u", signal_id);
@@ -2671,6 +2918,7 @@
 				avdtp_strerror(&err), err.err.error_code);
 		return TRUE;
 	case AVDTP_GET_CAPABILITIES:
+	case AVDTP_GET_ALL_CAPABILITIES:
 		if (!seid_rej_to_err(buf, size, &err))
 			return FALSE;
 		error("GET_CAPABILITIES request rejected: %s (%d)",
@@ -2740,6 +2988,15 @@
 		if (sep && sep->cfm && sep->cfm->abort)
 			sep->cfm->abort(session, sep, stream, &err,
 					sep->user_data);
+		return FALSE;
+	case AVDTP_DELAY_REPORT:
+		if (!stream_rej_to_err(buf, size, &err, &acp_seid))
+			return FALSE;
+		error("DELAY_REPORT request rejected: %s (%d)",
+				avdtp_strerror(&err), err.err.error_code);
+		if (sep && sep->cfm && sep->cfm->delay_report)
+			sep->cfm->delay_report(session, sep, stream, &err,
+							sep->user_data);
 		return TRUE;
 	default:
 		error("Unknown reject response signal id: %u", signal_id);
@@ -2892,6 +3149,11 @@
 	return sep->codec;
 }
 
+gboolean avdtp_get_delay_reporting(struct avdtp_remote_sep *sep)
+{
+	return sep->delay_reporting;
+}
+
 struct avdtp_stream *avdtp_get_stream(struct avdtp_remote_sep *sep)
 {
 	return sep->stream;
@@ -2902,7 +3164,7 @@
 {
 	struct avdtp_service_capability *cap;
 
-	if (category < AVDTP_MEDIA_TRANSPORT || category > AVDTP_MEDIA_CODEC)
+	if (category < AVDTP_MEDIA_TRANSPORT || category > AVDTP_DELAY_REPORTING)
 		return NULL;
 
 	cap = g_malloc(sizeof(struct avdtp_service_capability) + length);
@@ -2925,7 +3187,7 @@
 int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb,
 			void *user_data)
 {
-	int ret;
+	int err;
 
 	if (session->discov_cb)
 		return -EBUSY;
@@ -2937,13 +3199,13 @@
 		return 0;
 	}
 
-	ret = send_request(session, FALSE, NULL, AVDTP_DISCOVER, NULL, 0);
-	if (ret == 0) {
+	err = send_request(session, FALSE, NULL, AVDTP_DISCOVER, NULL, 0);
+	if (err == 0) {
 		session->discov_cb = cb;
 		session->user_data = user_data;
 	}
 
-	return ret;
+	return err;
 }
 
 int avdtp_get_seps(struct avdtp *session, uint8_t acp_type, uint8_t media_type,
@@ -3068,7 +3330,7 @@
 	struct setconf_req *req;
 	struct avdtp_stream *new_stream;
 	unsigned char *ptr;
-	int ret, caps_len;
+	int err, caps_len;
 	struct avdtp_service_capability *cap;
 	GSList *l;
 
@@ -3078,14 +3340,17 @@
 	if (!(lsep && rsep))
 		return -EINVAL;
 
-	debug("avdtp_set_configuration(%p): int_seid=%u, acp_seid=%u",
-			session, lsep->info.seid, rsep->seid);
+	DBG("%p: int_seid=%u, acp_seid=%u", session,
+			lsep->info.seid, rsep->seid);
 
 	new_stream = g_new0(struct avdtp_stream, 1);
 	new_stream->session = session;
 	new_stream->lsep = lsep;
 	new_stream->rseid = rsep->seid;
 
+	if (rsep->delay_reporting && lsep->delay_reporting)
+		new_stream->delay_reporting = TRUE;
+
 	g_slist_foreach(caps, copy_capabilities, &new_stream->caps);
 
 	/* Calculate total size of request */
@@ -3106,10 +3371,10 @@
 		ptr += cap->length + 2;
 	}
 
-	ret = send_request(session, FALSE, new_stream,
+	err = send_request(session, FALSE, new_stream,
 				AVDTP_SET_CONFIGURATION, req,
 				sizeof(struct setconf_req) + caps_len);
-	if (ret < 0)
+	if (err < 0)
 		stream_free(new_stream);
 	else {
 		lsep->info.inuse = 1;
@@ -3122,7 +3387,7 @@
 
 	g_free(req);
 
-	return ret;
+	return err;
 }
 
 int avdtp_reconfigure(struct avdtp *session, GSList *caps,
@@ -3203,7 +3468,8 @@
 							&req, sizeof(req));
 }
 
-int avdtp_close(struct avdtp *session, struct avdtp_stream *stream)
+int avdtp_close(struct avdtp *session, struct avdtp_stream *stream,
+		gboolean immediate)
 {
 	struct seid_req req;
 	int ret;
@@ -3219,6 +3485,9 @@
 		return -EINVAL;
 	}
 
+	if (immediate && session->req && stream == session->req->stream)
+		return avdtp_abort(session, stream);
+
 	memset(&req, 0, sizeof(req));
 	req.acp_seid = stream->rseid;
 
@@ -3255,9 +3524,13 @@
 	if (!g_slist_find(session->streams, stream))
 		return -EINVAL;
 
-	if (stream->lsep->state <= AVDTP_STATE_OPEN)
+	if (stream->lsep->state == AVDTP_STATE_IDLE ||
+			stream->lsep->state == AVDTP_STATE_ABORTING)
 		return -EINVAL;
 
+	if (session->req && stream == session->req->stream)
+		return cancel_request(session, ECANCELED);
+
 	memset(&req, 0, sizeof(req));
 	req.acp_seid = stream->rseid;
 
@@ -3269,9 +3542,36 @@
 	return ret;
 }
 
+int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
+							uint16_t delay)
+{
+	struct delay_req req;
+
+	if (!g_slist_find(session->streams, stream))
+		return -EINVAL;
+
+	if (stream->lsep->state != AVDTP_STATE_CONFIGURED &&
+				stream->lsep->state != AVDTP_STATE_STREAMING)
+		return -EINVAL;
+
+	if (!stream->delay_reporting || session->version < 0x0103 ||
+					session->server->version < 0x0103)
+		return -EINVAL;
+
+	stream->delay = delay;
+
+	memset(&req, 0, sizeof(req));
+	req.acp_seid = stream->rseid;
+	req.delay = htons(delay);
+
+	return send_request(session, TRUE, stream, AVDTP_DELAY_REPORT,
+							&req, sizeof(req));
+}
+
 struct avdtp_local_sep *avdtp_register_sep(const bdaddr_t *src, uint8_t type,
 						uint8_t media_type,
 						uint8_t codec_type,
+						gboolean delay_reporting,
 						struct avdtp_sep_ind *ind,
 						struct avdtp_sep_cfm *cfm,
 						void *user_data)
@@ -3297,8 +3597,9 @@
 	sep->cfm = cfm;
 	sep->user_data = user_data;
 	sep->server = server;
+	sep->delay_reporting = TRUE;
 
-	debug("SEP %p registered: type:%d codec:%d seid:%d", sep,
+	DBG("SEP %p registered: type:%d codec:%d seid:%d", sep,
 			sep->info.type, sep->codec, sep->info.seid);
 	server->seps = g_slist_append(server->seps, sep);
 
@@ -3401,33 +3702,44 @@
 		bacpy(dst, &session->dst);
 }
 
-int avdtp_init(const bdaddr_t *src, GKeyFile *config)
+int avdtp_init(const bdaddr_t *src, GKeyFile *config, uint16_t *version)
 {
 	GError *err = NULL;
 	gboolean tmp, master = TRUE;
 	struct avdtp_server *server;
+	uint16_t ver = 0x0102;
 
-	if (config) {
-		tmp = g_key_file_get_boolean(config, "General",
-							"Master", &err);
-		if (err) {
-			debug("audio.conf: %s", err->message);
-			g_clear_error(&err);
-		} else
-			master = tmp;
+	if (!config)
+		goto proceed;
 
-		tmp = g_key_file_get_boolean(config, "General", "AutoConnect",
-									&err);
-		if (err)
-			g_clear_error(&err);
-		else
-			auto_connect = tmp;
-	}
+	tmp = g_key_file_get_boolean(config, "General",
+			"Master", &err);
+	if (err) {
+		DBG("audio.conf: %s", err->message);
+		g_clear_error(&err);
+	} else
+		master = tmp;
 
+	tmp = g_key_file_get_boolean(config, "General", "AutoConnect",
+			&err);
+	if (err)
+		g_clear_error(&err);
+	else
+		auto_connect = tmp;
+
+	if (g_key_file_get_boolean(config, "A2DP", "DelayReporting", NULL))
+		ver = 0x0103;
+
+proceed:
 	server = g_new0(struct avdtp_server, 1);
 	if (!server)
 		return -ENOMEM;
 
+	server->version = ver;
+
+	if (version)
+		*version = server->version;
+
 	server->io = avdtp_server_socket(src, master);
 	if (!server->io) {
 		g_free(server);
diff --git a/audio/avdtp.h b/audio/avdtp.h
index 81b8f58..3fe682b 100644
--- a/audio/avdtp.h
+++ b/audio/avdtp.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -53,6 +53,7 @@
 #define AVDTP_HEADER_COMPRESSION		0x05
 #define AVDTP_MULTIPLEXING			0x06
 #define AVDTP_MEDIA_CODEC			0x07
+#define AVDTP_DELAY_REPORTING			0x08
 
 /* AVDTP error definitions */
 #define AVDTP_BAD_HEADER_FORMAT			0x01
@@ -162,6 +163,9 @@
 				struct avdtp_local_sep *lsep,
 				struct avdtp_stream *stream,
 				struct avdtp_error *err, void *user_data);
+	void (*delay_report) (struct avdtp *session, struct avdtp_local_sep *lsep,
+				struct avdtp_stream *stream,
+				struct avdtp_error *err, void *user_data);
 };
 
 /* Callbacks for indicating when we received a new command. The return value
@@ -169,6 +173,7 @@
 struct avdtp_sep_ind {
 	gboolean (*get_capability) (struct avdtp *session,
 					struct avdtp_local_sep *sep,
+					gboolean get_all,
 					GSList **caps, uint8_t *err,
 					void *user_data);
 	gboolean (*set_configuration) (struct avdtp *session,
@@ -198,6 +203,10 @@
 	gboolean (*reconfigure) (struct avdtp *session,
 					struct avdtp_local_sep *lsep,
 					uint8_t *err, void *user_data);
+	gboolean (*delayreport) (struct avdtp *session,
+					struct avdtp_local_sep *lsep,
+					uint8_t rseid, uint16_t delay,
+					uint8_t *err, void *user_data);
 };
 
 typedef void (*avdtp_discover_cb_t) (struct avdtp *session, GSList *seps,
@@ -222,6 +231,8 @@
 
 struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep);
 
+gboolean avdtp_get_delay_reporting(struct avdtp_remote_sep *sep);
+
 struct avdtp_stream *avdtp_get_stream(struct avdtp_remote_sep *sep);
 
 int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb,
@@ -264,12 +275,16 @@
 			struct avdtp_stream *stream);
 int avdtp_start(struct avdtp *session, struct avdtp_stream *stream);
 int avdtp_suspend(struct avdtp *session, struct avdtp_stream *stream);
-int avdtp_close(struct avdtp *session, struct avdtp_stream *stream);
+int avdtp_close(struct avdtp *session, struct avdtp_stream *stream,
+		gboolean immediate);
 int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream);
+int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
+							uint16_t delay);
 
 struct avdtp_local_sep *avdtp_register_sep(const bdaddr_t *src, uint8_t type,
 						uint8_t media_type,
 						uint8_t codec_type,
+						gboolean delay_reporting,
 						struct avdtp_sep_ind *ind,
 						struct avdtp_sep_cfm *cfm,
 						void *user_data);
@@ -294,5 +309,5 @@
 void avdtp_set_auto_disconnect(struct avdtp *session, gboolean auto_dc);
 gboolean avdtp_stream_setup_active(struct avdtp *session);
 
-int avdtp_init(const bdaddr_t *src, GKeyFile *config);
+int avdtp_init(const bdaddr_t *src, GKeyFile *config, uint16_t *version);
 void avdtp_exit(const bdaddr_t *src);
diff --git a/audio/control.c b/audio/control.c
index e55d1f4..f74bb0a 100644
--- a/audio/control.c
+++ b/audio/control.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -46,7 +46,7 @@
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 #include "error.h"
 #include "uinput.h"
 #include "adapter.h"
@@ -102,6 +102,8 @@
 #define FORWARD_OP		0x4b
 #define BACKWARD_OP		0x4c
 
+#define QUIRK_NO_RELEASE	1 << 0
+
 static DBusConnection *connection = NULL;
 static gchar *input_device_name = NULL;
 static GSList *servers = NULL;
@@ -178,6 +180,8 @@
 	uint16_t mtu;
 
 	gboolean target;
+
+	uint8_t key_quirks[256];
 };
 
 static struct {
@@ -197,6 +201,8 @@
 
 static GSList *avctp_callbacks = NULL;
 
+static void auth_cb(DBusError *derr, void *user_data);
+
 static sdp_record_t *avrcp_ct_record()
 {
 	sdp_list_t *svclass_id, *pfseq, *apseq, *root;
@@ -205,7 +211,8 @@
 	sdp_list_t *aproto, *proto[2];
 	sdp_record_t *record;
 	sdp_data_t *psm, *version, *features;
-	uint16_t lp = AVCTP_PSM, ver = 0x0100, feat = 0x000f;
+	uint16_t lp = AVCTP_PSM;
+	uint16_t avrcp_ver = 0x0100, avctp_ver = 0x0103, feat = 0x000f;
 
 	record = sdp_record_alloc();
 	if (!record)
@@ -229,7 +236,7 @@
 
 	sdp_uuid16_create(&avctp, AVCTP_UUID);
 	proto[1] = sdp_list_append(0, &avctp);
-	version = sdp_data_alloc(SDP_UINT16, &ver);
+	version = sdp_data_alloc(SDP_UINT16, &avctp_ver);
 	proto[1] = sdp_list_append(proto[1], version);
 	apseq = sdp_list_append(apseq, proto[1]);
 
@@ -238,7 +245,7 @@
 
 	/* Bluetooth Profile Descriptor List */
 	sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
-	profile[0].version = ver;
+	profile[0].version = avrcp_ver;
 	pfseq = sdp_list_append(0, &profile[0]);
 	sdp_set_profile_descs(record, pfseq);
 
@@ -268,7 +275,8 @@
 	sdp_list_t *aproto, *proto[2];
 	sdp_record_t *record;
 	sdp_data_t *psm, *version, *features;
-	uint16_t lp = AVCTP_PSM, ver = 0x0100, feat = 0x000f;
+	uint16_t lp = AVCTP_PSM;
+	uint16_t avrcp_ver = 0x0100, avctp_ver = 0x0103, feat = 0x000f;
 
 	record = sdp_record_alloc();
 	if (!record)
@@ -292,7 +300,7 @@
 
 	sdp_uuid16_create(&avctp, AVCTP_UUID);
 	proto[1] = sdp_list_append(0, &avctp);
-	version = sdp_data_alloc(SDP_UINT16, &ver);
+	version = sdp_data_alloc(SDP_UINT16, &avctp_ver);
 	proto[1] = sdp_list_append(proto[1], version);
 	apseq = sdp_list_append(apseq, proto[1]);
 
@@ -301,7 +309,7 @@
 
 	/* Bluetooth Profile Descriptor List */
 	sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
-	profile[0].version = ver;
+	profile[0].version = avrcp_ver;
 	pfseq = sdp_list_append(0, &profile[0]);
 	sdp_set_profile_descs(record, pfseq);
 
@@ -363,15 +371,33 @@
 	}
 
 	for (i = 0; key_map[i].name != NULL; i++) {
-		if ((operands[0] & 0x7F) == key_map[i].avrcp) {
-			debug("AVRCP: %s %s", key_map[i].name, status);
-			send_key(control->uinput, key_map[i].uinput, pressed);
+		uint8_t key_quirks;
+
+		if ((operands[0] & 0x7F) != key_map[i].avrcp)
+			continue;
+
+		DBG("AVRCP: %s %s", key_map[i].name, status);
+
+		key_quirks = control->key_quirks[key_map[i].avrcp];
+
+		if (key_quirks & QUIRK_NO_RELEASE) {
+			if (!pressed) {
+				DBG("AVRCP: Ignoring release");
+				break;
+			}
+
+			DBG("AVRCP: treating key press as press + release");
+			send_key(control->uinput, key_map[i].uinput, 1);
+			send_key(control->uinput, key_map[i].uinput, 0);
 			break;
 		}
+
+		send_key(control->uinput, key_map[i].uinput, pressed);
+		break;
 	}
 
 	if (key_map[i].name == NULL)
-		debug("AVRCP: unknown button 0x%02X %s",
+		DBG("AVRCP: unknown button 0x%02X %s",
 						operands[0] & 0x7F, status);
 }
 
@@ -391,9 +417,18 @@
 	if (control->io_id) {
 		g_source_remove(control->io_id);
 		control->io_id = 0;
+
+		if (control->state == AVCTP_STATE_CONNECTING)
+			audio_device_cancel_authorization(dev, auth_cb,
+								control);
 	}
 
 	if (control->uinput >= 0) {
+		char address[18];
+
+		ba2str(&dev->dst, address);
+		DBG("AVRCP: closing uinput for %s", address);
+
 		ioctl(control->uinput, UI_DEV_DESTROY);
 		close(control->uinput);
 		control->uinput = -1;
@@ -409,6 +444,8 @@
 
 	switch (new_state) {
 	case AVCTP_STATE_DISCONNECTED:
+		DBG("AVCTP Disconnected");
+
 		avctp_disconnected(control->dev);
 
 		if (old_state != AVCTP_STATE_CONNECTED)
@@ -421,10 +458,16 @@
 		emit_property_changed(dev->conn, dev->path,
 					AUDIO_CONTROL_INTERFACE, "Connected",
 					DBUS_TYPE_BOOLEAN, &value);
+
+		if (!audio_device_is_active(dev, NULL))
+			audio_device_set_authorized(dev, FALSE);
+
 		break;
 	case AVCTP_STATE_CONNECTING:
+		DBG("AVCTP Connecting");
 		break;
 	case AVCTP_STATE_CONNECTED:
+		DBG("AVCTP Connected");
 		value = TRUE;
 		g_dbus_emit_signal(control->dev->conn, control->dev->path,
 				AUDIO_CONTROL_INTERFACE, "Connected",
@@ -455,7 +498,7 @@
 	struct avrcp_header *avrcp;
 	int ret, packet_size, operand_count, sock;
 
-	if (!(cond | G_IO_IN))
+	if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
 		goto failed;
 
 	sock = g_io_channel_unix_get_fd(control->io);
@@ -464,7 +507,7 @@
 	if (ret <= 0)
 		goto failed;
 
-	debug("Got %d bytes of data for AVCTP session %p", ret, control);
+	DBG("Got %d bytes of data for AVCTP session %p", ret, control);
 
 	if ((unsigned int) ret < sizeof(struct avctp_header)) {
 		error("Too small AVCTP packet");
@@ -475,7 +518,7 @@
 
 	avctp = (struct avctp_header *) buf;
 
-	debug("AVCTP transaction %u, packet type %u, C/R %u, IPID %u, "
+	DBG("AVCTP transaction %u, packet type %u, C/R %u, IPID %u, "
 			"PID 0x%04X",
 			avctp->transaction, avctp->packet_type,
 			avctp->cr, avctp->ipid, ntohs(avctp->pid));
@@ -493,7 +536,7 @@
 	operands = buf + sizeof(struct avctp_header) + sizeof(struct avrcp_header);
 	operand_count = ret;
 
-	debug("AVRCP %s 0x%01X, subunit_type 0x%02X, subunit_id 0x%01X, "
+	DBG("AVRCP %s 0x%01X, subunit_type 0x%02X, subunit_id 0x%01X, "
 			"opcode 0x%02X, %d operands",
 			avctp->cr ? "response" : "command",
 			avrcp->code, avrcp->subunit_type, avrcp->subunit_id,
@@ -527,7 +570,7 @@
 			operands[0] = 0x07;
 		if (operand_count >= 2)
 			operands[1] = SUBUNIT_PANEL << 3;
-		debug("reply to %s", avrcp->opcode == OP_UNITINFO ?
+		DBG("reply to %s", avrcp->opcode == OP_UNITINFO ?
 				"OP_UNITINFO" : "OP_SUBUNITINFO");
 	} else {
 		avctp->cr = AVCTP_RESPONSE;
@@ -538,7 +581,7 @@
 	return TRUE;
 
 failed:
-	debug("AVCTP session %p got disconnected", control);
+	DBG("AVCTP session %p got disconnected", control);
 	avctp_set_state(control, AVCTP_STATE_DISCONNECTED);
 	return FALSE;
 }
@@ -602,20 +645,29 @@
 
 static void init_uinput(struct control *control)
 {
-	char address[18], *name;
+	struct audio_device *dev = control->dev;
+	char address[18], name[248 + 1], *uinput_dev_name;
 
-	ba2str(&control->dev->dst, address);
+	device_get_name(dev->btd_dev, name, sizeof(name));
+	if (g_str_equal(name, "Nokia CK-20W")) {
+		control->key_quirks[FORWARD_OP] |= QUIRK_NO_RELEASE;
+		control->key_quirks[BACKWARD_OP] |= QUIRK_NO_RELEASE;
+		control->key_quirks[PLAY_OP] |= QUIRK_NO_RELEASE;
+		control->key_quirks[PAUSE_OP] |= QUIRK_NO_RELEASE;
+	}
+
+	ba2str(&dev->dst, address);
 
 	/* Use device name from config file if specified */
-	name = input_device_name;
-	if (!name)
-		name = address;
+	uinput_dev_name = input_device_name;
+	if (!uinput_dev_name)
+		uinput_dev_name = address;
 
-	control->uinput = uinput_create(name);
+	control->uinput = uinput_create(uinput_dev_name);
 	if (control->uinput < 0)
 		error("AVRCP: failed to init uinput for %s", address);
 	else
-		debug("AVRCP: uinput initialized for %s", address);
+		DBG("AVRCP: uinput initialized for %s", address);
 }
 
 static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data)
@@ -642,7 +694,7 @@
 		return;
 	}
 
-	debug("AVCTP: connected to %s", address);
+	DBG("AVCTP: connected to %s", address);
 
 	if (!control->io)
 		control->io = g_io_channel_ref(chan);
@@ -661,6 +713,11 @@
 	struct control *control = user_data;
 	GError *err = NULL;
 
+	if (control->io_id) {
+		g_source_remove(control->io_id);
+		control->io_id = 0;
+	}
+
 	if (derr && dbus_error_is_set(derr)) {
 		error("Access denied: %s", derr->message);
 		avctp_set_state(control, AVCTP_STATE_DISCONNECTED);
@@ -721,6 +778,8 @@
 						auth_cb, dev->control) < 0)
 		goto drop;
 
+	control->io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+							control_cb, control);
 	return;
 
 drop:
@@ -799,7 +858,7 @@
 		tmp = g_key_file_get_boolean(config, "General",
 							"Master", &err);
 		if (err) {
-			debug("audio.conf: %s", err->message);
+			DBG("audio.conf: %s", err->message);
 			g_error_free(err);
 		} else
 			master = tmp;
@@ -807,7 +866,7 @@
 		input_device_name = g_key_file_get_string(config,
 			"AVRCP", "InputDeviceName", &err);
 		if (err) {
-			debug("audio.conf: %s", err->message);
+			DBG("audio.conf: %s", err->message);
 			input_device_name = NULL;
 			g_error_free(err);
 		}
@@ -823,11 +882,13 @@
 	record = avrcp_tg_record();
 	if (!record) {
 		error("Unable to allocate new service record");
+		g_free(server);
 		return -1;
 	}
 
 	if (add_record_to_server(src, record) < 0) {
 		error("Unable to register AVRCP target service record");
+		g_free(server);
 		sdp_record_free(record);
 		return -1;
 	}
@@ -837,12 +898,14 @@
 	record = avrcp_ct_record();
 	if (!record) {
 		error("Unable to allocate new service record");
+		g_free(server);
 		return -1;
 	}
 
 	if (add_record_to_server(src, record) < 0) {
 		error("Unable to register AVRCP controller service record");
 		sdp_record_free(record);
+		g_free(server);
 		return -1;
 	}
 	server->ct_record_id = record->handle;
@@ -1070,7 +1133,7 @@
 	struct audio_device *dev = data;
 	struct control *control = dev->control;
 
-	debug("Unregistered interface %s on path %s",
+	DBG("Unregistered interface %s on path %s",
 		AUDIO_CONTROL_INTERFACE, dev->path);
 
 	if (control->state != AVCTP_STATE_DISCONNECTED)
@@ -1104,7 +1167,7 @@
 					dev, path_unregister))
 		return NULL;
 
-	debug("Registered interface %s on path %s",
+	DBG("Registered interface %s on path %s",
 		AUDIO_CONTROL_INTERFACE, dev->path);
 
 	control = g_new0(struct control, 1);
diff --git a/audio/control.h b/audio/control.h
index ad0aca5..49f25c2 100644
--- a/audio/control.h
+++ b/audio/control.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/audio/ctl_bluetooth.c b/audio/ctl_bluetooth.c
index 2e12f65..2981385 100644
--- a/audio/ctl_bluetooth.c
+++ b/audio/ctl_bluetooth.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/audio/device.c b/audio/device.c
index 9662dec..ea54f18 100644
--- a/audio/device.c
+++ b/audio/device.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -43,7 +43,7 @@
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 #include "textfile.h"
 #include "../src/adapter.h"
 #include "../src/device.h"
@@ -157,7 +157,7 @@
 		priv->authorized = FALSE;
 
 	if (dev->priv->state == new_state) {
-		debug("state change attempted from %s to %s",
+		DBG("state change attempted from %s to %s",
 							state_str, state_str);
 		return;
 	}
@@ -345,6 +345,11 @@
 			device_remove_control_timer(dev);
 			avrcp_disconnect(dev);
 		}
+		if (priv->hs_state != HEADSET_STATE_DISCONNECTED &&
+								priv->dc_req) {
+			headset_shutdown(dev);
+			break;
+		}
 		if (priv->hs_state == HEADSET_STATE_DISCONNECTED)
 			device_set_state(dev, AUDIO_STATE_DISCONNECTED);
 		else if (old_state == SINK_STATE_CONNECTING) {
@@ -372,11 +377,14 @@
 		if (dev->auto_connect) {
 			if (!dev->headset)
 				device_set_state(dev, AUDIO_STATE_CONNECTED);
-			if (priv->hs_state == HEADSET_STATE_DISCONNECTED)
+			else if (priv->hs_state == HEADSET_STATE_DISCONNECTED)
 				device_set_headset_timer(dev);
-			else if (priv->hs_state == HEADSET_STATE_CONNECTED)
+			else if (priv->hs_state == HEADSET_STATE_CONNECTED ||
+					priv->hs_state == HEADSET_STATE_PLAY_IN_PROGRESS ||
+					priv->hs_state == HEADSET_STATE_PLAYING)
 				device_set_state(dev, AUDIO_STATE_CONNECTED);
-		} else if (priv->hs_state != HEADSET_STATE_CONNECTED)
+		} else if (priv->hs_state == HEADSET_STATE_DISCONNECTED ||
+				priv->hs_state == HEADSET_STATE_CONNECTING)
 			device_set_state(dev, AUDIO_STATE_CONNECTED);
 		break;
 	case SINK_STATE_PLAYING:
@@ -427,12 +435,12 @@
 		}
 		if (priv->sink_state == SINK_STATE_DISCONNECTED)
 			device_set_state(dev, AUDIO_STATE_DISCONNECTED);
-		else if (old_state == HEADSET_STATE_CONNECT_IN_PROGRESS &&
+		else if (old_state == HEADSET_STATE_CONNECTING &&
 				(priv->sink_state == SINK_STATE_CONNECTED ||
 				priv->sink_state == SINK_STATE_PLAYING))
 			device_set_state(dev, AUDIO_STATE_CONNECTED);
 		break;
-	case HEADSET_STATE_CONNECT_IN_PROGRESS:
+	case HEADSET_STATE_CONNECTING:
 		device_remove_headset_timer(dev);
 		if (priv->sink_state == SINK_STATE_DISCONNECTED)
 			device_set_state(dev, AUDIO_STATE_CONNECTING);
@@ -447,9 +455,11 @@
 				device_set_state(dev, AUDIO_STATE_CONNECTED);
 			else if (priv->sink_state == SINK_STATE_DISCONNECTED)
 				device_set_avdtp_timer(dev);
-			else if (priv->sink_state == SINK_STATE_CONNECTED)
+			else if (priv->sink_state == SINK_STATE_CONNECTED ||
+					priv->sink_state == SINK_STATE_PLAYING)
 				device_set_state(dev, AUDIO_STATE_CONNECTED);
-		} else if (priv->sink_state != SINK_STATE_CONNECTED)
+		} else if (priv->sink_state == SINK_STATE_DISCONNECTED ||
+				priv->sink_state == SINK_STATE_CONNECTING)
 			device_set_state(dev, AUDIO_STATE_CONNECTED);
 		break;
 	case HEADSET_STATE_PLAY_IN_PROGRESS:
@@ -517,10 +527,15 @@
 
 	priv->dc_req = dbus_message_ref(msg);
 
-	if (priv->hs_state != HEADSET_STATE_DISCONNECTED)
-		headset_shutdown(dev);
-	else if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED)
+	if (dev->control) {
+		device_remove_control_timer(dev);
+		avrcp_disconnect(dev);
+	}
+
+	if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED)
 		sink_shutdown(dev->sink);
+	else if (priv->hs_state != HEADSET_STATE_DISCONNECTED)
+		headset_shutdown(dev);
 	else {
 		dbus_message_unref(priv->dc_req);
 		priv->dc_req = NULL;
@@ -603,7 +618,7 @@
 		return NULL;
 	}
 
-	debug("Registered interface %s on path %s", AUDIO_INTERFACE,
+	DBG("Registered interface %s on path %s", AUDIO_INTERFACE,
 								dev->path);
 
 	if (sink_callback_id == 0)
@@ -626,26 +641,24 @@
 {
 	if (!interface) {
 		if ((dev->sink || dev->source) &&
-			avdtp_is_connected(&dev->src, &dev->dst))
+				avdtp_is_connected(&dev->src, &dev->dst))
 			return TRUE;
-
 		if (dev->headset && headset_is_active(dev))
 			return TRUE;
-	}
-	else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink &&
-			avdtp_is_connected(&dev->src, &dev->dst))
+	} else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink &&
+				avdtp_is_connected(&dev->src, &dev->dst))
 		return TRUE;
 	else if (!strcmp(interface, AUDIO_SOURCE_INTERFACE) && dev->source &&
-			avdtp_is_connected(&dev->src, &dev->dst))
+				avdtp_is_connected(&dev->src, &dev->dst))
 		return TRUE;
 	else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset &&
-			headset_is_active(dev))
+				headset_is_active(dev))
 		return TRUE;
 	else if (!strcmp(interface, AUDIO_CONTROL_INTERFACE) && dev->control &&
-			control_is_active(dev))
+				control_is_active(dev))
 		return TRUE;
 	else if (!strcmp(interface, AUDIO_GATEWAY_INTERFACE) && dev->gateway &&
-			gateway_is_connected(dev))
+				gateway_is_connected(dev))
 		return TRUE;
 
 	return FALSE;
@@ -655,9 +668,17 @@
 {
 	unix_device_removed(device);
 
+	if (device->hs_preauth_id) {
+		g_source_remove(device->hs_preauth_id);
+		device->hs_preauth_id = 0;
+	}
+
 	if (device->headset)
 		headset_unregister(device);
 
+	if (device->gateway)
+		gateway_unregister(device);
+
 	if (device->sink)
 		sink_unregister(device);
 
@@ -773,7 +794,7 @@
 	GSList *l, *next;
 
 	for (l = priv->auths; l != NULL; l = next) {
-		struct service_auth *auth = priv->auths->data;
+		struct service_auth *auth = l->data;
 
 		next = g_slist_next(l);
 
@@ -797,3 +818,10 @@
 
 	return 0;
 }
+
+void audio_device_set_authorized(struct audio_device *dev, gboolean auth)
+{
+	struct dev_priv *priv = dev->priv;
+
+	priv->authorized = auth;
+}
diff --git a/audio/device.h b/audio/device.h
index 061c3da..6ec3938 100644
--- a/audio/device.h
+++ b/audio/device.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -67,6 +67,8 @@
 	struct control *control;
 	struct target *target;
 
+	guint hs_preauth_id;
+
 	struct dev_priv *priv;
 };
 
@@ -82,6 +84,11 @@
 
 typedef void (*authorization_cb) (DBusError *derr, void *user_data);
 
+int audio_device_cancel_authorization(struct audio_device *dev,
+					authorization_cb cb, void *user_data);
+
 int audio_device_request_authorization(struct audio_device *dev,
 					const char *uuid, authorization_cb cb,
 					void *user_data);
+
+void audio_device_set_authorized(struct audio_device *dev, gboolean auth);
diff --git a/audio/gateway.c b/audio/gateway.c
index 09a401c..07ebdd4 100644
--- a/audio/gateway.c
+++ b/audio/gateway.c
@@ -2,9 +2,10 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2008-2009  Leonid Movshovich <event.riga@gmail.org>
+ *  Copyright (C) 2010  ProFUSION embedded systems
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -47,444 +48,103 @@
 #include "glib-helper.h"
 #include "device.h"
 #include "gateway.h"
-#include "logging.h"
+#include "log.h"
 #include "error.h"
 #include "btio.h"
 #include "dbus-common.h"
 
-#define RFCOMM_BUF_SIZE 256
-/* not-more-then-16 defined by GSM + 1 for NULL + padding */
-#define AG_INDICATOR_DESCR_SIZE 20
-#define AG_CALLER_NUM_SIZE 64	/* size of number + type */
+#ifndef DBUS_TYPE_UNIX_FD
+#define DBUS_TYPE_UNIX_FD -1
+#endif
 
-/* commands */
-#define AG_FEATURES "AT+BRSF=26\r"     /* = 0x7F = All features supported */
-#define AG_INDICATORS_SUPP "AT+CIND=?\r"
-#define AG_INDICATORS_VAL "AT+CIND?\r"
-#define AG_INDICATORS_ENABLE "AT+CMER=3,0,0,1\r"
-#define AG_HOLD_MPTY_SUPP "AT+CHLD=?\r"
-#define AG_CALLER_IDENT_ENABLE "AT+CLIP=1\r"
-#define AG_CARRIER_FORMAT "AT+COPS=3,0\r"
-#define AG_EXTENDED_RESULT_CODE "AT+CMEE=1\r"
-
-#define AG_FEATURE_3WAY 0x1
-#define AG_FEATURE_EXTENDED_RES_CODE 0x100
-/* Hold and multipary AG features.
- * Comments below are copied from hands-free spec for reference */
-/* Releases all held calls or sets User Determined User Busy (UDUB)
- * for a waiting call */
-#define AG_CHLD_0 0x01
-/* Releases all active calls (if any exist) and accepts the other
- * (held or waiting) call */
-#define AG_CHLD_1 0x02
-/* Releases specified active call only <x> */
-#define AG_CHLD_1x 0x04
-/* Places all active calls (if any exist) on hold and accepts the other
- * (held or waiting) call */
-#define AG_CHLD_2 0x08
-/* Request private consultation mode with specified call <x> (Place all
- * calls on hold EXCEPT the call <x>) */
-#define AG_CHLD_2x 0x10
-/* Adds a held call to the conversation */
-#define AG_CHLD_3 0x20
-/* Connects the two calls and disconnects the subscriber from both calls
- * (Explicit Call Transfer). Support for this value and its associated
- * functionality is optional for the HF. */
-#define AG_CHLD_4 0x40
-
-#define OK_RESPONSE "\r\nOK\r\n"
-#define ERROR_RESPONSE "\r\nERROR\r\n"
-
-struct indicator {
-	gchar descr[AG_INDICATOR_DESCR_SIZE];
-	gint value;
+struct hf_agent {
+	char *name;	/* Bus id */
+	char *path;	/* D-Bus path */
+	guint watch;	/* Disconnect watch */
 };
 
 struct gateway {
 	gateway_state_t state;
 	GIOChannel *rfcomm;
-	guint rfcomm_watch_id;
 	GIOChannel *sco;
 	gateway_stream_cb_t sco_start_cb;
 	void *sco_start_cb_data;
-	DBusMessage *connect_message;
-	guint ag_features;
-	guint hold_multiparty_features;
-	GSList *indies;
-	gboolean is_dialing;
-	gboolean call_active;
-
-	int sp_gain;
-	int mic_gain;
+	struct hf_agent *agent;
+	DBusMessage *msg;
 };
 
-static gboolean rfcomm_ag_data_cb(GIOChannel *chan, GIOCondition cond,
-					struct audio_device *device);
-
 int gateway_close(struct audio_device *device);
 
-static void rfcomm_start_watch(struct audio_device *dev)
+static const char *state2str(gateway_state_t state)
 {
-	struct gateway *gw = dev->gateway;
-
-	gw->rfcomm_watch_id = g_io_add_watch(gw->rfcomm,
-			G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-			(GIOFunc) rfcomm_ag_data_cb, dev);
-}
-
-static void rfcomm_stop_watch(struct audio_device *dev)
-{
-	struct gateway *gw = dev->gateway;
-
-	g_source_remove(gw->rfcomm_watch_id);
-}
-
-static gboolean io_channel_write_all(GIOChannel *io, gchar *data,
-					gsize count)
-{
-	gsize written = 0;
-	GIOStatus status;
-
-	while (count > 0) {
-		status = g_io_channel_write_chars(io, data, count, &written,
-						NULL);
-		if (status != G_IO_STATUS_NORMAL)
-			return FALSE;
-
-		data += written;
-		count -= written;
+	switch (state) {
+	case GATEWAY_STATE_DISCONNECTED:
+		return "disconnected";
+	case GATEWAY_STATE_CONNECTING:
+		return "connecting";
+	case GATEWAY_STATE_CONNECTED:
+		return "connected";
+	case GATEWAY_STATE_PLAYING:
+		return "playing";
+	default:
+		return "";
 	}
-	return TRUE;
 }
 
-/* it's worth to mention that data and response could be the same pointers */
-static gboolean rfcomm_send_and_read(struct gateway *gw, gchar *data,
-                                    gchar *response, gsize count)
+static void agent_free(struct hf_agent *agent)
 {
-	GIOChannel *rfcomm = gw->rfcomm;
-	gsize read = 0;
-	gboolean got_ok = FALSE;
-	gboolean got_error = FALSE;
-	gchar *resp_buf = response;
-	gsize toread = RFCOMM_BUF_SIZE - 1;
-	GIOStatus status;
-
-	if (!io_channel_write_all(rfcomm, data, count))
-		return FALSE;
-
-	while (!(got_ok || got_error)) {
-		status = g_io_channel_read_chars(rfcomm, resp_buf, toread,
-						&read, NULL);
-		if (status == G_IO_STATUS_NORMAL)
-			resp_buf[read] = '\0';
-		else {
-			debug("rfcomm_send_and_read(): %m");
-			return FALSE;
-		}
-		got_ok = NULL != strstr(resp_buf, OK_RESPONSE);
-		got_error = NULL != strstr(resp_buf, ERROR_RESPONSE);
-		resp_buf += read;
-		toread -= read;
-	}
-	return TRUE;
-}
-
-/* get <descr> from the names: (<descr>, (<values>)), (<descr>, (<values>))
- * ... */
-static GSList *parse_indicator_names(gchar *names, GSList *indies)
-{
-	gchar *current = names - 1;
-	GSList *result = indies;
-	gchar *next;
-	struct indicator *ind;
-
-	while (current != NULL) {
-		current += 2;
-		next = strstr(current, ",(");
-		ind = g_slice_new(struct indicator);
-		strncpy(ind->descr, current, 20);
-		ind->descr[(intptr_t) next - (intptr_t) current] = '\0';
-		result = g_slist_append(result, (gpointer) ind);
-		current = strstr(next + 1, ",(");
-	}
-	return result;
-}
-
-/* get values from <val0>,<val1>,... */
-static GSList *parse_indicator_values(gchar *values, GSList *indies)
-{
-	gint val;
-	gchar *current = values - 1;
-	GSList *runner = indies;
-	struct indicator *ind;
-
-	while (current != NULL) {
-		current += 1;
-		sscanf(current, "%d", &val);
-		current = strchr(current, ',');
-		ind = g_slist_nth_data(runner, 0);
-		ind->value = val;
-		runner = g_slist_next(runner);
-	}
-	return indies;
-}
-
-/* get values from <val0>,<val1>,... */
-static guint get_hold_mpty_features(gchar *features)
-{
-	guint result = 0;
-
-	if (strstr(features, "0"))
-		result |= AG_CHLD_0;
-
-	if (strstr(features, "1"))
-		result |= AG_CHLD_1;
-
-	if (strstr(features, "1x"))
-		result |= AG_CHLD_1x;
-
-	if (strstr(features, "2"))
-		result |= AG_CHLD_2;
-
-	if (strstr(features, "2x"))
-		result |= AG_CHLD_2x;
-
-	if (strstr(features, "3"))
-		result |= AG_CHLD_3;
-
-	if (strstr(features, "4"))
-		result |= AG_CHLD_4;
-
-	return result;
-}
-
-static gboolean establish_service_level_conn(struct gateway *gw)
-{
-	gchar buf[RFCOMM_BUF_SIZE];
-	gboolean res;
-
-	debug("at the begin of establish_service_level_conn()");
-	res = rfcomm_send_and_read(gw, AG_FEATURES, buf,
-				sizeof(AG_FEATURES) - 1);
-	if (!res || sscanf(buf, "\r\n+BRSF:%d", &gw->ag_features) != 1)
-		return FALSE;
-
-	debug("features are 0x%X", gw->ag_features);
-	res = rfcomm_send_and_read(gw, AG_INDICATORS_SUPP, buf,
-				sizeof(AG_INDICATORS_SUPP) - 1);
-	if (!res || !strstr(buf, "+CIND:"))
-		return FALSE;
-
-	gw->indies = parse_indicator_names(strchr(buf, '('), NULL);
-
-	res = rfcomm_send_and_read(gw, AG_INDICATORS_VAL, buf,
-		sizeof(AG_INDICATORS_VAL) - 1);
-	if (!res || !strstr(buf, "+CIND:"))
-		return FALSE;
-
-	gw->indies = parse_indicator_values(strchr(buf, ':') + 1, gw->indies);
-
-	res = rfcomm_send_and_read(gw, AG_INDICATORS_ENABLE, buf,
-				sizeof(AG_INDICATORS_ENABLE) - 1);
-	if (!res || !strstr(buf, "OK"))
-		return FALSE;
-
-	if ((gw->ag_features & AG_FEATURE_3WAY) != 0) {
-		res = rfcomm_send_and_read(gw, AG_HOLD_MPTY_SUPP, buf,
-				sizeof(AG_HOLD_MPTY_SUPP) - 1);
-		if (!res || !strstr(buf, "+CHLD:")) {
-			g_slice_free1(RFCOMM_BUF_SIZE, buf);
-			return FALSE;
-		}
-		gw->hold_multiparty_features = get_hold_mpty_features(
-							strchr(buf, '('));
-
-	} else
-		gw->hold_multiparty_features = 0;
-
-	debug("Service layer connection successfully established!");
-	rfcomm_send_and_read(gw, AG_CALLER_IDENT_ENABLE, buf,
-			sizeof(AG_CALLER_IDENT_ENABLE) - 1);
-	rfcomm_send_and_read(gw, AG_CARRIER_FORMAT, buf,
-			sizeof(AG_CARRIER_FORMAT) - 1);
-	if ((gw->ag_features & AG_FEATURE_EXTENDED_RES_CODE) != 0)
-		rfcomm_send_and_read(gw, AG_EXTENDED_RESULT_CODE, buf,
-			sizeof(AG_EXTENDED_RESULT_CODE) - 1);
-
-	return TRUE;
-}
-
-static void process_ind_change(struct audio_device *dev, guint index,
-							gint value)
-{
-	struct gateway *gw = dev->gateway;
-	struct indicator *ind = g_slist_nth_data(gw->indies, index - 1);
-	gchar *name = ind->descr;
-
-	ind->value = value;
-
-	debug("at the begin of process_ind_change, name is %s", name);
-	if (!strcmp(name, "\"call\"")) {
-		if (value > 0) {
-			g_dbus_emit_signal(dev->conn, dev->path,
-					AUDIO_GATEWAY_INTERFACE,
-					"CallStarted", DBUS_TYPE_INVALID);
-			gw->is_dialing = FALSE;
-			gw->call_active = TRUE;
-		} else {
-			g_dbus_emit_signal(dev->conn, dev->path,
-					AUDIO_GATEWAY_INTERFACE,
-					"CallEnded", DBUS_TYPE_INVALID);
-			gw->call_active = FALSE;
-		}
-
-	} else if (!strcmp(name, "\"callsetup\"")) {
-		if (value == 0 && gw->is_dialing) {
-			g_dbus_emit_signal(dev->conn, dev->path,
-					AUDIO_GATEWAY_INTERFACE,
-					"CallTerminated",
-					DBUS_TYPE_INVALID);
-			gw->is_dialing = FALSE;
-		} else if (!gw->is_dialing && value > 0)
-			gw->is_dialing = TRUE;
-
-	} else if (!strcmp(name, "\"callheld\"")) {
-		/* FIXME: The following code is based on assumptions only.
-		 * Has to be tested for interoperability
-		 * I assume that callheld=2 would be sent when dial from HF
-		 * failed in case of 3-way call
-		 * Unfortunately this path is not covered by the HF spec so
-		 * the code has to be tested for interop
-		*/
-		/* '2' means: all calls held, no active calls */
-		if (value == 2) {
-			if (gw->is_dialing) {
-				g_dbus_emit_signal(dev->conn, dev->path,
-					AUDIO_GATEWAY_INTERFACE,
-					"CallTerminated",
-					DBUS_TYPE_INVALID);
-				gw->is_dialing = FALSE;
-			}
-		}
-	} else if (!strcmp(name, "\"service\""))
-		emit_property_changed(dev->conn, dev->path,
-				AUDIO_GATEWAY_INTERFACE, "RegistrationStatus",
-				DBUS_TYPE_UINT16, &value);
-	else if (!strcmp(name, "\"signal\""))
-		emit_property_changed(dev->conn, dev->path,
-				AUDIO_GATEWAY_INTERFACE, "SignalStrength",
-				DBUS_TYPE_UINT16, &value);
-	else if (!strcmp(name, "\"roam\""))
-		emit_property_changed(dev->conn, dev->path,
-				AUDIO_GATEWAY_INTERFACE, "RoamingStatus",
-				DBUS_TYPE_UINT16, &value);
-	else if (!strcmp(name, "\"battchg\""))
-		emit_property_changed(dev->conn, dev->path,
-				AUDIO_GATEWAY_INTERFACE, "BatteryCharge",
-				DBUS_TYPE_UINT16, &value);
-}
-
-static void process_ring(struct audio_device *device, GIOChannel *chan,
-			gchar *buf)
-{
-	gchar number[AG_CALLER_NUM_SIZE];
-	gchar *cli;
-	gchar *sep;
-	gsize read;
-	GIOStatus status;
-
-	rfcomm_stop_watch(device);
-	status = g_io_channel_read_chars(chan, buf, RFCOMM_BUF_SIZE - 1, &read, NULL);
-	if (status != G_IO_STATUS_NORMAL)
+	if (!agent)
 		return;
 
-	debug("at the begin of process_ring");
-	if (strlen(buf) > AG_CALLER_NUM_SIZE + 10)
-		error("process_ring(): buf is too long '%s'", buf);
-	else if ((cli = strstr(buf, "\r\n+CLIP"))) {
-		if (sscanf(cli, "\r\n+CLIP: \"%s", number) == 1) {
-			sep = strchr(number, '"');
-			sep[0] = '\0';
-
-			/* FIXME:signal will be emitted on each RING+CLIP.
-			 * That's bad */
-			cli = number;
-			g_dbus_emit_signal(device->conn, device->path,
-					AUDIO_GATEWAY_INTERFACE, "Ring",
-					DBUS_TYPE_STRING, &cli,
-					DBUS_TYPE_INVALID);
-			device->gateway->is_dialing = TRUE;
-		} else
-			error("process_ring(): '%s' in place of +CLIP after RING", buf);
-
-	}
-
-	rfcomm_start_watch(device);
+	g_free(agent->name);
+	g_free(agent->path);
+	g_free(agent);
 }
 
-static gboolean rfcomm_ag_data_cb(GIOChannel *chan, GIOCondition cond,
-					struct audio_device *device)
+static void change_state(struct audio_device *dev, gateway_state_t new_state)
 {
-	gchar buf[RFCOMM_BUF_SIZE];
-	struct gateway *gw;
-	gsize read;
-	/* some space for value */
-	gchar indicator[AG_INDICATOR_DESCR_SIZE + 4];
-	gint value;
-	guint index;
-	gchar *sep;
+	struct gateway *gw = dev->gateway;
+	const char *val;
 
-	debug("at the begin of rfcomm_ag_data_cb()");
-	if (cond & G_IO_NVAL)
+	if (gw->state == new_state)
+		return;
+
+	val = state2str(new_state);
+	gw->state = new_state;
+
+	emit_property_changed(dev->conn, dev->path,
+			AUDIO_GATEWAY_INTERFACE, "State",
+			DBUS_TYPE_STRING, &val);
+}
+
+static void agent_disconnect(struct audio_device *dev, struct hf_agent *agent)
+{
+	DBusMessage *msg;
+
+	msg = dbus_message_new_method_call(agent->name, agent->path,
+			"org.bluez.HandsfreeAgent", "Release");
+
+	g_dbus_send_message(dev->conn, msg);
+}
+
+static gboolean agent_sendfd(struct hf_agent *agent, int fd,
+		DBusPendingCallNotifyFunction notify, void *data)
+{
+	struct audio_device *dev = data;
+	DBusMessage *msg;
+	DBusPendingCall *call;
+
+	msg = dbus_message_new_method_call(agent->name, agent->path,
+			"org.bluez.HandsfreeAgent", "NewConnection");
+
+	dbus_message_append_args(msg, DBUS_TYPE_UNIX_FD, &fd,
+					DBUS_TYPE_INVALID);
+
+	if (dbus_connection_send_with_reply(dev->conn, msg, &call, -1) == FALSE)
 		return FALSE;
 
-	gw = device->gateway;
-
-	if (cond & (G_IO_ERR | G_IO_HUP)) {
-		debug("connection with remote BT is closed");
-		gateway_close(device);
-		return FALSE;
-	}
-
-	if (g_io_channel_read_chars(chan, buf, sizeof(buf) - 1, &read, NULL)
-			!= G_IO_STATUS_NORMAL)
-		return TRUE;
-	buf[read] = '\0';
-
-	if (strlen(buf) > AG_INDICATOR_DESCR_SIZE + 14)
-		error("rfcomm_ag_data_cb(): buf is too long '%s'", buf);
-	else if (sscanf(buf, "\r\n+CIEV:%s\r\n", indicator) == 1) {
-		sep = strchr(indicator, ',');
-		sep[0] = '\0';
-		sep += 1;
-		index = atoi(indicator);
-		value = atoi(sep);
-		process_ind_change(device, index, value);
-	} else if (strstr(buf, "RING"))
-		process_ring(device, chan, buf);
-	else if (sscanf(buf, "\r\n+BVRA:%d\r\n", &value) == 1) {
-		if (value == 0)
-			g_dbus_emit_signal(device->conn, device->path,
-					AUDIO_GATEWAY_INTERFACE,
-					"VoiceRecognitionActive",
-					DBUS_TYPE_INVALID);
-		else
-			g_dbus_emit_signal(device->conn, device->path,
-					AUDIO_GATEWAY_INTERFACE,
-					"VoiceRecognitionInactive",
-					DBUS_TYPE_INVALID);
-	} else if (sscanf(buf, "\r\n+VGS:%d\r\n", &value) == 1) {
-		gw->sp_gain = value;
-		emit_property_changed(device->conn, device->path,
-				AUDIO_GATEWAY_INTERFACE, "SpeakerGain",
-				DBUS_TYPE_UINT16, &value);
-	} else if (sscanf(buf, "\r\n+VGM:%d\r\n", &value) == 1) {
-		gw->mic_gain = value;
-		emit_property_changed(device->conn, device->path,
-				AUDIO_GATEWAY_INTERFACE, "MicrophoneGain",
-				DBUS_TYPE_UINT16, &value);
-	} else
-		error("rfcomm_ag_data_cb(): read wrong data '%s'", buf);
+	dbus_pending_call_set_notify(call, notify, dev, NULL);
+	dbus_pending_call_unref(call);
 
 	return TRUE;
 }
@@ -498,10 +158,11 @@
 		return FALSE;
 
 	if (cond & (G_IO_ERR | G_IO_HUP)) {
-		debug("sco connection is released");
+		DBG("sco connection is released");
 		g_io_channel_shutdown(gw->sco, TRUE, NULL);
 		g_io_channel_unref(gw->sco);
 		gw->sco = NULL;
+		change_state(dev, GATEWAY_STATE_CONNECTED);
 		return FALSE;
 	}
 
@@ -513,114 +174,129 @@
 	struct audio_device *dev = (struct audio_device *) user_data;
 	struct gateway *gw = dev->gateway;
 
-	debug("at the begin of sco_connect_cb() in gateway.c");
+	DBG("at the begin of sco_connect_cb() in gateway.c");
+
+	gw->sco = g_io_channel_ref(chan);
+
+	if (gw->sco_start_cb)
+		gw->sco_start_cb(dev, err, gw->sco_start_cb_data);
 
 	if (err) {
 		error("sco_connect_cb(): %s", err->message);
-		/* not sure, but from other point of view,
-		 * what is the reason to have headset which
-		 * cannot play audio? */
-		if (gw->sco_start_cb)
-			gw->sco_start_cb(NULL, gw->sco_start_cb_data);
 		gateway_close(dev);
 		return;
 	}
 
-	gw->sco = g_io_channel_ref(chan);
-	if (gw->sco_start_cb)
-		gw->sco_start_cb(dev, gw->sco_start_cb_data);
-
-	/* why is this here? */
-	fcntl(g_io_channel_unix_get_fd(chan), F_SETFL, 0);
 	g_io_add_watch(gw->sco, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
 				(GIOFunc) sco_io_cb, dev);
 }
 
+static void newconnection_reply(DBusPendingCall *call, void *data)
+{
+	struct audio_device *dev = data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError derr;
+
+	if (!dev->gateway->rfcomm) {
+		DBG("RFCOMM disconnected from server before agent reply");
+		goto done;
+	}
+
+	dbus_error_init(&derr);
+	if (!dbus_set_error_from_message(&derr, reply)) {
+		DBG("Agent reply: file descriptor passed successfully");
+		change_state(dev, GATEWAY_STATE_CONNECTED);
+		goto done;
+	}
+
+	DBG("Agent reply: %s", derr.message);
+
+	dbus_error_free(&derr);
+	gateway_close(dev);
+
+done:
+	dbus_message_unref(reply);
+}
+
 static void rfcomm_connect_cb(GIOChannel *chan, GError *err,
 				gpointer user_data)
 {
 	struct audio_device *dev = user_data;
 	struct gateway *gw = dev->gateway;
-	DBusMessage *conn_mes = gw->connect_message;
-	gchar gw_addr[18];
-	GIOFlags flags;
+	DBusMessage *reply;
+	int sk, ret;
 
 	if (err) {
 		error("connect(): %s", err->message);
 		if (gw->sco_start_cb)
-			gw->sco_start_cb(NULL, gw->sco_start_cb_data);
-		return;
+			gw->sco_start_cb(dev, err, gw->sco_start_cb_data);
+		goto fail;
 	}
 
-	ba2str(&dev->dst, gw_addr);
-	/* Blocking mode should be default, but just in case: */
-	flags = g_io_channel_get_flags(chan);
-	flags &= ~G_IO_FLAG_NONBLOCK;
-	flags &= G_IO_FLAG_MASK;
-	g_io_channel_set_flags(chan, flags, NULL);
-	g_io_channel_set_encoding(chan, NULL, NULL);
-	g_io_channel_set_buffered(chan, FALSE);
-	if (!gw->rfcomm)
-		gw->rfcomm = g_io_channel_ref(chan);
+	if (!gw->agent) {
+		error("Handsfree Agent not registered");
+		goto fail;
+	}
 
-	if (establish_service_level_conn(dev->gateway)) {
-		gboolean value = TRUE;
+	sk = g_io_channel_unix_get_fd(chan);
 
-		debug("%s: Connected to %s", dev->path, gw_addr);
-		rfcomm_start_watch(dev);
-		if (conn_mes) {
-			DBusMessage *reply =
-				dbus_message_new_method_return(conn_mes);
-			dbus_connection_send(dev->conn, reply, NULL);
-			dbus_message_unref(reply);
-			dbus_message_unref(conn_mes);
-			gw->connect_message = NULL;
-		}
+	gw->rfcomm = g_io_channel_ref(chan);
 
-		gw->state = GATEWAY_STATE_CONNECTED;
-		emit_property_changed(dev->conn, dev->path,
-				AUDIO_GATEWAY_INTERFACE,
-				"Connected", DBUS_TYPE_BOOLEAN,	&value);
+	ret = agent_sendfd(gw->agent, sk, newconnection_reply, dev);
+
+	if (!gw->msg)
 		return;
-	} else
-		error("%s: Failed to establish service layer connection to %s",
-			dev->path, gw_addr);
 
-	if (NULL != gw->sco_start_cb)
-		gw->sco_start_cb(NULL, gw->sco_start_cb_data);
+	if (ret)
+		reply = dbus_message_new_method_return(gw->msg);
+	else
+		reply = g_dbus_create_error(gw->msg, ERROR_INTERFACE ".Failed",
+					"Can not pass file descriptor");
 
-	gateway_close(dev);
+	g_dbus_send_message(dev->conn, reply);
+
+	return;
+
+fail:
+	if (gw->msg)
+		error_common_reply(dev->conn, gw->msg,
+						ERROR_INTERFACE ".Failed",
+						"Connection attempt failed");
+
+	change_state(dev, GATEWAY_STATE_DISCONNECTED);
 }
 
-static void get_record_cb(sdp_list_t *recs, int perr, gpointer user_data)
+static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
 {
 	struct audio_device *dev = user_data;
-	DBusMessage *msg = dev->gateway->connect_message;
-	int ch = -1;
+	struct gateway *gw = dev->gateway;
+	int ch;
 	sdp_list_t *protos, *classes;
 	uuid_t uuid;
-	gateway_stream_cb_t sco_cb;
 	GIOChannel *io;
-	GError *err = NULL;
+	GError *gerr = NULL;
 
-	if (perr < 0) {
-		error("Unable to get service record: %s (%d)", strerror(-perr),
-					-perr);
+	if (err < 0) {
+		error("Unable to get service record: %s (%d)", strerror(-err),
+					-err);
 		goto fail;
 	}
 
 	if (!recs || !recs->data) {
 		error("No records found");
+		err = -EIO;
 		goto fail;
 	}
 
 	if (sdp_get_service_classes(recs->data, &classes) < 0) {
 		error("Unable to get service classes from record");
+		err = -EINVAL;
 		goto fail;
 	}
 
 	if (sdp_get_access_protos(recs->data, &protos) < 0) {
 		error("Unable to get access protocols from record");
+		err = -ENODATA;
 		goto fail;
 	}
 
@@ -631,6 +307,7 @@
 			uuid.value.uuid16 != HANDSFREE_AGW_SVCLASS_ID) {
 		sdp_list_free(protos, NULL);
 		error("Invalid service record or not HFP");
+		err = -EIO;
 		goto fail;
 	}
 
@@ -639,39 +316,42 @@
 	sdp_list_free(protos, NULL);
 	if (ch <= 0) {
 		error("Unable to extract RFCOMM channel from service record");
+		err = -EIO;
 		goto fail;
 	}
 
-	io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, dev, NULL, &err,
+	io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, dev, NULL, &gerr,
 				BT_IO_OPT_SOURCE_BDADDR, &dev->src,
 				BT_IO_OPT_DEST_BDADDR, &dev->dst,
 				BT_IO_OPT_CHANNEL, ch,
 				BT_IO_OPT_INVALID);
 	if (!io) {
-		error("Unable to connect: %s", err->message);
-		if (msg) {
-			error_common_reply(dev->conn, msg, ERROR_INTERFACE
-						".ConnectionAttemptFailed",
-						err->message);
-			msg = NULL;
-		}
-		g_error_free(err);
+		error("Unable to connect: %s", gerr->message);
 		gateway_close(dev);
+		goto fail;
 	}
 
 	g_io_channel_unref(io);
+
+	change_state(dev, GATEWAY_STATE_CONNECTING);
 	return;
 
 fail:
-	if (msg)
-		error_common_reply(dev->conn, msg, ERROR_INTERFACE
-					".NotSupported", "Not supported");
+	if (gw->msg)
+		error_common_reply(dev->conn, gw->msg,
+					ERROR_INTERFACE ".NotSupported",
+					"Not supported");
 
-	dev->gateway->connect_message = NULL;
+	change_state(dev, GATEWAY_STATE_DISCONNECTED);
 
-	sco_cb = dev->gateway->sco_start_cb;
-	if (sco_cb)
-		sco_cb(NULL, dev->gateway->sco_start_cb_data);
+	if (!gerr)
+		g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED,
+				"connect: %s (%d)", strerror(-err), -err);
+
+	if (gw->sco_start_cb)
+		gw->sco_start_cb(dev, gerr, gw->sco_start_cb_data);
+
+	g_error_free(gerr);
 }
 
 static int get_records(struct audio_device *device)
@@ -689,23 +369,47 @@
 	struct audio_device *au_dev = (struct audio_device *) data;
 	struct gateway *gw = au_dev->gateway;
 
-	debug("at the begin of ag_connect()");
-	if (gw->rfcomm)
+	if (!gw->agent)
 		return g_dbus_create_error(msg, ERROR_INTERFACE
-					".AlreadyConnected",
-					"Already Connected");
+				".Failed", "Agent not assigned");
 
-	gw->connect_message = dbus_message_ref(msg);
-	if (get_records(au_dev) < 0) {
-		dbus_message_unref(gw->connect_message);
+	if (get_records(au_dev) < 0)
 		return g_dbus_create_error(msg, ERROR_INTERFACE
 					".ConnectAttemptFailed",
 					"Connect Attempt Failed");
-	}
-	debug("at the end of ag_connect()");
+
+	gw->msg = dbus_message_ref(msg);
+
 	return NULL;
 }
 
+int gateway_close(struct audio_device *device)
+{
+	struct gateway *gw = device->gateway;
+	int sock;
+
+	if (gw->rfcomm) {
+		sock = g_io_channel_unix_get_fd(gw->rfcomm);
+		shutdown(sock, SHUT_RDWR);
+
+		g_io_channel_shutdown(gw->rfcomm, TRUE, NULL);
+		g_io_channel_unref(gw->rfcomm);
+		gw->rfcomm = NULL;
+	}
+
+	if (gw->sco) {
+		g_io_channel_shutdown(gw->sco, TRUE, NULL);
+		g_io_channel_unref(gw->sco);
+		gw->sco = NULL;
+		gw->sco_start_cb = NULL;
+		gw->sco_start_cb_data = NULL;
+	}
+
+	change_state(device, GATEWAY_STATE_DISCONNECTED);
+
+	return 0;
+}
+
 static DBusMessage *ag_disconnect(DBusConnection *conn, DBusMessage *msg,
 					void *data)
 {
@@ -714,6 +418,9 @@
 	DBusMessage *reply = NULL;
 	char gw_addr[18];
 
+	if (!device->conn)
+		return NULL;
+
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
 		return NULL;
@@ -725,248 +432,20 @@
 
 	gateway_close(device);
 	ba2str(&device->dst, gw_addr);
-	debug("Disconnected from %s, %s", gw_addr, device->path);
+	DBG("Disconnected from %s, %s", gw_addr, device->path);
 
 	return reply;
 }
 
-static DBusMessage *process_ag_reponse(DBusMessage *msg, gchar *response)
+static void agent_exited(DBusConnection *conn, void *data)
 {
-	DBusMessage *reply;
+	struct gateway *gateway = data;
+	struct hf_agent *agent = gateway->agent;
 
+	DBG("Agent %s exited", agent->name);
 
-	debug("in process_ag_reponse, response is %s", response);
-	if (strstr(response, OK_RESPONSE))
-		reply = dbus_message_new_method_return(msg);
-	else {
-		/* FIXME: some code should be here to processes errors
-		 *  in better fasion */
-		debug("AG responded with '%s' to %s method call", response,
-				dbus_message_get_member(msg));
-		reply = dbus_message_new_error(msg, ERROR_INTERFACE
-					".OperationFailed",
-					"Operation failed.See log for details");
-	}
-	return reply;
-}
-
-static DBusMessage *process_simple(DBusMessage *msg, struct audio_device *dev,
-					gchar *data)
-{
-	struct gateway *gw = dev->gateway;
-	gchar buf[RFCOMM_BUF_SIZE];
-
-	rfcomm_stop_watch(dev);
-	rfcomm_send_and_read(gw, data, buf, strlen(data));
-	rfcomm_start_watch(dev);
-	return process_ag_reponse(msg, buf);
-}
-
-#define AG_ANSWER "ATA\r"
-
-static DBusMessage *ag_answer(DBusConnection *conn, DBusMessage *msg,
-				void *data)
-{
-	struct audio_device *dev = data;
-	struct gateway *gw = dev->gateway;
-
-	if (!gw->rfcomm)
-		return g_dbus_create_error(msg, ERROR_INTERFACE
-					".NotConnected",
-					"Not Connected");
-
-	if (gw->call_active)
-		return g_dbus_create_error(msg, ERROR_INTERFACE
-					".CallAlreadyAnswered",
-					"Call AlreadyAnswered");
-
-	return process_simple(msg, dev, AG_ANSWER);
-}
-
-#define AG_HANGUP "AT+CHUP\r"
-
-static DBusMessage *ag_terminate_call(DBusConnection *conn, DBusMessage *msg,
-				void *data)
-{
-	struct audio_device *dev = data;
-	struct gateway *gw = dev->gateway;
-
-	if (!gw->rfcomm)
-		return g_dbus_create_error(msg, ERROR_INTERFACE
-					".NotConnected",
-					"Not Connected");
-
-	return process_simple(msg, dev, AG_HANGUP);
-}
-
-/* according to GSM spec */
-#define ALLOWED_NUMBER_SYMBOLS "1234567890*#ABCD"
-#define AG_PLACE_CALL "ATD%s;\r"
-/* dialing from memory is not supported as headset spec doesn't define a way
- * to retreive phone memory entries.
- */
-static DBusMessage *ag_call(DBusConnection *conn, DBusMessage *msg,
-				void *data)
-{
-	struct audio_device *device = data;
-	struct gateway *gw = device->gateway;
-	gchar buf[RFCOMM_BUF_SIZE];
-	gchar *number;
-	gint atd_len;
-	DBusMessage *result;
-
-	debug("at the begin of ag_call()");
-	if (!gw->rfcomm)
-		return g_dbus_create_error(msg, ERROR_INTERFACE
-					".NotConnected",
-					"Not Connected");
-
-	dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
-				DBUS_TYPE_INVALID);
-	if (strlen(number) != strspn(number, ALLOWED_NUMBER_SYMBOLS))
-		return dbus_message_new_error(msg,
-			ERROR_INTERFACE ".BadNumber",
-			"Number contains characters which are not allowed");
-
-	atd_len = sprintf(buf, AG_PLACE_CALL, number);
-	rfcomm_stop_watch(device);
-	rfcomm_send_and_read(gw, buf, buf, atd_len);
-	rfcomm_start_watch(device);
-
-	result = process_ag_reponse(msg, buf);
-	return result;
-}
-
-#define AG_GET_CARRIER "AT+COPS?\r"
-
-static DBusMessage *ag_get_operator(DBusConnection *conn, DBusMessage *msg,
-					void *data)
-{
-	struct audio_device *dev = (struct audio_device *) data;
-	struct gateway *gw = dev->gateway;
-	gchar buf[RFCOMM_BUF_SIZE];
-	GIOChannel *rfcomm = gw->rfcomm;
-	gsize read;
-	gchar *result, *sep;
-	DBusMessage *reply;
-	GIOStatus status;
-
-	if (!gw->rfcomm)
-		return g_dbus_create_error(msg, ERROR_INTERFACE
-					".NotConnected",
-					"Not Connected");
-
-	rfcomm_stop_watch(dev);
-	io_channel_write_all(rfcomm, AG_GET_CARRIER, strlen(AG_GET_CARRIER));
-
-	status = g_io_channel_read_chars(rfcomm, buf, RFCOMM_BUF_SIZE - 1,
-						&read, NULL);
-	rfcomm_start_watch(dev);
-	if (G_IO_STATUS_NORMAL == status) {
-		buf[read] = '\0';
-		if (strstr(buf, "+COPS")) {
-			if (!strrchr(buf, ','))
-				result = "0";
-			else {
-				result = strchr(buf, '\"') + 1;
-				sep = strchr(result, '\"');
-				sep[0] = '\0';
-			}
-
-			reply = dbus_message_new_method_return(msg);
-			dbus_message_append_args(reply, DBUS_TYPE_STRING,
-						&result, DBUS_TYPE_INVALID);
-		} else {
-			info("ag_get_operator(): '+COPS' expected but"
-				" '%s' received", buf);
-			reply = dbus_message_new_error(msg, ERROR_INTERFACE
-						".Failed",
-						"Unexpected response from AG");
-		}
-	} else {
-		error("ag_get_operator(): %m");
-		reply = dbus_message_new_error(msg, ERROR_INTERFACE
-					".ConnectionFailed",
-					"Failed to receive response from AG");
-	}
-
-	return reply;
-}
-
-#define AG_SEND_DTMF "AT+VTS=%c\r"
-static DBusMessage *ag_send_dtmf(DBusConnection *conn, DBusMessage *msg,
-				void *data)
-{
-	struct audio_device *device = data;
-	struct gateway *gw = device->gateway;
-	gchar buf[RFCOMM_BUF_SIZE];
-	gchar *number;
-	gint com_len;
-	gboolean got_ok = TRUE;
-	gint num_len;
-	gint i = 0;
-
-	if (!gw->rfcomm)
-		return g_dbus_create_error(msg, ERROR_INTERFACE
-					".NotConnected",
-					"Not Connected");
-
-	dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
-				DBUS_TYPE_INVALID);
-	if (strlen(number) != strspn(number, ALLOWED_NUMBER_SYMBOLS))
-		return dbus_message_new_error(msg,
-			ERROR_INTERFACE ".BadNumber",
-			"Number contains characters which are not allowed");
-
-	num_len = strlen(number);
-	rfcomm_stop_watch(device);
-	while (i < num_len && got_ok) {
-		com_len = sprintf(buf, AG_SEND_DTMF, number[i]);
-		rfcomm_send_and_read(gw, buf, buf, com_len);
-		got_ok = NULL != strstr(buf, OK_RESPONSE);
-		i += 1;
-	}
-	rfcomm_start_watch(device);
-	return process_ag_reponse(msg, buf);
-}
-
-#define AG_GET_SUBSCRIBER_NUMS "AT+CNUM\r"
-#define CNUM_LEN 5             /* length of "+CNUM" string */
-#define MAX_NUMBER_CNT 16
-static DBusMessage *ag_get_subscriber_num(DBusConnection *conn,
-					DBusMessage *msg, void *data)
-{
-	struct audio_device *device = data;
-	struct gateway *gw = device->gateway;
-	gchar buf[RFCOMM_BUF_SIZE];
-	gchar *number, *end;
-	DBusMessage *reply = dbus_message_new_method_return(msg);
-
-	if (!gw->rfcomm)
-		return g_dbus_create_error(msg, ERROR_INTERFACE
-					".NotConnected",
-					"Not Connected");
-
-	rfcomm_stop_watch(device);
-	rfcomm_send_and_read(gw, AG_GET_SUBSCRIBER_NUMS, buf,
-			strlen(AG_GET_SUBSCRIBER_NUMS));
-	rfcomm_start_watch(device);
-
-	if (strlen(buf) > AG_CALLER_NUM_SIZE + 21)
-		error("ag_get_subscriber_num(): buf is too long '%s'", buf);
-	else if (strstr(buf, "+CNUM")) {
-		number = strchr(buf, ',');
-		number++;
-		end = strchr(number, ',');
-		if (end) {
-			*end = '\0';
-			dbus_message_append_args(reply, DBUS_TYPE_STRING,
-						&number, DBUS_TYPE_INVALID);
-		}
-	} else
-		error("ag_get_subscriber_num(): read wrong data '%s'", buf);
-
-	return reply;
+	agent_free(agent);
+	gateway->agent = NULL;
 }
 
 static DBusMessage *ag_get_properties(DBusConnection *conn, DBusMessage *msg,
@@ -977,9 +456,8 @@
 	DBusMessage *reply;
 	DBusMessageIter iter;
 	DBusMessageIter dict;
-	gboolean value;
-	guint index = 0;
-	struct indicator *ind;
+	const char *value;
+
 
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
@@ -992,80 +470,131 @@
 			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
 			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
 
-	/* Connected */
-	value = gateway_is_connected(device);
-	dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value);
+	value = state2str(gw->state);
+	dict_append_entry(&dict, "State",
+			DBUS_TYPE_STRING, &value);
 
-	if (!value)
+	dbus_message_iter_close_container(&iter, &dict);
+
+	return reply;
+}
+
+static DBusMessage *register_agent(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	struct audio_device *device = data;
+	struct gateway *gw = device->gateway;
+	struct hf_agent *agent;
+	const char *path, *name;
+
+	if (gw->agent)
+		return g_dbus_create_error(msg,
+					ERROR_INTERFACE ".AlreadyExists",
+					"Agent already exists");
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+						DBUS_TYPE_INVALID))
+		return g_dbus_create_error(msg,
+					ERROR_INTERFACE ".InvalidArguments",
+					"Invalid argument");
+
+	name = dbus_message_get_sender(msg);
+	agent = g_new0(struct hf_agent, 1);
+
+	agent->name = g_strdup(name);
+	agent->path = g_strdup(path);
+
+	agent->watch = g_dbus_add_disconnect_watch(conn, name,
+						agent_exited, gw, NULL);
+
+	gw->agent = agent;
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_agent(DBusConnection *conn,
+				DBusMessage *msg, void *data)
+{
+	struct audio_device *device = data;
+	struct gateway *gw = device->gateway;
+	const char *path;
+
+	if (!gw->agent)
 		goto done;
 
-	while ((ind = g_slist_nth_data(gw->indies, index))) {
-		if(!strcmp(ind->descr, "\"service\""))
-			dict_append_entry(&dict, "RegistrationStatus",
-					DBUS_TYPE_UINT16, &ind->value);
-		else if (!strcmp(ind->descr, "\"signal\""))
-			dict_append_entry(&dict, "SignalStrength",
-					DBUS_TYPE_UINT16, &ind->value);
-		else if (!strcmp(ind->descr, "\"roam\""))
-			dict_append_entry(&dict, "RoamingStatus",
-					DBUS_TYPE_UINT16, &ind->value);
-		else if (!strcmp(ind->descr, "\"battchg\""))
-			dict_append_entry(&dict, "BatteryCharge",
-					DBUS_TYPE_UINT16, &ind->value);
-		index++;
-	}
+	if (strcmp(gw->agent->name, dbus_message_get_sender(msg)) != 0)
+		return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+							"Permission denied");
 
-	/* SpeakerGain */
-	dict_append_entry(&dict, "SpeakerGain", DBUS_TYPE_UINT16,
-				&device->gateway->sp_gain);
+	if (!dbus_message_get_args(msg, NULL,
+				DBUS_TYPE_OBJECT_PATH, &path,
+				DBUS_TYPE_INVALID))
+		return g_dbus_create_error(msg,
+				ERROR_INTERFACE ".InvalidArguments",
+				"Invalid argument");
 
-	/* MicrophoneGain */
-	dict_append_entry(&dict, "MicrophoneGain", DBUS_TYPE_UINT16,
-				&device->gateway->mic_gain);
+	if (strcmp(gw->agent->path, path) != 0)
+		return g_dbus_create_error(msg,
+				ERROR_INTERFACE ".Failed",
+				"Unknown object path");
+
+	g_dbus_remove_watch(device->conn, gw->agent->watch);
+
+	agent_free(gw->agent);
+	gw->agent = NULL;
+
 done:
-	dbus_message_iter_close_container(&iter, &dict);
-	return reply;
+	return dbus_message_new_method_return(msg);
 }
 
 static GDBusMethodTable gateway_methods[] = {
 	{ "Connect", "", "", ag_connect, G_DBUS_METHOD_FLAG_ASYNC },
-	{ "Disconnect", "", "", ag_disconnect },
-	{ "AnswerCall", "", "", ag_answer },
-	{ "TerminateCall", "", "", ag_terminate_call },
-	{ "Call", "s", "", ag_call },
-	{ "GetOperatorName", "", "s", ag_get_operator },
-	{ "SendDTMF", "s", "", ag_send_dtmf },
-	{ "GetSubscriberNumber", "", "s", ag_get_subscriber_num },
+	{ "Disconnect", "", "", ag_disconnect, G_DBUS_METHOD_FLAG_ASYNC },
 	{ "GetProperties", "", "a{sv}", ag_get_properties },
+	{ "RegisterAgent", "o", "", register_agent },
+	{ "UnregisterAgent", "o", "", unregister_agent },
 	{ NULL, NULL, NULL, NULL }
 };
 
 static GDBusSignalTable gateway_signals[] = {
-	{ "Ring", "s" },
-	{ "CallTerminated", "" },
-	{ "CallStarted", "" },
-	{ "CallEnded", "" },
 	{ "PropertyChanged", "sv" },
 	{ NULL, NULL }
 };
 
+static void path_unregister(void *data)
+{
+	struct audio_device *dev = data;
+
+	DBG("Unregistered interface %s on path %s",
+		AUDIO_GATEWAY_INTERFACE, dev->path);
+
+	gateway_close(dev);
+
+	g_free(dev->gateway);
+	dev->gateway = NULL;
+}
+
+void gateway_unregister(struct audio_device *dev)
+{
+	if (dev->gateway->agent)
+		agent_disconnect(dev, dev->gateway->agent);
+
+	g_dbus_unregister_interface(dev->conn, dev->path,
+						AUDIO_GATEWAY_INTERFACE);
+}
+
 struct gateway *gateway_init(struct audio_device *dev)
 {
-	struct gateway *gw;
+	if (DBUS_TYPE_UNIX_FD < 0)
+		return NULL;
 
 	if (!g_dbus_register_interface(dev->conn, dev->path,
 					AUDIO_GATEWAY_INTERFACE,
 					gateway_methods, gateway_signals,
-					NULL, dev, NULL))
+					NULL, dev, path_unregister))
 		return NULL;
 
-	debug("in gateway_init, dev is %p", dev);
-	gw = g_new0(struct gateway, 1);
-	gw->indies = NULL;
-	gw->is_dialing = FALSE;
-	gw->call_active = FALSE;
-	gw->state = GATEWAY_STATE_DISCONNECTED;
-	return gw;
+	return g_new0(struct gateway, 1);
 
 }
 
@@ -1080,8 +609,7 @@
 	if (!io)
 		return -EINVAL;
 
-	g_io_channel_ref(io);
-	dev->gateway->rfcomm = io;
+	dev->gateway->rfcomm = g_io_channel_ref(io);
 
 	return 0;
 }
@@ -1096,49 +624,25 @@
 	gw->sco = g_io_channel_ref(io);
 
 	g_io_add_watch(gw->sco, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-                                (GIOFunc) sco_io_cb, dev);
+						(GIOFunc) sco_io_cb, dev);
+
+	change_state(dev, GATEWAY_STATE_PLAYING);
+
 	return 0;
 }
 
-void gateway_start_service(struct audio_device *device)
+void gateway_start_service(struct audio_device *dev)
 {
-	rfcomm_connect_cb(device->gateway->rfcomm, NULL, device);
-}
+	struct gateway *gw = dev->gateway;
+	GError *err = NULL;
 
-static void indicator_slice_free(gpointer mem)
-{
-	g_slice_free(struct indicator, mem);
-}
+	if (gw->rfcomm == NULL)
+		return;
 
-int gateway_close(struct audio_device *device)
-{
-	struct gateway *gw = device->gateway;
-	GIOChannel *rfcomm = gw->rfcomm;
-	GIOChannel *sco = gw->sco;
-	gboolean value = FALSE;
-
-	g_slist_foreach(gw->indies, (GFunc) indicator_slice_free, NULL);
-	g_slist_free(gw->indies);
-	if (rfcomm) {
-		g_io_channel_shutdown(rfcomm, TRUE, NULL);
-		g_io_channel_unref(rfcomm);
-		gw->rfcomm = NULL;
+	if (!bt_io_accept(gw->rfcomm, rfcomm_connect_cb, dev, NULL, &err)) {
+		error("bt_io_accept: %s", err->message);
+		g_error_free(err);
 	}
-
-	if (sco) {
-		g_io_channel_shutdown(sco, TRUE, NULL);
-		g_io_channel_unref(sco);
-		gw->sco = NULL;
-		gw->sco_start_cb = NULL;
-		gw->sco_start_cb_data = NULL;
-	}
-
-	gw->state = GATEWAY_STATE_DISCONNECTED;
-
-	emit_property_changed(device->conn, device->path,
-				AUDIO_GATEWAY_INTERFACE,
-				"Connected", DBUS_TYPE_BOOLEAN, &value);
-	return 0;
 }
 
 /* These are functions to be called from unix.c for audio system
@@ -1166,10 +670,8 @@
 			g_error_free(err);
 			return FALSE;
 		}
-	} else {
-		if (cb)
-			cb(dev, user_data);
-	}
+	} else if (cb)
+		cb(dev, err, user_data);
 
 	return TRUE;
 }
@@ -1186,7 +688,7 @@
 	}
 
 	if (sco_cb)
-		sco_cb(dev, user_data);
+		sco_cb(dev, NULL, user_data);
 
 	return 0;
 }
@@ -1220,4 +722,3 @@
 	gw->sco_start_cb = NULL;
 	gw->sco_start_cb_data = NULL;
 }
-
diff --git a/audio/gateway.h b/audio/gateway.h
index e539469..a45ef82 100644
--- a/audio/gateway.h
+++ b/audio/gateway.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -22,20 +22,24 @@
  *
  */
 
-#define AUDIO_GATEWAY_INTERFACE "org.bluez.HeadsetGateway"
+#define AUDIO_GATEWAY_INTERFACE "org.bluez.HandsfreeGateway"
 
-#define DEFAULT_HSP_HS_CHANNEL 6
 #define DEFAULT_HFP_HS_CHANNEL 7
 
 typedef enum {
 	GATEWAY_STATE_DISCONNECTED,
-	GATEWAY_STATE_CONNECTED
+	GATEWAY_STATE_CONNECTING,
+	GATEWAY_STATE_CONNECTED,
+	GATEWAY_STATE_PLAYING,
 } gateway_state_t;
 
-typedef void (*gateway_stream_cb_t) (struct audio_device *dev, void *user_data);
+typedef void (*gateway_stream_cb_t) (struct audio_device *dev, GError *err,
+		void *user_data);
+
+void gateway_unregister(struct audio_device *dev);
 struct gateway *gateway_init(struct audio_device *device);
 gboolean gateway_is_connected(struct audio_device *dev);
-int gateway_connect_rfcomm(struct audio_device *dev, GIOChannel *chan);
+int gateway_connect_rfcomm(struct audio_device *dev, GIOChannel *io);
 int gateway_connect_sco(struct audio_device *dev, GIOChannel *chan);
 void gateway_start_service(struct audio_device *device);
 gboolean gateway_request_stream(struct audio_device *dev,
diff --git a/audio/gsta2dpsink.c b/audio/gsta2dpsink.c
index 0753f38..492fc63 100644
--- a/audio/gsta2dpsink.c
+++ b/audio/gsta2dpsink.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
@@ -28,6 +28,7 @@
 #include <unistd.h>
 #include <pthread.h>
 
+#include "gstpragma.h"
 #include "gsta2dpsink.h"
 
 GType gst_avdtp_sink_get_type(void);
@@ -143,8 +144,7 @@
 	return NULL;
 
 cleanup_and_fail:
-	if (element != NULL)
-		g_object_unref(G_OBJECT(element));
+	g_object_unref(G_OBJECT(element));
 
 	return NULL;
 }
diff --git a/audio/gsta2dpsink.h b/audio/gsta2dpsink.h
index 902b678..3ff4e45 100644
--- a/audio/gsta2dpsink.h
+++ b/audio/gsta2dpsink.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/audio/gstavdtpsink.c b/audio/gstavdtpsink.c
index bc25bd1..f0e5b76 100644
--- a/audio/gstavdtpsink.c
+++ b/audio/gstavdtpsink.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
@@ -40,6 +40,7 @@
 #include "ipc.h"
 #include "rtp.h"
 
+#include "gstpragma.h"
 #include "gstavdtpsink.h"
 
 GST_DEBUG_CATEGORY_STATIC(avdtp_sink_debug);
@@ -1089,6 +1090,7 @@
 	req->h.type = BT_REQUEST;
 	req->h.name = BT_SET_CONFIGURATION;
 	req->h.length = sizeof(*req);
+	memcpy(&req->codec, codec, sizeof(req->codec));
 
 	if (codec->type == BT_A2DP_SBC_SINK)
 		ret = gst_avdtp_sink_init_sbc_pkt_conf(self, caps,
diff --git a/audio/gstavdtpsink.h b/audio/gstavdtpsink.h
index b4bee39..eb78248 100644
--- a/audio/gstavdtpsink.h
+++ b/audio/gstavdtpsink.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/audio/gstbluetooth.c b/audio/gstbluetooth.c
index 7775b48..9930820 100644
--- a/audio/gstbluetooth.c
+++ b/audio/gstbluetooth.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
@@ -50,21 +50,24 @@
 	sbc_t sbc;
 	guint8 *data = gst_type_find_peek(tf, 0, 32);
 
-	if (sbc_init(&sbc, 0) < 0)
+	if (data == NULL)
 		return;
 
-	if (data == NULL || *data != 0x9c)	/* SBC syncword */
+	if (sbc_init(&sbc, 0) < 0)
 		return;
 
 	aux = g_new(guint8, 32);
 	memcpy(aux, data, 32);
-	sbc_parse(&sbc, aux, 32);
-	g_free(aux);
-	caps = gst_sbc_parse_caps_from_sbc(&sbc);
-	sbc_finish(&sbc);
+	if (sbc_parse(&sbc, aux, 32) < 0)
+		goto done;
 
+	caps = gst_sbc_parse_caps_from_sbc(&sbc);
 	gst_type_find_suggest(tf, GST_TYPE_FIND_POSSIBLE, caps);
 	gst_caps_unref(caps);
+
+done:
+	g_free(aux);
+	sbc_finish(&sbc);
 }
 
 static gchar *sbc_exts[] = { "sbc", NULL };
diff --git a/audio/gstpragma.h b/audio/gstpragma.h
new file mode 100644
index 0000000..00eb408
--- /dev/null
+++ b/audio/gstpragma.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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
+ *
+ */
+
+#pragma GCC diagnostic warning "-Wmissing-declarations"
diff --git a/audio/gstrtpsbcpay.c b/audio/gstrtpsbcpay.c
index 78ffb2a..1159bfe 100644
--- a/audio/gstrtpsbcpay.c
+++ b/audio/gstrtpsbcpay.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
@@ -25,6 +25,7 @@
 #include <config.h>
 #endif
 
+#include "gstpragma.h"
 #include "gstrtpsbcpay.h"
 #include <math.h>
 #include <string.h>
diff --git a/audio/gstrtpsbcpay.h b/audio/gstrtpsbcpay.h
index 7b314aa..a444b49 100644
--- a/audio/gstrtpsbcpay.h
+++ b/audio/gstrtpsbcpay.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/audio/gstsbcdec.c b/audio/gstsbcdec.c
index 4b46f52..2e5cb0a 100644
--- a/audio/gstsbcdec.c
+++ b/audio/gstsbcdec.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
@@ -27,6 +27,7 @@
 
 #include <string.h>
 
+#include "gstpragma.h"
 #include "gstsbcutil.h"
 #include "gstsbcdec.h"
 
diff --git a/audio/gstsbcdec.h b/audio/gstsbcdec.h
index 383a3bf..6a15fb0 100644
--- a/audio/gstsbcdec.h
+++ b/audio/gstsbcdec.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c
index 0ecf39c..d2de4ee 100644
--- a/audio/gstsbcenc.c
+++ b/audio/gstsbcenc.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
@@ -27,6 +27,7 @@
 
 #include <string.h>
 
+#include "gstpragma.h"
 #include "gstsbcutil.h"
 #include "gstsbcenc.h"
 
diff --git a/audio/gstsbcenc.h b/audio/gstsbcenc.h
index 6d69922..0c8508b 100644
--- a/audio/gstsbcenc.h
+++ b/audio/gstsbcenc.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/audio/gstsbcparse.c b/audio/gstsbcparse.c
index 30d56ba..a44b52c 100644
--- a/audio/gstsbcparse.c
+++ b/audio/gstsbcparse.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
@@ -27,6 +27,7 @@
 
 #include <string.h>
 
+#include "gstpragma.h"
 #include "gstsbcutil.h"
 #include "gstsbcparse.h"
 
diff --git a/audio/gstsbcparse.h b/audio/gstsbcparse.h
index ef3d1d8..d7331ad 100644
--- a/audio/gstsbcparse.h
+++ b/audio/gstsbcparse.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/audio/gstsbcutil.c b/audio/gstsbcutil.c
index b102da3..63c90c2 100644
--- a/audio/gstsbcutil.c
+++ b/audio/gstsbcutil.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/audio/gstsbcutil.h b/audio/gstsbcutil.h
index b8f626b..a7f84d5 100644
--- a/audio/gstsbcutil.h
+++ b/audio/gstsbcutil.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/audio/headset.c b/audio/headset.c
index 2c852d1..99d4c7a 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -51,7 +51,7 @@
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 #include "device.h"
 #include "manager.h"
 #include "error.h"
@@ -100,7 +100,7 @@
 
 static char *str_state[] = {
 	"HEADSET_STATE_DISCONNECTED",
-	"HEADSET_STATE_CONNECT_IN_PROGRESS",
+	"HEADSET_STATE_CONNECTING",
 	"HEADSET_STATE_CONNECTED",
 	"HEADSET_STATE_PLAY_IN_PROGRESS",
 	"HEADSET_STATE_PLAYING",
@@ -128,6 +128,25 @@
 	uint16_t svclass;
 };
 
+struct headset_slc {
+	char buf[BUF_SIZE];
+	int data_start;
+	int data_length;
+
+	gboolean cli_active;
+	gboolean cme_enabled;
+	gboolean cwa_enabled;
+	gboolean pending_ring;
+	gboolean inband_ring;
+	gboolean nrec;
+	gboolean nrec_req;
+
+	int sp_gain;
+	int mic_gain;
+
+	unsigned int hf_features;
+};
+
 struct headset {
 	uint32_t hsp_handle;
 	uint32_t hfp_handle;
@@ -144,28 +163,14 @@
 
 	guint dc_timer;
 
-	char buf[BUF_SIZE];
-	int data_start;
-	int data_length;
-
 	gboolean hfp_active;
 	gboolean search_hfp;
-	gboolean cli_active;
-	gboolean cme_enabled;
-	gboolean cwa_enabled;
-	gboolean pending_ring;
-	gboolean inband_ring;
-	gboolean nrec;
-	gboolean nrec_req;
 
 	headset_state_t state;
 	struct pending_connect *pending;
 
-	int sp_gain;
-	int mic_gain;
-
-	unsigned int hf_features;
 	headset_lock_t lock;
+	struct headset_slc *slc;
 };
 
 struct event {
@@ -193,7 +198,7 @@
 {
 	return error_common_reply(conn, msg,
 			ERROR_INTERFACE ".ConnectionAttemptFailed",
-			err > 0 ? strerror(err) : "Connection attempt failed");
+			err < 0 ? strerror(-err) : "Connection attempt failed");
 }
 
 static int rfcomm_connect(struct audio_device *device, headset_stream_cb_t cb,
@@ -207,7 +212,7 @@
 	char *str;
 
 	if (features == 0) {
-		debug("HFP AG features: (none)");
+		DBG("HFP AG features: (none)");
 		return;
 	}
 
@@ -234,7 +239,7 @@
 
 	str = g_string_free(gstr, FALSE);
 
-	debug("%s", str);
+	DBG("%s", str);
 
 	g_free(str);
 }
@@ -245,7 +250,7 @@
 	char *str;
 
 	if (features == 0) {
-		debug("HFP HF features: (none)");
+		DBG("HFP HF features: (none)");
 		return;
 	}
 
@@ -268,7 +273,7 @@
 
 	str = g_string_free(gstr, FALSE);
 
-	debug("%s", str);
+	DBG("%s", str);
 
 	g_free(str);
 }
@@ -278,7 +283,7 @@
 	switch (state) {
 	case HEADSET_STATE_DISCONNECTED:
 		return "disconnected";
-	case HEADSET_STATE_CONNECT_IN_PROGRESS:
+	case HEADSET_STATE_CONNECTING:
 		return "connecting";
 	case HEADSET_STATE_CONNECTED:
 	case HEADSET_STATE_PLAY_IN_PROGRESS:
@@ -338,14 +343,15 @@
 static int supported_features(struct audio_device *device, const char *buf)
 {
 	struct headset *hs = device->headset;
+	struct headset_slc *slc = hs->slc;
 	int err;
 
 	if (strlen(buf) < 9)
 		return -EINVAL;
 
-	hs->hf_features = strtoul(&buf[8], NULL, 10);
+	slc->hf_features = strtoul(&buf[8], NULL, 10);
 
-	print_hf_features(hs->hf_features);
+	print_hf_features(slc->hf_features);
 
 	err = headset_send(hs, "\r\n+BRSF: %u\r\n", ag.features);
 	if (err < 0)
@@ -429,7 +435,7 @@
 {
 	struct headset *hs = dev->headset;
 
-	if (hs->pending->err)
+	if (hs->pending->err < 0)
 		cb->cb(NULL, cb->cb_data);
 	else
 		cb->cb(dev, cb->cb_data);
@@ -534,10 +540,12 @@
 
 static int cli_cmp(struct headset *hs)
 {
+	struct headset_slc *slc = hs->slc;
+
 	if (!hs->hfp_active)
 		return -1;
 
-	if (hs->cli_active)
+	if (slc->cli_active)
 		return 0;
 	else
 		return -1;
@@ -560,15 +568,20 @@
 	int sk;
 	struct audio_device *dev = user_data;
 	struct headset *hs = dev->headset;
+	struct headset_slc *slc = hs->slc;
 	struct pending_connect *p = hs->pending;
 
 	if (err) {
 		error("%s", err->message);
 
-		if (p && p->msg)
-			error_connection_attempt_failed(dev->conn, p->msg, p->err);
-
-		pending_connect_finalize(dev);
+		if (p != NULL) {
+			p->err = -errno;
+			if (p->msg)
+				error_connection_attempt_failed(dev->conn,
+								p->msg,
+								p->err);
+			pending_connect_finalize(dev);
+		}
 
 		if (hs->rfcomm)
 			headset_set_state(dev, HEADSET_STATE_CONNECTED);
@@ -578,11 +591,11 @@
 		return;
 	}
 
-	debug("SCO socket opened for headset %s", dev->path);
+	DBG("SCO socket opened for headset %s", dev->path);
 
 	sk = g_io_channel_unix_get_fd(chan);
 
-	debug("SCO fd=%d", sk);
+	DBG("SCO fd=%d", sk);
 
 	if (p) {
 		p->io = NULL;
@@ -599,12 +612,12 @@
 
 	headset_set_state(dev, HEADSET_STATE_PLAYING);
 
-	if (hs->pending_ring) {
+	if (slc->pending_ring) {
 		ring_timer_cb(NULL);
 		ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL,
 						ring_timer_cb,
 						NULL);
-		hs->pending_ring = FALSE;
+		slc->pending_ring = FALSE;
 	}
 }
 
@@ -657,7 +670,7 @@
 	struct headset *hs = dev->headset;
 	struct pending_connect *p = hs->pending;
 
-	debug("HFP Service Level Connection established");
+	DBG("HFP Service Level Connection established");
 
 	headset_set_state(dev, HEADSET_STATE_CONNECTED);
 
@@ -684,9 +697,10 @@
 static int telephony_generic_rsp(struct audio_device *device, cme_error_t err)
 {
 	struct headset *hs = device->headset;
+	struct headset_slc *slc = hs->slc;
 
 	if (err != CME_ERROR_NONE) {
-		if (hs->cme_enabled)
+		if (slc->cme_enabled)
 			return headset_send(hs, "\r\n+CME ERROR: %d\r\n", err);
 		else
 			return headset_send(hs, "\r\nERROR\r\n");
@@ -699,6 +713,7 @@
 {
 	struct audio_device *device = telephony_device;
 	struct headset *hs = device->headset;
+	struct headset_slc *slc = hs->slc;
 	int ret;
 
 	if (err != CME_ERROR_NONE)
@@ -708,10 +723,10 @@
 	if (ret < 0)
 		return ret;
 
-	if (hs->state != HEADSET_STATE_CONNECT_IN_PROGRESS)
+	if (hs->state != HEADSET_STATE_CONNECTING)
 		return 0;
 
-	if (hs->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY &&
+	if (slc->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY &&
 			ag.features & AG_FEATURE_THREE_WAY_CALLING)
 		return 0;
 
@@ -739,7 +754,7 @@
 	g_strfreev(tokens);
 	tokens = NULL;
 
-	debug("Event reporting (CMER): mode=%d, ind=%d",
+	DBG("Event reporting (CMER): mode=%d, ind=%d",
 			ag.er_mode, ag.er_ind);
 
 	switch (ag.er_ind) {
@@ -775,7 +790,7 @@
 	if (err < 0)
 		return err;
 
-	if (hs->state != HEADSET_STATE_CONNECT_IN_PROGRESS)
+	if (hs->state != HEADSET_STATE_CONNECTING)
 		return 0;
 
 	hfp_slc_complete(dev);
@@ -865,11 +880,12 @@
 static int cli_notification(struct audio_device *device, const char *buf)
 {
 	struct headset *hs = device->headset;
+	struct headset_slc *slc = hs->slc;
 
 	if (strlen(buf) < 9)
 		return -EINVAL;
 
-	hs->cli_active = buf[8] == '1' ? TRUE : FALSE;
+	slc->cli_active = buf[8] == '1' ? TRUE : FALSE;
 
 	return headset_send(hs, "\r\nOK\r\n");
 }
@@ -922,7 +938,7 @@
 	buf_len = strlen(buf);
 
 	if (buf[buf_len - 1] != ';') {
-		debug("Rejecting non-voice call dial request");
+		DBG("Rejecting non-voice call dial request");
 		return -EINVAL;
 	}
 
@@ -934,39 +950,35 @@
 	return 0;
 }
 
-static int signal_gain_setting(struct audio_device *device, const char *buf)
+static int headset_set_gain(struct audio_device *device, uint16_t gain, char type)
 {
 	struct headset *hs = device->headset;
-	const char *property;
-	const char *name;
-	dbus_uint16_t gain;
-
-	if (strlen(buf) < 8) {
-		error("Too short string for Gain setting");
-		return -EINVAL;
-	}
-
-	gain = (dbus_uint16_t) strtol(&buf[7], NULL, 10);
+	struct headset_slc *slc = hs->slc;
+	const char *name, *property;
 
 	if (gain > 15) {
-		error("Invalid gain value received: %u", gain);
+		error("Invalid gain value: %u", gain);
 		return -EINVAL;
 	}
 
-	switch (buf[5]) {
+	switch (type) {
 	case HEADSET_GAIN_SPEAKER:
-		if (hs->sp_gain == gain)
-			goto ok;
+		if (slc->sp_gain == gain) {
+			DBG("Ignoring no-change in speaker gain");
+			return 0;
+		}
 		name = "SpeakerGainChanged";
 		property = "SpeakerGain";
-		hs->sp_gain = gain;
+		slc->sp_gain = gain;
 		break;
 	case HEADSET_GAIN_MICROPHONE:
-		if (hs->mic_gain == gain)
-			goto ok;
+		if (slc->mic_gain == gain) {
+			DBG("Ignoring no-change in microphone gain");
+			return 0;
+		}
 		name = "MicrophoneGainChanged";
 		property = "MicrophoneGain";
-		hs->mic_gain = gain;
+		slc->mic_gain = gain;
 		break;
 	default:
 		error("Unknown gain setting");
@@ -982,7 +994,26 @@
 				AUDIO_HEADSET_INTERFACE, property,
 				DBUS_TYPE_UINT16, &gain);
 
-ok:
+	return 0;
+}
+
+static int signal_gain_setting(struct audio_device *device, const char *buf)
+{
+	struct headset *hs = device->headset;
+	dbus_uint16_t gain;
+	int err;
+
+	if (strlen(buf) < 8) {
+		error("Too short string for Gain setting");
+		return -EINVAL;
+	}
+
+	gain = (dbus_uint16_t) strtol(&buf[7], NULL, 10);
+
+	err = headset_set_gain(device, gain, buf[5]);
+	if (err < 0)
+		return err;
+
 	return headset_send(hs, "\r\nOK\r\n");
 }
 
@@ -1030,16 +1061,17 @@
 static int extended_errors(struct audio_device *device, const char *buf)
 {
 	struct headset *hs = device->headset;
+	struct headset_slc *slc = hs->slc;
 
 	if (strlen(buf) < 9)
 		return -EINVAL;
 
 	if (buf[8] == '1') {
-		hs->cme_enabled = TRUE;
-		debug("CME errors enabled for headset %p", hs);
+		slc->cme_enabled = TRUE;
+		DBG("CME errors enabled for headset %p", hs);
 	} else {
-		hs->cme_enabled = FALSE;
-		debug("CME errors disabled for headset %p", hs);
+		slc->cme_enabled = FALSE;
+		DBG("CME errors disabled for headset %p", hs);
 	}
 
 	return headset_send(hs, "\r\nOK\r\n");
@@ -1048,16 +1080,17 @@
 static int call_waiting_notify(struct audio_device *device, const char *buf)
 {
 	struct headset *hs = device->headset;
+	struct headset_slc *slc = hs->slc;
 
 	if (strlen(buf) < 9)
 		return -EINVAL;
 
 	if (buf[8] == '1') {
-		hs->cwa_enabled = TRUE;
-		debug("Call waiting notification enabled for headset %p", hs);
+		slc->cwa_enabled = TRUE;
+		DBG("Call waiting notification enabled for headset %p", hs);
 	} else {
-		hs->cwa_enabled = FALSE;
-		debug("Call waiting notification disabled for headset %p", hs);
+		slc->cwa_enabled = FALSE;
+		DBG("Call waiting notification disabled for headset %p", hs);
 	}
 
 	return headset_send(hs, "\r\nOK\r\n");
@@ -1077,13 +1110,19 @@
 {
 	struct audio_device *device = telephony_device;
 	struct headset *hs = device->headset;
+	struct headset_slc *slc = hs->slc;
 
 	if (err == CME_ERROR_NONE)
-		hs->nrec = hs->nrec_req;
+		slc->nrec = hs->slc->nrec_req;
 
 	return telephony_generic_rsp(telephony_device, err);
 }
 
+int telephony_voice_dial_rsp(void *telephony_device, cme_error_t err)
+{
+	return telephony_generic_rsp(telephony_device, err);
+}
+
 int telephony_operator_selection_ind(int mode, const char *oper)
 {
 	if (!active_devices)
@@ -1118,16 +1157,34 @@
 static int nr_and_ec(struct audio_device *device, const char *buf)
 {
 	struct headset *hs = device->headset;
+	struct headset_slc *slc = hs->slc;
 
 	if (strlen(buf) < 9)
 		return -EINVAL;
 
 	if (buf[8] == '0')
-		hs->nrec_req = FALSE;
+		slc->nrec_req = FALSE;
 	else
-		hs->nrec_req = TRUE;
+		slc->nrec_req = TRUE;
 
-	telephony_nr_and_ec_req(device, hs->nrec_req);
+	telephony_nr_and_ec_req(device, slc->nrec_req);
+
+	return 0;
+}
+
+static int voice_dial(struct audio_device *device, const char *buf)
+{
+	gboolean enable;
+
+	if (strlen(buf) < 9)
+		return -EINVAL;
+
+	if (buf[8] == '0')
+		enable = FALSE;
+	else
+		enable = TRUE;
+
+	telephony_voice_dial_req(device, enable);
 
 	return 0;
 }
@@ -1152,6 +1209,7 @@
 	{ "AT+CCWA", call_waiting_notify },
 	{ "AT+COPS", operator_selection },
 	{ "AT+NREC", nr_and_ec },
+	{ "AT+BVRA", voice_dial },
 	{ 0 }
 };
 
@@ -1159,7 +1217,7 @@
 {
 	struct event *ev;
 
-	debug("Received %s", buf);
+	DBG("Received %s", buf);
 
 	for (ev = event_callbacks; ev->cmd; ev++) {
 		if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))
@@ -1191,6 +1249,7 @@
 				struct audio_device *device)
 {
 	struct headset *hs;
+	struct headset_slc *slc;
 	unsigned char buf[BUF_SIZE];
 	gsize bytes_read = 0;
 	gsize free_space;
@@ -1199,9 +1258,10 @@
 		return FALSE;
 
 	hs = device->headset;
+	slc = hs->slc;
 
 	if (cond & (G_IO_ERR | G_IO_HUP)) {
-		debug("ERR or HUP on RFCOMM socket");
+		DBG("ERR or HUP on RFCOMM socket");
 		goto failed;
 	}
 
@@ -1209,7 +1269,8 @@
 				&bytes_read) != G_IO_ERROR_NONE)
 		return TRUE;
 
-	free_space = sizeof(hs->buf) - hs->data_start - hs->data_length - 1;
+	free_space = sizeof(slc->buf) - slc->data_start -
+			slc->data_length - 1;
 
 	if (free_space < bytes_read) {
 		/* Very likely that the HS is sending us garbage so
@@ -1218,45 +1279,45 @@
 		goto failed;
 	}
 
-	memcpy(&hs->buf[hs->data_start], buf, bytes_read);
-	hs->data_length += bytes_read;
+	memcpy(&slc->buf[slc->data_start], buf, bytes_read);
+	slc->data_length += bytes_read;
 
 	/* Make sure the data is null terminated so we can use string
 	 * functions */
-	hs->buf[hs->data_start + hs->data_length] = '\0';
+	slc->buf[slc->data_start + slc->data_length] = '\0';
 
-	while (hs->data_length > 0) {
+	while (slc->data_length > 0) {
 		char *cr;
 		int err;
 		off_t cmd_len;
 
-		cr = strchr(&hs->buf[hs->data_start], '\r');
+		cr = strchr(&slc->buf[slc->data_start], '\r');
 		if (!cr)
 			break;
 
-		cmd_len = 1 + (off_t) cr - (off_t) &hs->buf[hs->data_start];
+		cmd_len = 1 + (off_t) cr - (off_t) &slc->buf[slc->data_start];
 		*cr = '\0';
 
 		if (cmd_len > 1)
-			err = handle_event(device, &hs->buf[hs->data_start]);
+			err = handle_event(device, &slc->buf[slc->data_start]);
 		else
 			/* Silently skip empty commands */
 			err = 0;
 
 		if (err == -EINVAL) {
 			error("Badly formated or unrecognized command: %s",
-					&hs->buf[hs->data_start]);
+					&slc->buf[slc->data_start]);
 			err = headset_send(hs, "\r\nERROR\r\n");
 		} else if (err < 0)
 			error("Error handling command %s: %s (%d)",
-						&hs->buf[hs->data_start],
+						&slc->buf[slc->data_start],
 						strerror(-err), -err);
 
-		hs->data_start += cmd_len;
-		hs->data_length -= cmd_len;
+		slc->data_start += cmd_len;
+		slc->data_length -= cmd_len;
 
-		if (!hs->data_length)
-			hs->data_start = 0;
+		if (!slc->data_length)
+			slc->data_start = 0;
 	}
 
 	return TRUE;
@@ -1312,7 +1373,10 @@
 	g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
 			(GIOFunc) rfcomm_io_cb, dev);
 
-	debug("%s: Connected to %s", dev->path, hs_address);
+	DBG("%s: Connected to %s", dev->path, hs_address);
+
+	hs->slc = g_new0(struct headset_slc, 1);
+	hs->slc->nrec = TRUE;
 
 	/* In HFP mode wait for Service Level Connection */
 	if (hs->hfp_active)
@@ -1371,10 +1435,10 @@
 
 	if (svc == HANDSFREE_SVCLASS_ID) {
 		headset->hfp_handle = record->handle;
-		debug("Discovered Handsfree service on channel %d", ch);
+		DBG("Discovered Handsfree service on channel %d", ch);
 	} else {
 		headset->hsp_handle = record->handle;
-		debug("Discovered Headset service on channel %d", ch);
+		DBG("Discovered Headset service on channel %d", ch);
 	}
 
 	return 0;
@@ -1387,6 +1451,7 @@
 	struct pending_connect *p = hs->pending;
 	sdp_record_t *record = NULL;
 	sdp_list_t *r;
+	uuid_t uuid;
 
 	assert(hs->pending != NULL);
 
@@ -1403,9 +1468,11 @@
 		goto failed_not_supported;
 	}
 
+	sdp_uuid16_create(&uuid, p->svclass);
+
 	for (r = recs; r != NULL; r = r->next) {
 		sdp_list_t *classes;
-		uuid_t uuid;
+		uuid_t class;
 
 		record = r->data;
 
@@ -1414,16 +1481,12 @@
 			continue;
 		}
 
-		memcpy(&uuid, classes->data, sizeof(uuid));
+		memcpy(&class, classes->data, sizeof(uuid));
 
 		sdp_list_free(classes, free);
 
-		if (!sdp_uuid128_to_uuid(&uuid) || uuid.type != SDP_UUID16) {
-			error("Not a 16 bit UUID");
-			continue;
-		}
 
-		if (uuid.value.uuid16 == p->svclass)
+		if (sdp_uuid_cmp(&class, &uuid) == 0)
 			break;
 	}
 
@@ -1489,7 +1552,7 @@
 		return 0;
 	}
 
-	headset_set_state(device, HEADSET_STATE_CONNECT_IN_PROGRESS);
+	headset_set_state(device, HEADSET_STATE_CONNECTING);
 
 	pending_connect_init(hs, HEADSET_STATE_CONNECTED);
 
@@ -1521,7 +1584,7 @@
 
 	ba2str(&dev->dst, address);
 
-	debug("%s: Connecting to %s channel %d", dev->path, address,
+	DBG("%s: Connecting to %s channel %d", dev->path, address,
 		hs->rfcomm_ch);
 
 	hs->tmp_rfcomm = bt_io_connect(BT_IO_RFCOMM, headset_connect_cb, dev,
@@ -1541,7 +1604,7 @@
 
 	hs->hfp_active = hs->hfp_handle != 0 ? TRUE : FALSE;
 
-	headset_set_state(dev, HEADSET_STATE_CONNECT_IN_PROGRESS);
+	headset_set_state(dev, HEADSET_STATE_CONNECTING);
 
 	pending_connect_init(hs, HEADSET_STATE_CONNECTED);
 
@@ -1643,10 +1706,10 @@
 	struct headset *hs = device->headset;
 	int err;
 
-	if (hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS)
+	if (hs->state == HEADSET_STATE_CONNECTING)
 		return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress",
 						"Connect in Progress");
-	else if (hs->state > HEADSET_STATE_CONNECT_IN_PROGRESS)
+	else if (hs->state > HEADSET_STATE_CONNECTING)
 		return g_dbus_create_error(msg, ERROR_INTERFACE
 						".AlreadyConnected",
 						"Already Connected");
@@ -1691,7 +1754,7 @@
 		return NULL;
 
 	if (ag.ring_timer) {
-		debug("IndicateCall received when already indicating");
+		DBG("IndicateCall received when already indicating");
 		goto done;
 	}
 
@@ -1731,7 +1794,7 @@
 		g_source_remove(ag.ring_timer);
 		ag.ring_timer = 0;
 	} else
-		debug("Got CancelCall method call but no call is active");
+		DBG("Got CancelCall method call but no call is active");
 
 	return reply;
 }
@@ -1752,7 +1815,7 @@
 
 	switch (hs->state) {
 	case HEADSET_STATE_DISCONNECTED:
-	case HEADSET_STATE_CONNECT_IN_PROGRESS:
+	case HEADSET_STATE_CONNECTING:
 		return g_dbus_create_error(msg, ERROR_INTERFACE
 						".NotConnected",
 						"Device not Connected");
@@ -1789,10 +1852,11 @@
 {
 	struct audio_device *device = data;
 	struct headset *hs = device->headset;
+	struct headset_slc *slc = hs->slc;
 	DBusMessage *reply;
 	dbus_uint16_t gain;
 
-	if (hs->state < HEADSET_STATE_CONNECTED || hs->sp_gain < 0)
+	if (hs->state < HEADSET_STATE_CONNECTED)
 		return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",
 						"Operation not Available");
 
@@ -1800,7 +1864,7 @@
 	if (!reply)
 		return NULL;
 
-	gain = (dbus_uint16_t) hs->sp_gain;
+	gain = (dbus_uint16_t) slc->sp_gain;
 
 	dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
 					DBUS_TYPE_INVALID);
@@ -1814,10 +1878,11 @@
 {
 	struct audio_device *device = data;
 	struct headset *hs = device->headset;
+	struct headset_slc *slc = hs->slc;
 	DBusMessage *reply;
 	dbus_uint16_t gain;
 
-	if (hs->state < HEADSET_STATE_CONNECTED || hs->mic_gain < 0)
+	if (hs->state < HEADSET_STATE_CONNECTED || slc == NULL)
 		return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",
 						"Operation not Available");
 
@@ -1825,7 +1890,7 @@
 	if (!reply)
 		return NULL;
 
-	gain = (dbus_uint16_t) hs->mic_gain;
+	gain = (dbus_uint16_t) slc->mic_gain;
 
 	dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
 					DBUS_TYPE_INVALID);
@@ -1848,7 +1913,8 @@
 						".NotConnected",
 						"Device not Connected");
 
-	if (gain > 15)
+	err = headset_set_gain(device, gain, type);
+	if (err < 0)
 		return g_dbus_create_error(msg, ERROR_INTERFACE
 						".InvalidArgument",
 						"Must be less than or equal to 15");
@@ -1857,31 +1923,13 @@
 	if (!reply)
 		return NULL;
 
-	if (hs->state != HEADSET_STATE_PLAYING)
-		goto done;
-
-	err = headset_send(hs, "\r\n+VG%c=%u\r\n", type, gain);
-	if (err < 0) {
-		dbus_message_unref(reply);
-		return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+	if (hs->state == HEADSET_STATE_PLAYING) {
+		err = headset_send(hs, "\r\n+VG%c=%u\r\n", type, gain);
+		if (err < 0) {
+			dbus_message_unref(reply);
+			return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 						"%s", strerror(-err));
-	}
-
-done:
-	if (type == HEADSET_GAIN_SPEAKER) {
-		hs->sp_gain = gain;
-		g_dbus_emit_signal(conn, device->path,
-					AUDIO_HEADSET_INTERFACE,
-					"SpeakerGainChanged",
-					DBUS_TYPE_UINT16, &gain,
-					DBUS_TYPE_INVALID);
-	} else {
-		hs->mic_gain = gain;
-		g_dbus_emit_signal(conn, device->path,
-					AUDIO_HEADSET_INTERFACE,
-					"MicrophoneGainChanged",
-					DBUS_TYPE_UINT16, &gain,
-					DBUS_TYPE_INVALID);
+		}
 	}
 
 	return reply;
@@ -1953,11 +2001,13 @@
 
 	/* SpeakerGain */
 	dict_append_entry(&dict, "SpeakerGain",
-				DBUS_TYPE_UINT16, &device->headset->sp_gain);
+				DBUS_TYPE_UINT16,
+				&device->headset->slc->sp_gain);
 
 	/* MicrophoneGain */
 	dict_append_entry(&dict, "MicrophoneGain",
-				DBUS_TYPE_UINT16, &device->headset->mic_gain);
+				DBUS_TYPE_UINT16,
+				&device->headset->slc->mic_gain);
 
 done:
 	dbus_message_iter_close_container(&iter, &dict);
@@ -2079,7 +2129,7 @@
 		break;
 
 	default:
-		debug("Invalid record passed to headset_update");
+		DBG("Invalid record passed to headset_update");
 		return;
 	}
 }
@@ -2096,10 +2146,8 @@
 		hs->rfcomm = NULL;
 	}
 
-	hs->data_start = 0;
-	hs->data_length = 0;
-
-	hs->nrec = TRUE;
+	g_free(hs->slc);
+	hs->slc = NULL;
 
 	return 0;
 }
@@ -2130,11 +2178,11 @@
 	struct headset *hs = dev->headset;
 
 	if (hs->state > HEADSET_STATE_DISCONNECTED) {
-		debug("Headset unregistered while device was connected!");
+		DBG("Headset unregistered while device was connected!");
 		headset_shutdown(dev);
 	}
 
-	debug("Unregistered interface %s on path %s",
+	DBG("Unregistered interface %s on path %s",
 		AUDIO_HEADSET_INTERFACE, dev->path);
 
 	headset_free(dev);
@@ -2154,12 +2202,7 @@
 
 	hs = g_new0(struct headset, 1);
 	hs->rfcomm_ch = -1;
-	hs->sp_gain = -1;
-	hs->mic_gain = -1;
 	hs->search_hfp = server_is_enabled(&dev->src, HANDSFREE_SVCLASS_ID);
-	hs->hfp_active = FALSE;
-	hs->cli_active = FALSE;
-	hs->nrec = TRUE;
 
 	record = btd_device_get_record(dev->btd_dev, uuidstr);
 	if (!record)
@@ -2175,7 +2218,7 @@
 		break;
 
 	default:
-		debug("Invalid record passed to headset_init");
+		DBG("Invalid record passed to headset_init");
 		g_free(hs);
 		return NULL;
 	}
@@ -2189,7 +2232,7 @@
 		return NULL;
 	}
 
-	debug("Registered interface %s on path %s",
+	DBG("Registered interface %s on path %s",
 		AUDIO_HEADSET_INTERFACE, dev->path);
 
 	return hs;
@@ -2207,7 +2250,7 @@
 	str = g_key_file_get_string(config, "General", "SCORouting",
 					&err);
 	if (err) {
-		debug("audio.conf: %s", err->message);
+		DBG("audio.conf: %s", err->message);
 		g_clear_error(&err);
 	} else {
 		if (strcmp(str, "PCM") == 0)
@@ -2292,7 +2335,7 @@
 		hs->dc_timer = 0;
 	}
 
-	if (hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS ||
+	if (hs->state == HEADSET_STATE_CONNECTING ||
 			hs->state == HEADSET_STATE_PLAY_IN_PROGRESS)
 		return connect_cb_new(hs, HEADSET_STATE_PLAYING, cb, user_data);
 
@@ -2321,7 +2364,7 @@
 		hs->dc_timer = 0;
 	}
 
-	if (hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS)
+	if (hs->state == HEADSET_STATE_CONNECTING)
 		return connect_cb_new(hs, HEADSET_STATE_CONNECTED, cb,
 					user_data);
 
@@ -2349,6 +2392,10 @@
 	struct headset *hs = dev->headset;
 	unsigned int id;
 
+	if (hs->state == HEADSET_STATE_DISCONNECTED ||
+				hs->state == HEADSET_STATE_CONNECTING)
+		return 0;
+
 	if (hs->dc_timer) {
 		g_source_remove(hs->dc_timer);
 		hs->dc_timer = 0;
@@ -2398,18 +2445,19 @@
 int headset_connect_sco(struct audio_device *dev, GIOChannel *io)
 {
 	struct headset *hs = dev->headset;
+	struct headset_slc *slc = hs->slc;
 
 	if (hs->sco)
 		return -EISCONN;
 
 	hs->sco = g_io_channel_ref(io);
 
-	if (hs->pending_ring) {
+	if (slc->pending_ring) {
 		ring_timer_cb(NULL);
 		ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL,
 						ring_timer_cb,
 						NULL);
-		hs->pending_ring = FALSE;
+		slc->pending_ring = FALSE;
 	}
 
 	return 0;
@@ -2428,6 +2476,7 @@
 void headset_set_state(struct audio_device *dev, headset_state_t state)
 {
 	struct headset *hs = dev->headset;
+	struct headset_slc *slc = hs->slc;
 	gboolean value;
 	const char *state_str;
 	headset_state_t old_state = hs->state;
@@ -2450,17 +2499,17 @@
 					AUDIO_HEADSET_INTERFACE,
 					"Disconnected",
 					DBUS_TYPE_INVALID);
-		if (hs->state > HEADSET_STATE_CONNECT_IN_PROGRESS)
+		if (hs->state > HEADSET_STATE_CONNECTING) {
 			emit_property_changed(dev->conn, dev->path,
 					AUDIO_HEADSET_INTERFACE, "Connected",
 					DBUS_TYPE_BOOLEAN, &value);
-
-		telephony_device_disconnected(dev);
+			telephony_device_disconnected(dev);
+		}
 		active_devices = g_slist_remove(active_devices, dev);
 		device_remove_disconnect_watch(dev->btd_dev, hs->dc_id);
 		hs->dc_id = 0;
 		break;
-	case HEADSET_STATE_CONNECT_IN_PROGRESS:
+	case HEADSET_STATE_CONNECTING:
 		emit_property_changed(dev->conn, dev->path,
 					AUDIO_HEADSET_INTERFACE, "State",
 					DBUS_TYPE_STRING, &state_str);
@@ -2473,9 +2522,9 @@
 					DBUS_TYPE_STRING, &state_str);
 		if (hs->state < state) {
 			if (ag.features & AG_FEATURE_INBAND_RINGTONE)
-				hs->inband_ring = TRUE;
+				slc->inband_ring = TRUE;
 			else
-				hs->inband_ring = FALSE;
+				slc->inband_ring = FALSE;
 			g_dbus_emit_signal(dev->conn, dev->path,
 						AUDIO_HEADSET_INTERFACE,
 						"Connected",
@@ -2520,16 +2569,16 @@
 					AUDIO_HEADSET_INTERFACE, "Playing",
 					DBUS_TYPE_BOOLEAN, &value);
 
-		if (hs->sp_gain >= 0)
-			headset_send(hs, "\r\n+VGS=%u\r\n", hs->sp_gain);
-		if (hs->mic_gain >= 0)
-			headset_send(hs, "\r\n+VGM=%u\r\n", hs->mic_gain);
+		if (slc->sp_gain >= 0)
+			headset_send(hs, "\r\n+VGS=%u\r\n", slc->sp_gain);
+		if (slc->mic_gain >= 0)
+			headset_send(hs, "\r\n+VGM=%u\r\n", slc->mic_gain);
 		break;
 	}
 
 	hs->state = state;
 
-	debug("State changed %s: %s -> %s", dev->path, str_state[old_state],
+	DBG("State changed %s: %s -> %s", dev->path, str_state[old_state],
 		str_state[state]);
 
 	for (l = headset_callbacks; l != NULL; l = l->next) {
@@ -2632,7 +2681,10 @@
 {
 	struct headset *hs = dev->headset;
 
-	return hs->nrec;
+	if (!hs->slc)
+		return TRUE;
+
+	return hs->slc->nrec;
 }
 
 gboolean headset_get_sco_hci(struct audio_device *dev)
@@ -2657,7 +2709,7 @@
 		return -ENODEV;
 
 	if (!ag.er_ind) {
-		debug("telephony_report_event called but events are disabled");
+		DBG("telephony_report_event called but events are disabled");
 		return -EINVAL;
 	}
 
@@ -2689,6 +2741,7 @@
 {
 	struct audio_device *dev;
 	struct headset *hs;
+	struct headset_slc *slc;
 
 	if (!active_devices)
 		return -ENODEV;
@@ -2696,24 +2749,25 @@
 	/* Get the latest connected device */
 	dev = active_devices->data;
 	hs = dev->headset;
+	slc = hs->slc;
 
 	if (ag.ring_timer) {
-		debug("telephony_incoming_call_ind: already calling");
+		DBG("telephony_incoming_call_ind: already calling");
 		return -EBUSY;
 	}
 
 	/* With HSP 1.2 the RING messages should *not* be sent if inband
 	 * ringtone is being used */
-	if (!hs->hfp_active && hs->inband_ring)
+	if (!hs->hfp_active && slc->inband_ring)
 		return 0;
 
 	g_free(ag.number);
 	ag.number = g_strdup(number);
 	ag.number_type = type;
 
-	if (hs->inband_ring && hs->hfp_active &&
+	if (slc->inband_ring && hs->hfp_active &&
 					hs->state != HEADSET_STATE_PLAYING) {
-		hs->pending_ring = TRUE;
+		slc->pending_ring = TRUE;
 		return 0;
 	}
 
@@ -2739,10 +2793,10 @@
 	/* In case SCO isn't fully up yet */
 	dev = active_devices->data;
 
-	if (!dev->headset->pending_ring && !ag.ring_timer)
+	if (!dev->headset->slc->pending_ring && !ag.ring_timer)
 		return -EINVAL;
 
-	dev->headset->pending_ring = FALSE;
+	dev->headset->slc->pending_ring = FALSE;
 
 	return 0;
 }
@@ -2757,7 +2811,7 @@
 	ag.rh = rh;
 	ag.chld = g_strdup(chld);
 
-	debug("Telephony plugin initialized");
+	DBG("Telephony plugin initialized");
 
 	print_ag_features(ag.features);
 
@@ -2800,7 +2854,7 @@
 	if (!hs->hfp_active)
 		return -1;
 
-	if (hs->cwa_enabled)
+	if (hs->slc->cwa_enabled)
 		return 0;
 	else
 		return -1;
diff --git a/audio/headset.h b/audio/headset.h
index ace1edf..8b7c738 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -29,7 +29,7 @@
 
 typedef enum {
 	HEADSET_STATE_DISCONNECTED,
-	HEADSET_STATE_CONNECT_IN_PROGRESS,
+	HEADSET_STATE_CONNECTING,
 	HEADSET_STATE_CONNECTED,
 	HEADSET_STATE_PLAY_IN_PROGRESS,
 	HEADSET_STATE_PLAYING
diff --git a/audio/ipc.c b/audio/ipc.c
index 28569dc..1bdad78 100644
--- a/audio/ipc.c
+++ b/audio/ipc.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
diff --git a/audio/ipc.h b/audio/ipc.h
index 2e170f5..d69b97e 100644
--- a/audio/ipc.h
+++ b/audio/ipc.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -101,6 +101,7 @@
 #define BT_STOP_STREAM			5
 #define BT_CLOSE			6
 #define BT_CONTROL			7
+#define BT_DELAY_REPORT			8
 
 #define BT_CAPABILITIES_TRANSPORT_A2DP	0
 #define BT_CAPABILITIES_TRANSPORT_SCO	1
@@ -324,6 +325,16 @@
 	uint8_t			key;		/* Control Key */
 } __attribute__ ((packed));
 
+struct bt_delay_report_req {
+	bt_audio_msg_header_t	h;
+	uint16_t		delay;
+} __attribute__ ((packed));
+
+struct bt_delay_report_ind {
+	bt_audio_msg_header_t	h;
+	uint16_t		delay;
+} __attribute__ ((packed));
+
 /* Function declaration */
 
 /* Opens a connection to the audio service: return a socket descriptor */
diff --git a/audio/main.c b/audio/main.c
index 9defe60..9d316ec 100644
--- a/audio/main.c
+++ b/audio/main.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -40,7 +40,7 @@
 #include "glib-helper.h"
 #include "btio.h"
 #include "plugin.h"
-#include "logging.h"
+#include "log.h"
 #include "device.h"
 #include "unix.h"
 #include "headset.h"
@@ -102,7 +102,7 @@
 
 	if (device->headset) {
 		if (headset_get_state(device) < HEADSET_STATE_CONNECTED) {
-			debug("Refusing SCO from non-connected headset");
+			DBG("Refusing SCO from non-connected headset");
 			goto drop;
 		}
 
@@ -118,7 +118,7 @@
 		headset_set_state(device, HEADSET_STATE_PLAYING);
 	} else if (device->gateway) {
 		if (!gateway_is_connected(device)) {
-			debug("Refusing SCO from non-connected AG");
+			DBG("Refusing SCO from non-connected AG");
 			goto drop;
 		}
 
@@ -130,7 +130,7 @@
 	sk = g_io_channel_unix_get_fd(chan);
 	fcntl(sk, F_SETFL, 0);
 
-	debug("Accepted SCO connection from %s", addr);
+	DBG("Accepted SCO connection from %s", addr);
 
 	return;
 
diff --git a/audio/manager.c b/audio/manager.c
index ca4b1ab..6dd0f87 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -55,7 +55,7 @@
 #include "../src/adapter.h"
 #include "../src/device.h"
 
-#include "logging.h"
+#include "log.h"
 #include "textfile.h"
 #include "ipc.h"
 #include "device.h"
@@ -171,14 +171,13 @@
 	uuid16 = uuid.value.uuid16;
 
 	if (!server_is_enabled(&device->src, uuid16)) {
-		debug("audio handle_uuid: server not enabled for %s (0x%04x)",
-				uuidstr, uuid16);
+		DBG("server not enabled for %s (0x%04x)", uuidstr, uuid16);
 		return;
 	}
 
 	switch (uuid16) {
 	case HEADSET_SVCLASS_ID:
-		debug("Found Headset record");
+		DBG("Found Headset record");
 		if (device->headset)
 			headset_update(device, uuid16, uuidstr);
 		else
@@ -186,34 +185,34 @@
 							uuidstr);
 		break;
 	case HEADSET_AGW_SVCLASS_ID:
-		debug("Found Headset AG record");
+		DBG("Found Headset AG record");
 		break;
 	case HANDSFREE_SVCLASS_ID:
-		debug("Found Handsfree record");
+		DBG("Found Handsfree record");
 		if (device->headset)
 			headset_update(device, uuid16, uuidstr);
 		else
 			device->headset = headset_init(device, uuid16,
-							uuidstr);
+								uuidstr);
 		break;
 	case HANDSFREE_AGW_SVCLASS_ID:
-		debug("Found Handsfree AG record");
-		if (device->gateway == NULL)
+		DBG("Found Handsfree AG record");
+		if (enabled.gateway && (device->gateway == NULL))
 			device->gateway = gateway_init(device);
 		break;
 	case AUDIO_SINK_SVCLASS_ID:
-		debug("Found Audio Sink");
+		DBG("Found Audio Sink");
 		if (device->sink == NULL)
 			device->sink = sink_init(device);
 		break;
 	case AUDIO_SOURCE_SVCLASS_ID:
-		debug("Found Audio Source");
+		DBG("Found Audio Source");
 		if (device->source == NULL)
 			device->source = source_init(device);
 		break;
 	case AV_REMOTE_SVCLASS_ID:
 	case AV_REMOTE_TARGET_SVCLASS_ID:
-		debug("Found AV %s", uuid16 == AV_REMOTE_SVCLASS_ID ?
+		DBG("Found AV %s", uuid16 == AV_REMOTE_SVCLASS_ID ?
 							"Remote" : "Target");
 		if (device->control)
 			control_update(device, uuid16);
@@ -223,7 +222,7 @@
 			avrcp_connect(device);
 		break;
 	default:
-		debug("Unrecognized UUID: 0x%04X", uuid16);
+		DBG("Unrecognized UUID: 0x%04X", uuid16);
 		break;
 	}
 }
@@ -309,7 +308,7 @@
 	sdp_set_service_classes(record, svclass_id);
 
 	sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
-	profile.version = 0x0100;
+	profile.version = 0x0105;
 	pfseq = sdp_list_append(0, &profile);
 	sdp_set_profile_descs(record, pfseq);
 
@@ -351,12 +350,18 @@
 	sdp_data_t *channel, *features;
 	uint8_t netid = 0x01;
 	uint16_t sdpfeat;
-	sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
+	sdp_data_t *network;
 
 	record = sdp_record_alloc();
 	if (!record)
 		return NULL;
 
+	network = sdp_data_alloc(SDP_UINT8, &netid);
+	if (!network) {
+		sdp_record_free(record);
+		return NULL;
+	}
+
 	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
 	root = sdp_list_append(0, &root_uuid);
 	sdp_set_browse_groups(record, root);
@@ -411,6 +416,11 @@
 	GError *err = NULL;
 	GIOChannel *io;
 
+	if (device->hs_preauth_id) {
+		g_source_remove(device->hs_preauth_id);
+		device->hs_preauth_id = 0;
+	}
+
 	if (derr && dbus_error_is_set(derr)) {
 		error("Access denied: %s", derr->message);
 		headset_set_state(device, HEADSET_STATE_DISCONNECTED);
@@ -427,6 +437,22 @@
 	}
 }
 
+static gboolean hs_preauth_cb(GIOChannel *chan, GIOCondition cond,
+							gpointer user_data)
+{
+	struct audio_device *device = user_data;
+
+	DBG("Headset disconnected during authorization");
+
+	audio_device_cancel_authorization(device, headset_auth_cb, device);
+
+	headset_set_state(device, HEADSET_STATE_DISCONNECTED);
+
+	device->hs_preauth_id = 0;
+
+	return FALSE;
+}
+
 static void ag_confirm(GIOChannel *chan, gpointer data)
 {
 	const char *server_uuid, *remote_uuid;
@@ -463,7 +489,7 @@
 		goto drop;
 
 	if (!manager_allow_headset_connection(device)) {
-		debug("Refusing headset: too many existing connections");
+		DBG("Refusing headset: too many existing connections");
 		goto drop;
 	}
 
@@ -474,7 +500,7 @@
 	}
 
 	if (headset_get_state(device) > HEADSET_STATE_DISCONNECTED) {
-		debug("Refusing new connection since one already exists");
+		DBG("Refusing new connection since one already exists");
 		goto drop;
 	}
 
@@ -485,16 +511,20 @@
 		goto drop;
 	}
 
-	headset_set_state(device, HEADSET_STATE_CONNECT_IN_PROGRESS);
+	headset_set_state(device, HEADSET_STATE_CONNECTING);
 
 	perr = audio_device_request_authorization(device, server_uuid,
 						headset_auth_cb, device);
 	if (perr < 0) {
-		debug("Authorization denied: %s", strerror(-perr));
+		DBG("Authorization denied: %s", strerror(-perr));
 		headset_set_state(device, HEADSET_STATE_DISCONNECTED);
 		return;
 	}
 
+	device->hs_preauth_id = g_io_add_watch(chan,
+					G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+					hs_preauth_cb, device);
+
 	device->auto_connect = auto_connect;
 
 	return;
@@ -513,7 +543,7 @@
 		char ag_address[18];
 
 		ba2str(&device->dst, ag_address);
-		debug("Accepted AG connection from %s for %s",
+		DBG("Accepted AG connection from %s for %s",
 			ag_address, device->path);
 
 		gateway_start_service(device);
@@ -542,8 +572,8 @@
 		return;
 	}
 
-	server_uuid = HFP_HS_UUID;
-	remote_uuid = HFP_AG_UUID;
+	server_uuid = HFP_AG_UUID;
+	remote_uuid = HFP_HS_UUID;
 	svclass = HANDSFREE_AGW_SVCLASS_ID;
 
 	device = manager_get_device(&src, &dst, TRUE);
@@ -557,7 +587,7 @@
 	}
 
 	if (gateway_is_connected(device)) {
-		debug("Refusing new connection since one already exists");
+		DBG("Refusing new connection since one already exists");
 		goto drop;
 	}
 
@@ -569,7 +599,7 @@
 	perr = audio_device_request_authorization(device, server_uuid,
 						gateway_auth_cb, device);
 	if (perr < 0) {
-		debug("Authorization denied!");
+		DBG("Authorization denied!");
 		goto drop;
 	}
 
@@ -578,7 +608,6 @@
 drop:
 	g_io_channel_shutdown(chan, TRUE, NULL);
 	g_io_channel_unref(chan);
-	return;
 }
 
 static int headset_server_init(struct audio_adapter *adapter)
@@ -597,7 +626,7 @@
 		tmp = g_key_file_get_boolean(config, "General", "Master",
 						&err);
 		if (err) {
-			debug("audio.conf: %s", err->message);
+			DBG("audio.conf: %s", err->message);
 			g_clear_error(&err);
 		} else
 			master = tmp;
@@ -695,7 +724,7 @@
 		tmp = g_key_file_get_boolean(config, "General", "Master",
 						&err);
 		if (err) {
-			debug("audio.conf: %s", err->message);
+			DBG("audio.conf: %s", err->message);
 			g_clear_error(&err);
 		} else
 			master = tmp;
@@ -746,7 +775,7 @@
 
 	audio_dev = manager_get_device(&src, &dst, TRUE);
 	if (!audio_dev) {
-		debug("audio_probe: unable to get a device object");
+		DBG("unable to get a device object");
 		return -1;
 	}
 
@@ -769,13 +798,14 @@
 	devices = g_slist_remove(devices, dev);
 
 	audio_device_unregister(dev);
+
 }
 
 static struct audio_adapter *audio_adapter_ref(struct audio_adapter *adp)
 {
 	adp->ref++;
 
-	debug("audio_adapter_ref(%p): ref=%d", adp, adp->ref);
+	DBG("%p: ref=%d", adp, adp->ref);
 
 	return adp;
 }
@@ -784,7 +814,7 @@
 {
 	adp->ref--;
 
-	debug("audio_adapter_unref(%p): ref=%d", adp, adp->ref);
+	DBG("%p: ref=%d", adp, adp->ref);
 
 	if (adp->ref > 0)
 		return;
@@ -824,7 +854,7 @@
 {
 	struct audio_adapter *adp;
 	const gchar *path = adapter_get_path(adapter);
-	int ret;
+	int err;
 
 	DBG("path %s", path);
 
@@ -832,13 +862,11 @@
 	if (!adp)
 		return -EINVAL;
 
-	ret = headset_server_init(adp);
-	if (ret < 0) {
+	err = headset_server_init(adp);
+	if (err < 0)
 		audio_adapter_unref(adp);
-		return ret;
-	}
 
-	return 0;
+	return err;
 }
 
 static void headset_server_remove(struct btd_adapter *adapter)
@@ -880,22 +908,12 @@
 static int gateway_server_probe(struct btd_adapter *adapter)
 {
 	struct audio_adapter *adp;
-	const gchar *path = adapter_get_path(adapter);
-	int ret;
-
-	DBG("path %s", path);
 
 	adp = audio_adapter_get(adapter);
 	if (!adp)
 		return -EINVAL;
 
-	ret = gateway_server_init(adp);
-	if (ret < 0) {
-		audio_adapter_ref(adp);
-		return ret;
-	}
-
-	return 0;
+	return gateway_server_init(adp);
 }
 
 static void gateway_server_remove(struct btd_adapter *adapter)
@@ -919,7 +937,7 @@
 		adp->hfp_hs_server = NULL;
 	}
 
-	audio_adapter_ref(adp);
+	audio_adapter_unref(adp);
 }
 
 static int a2dp_server_probe(struct btd_adapter *adapter)
@@ -927,7 +945,7 @@
 	struct audio_adapter *adp;
 	const gchar *path = adapter_get_path(adapter);
 	bdaddr_t src;
-	int ret;
+	int err;
 
 	DBG("path %s", path);
 
@@ -937,13 +955,11 @@
 
 	adapter_get_address(adapter, &src);
 
-	ret = a2dp_register(connection, &src, config);
-	if (ret < 0) {
+	err = a2dp_register(connection, &src, config);
+	if (err < 0)
 		audio_adapter_unref(adp);
-		return ret;
-	}
 
-	return 0;
+	return err;
 }
 
 static void a2dp_server_remove(struct btd_adapter *adapter)
@@ -1079,7 +1095,7 @@
 
 	b = g_key_file_get_boolean(config, "General", "AutoConnect", &err);
 	if (err) {
-		debug("audio.conf: %s", err->message);
+		DBG("audio.conf: %s", err->message);
 		g_clear_error(&err);
 	} else
 		auto_connect = b;
@@ -1095,7 +1111,7 @@
 	i = g_key_file_get_integer(config, "Headset", "MaxConnected",
 					&err);
 	if (err) {
-		debug("audio.conf: %s", err->message);
+		DBG("audio.conf: %s", err->message);
 		g_clear_error(&err);
 	} else
 		max_connected_headsets = i;
diff --git a/audio/manager.h b/audio/manager.h
index cb9d63c..8e1abf4 100644
--- a/audio/manager.h
+++ b/audio/manager.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/audio/module-bluetooth-sink.c b/audio/module-bluetooth-sink.c
index 2944d18..a0117c0 100644
--- a/audio/module-bluetooth-sink.c
+++ b/audio/module-bluetooth-sink.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/audio/pcm_bluetooth.c b/audio/pcm_bluetooth.c
index 13cf3ee..4c0ab6f 100644
--- a/audio/pcm_bluetooth.c
+++ b/audio/pcm_bluetooth.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
@@ -1007,7 +1007,7 @@
 	snd_pcm_sframes_t ret = 0;
 	unsigned int bytes_left;
 	int frame_size, encoded;
-	size_t written;
+	ssize_t written;
 	uint8_t *buff;
 
 	DBG("areas->step=%u areas->first=%u offset=%lu size=%lu",
diff --git a/audio/rtp.h b/audio/rtp.h
index 1457362..45fddcf 100644
--- a/audio/rtp.h
+++ b/audio/rtp.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This library is free software; you can redistribute it and/or
diff --git a/audio/sink.c b/audio/sink.c
index 90bceab..94fe9f2 100644
--- a/audio/sink.c
+++ b/audio/sink.c
@@ -36,7 +36,7 @@
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 
 #include "device.h"
 #include "avdtp.h"
@@ -176,9 +176,9 @@
 	struct audio_device *device = user_data;
 	struct sink *sink = device->sink;
 
-	debug("Sink: disconnect %s", device->path);
+	DBG("Sink: disconnect %s", device->path);
 
-	avdtp_close(sink->session, sink->stream);
+	avdtp_close(sink->session, sink->stream, TRUE);
 }
 
 static void stream_state_changed(struct avdtp_stream *stream,
@@ -282,14 +282,14 @@
 	sink->retry_id = 0;
 
 	if (sink->stream_state >= AVDTP_STATE_OPEN) {
-		debug("Stream successfully created, after XCASE connect:connect");
+		DBG("Stream successfully created, after XCASE connect:connect");
 		if (pending->msg) {
 			DBusMessage *reply;
 			reply = dbus_message_new_method_return(pending->msg);
 			g_dbus_send_message(pending->conn, reply);
 		}
 	} else {
-		debug("Stream setup failed, after XCASE connect:connect");
+		DBG("Stream setup failed, after XCASE connect:connect");
 		if (pending->msg)
 			error_failed(pending->conn, pending->msg, "Stream setup failed");
 	}
@@ -312,7 +312,7 @@
 	pending->id = 0;
 
 	if (stream) {
-		debug("Stream successfully created");
+		DBG("Stream successfully created");
 
 		if (pending->msg) {
 			DBusMessage *reply;
@@ -330,7 +330,7 @@
 	sink->session = NULL;
 	if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO
 			&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
-		debug("connect:connect XCASE detected");
+		DBG("connect:connect XCASE detected");
 		sink->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
 							stream_setup_retry,
 							sink);
@@ -339,7 +339,7 @@
 			error_failed(pending->conn, pending->msg, "Stream setup failed");
 		sink->connect = NULL;
 		pending_request_free(sink->dev, pending);
-		debug("Stream setup failed : %s", avdtp_strerror(err));
+		DBG("Stream setup failed : %s", avdtp_strerror(err));
 	}
 }
 
@@ -475,6 +475,12 @@
 
 	*caps = g_slist_append(*caps, media_codec);
 
+	if (avdtp_get_delay_reporting(rsep)) {
+		struct avdtp_service_capability *delay_reporting;
+		delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
+								NULL, 0);
+		*caps = g_slist_append(*caps, delay_reporting);
+	}
 
 	return TRUE;
 }
@@ -497,7 +503,7 @@
 		sink->session = NULL;
 		if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO
 				&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
-			debug("connect:connect XCASE detected");
+			DBG("connect:connect XCASE detected");
 			sink->retry_id =
 				g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
 							stream_setup_retry,
@@ -507,7 +513,7 @@
 		return;
 	}
 
-	debug("Discovery complete");
+	DBG("Discovery complete");
 
 	if (avdtp_get_seps(session, AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
 				A2DP_CODEC_SBC, &lsep, &rsep) < 0) {
@@ -597,7 +603,7 @@
 	pending->conn = dbus_connection_ref(conn);
 	pending->msg = dbus_message_ref(msg);
 
-	debug("stream creation in progress");
+	DBG("stream creation in progress");
 
 	return NULL;
 }
@@ -628,7 +634,7 @@
 		return reply;
 	}
 
-	err = avdtp_close(sink->session, sink->stream);
+	err = avdtp_close(sink->session, sink->stream, FALSE);
 	if (err < 0)
 		return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 						"%s", strerror(-err));
@@ -825,7 +831,7 @@
 {
 	struct audio_device *dev = data;
 
-	debug("Unregistered interface %s on path %s",
+	DBG("Unregistered interface %s on path %s",
 		AUDIO_SINK_INTERFACE, dev->path);
 
 	sink_free(dev);
@@ -847,7 +853,7 @@
 					dev, path_unregister))
 		return NULL;
 
-	debug("Registered interface %s on path %s",
+	DBG("Registered interface %s on path %s",
 		AUDIO_SINK_INTERFACE, dev->path);
 
 	if (avdtp_callback_id == 0)
@@ -902,7 +908,7 @@
 	if (!sink->stream)
 		return FALSE;
 
-	if (avdtp_close(sink->session, sink->stream) < 0)
+	if (avdtp_close(sink->session, sink->stream, FALSE) < 0)
 		return FALSE;
 
 	return TRUE;
diff --git a/audio/sink.h b/audio/sink.h
index 3f822bc..7b1902b 100644
--- a/audio/sink.h
+++ b/audio/sink.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/audio/source.c b/audio/source.c
index 1cec1f6..35d8136 100644
--- a/audio/source.c
+++ b/audio/source.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2009  Joao Paulo Rechi Vita
  *
  *
@@ -37,7 +37,7 @@
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 
 #include "device.h"
 #include "avdtp.h"
@@ -169,9 +169,9 @@
 	struct audio_device *device = user_data;
 	struct source *source = device->source;
 
-	debug("Source: disconnect %s", device->path);
+	DBG("Source: disconnect %s", device->path);
 
-	avdtp_close(source->session, source->stream);
+	avdtp_close(source->session, source->stream, TRUE);
 }
 
 static void stream_state_changed(struct avdtp_stream *stream,
@@ -249,14 +249,14 @@
 	source->retry_id = 0;
 
 	if (source->stream_state >= AVDTP_STATE_OPEN) {
-		debug("Stream successfully created, after XCASE connect:connect");
+		DBG("Stream successfully created, after XCASE connect:connect");
 		if (pending->msg) {
 			DBusMessage *reply;
 			reply = dbus_message_new_method_return(pending->msg);
 			g_dbus_send_message(pending->conn, reply);
 		}
 	} else {
-		debug("Stream setup failed, after XCASE connect:connect");
+		DBG("Stream setup failed, after XCASE connect:connect");
 		if (pending->msg)
 			error_failed(pending->conn, pending->msg, "Stream setup failed");
 	}
@@ -279,7 +279,7 @@
 	pending->id = 0;
 
 	if (stream) {
-		debug("Stream successfully created");
+		DBG("Stream successfully created");
 
 		if (pending->msg) {
 			DBusMessage *reply;
@@ -297,7 +297,7 @@
 	source->session = NULL;
 	if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO
 			&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
-		debug("connect:connect XCASE detected");
+		DBG("connect:connect XCASE detected");
 		source->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
 							stream_setup_retry,
 							source);
@@ -306,7 +306,7 @@
 			error_failed(pending->conn, pending->msg, "Stream setup failed");
 		source->connect = NULL;
 		pending_request_free(source->dev, pending);
-		debug("Stream setup failed : %s", avdtp_strerror(err));
+		DBG("Stream setup failed : %s", avdtp_strerror(err));
 	}
 }
 
@@ -464,7 +464,7 @@
 		source->session = NULL;
 		if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO
 				&& avdtp_error_posix_errno(err) != EHOSTDOWN) {
-			debug("connect:connect XCASE detected");
+			DBG("connect:connect XCASE detected");
 			source->retry_id =
 				g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
 							stream_setup_retry,
@@ -474,7 +474,7 @@
 		return;
 	}
 
-	debug("Discovery complete");
+	DBG("Discovery complete");
 
 	if (avdtp_get_seps(session, AVDTP_SEP_TYPE_SOURCE, AVDTP_MEDIA_TYPE_AUDIO,
 				A2DP_CODEC_SBC, &lsep, &rsep) < 0) {
@@ -565,7 +565,7 @@
 	pending->conn = dbus_connection_ref(conn);
 	pending->msg = dbus_message_ref(msg);
 
-	debug("stream creation in progress");
+	DBG("stream creation in progress");
 
 	return NULL;
 }
@@ -596,7 +596,7 @@
 		return reply;
 	}
 
-	err = avdtp_close(source->session, source->stream);
+	err = avdtp_close(source->session, source->stream, FALSE);
 	if (err < 0)
 		return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 						"%s", strerror(-err));
@@ -685,7 +685,7 @@
 {
 	struct audio_device *dev = data;
 
-	debug("Unregistered interface %s on path %s",
+	DBG("Unregistered interface %s on path %s",
 		AUDIO_SOURCE_INTERFACE, dev->path);
 
 	source_free(dev);
@@ -707,7 +707,7 @@
 					dev, path_unregister))
 		return NULL;
 
-	debug("Registered interface %s on path %s",
+	DBG("Registered interface %s on path %s",
 		AUDIO_SOURCE_INTERFACE, dev->path);
 
 	if (avdtp_callback_id == 0)
@@ -762,7 +762,7 @@
 	if (!source->stream)
 		return FALSE;
 
-	if (avdtp_close(source->session, source->stream) < 0)
+	if (avdtp_close(source->session, source->stream, FALSE) < 0)
 		return FALSE;
 
 	return TRUE;
diff --git a/audio/source.h b/audio/source.h
index 8250814..7837284 100644
--- a/audio/source.h
+++ b/audio/source.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2009  Joao Paulo Rechi Vita
  *
  *
diff --git a/audio/telephony-dummy.c b/audio/telephony-dummy.c
index deb604c..06cb798 100644
--- a/audio/telephony-dummy.c
+++ b/audio/telephony-dummy.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -33,9 +33,14 @@
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 #include "telephony.h"
 
+#define TELEPHONY_DUMMY_IFACE "org.bluez.TelephonyTest"
+#define TELEPHONY_DUMMY_PATH "/org/bluez/test"
+
+static DBusConnection *connection = NULL;
+
 static const char *chld_str = "0,1,1x,2,2x,3,4";
 static char *subscriber_number = NULL;
 static char *active_call_number = NULL;
@@ -72,12 +77,12 @@
 
 void telephony_device_connected(void *telephony_device)
 {
-	debug("telephony-dummy: device %p connected", telephony_device);
+	DBG("telephony-dummy: device %p connected", telephony_device);
 }
 
 void telephony_device_disconnected(void *telephony_device)
 {
-	debug("telephony-dummy: device %p disconnected", telephony_device);
+	DBG("telephony-dummy: device %p disconnected", telephony_device);
 	events_enabled = FALSE;
 }
 
@@ -142,7 +147,7 @@
 	g_free(active_call_number);
 	active_call_number = g_strdup(number);
 
-	debug("telephony-dummy: dial request to %s", active_call_number);
+	DBG("telephony-dummy: dial request to %s", active_call_number);
 
 	telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
 
@@ -158,13 +163,13 @@
 
 void telephony_transmit_dtmf_req(void *telephony_device, char tone)
 {
-	debug("telephony-dummy: transmit dtmf: %c", tone);
+	DBG("telephony-dummy: transmit dtmf: %c", tone);
 	telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
 }
 
 void telephony_subscriber_number_req(void *telephony_device)
 {
-	debug("telephony-dummy: subscriber number request");
+	DBG("telephony-dummy: subscriber number request");
 	if (subscriber_number)
 		telephony_subscriber_number_ind(subscriber_number,
 						NUMBER_TYPE_TELEPHONY,
@@ -174,7 +179,7 @@
 
 void telephony_list_current_calls_req(void *telephony_device)
 {
-	debug("telephony-dummy: list current calls request");
+	DBG("telephony-dummy: list current calls request");
 	if (active_call_number)
 		telephony_list_current_call_ind(1, active_call_dir,
 						active_call_status,
@@ -193,21 +198,33 @@
 
 void telephony_call_hold_req(void *telephony_device, const char *cmd)
 {
-	debug("telephony-dymmy: got call hold request %s", cmd);
+	DBG("telephony-dymmy: got call hold request %s", cmd);
 	telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
 }
 
 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
 {
-	debug("telephony-dummy: got %s NR and EC request",
+	DBG("telephony-dummy: got %s NR and EC request",
 			enable ? "enable" : "disable");
 
 	telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
 }
 
+void telephony_voice_dial_req(void *telephony_device, gboolean enable)
+{
+	DBG("telephony-dummy: got %s voice dial request",
+			enable ? "enable" : "disable");
+
+	g_dbus_emit_signal(connection, TELEPHONY_DUMMY_PATH,
+			TELEPHONY_DUMMY_IFACE, "VoiceDial",
+			DBUS_TYPE_INVALID);
+
+	telephony_voice_dial_rsp(telephony_device, CME_ERROR_NONE);
+}
+
 void telephony_key_press_req(void *telephony_device, const char *keys)
 {
-	debug("telephony-dummy: got key press request for %s", keys);
+	DBG("telephony-dummy: got key press request for %s", keys);
 	telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
 }
 
@@ -221,7 +238,7 @@
 						DBUS_TYPE_INVALID))
 		return invalid_args(msg);
 
-	debug("telephony-dummy: outgoing call to %s", number);
+	DBG("telephony-dummy: outgoing call to %s", number);
 
 	g_free(active_call_number);
 	active_call_number = g_strdup(number);
@@ -246,7 +263,7 @@
 						DBUS_TYPE_INVALID))
 		return invalid_args(msg);
 
-	debug("telephony-dummy: incoming call to %s", number);
+	DBG("telephony-dummy: incoming call to %s", number);
 
 	g_free(active_call_number);
 	active_call_number = g_strdup(number);
@@ -265,7 +282,7 @@
 static DBusMessage *cancel_call(DBusConnection *conn, DBusMessage *msg,
 					void *data)
 {
-	debug("telephony-dummy: cancel call");
+	DBG("telephony-dummy: cancel call");
 
 	g_free(active_call_number);
 	active_call_number = NULL;
@@ -297,7 +314,7 @@
 
 	telephony_update_indicator(dummy_indicators, "signal", strength);
 
-	debug("telephony-dummy: signal strength set to %u", strength);
+	DBG("telephony-dummy: signal strength set to %u", strength);
 
 	return dbus_message_new_method_return(msg);
 }
@@ -316,7 +333,7 @@
 
 	telephony_update_indicator(dummy_indicators, "battchg", level);
 
-	debug("telephony-dummy: battery level set to %u", level);
+	DBG("telephony-dummy: battery level set to %u", level);
 
 	return dbus_message_new_method_return(msg);
 }
@@ -335,7 +352,7 @@
 
 	telephony_update_indicator(dummy_indicators, "roam", val);
 
-	debug("telephony-dummy: roaming status set to %d", val);
+	DBG("telephony-dummy: roaming status set to %d", val);
 
 	return dbus_message_new_method_return(msg);
 }
@@ -354,7 +371,7 @@
 
 	telephony_update_indicator(dummy_indicators, "service", val);
 
-	debug("telephony-dummy: registration status set to %d", val);
+	DBG("telephony-dummy: registration status set to %d", val);
 
 	return dbus_message_new_method_return(msg);
 }
@@ -372,7 +389,7 @@
 	g_free(subscriber_number);
 	subscriber_number = g_strdup(number);
 
-	debug("telephony-dummy: subscriber number set to %s", number);
+	DBG("telephony-dummy: subscriber number set to %s", number);
 
 	return dbus_message_new_method_return(msg);
 }
@@ -389,7 +406,10 @@
 	{ }
 };
 
-static DBusConnection *connection = NULL;
+static GDBusSignalTable dummy_signals[] = {
+	{ "VoiceDial",	"" },
+	{ }
+};
 
 int telephony_init(void)
 {
@@ -399,10 +419,14 @@
 
 	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
 
-	g_dbus_register_interface(connection, "/org/bluez/test",
-					"org.bluez.TelephonyTest",
-					dummy_methods, NULL,
-					NULL, NULL, NULL);
+	if (g_dbus_register_interface(connection, TELEPHONY_DUMMY_PATH,
+					TELEPHONY_DUMMY_IFACE,
+					dummy_methods, dummy_signals,
+					NULL, NULL, NULL) == FALSE) {
+		error("telephony-dummy interface %s init failed on path %s",
+			TELEPHONY_DUMMY_IFACE, TELEPHONY_DUMMY_PATH);
+		return -1;
+	}
 
 	telephony_ready_ind(features, dummy_indicators, response_and_hold,
 				chld_str);
diff --git a/audio/telephony-maemo.c b/audio/telephony-maemo5.c
similarity index 90%
rename from audio/telephony-maemo.c
rename to audio/telephony-maemo5.c
index f302cdf..4d0134c 100644
--- a/audio/telephony-maemo.c
+++ b/audio/telephony-maemo5.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2008-2009  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -36,9 +36,14 @@
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 #include "telephony.h"
 
+/* SSC D-Bus definitions */
+#define SSC_DBUS_NAME  "com.nokia.phone.SSC"
+#define SSC_DBUS_IFACE "com.nokia.phone.SSC"
+#define SSC_DBUS_PATH  "/com/nokia/phone/SSC"
+
 /* libcsnet D-Bus definitions */
 #define NETWORK_BUS_NAME		"com.nokia.phone.net"
 #define NETWORK_INTERFACE		"Phone.Net"
@@ -101,6 +106,7 @@
 #define CSD_CALL_INSTANCE	"com.nokia.csd.Call.Instance"
 #define CSD_CALL_CONFERENCE	"com.nokia.csd.Call.Conference"
 #define CSD_CALL_PATH		"/com/nokia/csd/call"
+#define CSD_CALL_CONFERENCE_PATH "/com/nokia/csd/call/conference"
 
 /* Call status values as exported by the CSD CALL plugin */
 #define CSD_CALL_STATUS_IDLE			0
@@ -181,8 +187,6 @@
 	.operator_name = NULL,
 };
 
-static guint csd_watch = 0;
-
 static DBusConnection *connection = NULL;
 
 static GSList *calls = NULL;
@@ -198,6 +202,8 @@
 static int battchg_last = -1;	/* "battery.charge_level.last_full" */
 static int battchg_design = -1;	/* "battery.charge_level.design" */
 
+static gboolean get_calls_active = FALSE;
+
 static gboolean events_enabled = FALSE;
 
 /* Supported set of call hold operations */
@@ -219,8 +225,8 @@
 static struct indicator maemo_indicators[] =
 {
 	{ "battchg",	"0-5",	5,	TRUE },
-	{ "signal",	"0-5",	5,	TRUE },
-	{ "service",	"0,1",	1,	TRUE },
+	{ "signal",	"0-5",	0,	TRUE },
+	{ "service",	"0,1",	0,	TRUE },
 	{ "call",	"0,1",	0,	TRUE },
 	{ "callsetup",	"0-3",	0,	TRUE },
 	{ "callheld",	"0-2",	0,	FALSE },
@@ -308,6 +314,26 @@
 	return NULL;
 }
 
+static int release_conference(void)
+{
+	DBusMessage *msg;
+
+	DBG("telephony-maemo: releasing conference call");
+
+	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
+						CSD_CALL_CONFERENCE_PATH,
+						CSD_CALL_INSTANCE,
+						"Release");
+	if (!msg) {
+		error("Unable to allocate new D-Bus message");
+		return -ENOMEM;
+	}
+
+	g_dbus_send_message(connection, msg);
+
+	return 0;
+}
+
 static int release_call(struct csd_call *call)
 {
 	DBusMessage *msg;
@@ -462,7 +488,7 @@
 {
 	struct csd_call *coming;
 
-	debug("telephony-maemo: device %p connected", telephony_device);
+	DBG("telephony-maemo: device %p connected", telephony_device);
 
 	coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
 	if (coming) {
@@ -477,7 +503,7 @@
 
 void telephony_device_disconnected(void *telephony_device)
 {
-	debug("telephony-maemo: device %p disconnected", telephony_device);
+	DBG("telephony-maemo: device %p disconnected", telephony_device);
 	events_enabled = FALSE;
 }
 
@@ -499,7 +525,7 @@
 
 void telephony_last_dialed_number_req(void *telephony_device)
 {
-	debug("telephony-maemo: last dialed number request");
+	DBG("telephony-maemo: last dialed number request");
 
 	if (last_dialed_number)
 		telephony_dial_number_req(telephony_device,
@@ -512,6 +538,7 @@
 void telephony_terminate_call_req(void *telephony_device)
 {
 	struct csd_call *call;
+	int err;
 
 	call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
 	if (!call)
@@ -524,7 +551,12 @@
 		return;
 	}
 
-	if (release_call(call) < 0)
+	if (call->conference)
+		err = release_conference();
+	else
+		err = release_call(call);
+
+	if (err < 0)
 		telephony_terminate_call_rsp(telephony_device,
 						CME_ERROR_AG_FAILURE);
 	else
@@ -614,7 +646,7 @@
 	uint32_t flags = callerid;
 	int ret;
 
-	debug("telephony-maemo: dial request to %s", number);
+	DBG("telephony-maemo: dial request to %s", number);
 
 	if (strncmp(number, "*31#", 4) == 0) {
 		number += 4;
@@ -654,7 +686,7 @@
 	int ret;
 	char buf[2] = { tone, '\0' }, *buf_ptr = buf;
 
-	debug("telephony-maemo: transmit dtmf: %s", buf);
+	DBG("telephony-maemo: transmit dtmf: %s", buf);
 
 	ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
 				CSD_CALL_INTERFACE, "SendDTMF",
@@ -672,7 +704,7 @@
 
 void telephony_subscriber_number_req(void *telephony_device)
 {
-	debug("telephony-maemo: subscriber number request");
+	DBG("telephony-maemo: subscriber number request");
 	if (msisdn)
 		telephony_subscriber_number_ind(msisdn,
 						number_type(msisdn),
@@ -723,7 +755,7 @@
 	GSList *l;
 	int i;
 
-	debug("telephony-maemo: list current calls request");
+	DBG("telephony-maemo: list current calls request");
 
 	for (l = calls, i = 1; l != NULL; l = l->next, i++) {
 		struct csd_call *call = l->data;
@@ -774,7 +806,7 @@
 	struct csd_call *call;
 	int err = 0;
 
-	debug("telephony-maemo: got call hold request %s", cmd);
+	DBG("telephony-maemo: got call hold request %s", cmd);
 
 	if (strlen(cmd) > 1)
 		idx = &cmd[1];
@@ -835,7 +867,7 @@
 		err = call_transfer();
 		break;
 	default:
-		debug("Unknown call hold request");
+		DBG("Unknown call hold request");
 		break;
 	}
 
@@ -848,7 +880,7 @@
 
 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
 {
-	debug("telephony-maemo: got %s NR and EC request",
+	DBG("telephony-maemo: got %s NR and EC request",
 			enable ? "enable" : "disable");
 	telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
 }
@@ -858,7 +890,7 @@
 	struct csd_call *active, *waiting;
 	int err;
 
-	debug("telephony-maemo: got key press request for %s", keys);
+	DBG("telephony-maemo: got key press request for %s", keys);
 
 	waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
 	if (!waiting)
@@ -882,6 +914,14 @@
 		telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
 }
 
+void telephony_voice_dial_req(void *telephony_device, gboolean enable)
+{
+	DBG("telephony-maemo: got %s voice dial request",
+			enable ? "enable" : "disable");
+
+	telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
+}
+
 static void handle_incoming_call(DBusMessage *msg)
 {
 	const char *number, *call_path;
@@ -902,7 +942,7 @@
 		return;
 	}
 
-	debug("Incoming call to %s from number %s", call_path, number);
+	DBG("Incoming call to %s from number %s", call_path, number);
 
 	g_free(call->number);
 	call->number = g_strdup(number);
@@ -938,7 +978,7 @@
 		return;
 	}
 
-	debug("Outgoing call from %s to number %s", call_path, number);
+	DBG("Outgoing call from %s to number %s", call_path, number);
 
 	g_free(call->number);
 	call->number = g_strdup(number);
@@ -962,7 +1002,7 @@
 
 static void handle_create_requested(DBusMessage *msg)
 {
-	debug("Call.CreateRequested()");
+	DBG("Call.CreateRequested()");
 
 	if (create_request_timer)
 		g_source_remove(create_request_timer);
@@ -1000,11 +1040,11 @@
 		return;
 	}
 
-	debug("Call %s changed from %s to %s", call_path,
+	DBG("Call %s changed from %s to %s", call_path,
 		call_status_str[call->status], call_status_str[status]);
 
 	if (call->status == (int) status) {
-		debug("Ignoring CSD Call state change to existing state");
+		DBG("Ignoring CSD Call state change to existing state");
 		return;
 	}
 
@@ -1142,7 +1182,7 @@
 		return;
 	}
 
-	debug("Call %s %s the conference", path, joined ? "joined" : "left");
+	DBG("Call %s %s the conference", path, joined ? "joined" : "left");
 
 	call->conference = joined;
 }
@@ -1187,7 +1227,7 @@
 	g_free(net.operator_name);
 	net.operator_name = g_strdup(name);
 
-	debug("telephony-maemo: operator name updated: %s", name);
+	DBG("telephony-maemo: operator name updated: %s", name);
 
 done:
 	dbus_message_unref(reply);
@@ -1295,7 +1335,7 @@
 	int signal;
 
 	if (signals_bar > 100) {
-		debug("signals_bar greater than expected: %u", signals_bar);
+		DBG("signals_bar greater than expected: %u", signals_bar);
 		signals_bar = 100;
 	}
 
@@ -1309,7 +1349,7 @@
 
 	net.signals_bar = signals_bar;
 
-	debug("Signal strength updated: %u/100, %d/5", signals_bar, signal);
+	DBG("Signal strength updated: %u/100, %d/5", signals_bar, signal);
 }
 
 static void handle_signal_strength_change(DBusMessage *msg)
@@ -1372,20 +1412,26 @@
 		goto done;
 	}
 
-	dbus_message_get_args(reply, NULL,
+	dbus_error_init(&err);
+	if (dbus_message_get_args(reply, &err,
 				DBUS_TYPE_INT32, &level,
-				DBUS_TYPE_INVALID);
+				DBUS_TYPE_INVALID) == FALSE) {
+		error("Unable to parse GetPropertyInteger reply: %s, %s",
+							err.name, err.message);
+		dbus_error_free(&err);
+		goto done;
+	}
 
 	*value = (int) level;
 
 	if (value == &battchg_last)
-		debug("telephony-maemo: battery.charge_level.last_full is %d",
+		DBG("telephony-maemo: battery.charge_level.last_full is %d",
 				*value);
 	else if (value == &battchg_design)
-		debug("telephony-maemo: battery.charge_level.design is %d",
+		DBG("telephony-maemo: battery.charge_level.design is %d",
 				*value);
 	else
-		debug("telephony-maemo: battery.charge_level.current is %d",
+		DBG("telephony-maemo: battery.charge_level.current is %d",
 				*value);
 
 	if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
@@ -1466,40 +1512,6 @@
 	}
 }
 
-static DBusHandlerResult signal_filter(DBusConnection *conn,
-						DBusMessage *msg, void *data)
-{
-	const char *path = dbus_message_get_path(msg);
-
-	if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
-		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-	if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
-		handle_incoming_call(msg);
-	else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
-		handle_outgoing_call(msg);
-	else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
-							"CreateRequested"))
-		handle_create_requested(msg);
-	else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
-		handle_call_status(msg, path);
-	else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
-		handle_conference(msg, TRUE);
-	else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
-		handle_conference(msg, FALSE);
-	else if (dbus_message_is_signal(msg, NETWORK_INTERFACE,
-					"registration_status_change"))
-		handle_registration_status_change(msg);
-	else if (dbus_message_is_signal(msg, NETWORK_INTERFACE,
-					"signal_strength_change"))
-		handle_signal_strength_change(msg);
-	else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
-					"PropertyModified"))
-		handle_hal_property_modified(msg);
-
-	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
 static void csd_call_free(struct csd_call *call)
 {
 	if (!call)
@@ -1547,7 +1559,7 @@
 			call->object_path = g_strdup(object_path);
 			call->status = (int) status;
 			calls = g_slist_append(calls, call);
-			debug("telephony-maemo: new csd call instance at %s",
+			DBG("telephony-maemo: new csd call instance at %s",
 								object_path);
 		}
 
@@ -1589,7 +1601,7 @@
 	}
 
 	dbus_error_init(&err);
-	if (!dbus_message_get_args(reply, NULL,
+	if (!dbus_message_get_args(reply, &err,
 					DBUS_TYPE_BYTE, &signals_bar,
 					DBUS_TYPE_BYTE, &rssi_in_dbm,
 					DBUS_TYPE_INT32, &net_err,
@@ -1627,13 +1639,6 @@
 	dbus_uint16_t lac, network_type, supported_services;
 	dbus_uint32_t cell_id, operator_code, country_code;
 	dbus_int32_t net_err;
-	uint32_t features = AG_FEATURE_EC_ANDOR_NR |
-				AG_FEATURE_INBAND_RINGTONE |
-				AG_FEATURE_REJECT_A_CALL |
-				AG_FEATURE_ENHANCED_CALL_STATUS |
-				AG_FEATURE_ENHANCED_CALL_CONTROL |
-				AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
-				AG_FEATURE_THREE_WAY_CALLING;
 
 	reply = dbus_pending_call_steal_reply(call);
 
@@ -1646,7 +1651,7 @@
 	}
 
 	dbus_error_init(&err);
-	if (!dbus_message_get_args(reply, NULL,
+	if (!dbus_message_get_args(reply, &err,
 					DBUS_TYPE_BYTE, &status,
 					DBUS_TYPE_UINT16, &lac,
 					DBUS_TYPE_UINT32, &cell_id,
@@ -1671,9 +1676,6 @@
 					country_code, network_type,
 					supported_services);
 
-	telephony_ready_ind(features, maemo_indicators, response_and_hold,
-				chld_str);
-
 	get_signal_strength();
 
 done:
@@ -1694,6 +1696,8 @@
 	DBusMessage *reply;
 	DBusMessageIter iter, sub;;
 
+	get_calls_active = FALSE;
+
 	reply = dbus_pending_call_steal_reply(call);
 
 	dbus_error_init(&err);
@@ -1743,7 +1747,7 @@
 	dbus_message_iter_init(reply, &iter);
 
 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-		error("Unexpected signature in GetCallInfoAll return");
+		error("Unexpected signature in FindDeviceByCapability return");
 		goto done;
 	}
 
@@ -1758,7 +1762,7 @@
 
 	dbus_message_iter_get_basic(&sub, &path);
 
-	debug("telephony-maemo: found battery device at %s", path);
+	DBG("telephony-maemo: found battery device at %s", path);
 
 	snprintf(match_string, sizeof(match_string),
 			"type='signal',"
@@ -1794,14 +1798,12 @@
 	}
 
 	dbus_error_init(&derr);
-	dbus_message_get_args(reply, NULL,
+	if (dbus_message_get_args(reply, &derr,
 				DBUS_TYPE_STRING, &name,
 				DBUS_TYPE_STRING, &number,
 				DBUS_TYPE_INT32, &current_location,
 				DBUS_TYPE_INT32, &err,
-				DBUS_TYPE_INVALID);
-
-	if (dbus_error_is_set(&derr)) {
+				DBUS_TYPE_INVALID) == FALSE) {
 		error("Unable to parse SIM.Phonebook.read arguments: %s, %s",
 				derr.name, derr.message);
 		dbus_error_free(&derr);
@@ -1818,66 +1820,32 @@
 	if (number_type == &msisdn) {
 		g_free(msisdn);
 		msisdn = g_strdup(number);
-		debug("Got MSISDN %s (%s)", number, name);
+		DBG("Got MSISDN %s (%s)", number, name);
 	} else {
 		g_free(vmbx);
 		vmbx = g_strdup(number);
-		debug("Got voice mailbox number %s (%s)", number, name);
+		DBG("Got voice mailbox number %s (%s)", number, name);
 	}
 
 done:
 	dbus_message_unref(reply);
 }
 
-static gboolean csd_init(gpointer user_data)
+static void csd_init(void)
 {
-	char match_string[128];
-	const char *battery_cap = "battery";
 	dbus_uint32_t location;
 	uint8_t pb_type, location_type;
 	int ret;
 
-	if (!dbus_connection_add_filter(connection, signal_filter,
-						NULL, NULL)) {
-		error("Can't add signal filter");
-		return FALSE;
-	}
-
-	snprintf(match_string, sizeof(match_string),
-			"type=signal,interface=%s", CSD_CALL_INTERFACE);
-	dbus_bus_add_match(connection, match_string, NULL);
-
-	snprintf(match_string, sizeof(match_string),
-			"type=signal,interface=%s", CSD_CALL_INSTANCE);
-	dbus_bus_add_match(connection, match_string, NULL);
-
-	snprintf(match_string, sizeof(match_string),
-			"type=signal,interface=%s", CSD_CALL_CONFERENCE);
-	dbus_bus_add_match(connection, match_string, NULL);
-
-	snprintf(match_string, sizeof(match_string),
-			"type=signal,interface=%s", NETWORK_INTERFACE);
-	dbus_bus_add_match(connection, match_string, NULL);
-
 	ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
 				CSD_CALL_INTERFACE, "GetCallInfoAll",
 				call_info_reply, NULL, DBUS_TYPE_INVALID);
 	if (ret < 0) {
 		error("Unable to sent GetCallInfoAll method call");
-		return FALSE;
+		return;
 	}
 
-	ret = send_method_call("org.freedesktop.Hal",
-				"/org/freedesktop/Hal/Manager",
-				"org.freedesktop.Hal.Manager",
-				"FindDeviceByCapability",
-				hal_find_device_reply, NULL,
-				DBUS_TYPE_STRING, &battery_cap,
-				DBUS_TYPE_INVALID);
-	if (ret < 0) {
-		error("Unable to send HAL method call");
-		return FALSE;
-	}
+	get_calls_active = TRUE;
 
 	pb_type = SIM_PHONEBOOK_TYPE_MSISDN;
 	location = PHONEBOOK_INDEX_FIRST_ENTRY;
@@ -1892,10 +1860,10 @@
 				DBUS_TYPE_INVALID);
 	if (ret < 0) {
 		error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
-		return FALSE;
+		return;
 	}
 
-	pb_type = SIM_PHONEBOOK_TYPE_VMBX;
+	pb_type = SIM_PHONEBOOK_TYPE_MBDN;
 	location = PHONEBOOK_INDEX_FIRST_ENTRY;
 	location_type = SIM_PHONEBOOK_LOCATION_NEXT;
 
@@ -1908,18 +1876,8 @@
 				DBUS_TYPE_INVALID);
 	if (ret < 0) {
 		error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
-		return FALSE;
+		return;
 	}
-
-	return FALSE;
-}
-
-static void csd_ready(DBusConnection *conn, void *user_data)
-{
-	g_dbus_remove_watch(conn, csd_watch);
-	csd_watch = 0;
-
-	g_timeout_add_seconds(2, csd_init, NULL);
 }
 
 static inline DBusMessage *invalid_args(DBusMessage *msg)
@@ -1999,7 +1957,7 @@
 			g_str_equal(callerid_setting, "none")) {
 		save_callerid_to_file(callerid_setting);
 		callerid = get_callflag(callerid_setting);
-		debug("telephony-maemo setting callerid flag: %s",
+		DBG("telephony-maemo setting callerid flag: %s",
 							callerid_setting);
 		return dbus_message_new_method_return(msg);
 	}
@@ -2015,17 +1973,110 @@
 	{ }
 };
 
+static void handle_modem_state(DBusMessage *msg)
+{
+	const char *state;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &state,
+							DBUS_TYPE_INVALID)) {
+		error("Unexpected modem state parameters");
+		return;
+	}
+
+	DBG("SSC modem state: %s", state);
+
+	if (calls != NULL || get_calls_active)
+		return;
+
+	if (g_str_equal(state, "cmt_ready") || g_str_equal(state, "online"))
+		csd_init();
+}
+
+static void modem_state_reply(DBusPendingCall *call, void *user_data)
+{
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError err;
+
+	dbus_error_init(&err);
+	if (dbus_set_error_from_message(&err, reply)) {
+		error("get_modem_status: %s, %s", err.name, err.message);
+		dbus_error_free(&err);
+	} else
+		handle_modem_state(reply);
+
+	dbus_message_unref(reply);
+}
+
+static DBusHandlerResult signal_filter(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	const char *path = dbus_message_get_path(msg);
+
+	if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+	if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
+		handle_incoming_call(msg);
+	else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
+		handle_outgoing_call(msg);
+	else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
+							"CreateRequested"))
+		handle_create_requested(msg);
+	else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
+		handle_call_status(msg, path);
+	else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
+		handle_conference(msg, TRUE);
+	else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
+		handle_conference(msg, FALSE);
+	else if (dbus_message_is_signal(msg, NETWORK_INTERFACE,
+					"registration_status_change"))
+		handle_registration_status_change(msg);
+	else if (dbus_message_is_signal(msg, NETWORK_INTERFACE,
+					"signal_strength_change"))
+		handle_signal_strength_change(msg);
+	else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
+					"PropertyModified"))
+		handle_hal_property_modified(msg);
+	else if (dbus_message_is_signal(msg, SSC_DBUS_IFACE,
+						"modem_state_changed_ind"))
+		handle_modem_state(msg);
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
 int telephony_init(void)
 {
+	const char *battery_cap = "battery";
+	uint32_t features = AG_FEATURE_EC_ANDOR_NR |
+				AG_FEATURE_INBAND_RINGTONE |
+				AG_FEATURE_REJECT_A_CALL |
+				AG_FEATURE_ENHANCED_CALL_STATUS |
+				AG_FEATURE_ENHANCED_CALL_CONTROL |
+				AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
+				AG_FEATURE_THREE_WAY_CALLING;
+
 	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
 
-	csd_watch = g_dbus_add_service_watch(connection, CSD_CALL_BUS_NAME,
-						csd_ready, NULL, NULL, NULL);
+	if (!dbus_connection_add_filter(connection, signal_filter,
+						NULL, NULL))
+		error("Can't add signal filter");
 
-	if (dbus_bus_name_has_owner(connection, CSD_CALL_BUS_NAME, NULL))
-		csd_ready(connection, NULL);
-	else
-		info("CSD not yet available. Waiting for it...");
+	dbus_bus_add_match(connection,
+			"type=signal,interface=" CSD_CALL_INTERFACE, NULL);
+	dbus_bus_add_match(connection,
+			"type=signal,interface=" CSD_CALL_INSTANCE, NULL);
+	dbus_bus_add_match(connection,
+			"type=signal,interface=" CSD_CALL_CONFERENCE, NULL);
+	dbus_bus_add_match(connection,
+			"type=signal,interface=" NETWORK_INTERFACE, NULL);
+	dbus_bus_add_match(connection,
+				"type=signal,interface=" SSC_DBUS_IFACE
+				",member=modem_state_changed_ind", NULL);
+
+	if (send_method_call(SSC_DBUS_NAME, SSC_DBUS_PATH, SSC_DBUS_IFACE,
+					"get_modem_state", modem_state_reply,
+					NULL, DBUS_TYPE_INVALID) < 0)
+		error("Unable to send " SSC_DBUS_IFACE ".get_modem_state()");
 
 	generate_flag_file(NONE_FLAG_FILE);
 	callerid = callerid_from_file();
@@ -2037,19 +2088,25 @@
 			TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
 	}
 
-	debug("telephony-maemo registering %s interface on path %s",
+	DBG("telephony-maemo registering %s interface on path %s",
 			TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
 
+	telephony_ready_ind(features, maemo_indicators, response_and_hold,
+								chld_str);
+	if (send_method_call("org.freedesktop.Hal",
+				"/org/freedesktop/Hal/Manager",
+				"org.freedesktop.Hal.Manager",
+				"FindDeviceByCapability",
+				hal_find_device_reply, NULL,
+				DBUS_TYPE_STRING, &battery_cap,
+				DBUS_TYPE_INVALID) < 0)
+		error("Unable to send HAL method call");
+
 	return 0;
 }
 
 void telephony_exit(void)
 {
-	if (csd_watch) {
-		g_dbus_remove_watch(connection, csd_watch);
-		csd_watch = 0;
-	}
-
 	g_slist_foreach(calls, (GFunc) csd_call_free, NULL);
 	g_slist_free(calls);
 	calls = NULL;
diff --git a/audio/telephony-maemo.c b/audio/telephony-maemo6.c
similarity index 73%
copy from audio/telephony-maemo.c
copy to audio/telephony-maemo6.c
index f302cdf..046620c 100644
--- a/audio/telephony-maemo.c
+++ b/audio/telephony-maemo6.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2008-2009  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -36,55 +36,36 @@
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 #include "telephony.h"
 
+/* SSC D-Bus definitions */
+#define SSC_DBUS_NAME  "com.nokia.phone.SSC"
+#define SSC_DBUS_IFACE "com.nokia.phone.SSC"
+#define SSC_DBUS_PATH  "/com/nokia/phone/SSC"
+
 /* libcsnet D-Bus definitions */
-#define NETWORK_BUS_NAME		"com.nokia.phone.net"
-#define NETWORK_INTERFACE		"Phone.Net"
-#define NETWORK_PATH			"/com/nokia/phone/net"
-
-/* Mask bits for supported services */
-#define NETWORK_MASK_GPRS_SUPPORT	0x01
-#define NETWORK_MASK_CS_SERVICES	0x02
-#define NETWORK_MASK_EGPRS_SUPPORT	0x04
-#define NETWORK_MASK_HSDPA_AVAIL	0x08
-#define NETWORK_MASK_HSUPA_AVAIL	0x10
-
-/* network get cell info: cell type */
-#define NETWORK_UNKNOWN_CELL		0
-#define NETWORK_GSM_CELL		1
-#define NETWORK_WCDMA_CELL		2
+#define CSD_CSNET_BUS_NAME	"com.nokia.csd.CSNet"
+#define CSD_CSNET_PATH		"/com/nokia/csd/csnet"
+#define CSD_CSNET_IFACE		"com.nokia.csd.CSNet"
+#define CSD_CSNET_REGISTRATION	"com.nokia.csd.CSNet.NetworkRegistration"
+#define CSD_CSNET_OPERATOR	"com.nokia.csd.CSNet.NetworkOperator"
+#define CSD_CSNET_SIGNAL	"com.nokia.csd.CSNet.SignalStrength"
 
 enum net_registration_status {
-	NETWORK_REG_STATUS_HOME = 0x00,
-	NETWORK_REG_STATUS_ROAM,
-	NETWORK_REG_STATUS_ROAM_BLINK,
-	NETWORK_REG_STATUS_NOSERV,
-	NETWORK_REG_STATUS_NOSERV_SEARCHING,
-	NETWORK_REG_STATUS_NOSERV_NOTSEARCHING,
-	NETWORK_REG_STATUS_NOSERV_NOSIM,
-	NETWORK_REG_STATUS_POWER_OFF = 0x08,
-	NETWORK_REG_STATUS_NSPS,
-	NETWORK_REG_STATUS_NSPS_NO_COVERAGE,
-	NETWORK_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW
+	NETWORK_REG_STATUS_HOME,
+	NETWORK_REG_STATUS_ROAMING,
+	NETWORK_REG_STATUS_OFFLINE,
+	NETWORK_REG_STATUS_SEARCHING,
+	NETWORK_REG_STATUS_NO_SIM,
+	NETWORK_REG_STATUS_POWEROFF,
+	NETWORK_REG_STATUS_POWERSAFE,
+	NETWORK_REG_STATUS_NO_COVERAGE,
+	NETWORK_REG_STATUS_REJECTED,
+	NETWORK_REG_STATUS_UNKOWN
 };
 
-enum network_types {
-	NETWORK_GSM_HOME_PLMN = 0,
-	NETWORK_GSM_PREFERRED_PLMN,
-	NETWORK_GSM_FORBIDDEN_PLMN,
-	NETWORK_GSM_OTHER_PLMN,
-	NETWORK_GSM_NO_PLMN_AVAIL
-};
-
-enum network_alpha_tag_name_type {
-	NETWORK_HARDCODED_LATIN_OPER_NAME = 0,
-	NETWORK_HARDCODED_USC2_OPER_NAME,
-	NETWORK_NITZ_SHORT_OPER_NAME,
-	NETWORK_NITZ_FULL_OPER_NAME,
-};
-
+/* Driver definitions */
 #define TELEPHONY_MAEMO_PATH		"/com/nokia/MaemoTelephony"
 #define TELEPHONY_MAEMO_INTERFACE	"com.nokia.MaemoTelephony"
 
@@ -101,6 +82,7 @@
 #define CSD_CALL_INSTANCE	"com.nokia.csd.Call.Instance"
 #define CSD_CALL_CONFERENCE	"com.nokia.csd.Call.Conference"
 #define CSD_CALL_PATH		"/com/nokia/csd/call"
+#define CSD_CALL_CONFERENCE_PATH "/com/nokia/csd/call/conference"
 
 /* Call status values as exported by the CSD CALL plugin */
 #define CSD_CALL_STATUS_IDLE			0
@@ -126,27 +108,17 @@
 #define CALL_FLAG_PRESENTATION_RESTRICTED	0x02
 
 /* SIM Phonebook D-Bus definitions */
-#define SIM_PHONEBOOK_BUS_NAME			"com.nokia.phone.SIM"
-#define SIM_PHONEBOOK_INTERFACE			"Phone.Sim.Phonebook"
-#define SIM_PHONEBOOK_PATH			"/com/nokia/phone/SIM/phonebook"
+#define CSD_SIMPB_BUS_NAME			"com.nokia.csd.SIM"
+#define CSD_SIMPB_INTERFACE			"com.nokia.csd.SIM.Phonebook"
+#define CSD_SIMPB_PATH				"/com/nokia/csd/sim/phonebook"
 
-#define PHONEBOOK_INDEX_FIRST_ENTRY		0xFFFF
-#define PHONEBOOK_INDEX_NEXT_FREE_LOCATION	0xFFFE
-
-enum sim_phonebook_type {
-	SIM_PHONEBOOK_TYPE_ADN = 0x0,
-	SIM_PHONEBOOK_TYPE_SDN,
-	SIM_PHONEBOOK_TYPE_FDN,
-	SIM_PHONEBOOK_TYPE_VMBX,
-	SIM_PHONEBOOK_TYPE_MBDN,
-	SIM_PHONEBOOK_TYPE_EN,
-	SIM_PHONEBOOK_TYPE_MSISDN
-};
-
-enum sim_phonebook_location_type {
-	SIM_PHONEBOOK_LOCATION_EXACT = 0x0,
-	SIM_PHONEBOOK_LOCATION_NEXT
-};
+#define CSD_SIMPB_TYPE_ADN			"ADN"
+#define CSD_SIMPB_TYPE_FDN			"FDN"
+#define CSD_SIMPB_TYPE_SDN			"SDN"
+#define CSD_SIMPB_TYPE_VMBX			"VMBX"
+#define CSD_SIMPB_TYPE_MBDN			"MBDN"
+#define CSD_SIMPB_TYPE_EN			"EN"
+#define CSD_SIMPB_TYPE_MSISDN			"MSISDN"
 
 struct csd_call {
 	char *object_path;
@@ -160,28 +132,19 @@
 };
 
 static struct {
-	uint8_t status;
-	uint16_t lac;
-	uint32_t cell_id;
-	uint32_t operator_code;
-	uint32_t country_code;
-	uint8_t network_type;
-	uint8_t supported_services;
-	uint16_t signals_bar;
 	char *operator_name;
+	uint8_t status;
+	int32_t signal_bars;
 } net = {
-	.status = NETWORK_REG_STATUS_NOSERV,
-	.lac = 0,
-	.cell_id = 0,
-	.operator_code = 0,
-	.country_code = 0,
-	.network_type = NETWORK_GSM_NO_PLMN_AVAIL,
-	.supported_services = 0,
-	.signals_bar = 0,
 	.operator_name = NULL,
+	.status = NETWORK_REG_STATUS_UNKOWN,
+	/* Init as 0 meaning inactive mode. In modem power off state
+	 * can be be -1, but we treat all values as 0s regardless
+	 * inactive or power off. */
+	.signal_bars = 0,
 };
 
-static guint csd_watch = 0;
+static int get_property(const char *iface, const char *prop);
 
 static DBusConnection *connection = NULL;
 
@@ -198,6 +161,8 @@
 static int battchg_last = -1;	/* "battery.charge_level.last_full" */
 static int battchg_design = -1;	/* "battery.charge_level.design" */
 
+static gboolean get_calls_active = FALSE;
+
 static gboolean events_enabled = FALSE;
 
 /* Supported set of call hold operations */
@@ -219,8 +184,9 @@
 static struct indicator maemo_indicators[] =
 {
 	{ "battchg",	"0-5",	5,	TRUE },
-	{ "signal",	"0-5",	5,	TRUE },
-	{ "service",	"0,1",	1,	TRUE },
+	/* signal strength in terms of bars */
+	{ "signal",	"0-5",	0,	TRUE },
+	{ "service",	"0,1",	0,	TRUE },
 	{ "call",	"0,1",	0,	TRUE },
 	{ "callsetup",	"0-3",	0,	TRUE },
 	{ "callheld",	"0-2",	0,	FALSE },
@@ -308,6 +274,26 @@
 	return NULL;
 }
 
+static int release_conference(void)
+{
+	DBusMessage *msg;
+
+	DBG("telephony-maemo6: releasing conference call");
+
+	msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
+						CSD_CALL_CONFERENCE_PATH,
+						CSD_CALL_INSTANCE,
+						"Release");
+	if (!msg) {
+		error("Unable to allocate new D-Bus message");
+		return -ENOMEM;
+	}
+
+	g_dbus_send_message(connection, msg);
+
+	return 0;
+}
+
 static int release_call(struct csd_call *call)
 {
 	DBusMessage *msg;
@@ -462,7 +448,7 @@
 {
 	struct csd_call *coming;
 
-	debug("telephony-maemo: device %p connected", telephony_device);
+	DBG("telephony-maemo6: device %p connected", telephony_device);
 
 	coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
 	if (coming) {
@@ -477,7 +463,7 @@
 
 void telephony_device_disconnected(void *telephony_device)
 {
-	debug("telephony-maemo: device %p disconnected", telephony_device);
+	DBG("telephony-maemo6: device %p disconnected", telephony_device);
 	events_enabled = FALSE;
 }
 
@@ -499,7 +485,7 @@
 
 void telephony_last_dialed_number_req(void *telephony_device)
 {
-	debug("telephony-maemo: last dialed number request");
+	DBG("telephony-maemo6: last dialed number request");
 
 	if (last_dialed_number)
 		telephony_dial_number_req(telephony_device,
@@ -512,6 +498,7 @@
 void telephony_terminate_call_req(void *telephony_device)
 {
 	struct csd_call *call;
+	int err;
 
 	call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
 	if (!call)
@@ -524,7 +511,12 @@
 		return;
 	}
 
-	if (release_call(call) < 0)
+	if (call->conference)
+		err = release_conference();
+	else
+		err = release_call(call);
+
+	if (err < 0)
 		telephony_terminate_call_rsp(telephony_device,
 						CME_ERROR_AG_FAILURE);
 	else
@@ -614,7 +606,7 @@
 	uint32_t flags = callerid;
 	int ret;
 
-	debug("telephony-maemo: dial request to %s", number);
+	DBG("telephony-maemo6: dial request to %s", number);
 
 	if (strncmp(number, "*31#", 4) == 0) {
 		number += 4;
@@ -654,7 +646,7 @@
 	int ret;
 	char buf[2] = { tone, '\0' }, *buf_ptr = buf;
 
-	debug("telephony-maemo: transmit dtmf: %s", buf);
+	DBG("telephony-maemo6: transmit dtmf: %s", buf);
 
 	ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
 				CSD_CALL_INTERFACE, "SendDTMF",
@@ -672,7 +664,7 @@
 
 void telephony_subscriber_number_req(void *telephony_device)
 {
-	debug("telephony-maemo: subscriber number request");
+	DBG("telephony-maemo6: subscriber number request");
 	if (msisdn)
 		telephony_subscriber_number_ind(msisdn,
 						number_type(msisdn),
@@ -723,7 +715,7 @@
 	GSList *l;
 	int i;
 
-	debug("telephony-maemo: list current calls request");
+	DBG("telephony-maemo6: list current calls request");
 
 	for (l = calls, i = 1; l != NULL; l = l->next, i++) {
 		struct csd_call *call = l->data;
@@ -774,7 +766,7 @@
 	struct csd_call *call;
 	int err = 0;
 
-	debug("telephony-maemo: got call hold request %s", cmd);
+	DBG("telephony-maemo6: got call hold request %s", cmd);
 
 	if (strlen(cmd) > 1)
 		idx = &cmd[1];
@@ -835,7 +827,7 @@
 		err = call_transfer();
 		break;
 	default:
-		debug("Unknown call hold request");
+		DBG("Unknown call hold request");
 		break;
 	}
 
@@ -848,7 +840,7 @@
 
 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
 {
-	debug("telephony-maemo: got %s NR and EC request",
+	DBG("telephony-maemo6: got %s NR and EC request",
 			enable ? "enable" : "disable");
 	telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
 }
@@ -858,7 +850,7 @@
 	struct csd_call *active, *waiting;
 	int err;
 
-	debug("telephony-maemo: got key press request for %s", keys);
+	DBG("telephony-maemo6: got key press request for %s", keys);
 
 	waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
 	if (!waiting)
@@ -882,6 +874,14 @@
 		telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
 }
 
+void telephony_voice_dial_req(void *telephony_device, gboolean enable)
+{
+	DBG("telephony-maemo6: got %s voice dial request",
+			enable ? "enable" : "disable");
+
+	telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
+}
+
 static void handle_incoming_call(DBusMessage *msg)
 {
 	const char *number, *call_path;
@@ -902,7 +902,7 @@
 		return;
 	}
 
-	debug("Incoming call to %s from number %s", call_path, number);
+	DBG("Incoming call to %s from number %s", call_path, number);
 
 	g_free(call->number);
 	call->number = g_strdup(number);
@@ -938,7 +938,7 @@
 		return;
 	}
 
-	debug("Outgoing call from %s to number %s", call_path, number);
+	DBG("Outgoing call from %s to number %s", call_path, number);
 
 	g_free(call->number);
 	call->number = g_strdup(number);
@@ -962,7 +962,7 @@
 
 static void handle_create_requested(DBusMessage *msg)
 {
-	debug("Call.CreateRequested()");
+	DBG("Call.CreateRequested()");
 
 	if (create_request_timer)
 		g_source_remove(create_request_timer);
@@ -1000,11 +1000,11 @@
 		return;
 	}
 
-	debug("Call %s changed from %s to %s", call_path,
+	DBG("Call %s changed from %s to %s", call_path,
 		call_status_str[call->status], call_status_str[status]);
 
 	if (call->status == (int) status) {
-		debug("Ignoring CSD Call state change to existing state");
+		DBG("Ignoring CSD Call state change to existing state");
 		return;
 	}
 
@@ -1142,189 +1142,128 @@
 		return;
 	}
 
-	debug("Call %s %s the conference", path, joined ? "joined" : "left");
+	DBG("Call %s %s the conference", path, joined ? "joined" : "left");
 
 	call->conference = joined;
 }
 
-static void get_operator_name_reply(DBusPendingCall *pending_call,
-					void *user_data)
+static uint8_t str2status(const char *state)
 {
-	DBusMessage *reply;
-	DBusError err;
-	const char *name;
-	dbus_int32_t net_err;
-
-	reply = dbus_pending_call_steal_reply(pending_call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("get_operator_name failed: %s, %s",
-			err.name, err.message);
-		dbus_error_free(&err);
-		goto done;
-	}
-
-	dbus_error_init(&err);
-	if (!dbus_message_get_args(reply, &err,
-					DBUS_TYPE_STRING, &name,
-					DBUS_TYPE_INT32, &net_err,
-					DBUS_TYPE_INVALID)) {
-		error("Unexpected get_operator_name reply parameters: %s, %s",
-			err.name, err.message);
-		dbus_error_free(&err);
-		goto done;
-	}
-
-	if (net_err != 0) {
-		error("get_operator_name failed with code %d", net_err);
-		goto done;
-	}
-
-	if (strlen(name) == 0)
-		goto done;
-
-	g_free(net.operator_name);
-	net.operator_name = g_strdup(name);
-
-	debug("telephony-maemo: operator name updated: %s", name);
-
-done:
-	dbus_message_unref(reply);
+	if (g_strcmp0(state, "Home") == 0)
+		return NETWORK_REG_STATUS_HOME;
+	else if (g_strcmp0(state, "Roaming") == 0)
+		return NETWORK_REG_STATUS_ROAMING;
+	else if (g_strcmp0(state, "Offline") == 0)
+		return NETWORK_REG_STATUS_OFFLINE;
+	else if (g_strcmp0(state, "Searching") == 0)
+		return NETWORK_REG_STATUS_SEARCHING;
+	else if (g_strcmp0(state, "NoSim") == 0)
+		return NETWORK_REG_STATUS_NO_SIM;
+	else if (g_strcmp0(state, "Poweroff") == 0)
+		return NETWORK_REG_STATUS_POWEROFF;
+	else if (g_strcmp0(state, "Powersafe") == 0)
+		return NETWORK_REG_STATUS_POWERSAFE;
+	else if (g_strcmp0(state, "NoCoverage") == 0)
+		return NETWORK_REG_STATUS_NO_COVERAGE;
+	else if (g_strcmp0(state, "Reject") == 0)
+		return NETWORK_REG_STATUS_REJECTED;
+	else
+		return NETWORK_REG_STATUS_UNKOWN;
 }
 
-static void resolve_operator_name(uint32_t operator, uint32_t country)
+static void update_registration_status(const char *status)
 {
-	uint8_t name_type = NETWORK_HARDCODED_LATIN_OPER_NAME;
+	uint8_t new_status;
 
-	send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
-				NETWORK_INTERFACE, "get_operator_name",
-				get_operator_name_reply, NULL,
-				DBUS_TYPE_BYTE, &name_type,
-				DBUS_TYPE_UINT32, &operator,
-				DBUS_TYPE_UINT32, &country,
-				DBUS_TYPE_INVALID);
-}
+	new_status = str2status(status);
 
-static void update_registration_status(uint8_t status, uint16_t lac,
-					uint32_t cell_id,
-					uint32_t operator_code,
-					uint32_t country_code,
-					uint8_t network_type,
-					uint8_t supported_services)
-{
-	if (net.status != status) {
-		switch (status) {
-		case NETWORK_REG_STATUS_HOME:
-			telephony_update_indicator(maemo_indicators, "roam",
+	if (net.status == new_status)
+		return;
+
+	switch (new_status) {
+	case NETWORK_REG_STATUS_HOME:
+		telephony_update_indicator(maemo_indicators, "roam",
 							EV_ROAM_INACTIVE);
-			if (net.status >= NETWORK_REG_STATUS_NOSERV)
-				telephony_update_indicator(maemo_indicators,
+		if (net.status > NETWORK_REG_STATUS_ROAMING)
+			telephony_update_indicator(maemo_indicators,
 							"service",
 							EV_SERVICE_PRESENT);
-			break;
-		case NETWORK_REG_STATUS_ROAM:
-		case NETWORK_REG_STATUS_ROAM_BLINK:
-			telephony_update_indicator(maemo_indicators, "roam",
+		break;
+	case NETWORK_REG_STATUS_ROAMING:
+		telephony_update_indicator(maemo_indicators, "roam",
 							EV_ROAM_ACTIVE);
-			if (net.status >= NETWORK_REG_STATUS_NOSERV)
-				telephony_update_indicator(maemo_indicators,
+		if (net.status > NETWORK_REG_STATUS_ROAMING)
+			telephony_update_indicator(maemo_indicators,
 							"service",
 							EV_SERVICE_PRESENT);
-			break;
-		case NETWORK_REG_STATUS_NOSERV:
-		case NETWORK_REG_STATUS_NOSERV_SEARCHING:
-		case NETWORK_REG_STATUS_NOSERV_NOTSEARCHING:
-		case NETWORK_REG_STATUS_NOSERV_NOSIM:
-		case NETWORK_REG_STATUS_POWER_OFF:
-		case NETWORK_REG_STATUS_NSPS:
-		case NETWORK_REG_STATUS_NSPS_NO_COVERAGE:
-		case NETWORK_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW:
-			if (net.status < NETWORK_REG_STATUS_NOSERV)
-				telephony_update_indicator(maemo_indicators,
+		break;
+	case NETWORK_REG_STATUS_OFFLINE:
+	case NETWORK_REG_STATUS_SEARCHING:
+	case NETWORK_REG_STATUS_NO_SIM:
+	case NETWORK_REG_STATUS_POWEROFF:
+	case NETWORK_REG_STATUS_POWERSAFE:
+	case NETWORK_REG_STATUS_NO_COVERAGE:
+	case NETWORK_REG_STATUS_REJECTED:
+	case NETWORK_REG_STATUS_UNKOWN:
+		if (net.status < NETWORK_REG_STATUS_OFFLINE)
+			telephony_update_indicator(maemo_indicators,
 							"service",
 							EV_SERVICE_NONE);
-			break;
-		}
-
-		net.status = status;
+		break;
 	}
 
-	net.lac = lac;
-	net.cell_id = cell_id;
+	net.status = new_status;
 
-	if (net.operator_code != operator_code ||
-			net.country_code != country_code) {
-		g_free(net.operator_name);
-		net.operator_name = NULL;
-		resolve_operator_name(operator_code, country_code);
-		net.operator_code = operator_code;
-		net.country_code = country_code;
-	}
-
-	net.network_type = network_type;
-	net.supported_services = supported_services;
+	DBG("telephony-maemo6: registration status changed: %s", status);
 }
 
-static void handle_registration_status_change(DBusMessage *msg)
+static void handle_registration_changed(DBusMessage *msg)
 {
-	uint8_t status;
-	dbus_uint16_t lac, network_type, supported_services;
-	dbus_uint32_t cell_id, operator_code, country_code;
+	const char *status;
 
 	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_BYTE, &status,
-					DBUS_TYPE_UINT16, &lac,
-					DBUS_TYPE_UINT32, &cell_id,
-					DBUS_TYPE_UINT32, &operator_code,
-					DBUS_TYPE_UINT32, &country_code,
-					DBUS_TYPE_BYTE, &network_type,
-					DBUS_TYPE_BYTE, &supported_services,
+					DBUS_TYPE_STRING, &status,
 					DBUS_TYPE_INVALID)) {
-		error("Unexpected parameters in registration_status_change");
+		error("Unexpected parameters in RegistrationChanged");
 		return;
 	}
 
-	update_registration_status(status, lac, cell_id, operator_code,
-					country_code, network_type,
-					supported_services);
+	update_registration_status(status);
 }
 
-static void update_signal_strength(uint8_t signals_bar)
+static void update_signal_strength(int32_t signal_bars)
 {
-	int signal;
-
-	if (signals_bar > 100) {
-		debug("signals_bar greater than expected: %u", signals_bar);
-		signals_bar = 100;
+	if (signal_bars < 0) {
+		DBG("signal strength smaller than expected: %d < 0",
+								signal_bars);
+		signal_bars = 0;
+	} else if (signal_bars > 5) {
+		DBG("signal strength greater than expected: %d > 5",
+								signal_bars);
+		signal_bars = 5;
 	}
 
-	if (net.signals_bar == signals_bar)
+	if (net.signal_bars == signal_bars)
 		return;
 
-	/* A simple conversion from 0-100 to 0-5 (used by HFP) */
-	signal = (signals_bar + 20) / 21;
+	telephony_update_indicator(maemo_indicators, "signal", signal_bars);
 
-	telephony_update_indicator(maemo_indicators, "signal", signal);
-
-	net.signals_bar = signals_bar;
-
-	debug("Signal strength updated: %u/100, %d/5", signals_bar, signal);
+	net.signal_bars = signal_bars;
+	DBG("telephony-maemo6: signal strength updated: %d/5", signal_bars);
 }
 
-static void handle_signal_strength_change(DBusMessage *msg)
+static void handle_signal_bars_changed(DBusMessage *msg)
 {
-	uint8_t signals_bar, rssi_in_dbm;
+	int32_t signal_bars;
 
 	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_BYTE, &signals_bar,
-					DBUS_TYPE_BYTE, &rssi_in_dbm,
+					DBUS_TYPE_INT32, &signal_bars,
 					DBUS_TYPE_INVALID)) {
-		error("Unexpected parameters in signal_strength_change");
+		error("Unexpected parameters in SignalBarsChanged");
 		return;
 	}
 
-	update_signal_strength(signals_bar);
+	update_signal_strength(signal_bars);
 }
 
 static gboolean iter_get_basic_args(DBusMessageIter *iter,
@@ -1372,20 +1311,23 @@
 		goto done;
 	}
 
-	dbus_message_get_args(reply, NULL,
+	if (!dbus_message_get_args(reply, NULL,
 				DBUS_TYPE_INT32, &level,
-				DBUS_TYPE_INVALID);
+				DBUS_TYPE_INVALID)) {
+		error("Unexpected args in hald reply");
+		goto done;
+	}
 
 	*value = (int) level;
 
 	if (value == &battchg_last)
-		debug("telephony-maemo: battery.charge_level.last_full is %d",
+		DBG("telephony-maemo6: battery.charge_level.last_full is %d",
 				*value);
 	else if (value == &battchg_design)
-		debug("telephony-maemo: battery.charge_level.design is %d",
+		DBG("telephony-maemo6: battery.charge_level.design is %d",
 				*value);
 	else
-		debug("telephony-maemo: battery.charge_level.current is %d",
+		DBG("telephony-maemo6: battery.charge_level.current is %d",
 				*value);
 
 	if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
@@ -1466,40 +1408,6 @@
 	}
 }
 
-static DBusHandlerResult signal_filter(DBusConnection *conn,
-						DBusMessage *msg, void *data)
-{
-	const char *path = dbus_message_get_path(msg);
-
-	if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
-		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-	if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
-		handle_incoming_call(msg);
-	else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
-		handle_outgoing_call(msg);
-	else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
-							"CreateRequested"))
-		handle_create_requested(msg);
-	else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
-		handle_call_status(msg, path);
-	else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
-		handle_conference(msg, TRUE);
-	else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
-		handle_conference(msg, FALSE);
-	else if (dbus_message_is_signal(msg, NETWORK_INTERFACE,
-					"registration_status_change"))
-		handle_registration_status_change(msg);
-	else if (dbus_message_is_signal(msg, NETWORK_INTERFACE,
-					"signal_strength_change"))
-		handle_signal_strength_change(msg);
-	else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
-					"PropertyModified"))
-		handle_hal_property_modified(msg);
-
-	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
 static void csd_call_free(struct csd_call *call)
 {
 	if (!call)
@@ -1547,7 +1455,7 @@
 			call->object_path = g_strdup(object_path);
 			call->status = (int) status;
 			calls = g_slist_append(calls, call);
-			debug("telephony-maemo: new csd call instance at %s",
+			DBG("telephony-maemo6: new csd call instance at %s",
 								object_path);
 		}
 
@@ -1571,129 +1479,100 @@
 	} while (dbus_message_iter_next(iter));
 }
 
-static void signal_strength_reply(DBusPendingCall *call, void *user_data)
+static void update_operator_name(const char *name)
 {
+	if (name == NULL)
+		return;
+
+	g_free(net.operator_name);
+	net.operator_name = g_strdup(name);
+
+	DBG("telephony-maemo6: operator name updated: %s", name);
+}
+
+static void get_property_reply(DBusPendingCall *call, void *user_data)
+{
+	char *prop = user_data;
 	DBusError err;
 	DBusMessage *reply;
-	uint8_t signals_bar, rssi_in_dbm;
-	dbus_int32_t net_err;
+	DBusMessageIter iter, sub;
 
 	reply = dbus_pending_call_steal_reply(call);
 
 	dbus_error_init(&err);
 	if (dbus_set_error_from_message(&err, reply)) {
-		error("Unable to get signal strength: %s, %s",
-			err.name, err.message);
-		dbus_error_free(&err);
-		goto done;
-	}
-
-	dbus_error_init(&err);
-	if (!dbus_message_get_args(reply, NULL,
-					DBUS_TYPE_BYTE, &signals_bar,
-					DBUS_TYPE_BYTE, &rssi_in_dbm,
-					DBUS_TYPE_INT32, &net_err,
-					DBUS_TYPE_INVALID)) {
-		error("Unable to parse signal_strength reply: %s, %s",
-							err.name, err.message);
-		dbus_error_free(&err);
-		return;
-	}
-
-	if (net_err != 0) {
-		error("get_signal_strength failed with code %d", net_err);
-		return;
-	}
-
-	update_signal_strength(signals_bar);
-
-done:
-	dbus_message_unref(reply);
-}
-
-static int get_signal_strength(void)
-{
-	return send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
-				NETWORK_INTERFACE, "get_signal_strength",
-				signal_strength_reply, NULL,
-				DBUS_TYPE_INVALID);
-}
-
-static void registration_status_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusError err;
-	DBusMessage *reply;
-	uint8_t status;
-	dbus_uint16_t lac, network_type, supported_services;
-	dbus_uint32_t cell_id, operator_code, country_code;
-	dbus_int32_t net_err;
-	uint32_t features = AG_FEATURE_EC_ANDOR_NR |
-				AG_FEATURE_INBAND_RINGTONE |
-				AG_FEATURE_REJECT_A_CALL |
-				AG_FEATURE_ENHANCED_CALL_STATUS |
-				AG_FEATURE_ENHANCED_CALL_CONTROL |
-				AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
-				AG_FEATURE_THREE_WAY_CALLING;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("Unable to get registration status: %s, %s",
+		error("csd replied with an error: %s, %s",
 				err.name, err.message);
 		dbus_error_free(&err);
 		goto done;
 	}
 
-	dbus_error_init(&err);
-	if (!dbus_message_get_args(reply, NULL,
-					DBUS_TYPE_BYTE, &status,
-					DBUS_TYPE_UINT16, &lac,
-					DBUS_TYPE_UINT32, &cell_id,
-					DBUS_TYPE_UINT32, &operator_code,
-					DBUS_TYPE_UINT32, &country_code,
-					DBUS_TYPE_BYTE, &network_type,
-					DBUS_TYPE_BYTE, &supported_services,
-					DBUS_TYPE_INT32, &net_err,
-					DBUS_TYPE_INVALID)) {
-		error("Unable to parse registration_status_change reply:"
-					" %s, %s", err.name, err.message);
-		dbus_error_free(&err);
-		return;
+	dbus_message_iter_init(reply, &iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
+		error("Unexpected signature in Get return");
+		goto done;
 	}
 
-	if (net_err != 0) {
-		error("get_registration_status failed with code %d", net_err);
-		return;
+	dbus_message_iter_recurse(&iter, &sub);
+
+	if (g_strcmp0(prop, "RegistrationStatus") == 0) {
+		const char *status;
+
+		dbus_message_iter_get_basic(&sub, &status);
+		update_registration_status(status);
+
+		get_property(CSD_CSNET_OPERATOR, "OperatorName");
+		get_property(CSD_CSNET_SIGNAL, "SignalBars");
+	} else if (g_strcmp0(prop, "OperatorName") == 0) {
+		const char *name;
+
+		dbus_message_iter_get_basic(&sub, &name);
+		update_operator_name(name);
+	} else if (g_strcmp0(prop, "SignalBars") == 0) {
+		int32_t signal_bars;
+
+		dbus_message_iter_get_basic(&sub, &signal_bars);
+		update_signal_strength(signal_bars);
 	}
 
-	update_registration_status(status, lac, cell_id, operator_code,
-					country_code, network_type,
-					supported_services);
-
-	telephony_ready_ind(features, maemo_indicators, response_and_hold,
-				chld_str);
-
-	get_signal_strength();
-
 done:
+	g_free(prop);
 	dbus_message_unref(reply);
 }
 
-static int get_registration_status(void)
+static int get_property(const char *iface, const char *prop)
 {
-	return send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
-				NETWORK_INTERFACE, "get_registration_status",
-				registration_status_reply, NULL,
+	return send_method_call(CSD_CSNET_BUS_NAME, CSD_CSNET_PATH,
+				DBUS_INTERFACE_PROPERTIES, "Get",
+				get_property_reply, g_strdup(prop),
+				DBUS_TYPE_STRING, &iface,
+				DBUS_TYPE_STRING, &prop,
 				DBUS_TYPE_INVALID);
 }
 
+static void handle_operator_name_changed(DBusMessage *msg)
+{
+	const char *name;
+
+	if (!dbus_message_get_args(msg, NULL,
+					DBUS_TYPE_STRING, &name,
+					DBUS_TYPE_INVALID)) {
+		error("Unexpected parameters in OperatorNameChanged");
+		return;
+	}
+
+	update_operator_name(name);
+}
+
 static void call_info_reply(DBusPendingCall *call, void *user_data)
 {
 	DBusError err;
 	DBusMessage *reply;
 	DBusMessageIter iter, sub;;
 
+	get_calls_active = FALSE;
+
 	reply = dbus_pending_call_steal_reply(call);
 
 	dbus_error_init(&err);
@@ -1715,7 +1594,7 @@
 
 	parse_call_list(&sub);
 
-	get_registration_status();
+	get_property(CSD_CSNET_REGISTRATION, "RegistrationStatus");
 
 done:
 	dbus_message_unref(reply);
@@ -1743,7 +1622,7 @@
 	dbus_message_iter_init(reply, &iter);
 
 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-		error("Unexpected signature in GetCallInfoAll return");
+		error("Unexpected signature in FindDeviceByCapability return");
 		goto done;
 	}
 
@@ -1758,7 +1637,7 @@
 
 	dbus_message_iter_get_basic(&sub, &path);
 
-	debug("telephony-maemo: found battery device at %s", path);
+	DBG("telephony-maemo6: found battery device at %s", path);
 
 	snprintf(match_string, sizeof(match_string),
 			"type='signal',"
@@ -1779,147 +1658,90 @@
 {
 	DBusError derr;
 	DBusMessage *reply;
-	const char *name, *number;
+	const char *name, *number, *secondname, *additionalnumber, *email;
+	int index;
 	char **number_type = user_data;
-	dbus_int32_t current_location, err;
 
 	reply = dbus_pending_call_steal_reply(call);
 
 	dbus_error_init(&derr);
 	if (dbus_set_error_from_message(&derr, reply)) {
-		error("SIM.Phonebook replied with an error: %s, %s",
-				derr.name, derr.message);
+		error("%s.ReadFirst replied with an error: %s, %s",
+				CSD_SIMPB_INTERFACE, derr.name, derr.message);
 		dbus_error_free(&derr);
+		if (number_type == &vmbx)
+			vmbx = g_strdup(getenv("VMBX_NUMBER"));
 		goto done;
 	}
 
 	dbus_error_init(&derr);
-	dbus_message_get_args(reply, NULL,
+	if (dbus_message_get_args(reply, NULL,
+				DBUS_TYPE_INT32, &index,
 				DBUS_TYPE_STRING, &name,
 				DBUS_TYPE_STRING, &number,
-				DBUS_TYPE_INT32, &current_location,
-				DBUS_TYPE_INT32, &err,
-				DBUS_TYPE_INVALID);
-
-	if (dbus_error_is_set(&derr)) {
-		error("Unable to parse SIM.Phonebook.read arguments: %s, %s",
-				derr.name, derr.message);
+				DBUS_TYPE_STRING, &secondname,
+				DBUS_TYPE_STRING, &additionalnumber,
+				DBUS_TYPE_STRING, &email,
+				DBUS_TYPE_INVALID) == FALSE) {
+		error("Unable to parse %s.ReadFirst arguments: %s, %s",
+				CSD_SIMPB_INTERFACE, derr.name, derr.message);
 		dbus_error_free(&derr);
 		goto done;
 	}
 
-	if (err != 0) {
-		error("SIM.Phonebook.read failed with error %d", err);
-		if (number_type == &vmbx)
-			vmbx = g_strdup(getenv("VMBX_NUMBER"));
-		goto done;
-	}
-
 	if (number_type == &msisdn) {
 		g_free(msisdn);
 		msisdn = g_strdup(number);
-		debug("Got MSISDN %s (%s)", number, name);
+		DBG("Got MSISDN %s (%s)", number, name);
 	} else {
 		g_free(vmbx);
 		vmbx = g_strdup(number);
-		debug("Got voice mailbox number %s (%s)", number, name);
+		DBG("Got voice mailbox number %s (%s)", number, name);
 	}
 
 done:
 	dbus_message_unref(reply);
 }
 
-static gboolean csd_init(gpointer user_data)
+static void csd_init(void)
 {
-	char match_string[128];
-	const char *battery_cap = "battery";
-	dbus_uint32_t location;
-	uint8_t pb_type, location_type;
+	const char *pb_type;
 	int ret;
 
-	if (!dbus_connection_add_filter(connection, signal_filter,
-						NULL, NULL)) {
-		error("Can't add signal filter");
-		return FALSE;
-	}
-
-	snprintf(match_string, sizeof(match_string),
-			"type=signal,interface=%s", CSD_CALL_INTERFACE);
-	dbus_bus_add_match(connection, match_string, NULL);
-
-	snprintf(match_string, sizeof(match_string),
-			"type=signal,interface=%s", CSD_CALL_INSTANCE);
-	dbus_bus_add_match(connection, match_string, NULL);
-
-	snprintf(match_string, sizeof(match_string),
-			"type=signal,interface=%s", CSD_CALL_CONFERENCE);
-	dbus_bus_add_match(connection, match_string, NULL);
-
-	snprintf(match_string, sizeof(match_string),
-			"type=signal,interface=%s", NETWORK_INTERFACE);
-	dbus_bus_add_match(connection, match_string, NULL);
-
 	ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
 				CSD_CALL_INTERFACE, "GetCallInfoAll",
 				call_info_reply, NULL, DBUS_TYPE_INVALID);
 	if (ret < 0) {
 		error("Unable to sent GetCallInfoAll method call");
-		return FALSE;
+		return;
 	}
 
-	ret = send_method_call("org.freedesktop.Hal",
-				"/org/freedesktop/Hal/Manager",
-				"org.freedesktop.Hal.Manager",
-				"FindDeviceByCapability",
-				hal_find_device_reply, NULL,
-				DBUS_TYPE_STRING, &battery_cap,
-				DBUS_TYPE_INVALID);
-	if (ret < 0) {
-		error("Unable to send HAL method call");
-		return FALSE;
-	}
+	get_calls_active = TRUE;
 
-	pb_type = SIM_PHONEBOOK_TYPE_MSISDN;
-	location = PHONEBOOK_INDEX_FIRST_ENTRY;
-	location_type = SIM_PHONEBOOK_LOCATION_NEXT;
+	pb_type = CSD_SIMPB_TYPE_MSISDN;
 
-	ret = send_method_call(SIM_PHONEBOOK_BUS_NAME, SIM_PHONEBOOK_PATH,
-				SIM_PHONEBOOK_INTERFACE, "read",
+	ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
+				CSD_SIMPB_INTERFACE, "ReadFirst",
 				phonebook_read_reply, &msisdn,
-				DBUS_TYPE_BYTE, &pb_type,
-				DBUS_TYPE_INT32, &location,
-				DBUS_TYPE_BYTE, &location_type,
+				DBUS_TYPE_STRING, &pb_type,
 				DBUS_TYPE_INVALID);
 	if (ret < 0) {
-		error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
-		return FALSE;
+		error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
+		return;
 	}
 
-	pb_type = SIM_PHONEBOOK_TYPE_VMBX;
-	location = PHONEBOOK_INDEX_FIRST_ENTRY;
-	location_type = SIM_PHONEBOOK_LOCATION_NEXT;
+	/* Voicemail should be in MBDN index 0 */
+	pb_type = CSD_SIMPB_TYPE_MBDN;
 
-	ret = send_method_call(SIM_PHONEBOOK_BUS_NAME, SIM_PHONEBOOK_PATH,
-				SIM_PHONEBOOK_INTERFACE, "read",
+	ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
+				CSD_SIMPB_INTERFACE, "ReadFirst",
 				phonebook_read_reply, &vmbx,
-				DBUS_TYPE_BYTE, &pb_type,
-				DBUS_TYPE_INT32, &location,
-				DBUS_TYPE_BYTE, &location_type,
+				DBUS_TYPE_STRING, &pb_type,
 				DBUS_TYPE_INVALID);
 	if (ret < 0) {
-		error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
-		return FALSE;
+		error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
+		return;
 	}
-
-	return FALSE;
-}
-
-static void csd_ready(DBusConnection *conn, void *user_data)
-{
-	g_dbus_remove_watch(conn, csd_watch);
-	csd_watch = 0;
-
-	g_timeout_add_seconds(2, csd_init, NULL);
 }
 
 static inline DBusMessage *invalid_args(DBusMessage *msg)
@@ -1999,33 +1821,146 @@
 			g_str_equal(callerid_setting, "none")) {
 		save_callerid_to_file(callerid_setting);
 		callerid = get_callflag(callerid_setting);
-		debug("telephony-maemo setting callerid flag: %s",
+		DBG("telephony-maemo6 setting callerid flag: %s",
 							callerid_setting);
 		return dbus_message_new_method_return(msg);
 	}
 
-	error("telephony-maemo: invalid argument %s for method call"
+	error("telephony-maemo6: invalid argument %s for method call"
 					" SetCallerId", callerid_setting);
 		return invalid_args(msg);
 }
 
+static DBusMessage *clear_lastnumber(DBusConnection *conn, DBusMessage *msg,
+					void *data)
+{
+	g_free(last_dialed_number);
+	last_dialed_number = NULL;
+
+	return dbus_message_new_method_return(msg);
+}
+
 static GDBusMethodTable telephony_maemo_methods[] = {
-	{"SetCallerId",		"s",	"",	set_callerid,
-						G_DBUS_METHOD_FLAG_ASYNC},
+	{ "SetCallerId",	"s",	"",	set_callerid,
+						G_DBUS_METHOD_FLAG_ASYNC },
+	{ "ClearLastNumber",	"",	"",	clear_lastnumber },
 	{ }
 };
 
+static void handle_modem_state(DBusMessage *msg)
+{
+	const char *state;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &state,
+							DBUS_TYPE_INVALID)) {
+		error("Unexpected modem state parameters");
+		return;
+	}
+
+	DBG("SSC modem state: %s", state);
+
+	if (calls != NULL || get_calls_active)
+		return;
+
+	if (g_str_equal(state, "cmt_ready") || g_str_equal(state, "online"))
+		csd_init();
+}
+
+static void modem_state_reply(DBusPendingCall *call, void *user_data)
+{
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError err;
+
+	dbus_error_init(&err);
+	if (dbus_set_error_from_message(&err, reply)) {
+		error("get_modem_state: %s, %s", err.name, err.message);
+		dbus_error_free(&err);
+	} else
+		handle_modem_state(reply);
+
+	dbus_message_unref(reply);
+}
+
+static DBusHandlerResult signal_filter(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	const char *path = dbus_message_get_path(msg);
+
+	if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+	if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
+		handle_incoming_call(msg);
+	else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
+		handle_outgoing_call(msg);
+	else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
+							"CreateRequested"))
+		handle_create_requested(msg);
+	else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
+		handle_call_status(msg, path);
+	else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
+		handle_conference(msg, TRUE);
+	else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
+		handle_conference(msg, FALSE);
+	else if (dbus_message_is_signal(msg, CSD_CSNET_REGISTRATION,
+				"RegistrationChanged"))
+		handle_registration_changed(msg);
+	else if (dbus_message_is_signal(msg, CSD_CSNET_OPERATOR,
+				"OperatorNameChanged"))
+		handle_operator_name_changed(msg);
+	else if (dbus_message_is_signal(msg, CSD_CSNET_SIGNAL,
+				"SignalBarsChanged"))
+		handle_signal_bars_changed(msg);
+	else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
+					"PropertyModified"))
+		handle_hal_property_modified(msg);
+	else if (dbus_message_is_signal(msg, SSC_DBUS_IFACE,
+						"modem_state_changed_ind"))
+		handle_modem_state(msg);
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
 int telephony_init(void)
 {
+	const char *battery_cap = "battery";
+	uint32_t features = AG_FEATURE_EC_ANDOR_NR |
+				AG_FEATURE_INBAND_RINGTONE |
+				AG_FEATURE_REJECT_A_CALL |
+				AG_FEATURE_ENHANCED_CALL_STATUS |
+				AG_FEATURE_ENHANCED_CALL_CONTROL |
+				AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
+				AG_FEATURE_THREE_WAY_CALLING;
+
 	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
 
-	csd_watch = g_dbus_add_service_watch(connection, CSD_CALL_BUS_NAME,
-						csd_ready, NULL, NULL, NULL);
+	if (!dbus_connection_add_filter(connection, signal_filter,
+						NULL, NULL))
+		error("Can't add signal filter");
 
-	if (dbus_bus_name_has_owner(connection, CSD_CALL_BUS_NAME, NULL))
-		csd_ready(connection, NULL);
-	else
-		info("CSD not yet available. Waiting for it...");
+	dbus_bus_add_match(connection,
+			"type=signal,interface=" CSD_CALL_INTERFACE, NULL);
+	dbus_bus_add_match(connection,
+			"type=signal,interface=" CSD_CALL_INSTANCE, NULL);
+	dbus_bus_add_match(connection,
+			"type=signal,interface=" CSD_CALL_CONFERENCE, NULL);
+	dbus_bus_add_match(connection,
+			"type=signal,interface=" CSD_CSNET_REGISTRATION,
+			NULL);
+	dbus_bus_add_match(connection,
+			"type=signal,interface=" CSD_CSNET_OPERATOR,
+			NULL);
+	dbus_bus_add_match(connection,
+			"type=signal,interface=" CSD_CSNET_SIGNAL,
+			NULL);
+	dbus_bus_add_match(connection,
+				"type=signal,interface=" SSC_DBUS_IFACE
+				",member=modem_state_changed_ind", NULL);
+
+	if (send_method_call(SSC_DBUS_NAME, SSC_DBUS_PATH, SSC_DBUS_IFACE,
+					"get_modem_state", modem_state_reply,
+					NULL, DBUS_TYPE_INVALID) < 0)
+		error("Unable to send " SSC_DBUS_IFACE ".get_modem_state()");
 
 	generate_flag_file(NONE_FLAG_FILE);
 	callerid = callerid_from_file();
@@ -2033,22 +1968,34 @@
 	if (!g_dbus_register_interface(connection, TELEPHONY_MAEMO_PATH,
 			TELEPHONY_MAEMO_INTERFACE, telephony_maemo_methods,
 			NULL, NULL, NULL, NULL)) {
-		error("telephony-maemo interface %s init failed on path %s",
+		error("telephony-maemo6 interface %s init failed on path %s",
 			TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
 	}
 
-	debug("telephony-maemo registering %s interface on path %s",
+	DBG("telephony-maemo6 registering %s interface on path %s",
 			TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
 
+	telephony_ready_ind(features, maemo_indicators, response_and_hold,
+								chld_str);
+	if (send_method_call("org.freedesktop.Hal",
+				"/org/freedesktop/Hal/Manager",
+				"org.freedesktop.Hal.Manager",
+				"FindDeviceByCapability",
+				hal_find_device_reply, NULL,
+				DBUS_TYPE_STRING, &battery_cap,
+				DBUS_TYPE_INVALID) < 0)
+		error("Unable to send HAL method call");
+
 	return 0;
 }
 
 void telephony_exit(void)
 {
-	if (csd_watch) {
-		g_dbus_remove_watch(connection, csd_watch);
-		csd_watch = 0;
-	}
+	g_free(net.operator_name);
+	net.operator_name = NULL;
+
+	g_free(last_dialed_number);
+	last_dialed_number = NULL;
 
 	g_slist_foreach(calls, (GFunc) csd_call_free, NULL);
 	g_slist_free(calls);
diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
index 7c647b6..9c20112 100644
--- a/audio/telephony-ofono.c
+++ b/audio/telephony-ofono.c
@@ -2,9 +2,9 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2009       Intel Corporation
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2009-2010  Intel Corporation
+ *  Copyright (C) 2006-2009  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -35,7 +35,7 @@
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 #include "telephony.h"
 
 enum net_registration_status {
@@ -49,6 +49,7 @@
 	int status;
 	gboolean originating;
 	char *number;
+	guint watch;
 };
 
 static DBusConnection *connection = NULL;
@@ -63,6 +64,10 @@
 #define OFONO_VCMANAGER_INTERFACE "org.ofono.VoiceCallManager"
 #define OFONO_VC_INTERFACE "org.ofono.VoiceCall"
 
+static guint registration_watch = 0;
+static guint voice_watch = 0;
+static guint device_watch = 0;
+
 /* HAL battery namespace key values */
 static int battchg_cur = -1;    /* "battery.charge_level.current" */
 static int battchg_last = -1;   /* "battery.charge_level.last_full" */
@@ -131,20 +136,14 @@
 	return NULL;
 }
 
-static inline DBusMessage *invalid_args(DBusMessage *msg)
-{
-	return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
-					"Invalid arguments in method call");
-}
-
 void telephony_device_connected(void *telephony_device)
 {
-	debug("telephony-ofono: device %p connected", telephony_device);
+	DBG("telephony-ofono: device %p connected", telephony_device);
 }
 
 void telephony_device_disconnected(void *telephony_device)
 {
-	debug("telephony-ofono: device %p disconnected", telephony_device);
+	DBG("telephony-ofono: device %p disconnected", telephony_device);
 	events_enabled = FALSE;
 }
 
@@ -166,7 +165,7 @@
 
 void telephony_last_dialed_number_req(void *telephony_device)
 {
-	debug("telephony-ofono: last dialed number request");
+	DBG("telephony-ofono: last dialed number request");
 
 	if (last_dialed_number)
 		telephony_dial_number_req(telephony_device, last_dialed_number);
@@ -277,18 +276,25 @@
 
 void telephony_dial_number_req(void *telephony_device, const char *number)
 {
-	char *clir = "default";
+	const char *clir;
 	int ret;
 
-	debug("telephony-ofono: dial request to %s", number);
+	DBG("telephony-ofono: dial request to %s", number);
+
+	if (!modem_obj_path) {
+		telephony_dial_number_rsp(telephony_device,
+					CME_ERROR_AG_FAILURE);
+		return;
+	}
 
 	if (!strncmp(number, "*31#", 4)) {
 		number += 4;
-		clir = g_strdup("enabled");
+		clir = "enabled";
 	} else if (!strncmp(number, "#31#", 4)) {
 		number += 4;
-		clir = g_strdup("disabled");
-	}
+		clir =  "disabled";
+	} else
+		clir = "default";
 
 	ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
 			OFONO_VCMANAGER_INTERFACE,
@@ -309,7 +315,13 @@
 	char *tone_string;
 	int ret;
 
-	debug("telephony-ofono: transmit dtmf: %c", tone);
+	DBG("telephony-ofono: transmit dtmf: %c", tone);
+
+	if (!modem_obj_path) {
+		telephony_transmit_dtmf_rsp(telephony_device,
+					CME_ERROR_AG_FAILURE);
+		return;
+	}
 
 	tone_string = g_strdup_printf("%c", tone);
 	ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
@@ -328,7 +340,7 @@
 
 void telephony_subscriber_number_req(void *telephony_device)
 {
-	debug("telephony-ofono: subscriber number request");
+	DBG("telephony-ofono: subscriber number request");
 
 	if (subscriber_number)
 		telephony_subscriber_number_ind(subscriber_number,
@@ -342,7 +354,7 @@
 	GSList *l;
 	int i;
 
-	debug("telephony-ofono: list current calls request");
+	DBG("telephony-ofono: list current calls request");
 
 	for (l = calls, i = 1; l != NULL; l = l->next, i++) {
 		struct voice_call *vc = l->data;
@@ -360,7 +372,7 @@
 
 void telephony_operator_selection_req(void *telephony_device)
 {
-	debug("telephony-ofono: operator selection request");
+	DBG("telephony-ofono: operator selection request");
 
 	telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
 				net.operator_name ? net.operator_name : "");
@@ -369,13 +381,13 @@
 
 void telephony_call_hold_req(void *telephony_device, const char *cmd)
 {
-	debug("telephony-ofono: got call hold request %s", cmd);
+	DBG("telephony-ofono: got call hold request %s", cmd);
 	telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
 }
 
 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
 {
-	debug("telephony-ofono: got %s NR and EC request",
+	DBG("telephony-ofono: got %s NR and EC request",
 			enable ? "enable" : "disable");
 
 	telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
@@ -383,10 +395,18 @@
 
 void telephony_key_press_req(void *telephony_device, const char *keys)
 {
-	debug("telephony-ofono: got key press request for %s", keys);
+	DBG("telephony-ofono: got key press request for %s", keys);
 	telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
 }
 
+void telephony_voice_dial_req(void *telephony_device, gboolean enable)
+{
+	DBG("telephony-ofono: got %s voice dial request",
+			enable ? "enable" : "disable");
+
+	telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
+}
+
 static gboolean iter_get_basic_args(DBusMessageIter *iter,
 					int first_arg_type, ...)
 {
@@ -417,12 +437,12 @@
 
 static void handle_registration_property(const char *property, DBusMessageIter sub)
 {
-	char *status, *operator;
+	const char *status, *operator;
 	unsigned int signals_bar;
 
 	if (g_str_equal(property, "Status")) {
 		dbus_message_iter_get_basic(&sub, &status);
-		debug("Status is %s", status);
+		DBG("Status is %s", status);
 		if (g_str_equal(status, "registered")) {
 			net.status = NETWORK_REG_STATUS_HOME;
 			telephony_update_indicator(ofono_indicators,
@@ -444,12 +464,12 @@
 		}
 	} else if (g_str_equal(property, "Operator")) {
 		dbus_message_iter_get_basic(&sub, &operator);
-		debug("Operator is %s", operator);
+		DBG("Operator is %s", operator);
 		g_free(net.operator_name);
 		net.operator_name = g_strdup(operator);
 	} else if (g_str_equal(property, "SignalStrength")) {
 		dbus_message_iter_get_basic(&sub, &signals_bar);
-		debug("SignalStrength is %d", signals_bar);
+		DBG("SignalStrength is %d", signals_bar);
 		net.signals_bar = signals_bar;
 		telephony_update_indicator(ofono_indicators, "signal",
 						(signals_bar + 20) / 21);
@@ -478,7 +498,7 @@
 
 	dbus_message_iter_init(reply, &iter);
 
-	/* ARRAY -> ENTRY -> VARIANT*/
+	/* ARRAY -> ENTRY -> VARIANT */
 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
 		error("Unexpected signature in GetProperties return");
 		goto done;
@@ -523,6 +543,9 @@
 
 static int get_registration_and_signal_status()
 {
+	if (!modem_obj_path)
+		return -ENOENT;
+
 	return send_method_call(OFONO_BUS_NAME, modem_obj_path,
 			OFONO_NETWORKREG_INTERFACE,
 			"GetProperties", get_registration_reply,
@@ -537,7 +560,7 @@
 	char *property, *modem_obj_path_local;
 	int ret;
 
-	debug("list_modem_reply is called\n");
+	DBG("list_modem_reply is called\n");
 	reply = dbus_pending_call_steal_reply(call);
 
 	dbus_error_init(&err);
@@ -575,8 +598,11 @@
 
 		dbus_message_iter_get_basic(&sub, &modem_obj_path_local);
 		modem_obj_path = g_strdup(modem_obj_path_local);
-		debug("modem_obj_path is %p, %s\n", modem_obj_path,
-						modem_obj_path);
+		if (modem_obj_path != NULL) {
+			DBG("modem_obj_path is %p, %s\n", modem_obj_path,
+							modem_obj_path);
+			break;
+		}
 		dbus_message_iter_next(&sub);
 	}
 
@@ -587,8 +613,8 @@
 	dbus_message_unref(reply);
 }
 
-static void handle_networkregistration_property_changed(DBusMessage *msg,
-					const char *call_path)
+static gboolean handle_registration_property_changed(DBusConnection *conn,
+						DBusMessage *msg, void *data)
 {
 	DBusMessageIter iter, sub;
 	const char *property;
@@ -598,16 +624,18 @@
 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
 		error("Unexpected signature in networkregistration"
 					" PropertyChanged signal");
-		return;
+		return TRUE;
 	}
 	dbus_message_iter_get_basic(&iter, &property);
-	debug("in handle_networkregistration_property_changed(),"
+	DBG("in handle_registration_property_changed(),"
 					" the property is %s", property);
 
 	dbus_message_iter_next(&iter);
 	dbus_message_iter_recurse(&iter, &sub);
 
 	handle_registration_property(property, sub);
+
+	return TRUE;
 }
 
 static void vc_getproperties_reply(DBusPendingCall *call, void *user_data)
@@ -618,7 +646,7 @@
 	const char *path = user_data;
 	struct voice_call *vc;
 
-	debug("in vc_getproperties_reply");
+	DBG("in vc_getproperties_reply");
 
 	reply = dbus_pending_call_steal_reply(call);
 	dbus_error_init(&err);
@@ -627,7 +655,7 @@
 				err.name, err.message);
 		dbus_error_free(&err);
 		goto done;
-        }
+	}
 
 	vc = find_vc(path);
 	if (!vc) {
@@ -640,28 +668,28 @@
 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
 		error("Unexpected signature in vc_getproperties_reply()");
 		goto done;
-        }
+	}
 
 	dbus_message_iter_recurse(&iter, &iter_entry);
 
 	if (dbus_message_iter_get_arg_type(&iter_entry)
-				!= DBUS_TYPE_DICT_ENTRY) {
+			!= DBUS_TYPE_DICT_ENTRY) {
 		error("Unexpected signature in vc_getproperties_reply()");
 		goto done;
-        }
+	}
 
 	while (dbus_message_iter_get_arg_type(&iter_entry)
-				!= DBUS_TYPE_INVALID) {
+			!= DBUS_TYPE_INVALID) {
 		DBusMessageIter iter_property, sub;
 		char *property, *cli, *state;
 
 		dbus_message_iter_recurse(&iter_entry, &iter_property);
 		if (dbus_message_iter_get_arg_type(&iter_property)
-					!= DBUS_TYPE_STRING) {
+				!= DBUS_TYPE_STRING) {
 			error("Unexpected signature in"
 					" vc_getproperties_reply()");
 			goto done;
-                }
+		}
 
 		dbus_message_iter_get_basic(&iter_property, &property);
 
@@ -669,11 +697,11 @@
 		dbus_message_iter_recurse(&iter_property, &sub);
 		if (g_str_equal(property, "LineIdentification")) {
 			dbus_message_iter_get_basic(&sub, &cli);
-			debug("in vc_getproperties_reply(), cli is %s", cli);
+			DBG("in vc_getproperties_reply(), cli is %s", cli);
 			vc->number = g_strdup(cli);
 		} else if (g_str_equal(property, "State")) {
 			dbus_message_iter_get_basic(&sub, &state);
-			debug("in vc_getproperties_reply(),"
+			DBG("in vc_getproperties_reply(),"
 					" state is %s", state);
 			if (g_str_equal(state, "incoming"))
 				vc->status = CALL_STATUS_INCOMING;
@@ -713,7 +741,7 @@
 					EV_CALLSETUP_ALERTING);
 		break;
 	case CALL_STATUS_WAITING:
-		debug("in CALL_STATUS_WAITING: case");
+		DBG("in CALL_STATUS_WAITING: case");
 		vc->originating = FALSE;
 		telephony_update_indicator(ofono_indicators, "callsetup",
 					EV_CALLSETUP_INCOMING);
@@ -724,96 +752,42 @@
 	dbus_message_unref(reply);
 }
 
-static void handle_vcmanager_property_changed(DBusMessage *msg,
-						const char *obj_path)
-{
-	DBusMessageIter iter, sub, array;
-	const char *property, *vc_obj_path = NULL;
-	struct voice_call *vc = NULL, *vc_new = NULL;
-
-	debug("in handle_vcmanager_property_changed");
-
-	dbus_message_iter_init(msg, &iter);
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
-		error("Unexpected signature in vcmanager"
-					" PropertyChanged signal");
-		return;
-	}
-
-	dbus_message_iter_get_basic(&iter, &property);
-	debug("in handle_vcmanager_property_changed(),"
-				" the property is %s", property);
-
-	dbus_message_iter_next(&iter);
-	dbus_message_iter_recurse(&iter, &sub);
-	if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY) {
-		error("Unexpected signature in vcmanager"
-					" PropertyChanged signal");
-		return;
-	}
-	dbus_message_iter_recurse(&sub, &array);
-	while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
-		dbus_message_iter_get_basic(&array, &vc_obj_path);
-		vc = find_vc(vc_obj_path);
-		if (vc) {
-			debug("in handle_vcmanager_property_changed,"
-					" found an existing vc");
-		} else {
-			vc_new = g_new0(struct voice_call, 1);
-			vc_new->obj_path = g_strdup(vc_obj_path);
-			calls = g_slist_append(calls, vc_new);
-		}
-		dbus_message_iter_next(&array);
-	}
-
-	if (!vc_new)
-		return;
-
-	send_method_call(OFONO_BUS_NAME, vc_new->obj_path,
-				OFONO_VC_INTERFACE,
-				"GetProperties", vc_getproperties_reply,
-				vc_new->obj_path, DBUS_TYPE_INVALID);
-}
-
 static void vc_free(struct voice_call *vc)
 {
 	if (!vc)
 		return;
 
+	g_dbus_remove_watch(connection, vc->watch);
 	g_free(vc->obj_path);
 	g_free(vc->number);
 	g_free(vc);
 }
 
-static void handle_vc_property_changed(DBusMessage *msg, const char *obj_path)
+static gboolean handle_vc_property_changed(DBusConnection *conn,
+					DBusMessage *msg, void *data)
 {
+	struct voice_call *vc = data;
+	const char *obj_path = dbus_message_get_path(msg);
 	DBusMessageIter iter, sub;
 	const char *property, *state;
-	struct voice_call *vc = NULL;
 
-	debug("in handle_vc_property_changed, obj_path is %s", obj_path);
-
-	vc = find_vc(obj_path);
-
-	if (!vc)
-		return;
+	DBG("in handle_vc_property_changed, obj_path is %s", obj_path);
 
 	dbus_message_iter_init(msg, &iter);
 
 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
 		error("Unexpected signature in vc PropertyChanged signal");
-		return;
+		return TRUE;
 	}
 
 	dbus_message_iter_get_basic(&iter, &property);
-	debug("in handle_vc_property_changed(), the property is %s", property);
+	DBG("in handle_vc_property_changed(), the property is %s", property);
 
 	dbus_message_iter_next(&iter);
 	dbus_message_iter_recurse(&iter, &sub);
 	if (g_str_equal(property, "State")) {
 		dbus_message_iter_get_basic(&sub, &state);
-		debug("in handle_vc_property_changed(), State is %s", state);
+		DBG("in handle_vc_property_changed(), State is %s", state);
 		if (g_str_equal(state, "disconnected")) {
 			printf("in disconnected case\n");
 			if (vc->status == CALL_STATUS_ACTIVE)
@@ -832,16 +806,15 @@
 			telephony_update_indicator(ofono_indicators,
 							"callsetup",
 							EV_CALLSETUP_INACTIVE);
-			if (vc->status == CALL_STATUS_INCOMING) {
+			if (vc->status == CALL_STATUS_INCOMING)
 				telephony_calling_stopped_ind();
-			}
 			vc->status = CALL_STATUS_ACTIVE;
-			debug("vc status is CALL_STATUS_ACTIVE");
+			DBG("vc status is CALL_STATUS_ACTIVE");
 		} else if (g_str_equal(state, "alerting")) {
 			telephony_update_indicator(ofono_indicators,
-					 "callsetup", EV_CALLSETUP_ALERTING);
+					"callsetup", EV_CALLSETUP_ALERTING);
 			vc->status = CALL_STATUS_ALERTING;
-			debug("vc status is CALL_STATUS_ALERTING");
+			DBG("vc status is CALL_STATUS_ALERTING");
 		} else if (g_str_equal(state, "incoming")) {
 			/* state change from waiting to incoming */
 			telephony_update_indicator(ofono_indicators,
@@ -849,9 +822,71 @@
 			telephony_incoming_call_ind(vc->number,
 						NUMBER_TYPE_TELEPHONY);
 			vc->status = CALL_STATUS_INCOMING;
-			debug("vc status is CALL_STATUS_INCOMING");
+			DBG("vc status is CALL_STATUS_INCOMING");
 		}
 	}
+
+	return TRUE;
+}
+
+static gboolean handle_vcmanager_property_changed(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	DBusMessageIter iter, sub, array;
+	const char *property, *vc_obj_path = NULL;
+	struct voice_call *vc, *vc_new = NULL;
+
+	DBG("in handle_vcmanager_property_changed");
+
+	dbus_message_iter_init(msg, &iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
+		error("Unexpected signature in vcmanager"
+					" PropertyChanged signal");
+		return TRUE;
+	}
+
+	dbus_message_iter_get_basic(&iter, &property);
+	DBG("in handle_vcmanager_property_changed(),"
+				" the property is %s", property);
+
+	dbus_message_iter_next(&iter);
+	dbus_message_iter_recurse(&iter, &sub);
+	if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY) {
+		error("Unexpected signature in vcmanager"
+					" PropertyChanged signal");
+		return TRUE;
+	}
+	dbus_message_iter_recurse(&sub, &array);
+	while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
+		dbus_message_iter_get_basic(&array, &vc_obj_path);
+		vc = find_vc(vc_obj_path);
+		if (vc) {
+			DBG("in handle_vcmanager_property_changed,"
+					" found an existing vc");
+		} else {
+			vc_new = g_new0(struct voice_call, 1);
+			vc_new->obj_path = g_strdup(vc_obj_path);
+			calls = g_slist_append(calls, vc_new);
+			vc_new->watch = g_dbus_add_signal_watch(connection,
+					NULL, vc_obj_path,
+					OFONO_VC_INTERFACE,
+					"PropertyChanged",
+					handle_vc_property_changed,
+					vc_new, NULL);
+		}
+		dbus_message_iter_next(&array);
+	}
+
+	if (!vc_new)
+		return TRUE;
+
+	send_method_call(OFONO_BUS_NAME, vc_new->obj_path,
+				OFONO_VC_INTERFACE,
+				"GetProperties", vc_getproperties_reply,
+				vc_new->obj_path, DBUS_TYPE_INVALID);
+
+	return TRUE;
 }
 
 static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
@@ -871,20 +906,26 @@
 		goto done;
 	}
 
-	dbus_message_get_args(reply, NULL,
+	dbus_error_init(&err);
+	if (dbus_message_get_args(reply, &err,
 				DBUS_TYPE_INT32, &level,
-				DBUS_TYPE_INVALID);
+				DBUS_TYPE_INVALID) == FALSE) {
+		error("Unable to parse GetPropertyInteger reply: %s, %s",
+							err.name, err.message);
+		dbus_error_free(&err);
+		goto done;
+	}
 
 	*value = (int) level;
 
 	if (value == &battchg_last)
-		debug("telephony-ofono: battery.charge_level.last_full"
+		DBG("telephony-ofono: battery.charge_level.last_full"
 					" is %d", *value);
 	else if (value == &battchg_design)
-		debug("telephony-ofono: battery.charge_level.design"
+		DBG("telephony-ofono: battery.charge_level.design"
 					" is %d", *value);
 	else
-		debug("telephony-ofono: battery.charge_level.current"
+		DBG("telephony-ofono: battery.charge_level.current"
 					" is %d", *value);
 
 	if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
@@ -913,62 +954,8 @@
 			DBUS_TYPE_INVALID);
 }
 
-static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusMessage *reply;
-	DBusError err;
-	DBusMessageIter iter, sub;
-	int type;
-	const char *path;
-	char match_string[256];
-
-	debug("begin of hal_find_device_reply()");
-	reply = dbus_pending_call_steal_reply(call);
-
-	dbus_error_init(&err);
-
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("hald replied with an error: %s, %s",
-				err.name, err.message);
-		dbus_error_free(&err);
-		goto done;
-	}
-
-	dbus_message_iter_init(reply, &iter);
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-		error("Unexpected signature in hal_find_device_reply()");
-		goto done;
-	}
-
-	dbus_message_iter_recurse(&iter, &sub);
-
-	type = dbus_message_iter_get_arg_type(&sub);
-
-	if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
-		error("No hal device with battery capability found");
-		goto done;
-	}
-
-	dbus_message_iter_get_basic(&sub, &path);
-
-	debug("telephony-ofono: found battery device at %s", path);
-
-	snprintf(match_string, sizeof(match_string),
-			"type='signal',"
-			"path='%s',"
-			"interface='org.freedesktop.Hal.Device',"
-			"member='PropertyModified'", path);
-	dbus_bus_add_match(connection, match_string, NULL);
-
-	hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
-	hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
-	hal_get_integer(path, "battery.charge_level.design", &battchg_design);
-done:
-	dbus_message_unref(reply);
-}
-
-static void handle_hal_property_modified(DBusMessage *msg)
+static gboolean handle_hal_property_modified(DBusConnection *conn,
+						DBusMessage *msg, void *data)
 {
 	const char *path;
 	DBusMessageIter iter, array;
@@ -980,7 +967,7 @@
 
 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
 		error("Unexpected signature in hal PropertyModified signal");
-		return;
+		return TRUE;
 	}
 
 	dbus_message_iter_get_basic(&iter, &num_changes);
@@ -988,7 +975,7 @@
 
 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
 		error("Unexpected signature in hal PropertyModified signal");
-		return;
+		return TRUE;
 	}
 
 	dbus_message_iter_recurse(&iter, &array);
@@ -1018,58 +1005,81 @@
 
 		dbus_message_iter_next(&array);
 	}
+
+	return TRUE;
 }
 
-static DBusHandlerResult signal_filter(DBusConnection *conn,
-				DBusMessage *msg, void *data)
+static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
 {
-	const char *path = dbus_message_get_path(msg);
+	DBusMessage *reply;
+	DBusError err;
+	DBusMessageIter iter, sub;
+	int type;
+	const char *path;
 
-	if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
-		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+	DBG("begin of hal_find_device_reply()");
+	reply = dbus_pending_call_steal_reply(call);
 
-	if (dbus_message_is_signal(msg, OFONO_NETWORKREG_INTERFACE,
-				"PropertyChanged"))
-		handle_networkregistration_property_changed(msg, path);
-	else if (dbus_message_is_signal(msg, OFONO_VCMANAGER_INTERFACE,
-				"PropertyChanged"))
-		handle_vcmanager_property_changed(msg, path);
-	else if (dbus_message_is_signal(msg, OFONO_VC_INTERFACE,
-				"PropertyChanged"))
-		handle_vc_property_changed(msg, path);
-	else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
-				"PropertyModified"))
-		handle_hal_property_modified(msg);
+	dbus_error_init(&err);
 
-	debug("signal_filter is called, path is %s\n", path);
-	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+	if (dbus_set_error_from_message(&err, reply)) {
+		error("hald replied with an error: %s, %s",
+				err.name, err.message);
+		dbus_error_free(&err);
+		goto done;
+	}
+
+	dbus_message_iter_init(reply, &iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
+		error("Unexpected signature in hal_find_device_reply()");
+		goto done;
+	}
+
+	dbus_message_iter_recurse(&iter, &sub);
+
+	type = dbus_message_iter_get_arg_type(&sub);
+
+	if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
+		error("No hal device with battery capability found");
+		goto done;
+	}
+
+	dbus_message_iter_get_basic(&sub, &path);
+
+	DBG("telephony-ofono: found battery device at %s", path);
+
+	device_watch = g_dbus_add_signal_watch(connection, NULL, path,
+					"org.freedesktop.Hal.Device",
+					"PropertyModified",
+					handle_hal_property_modified,
+					NULL, NULL);
+
+	hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
+	hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
+	hal_get_integer(path, "battery.charge_level.design", &battchg_design);
+done:
+	dbus_message_unref(reply);
 }
 
 int telephony_init(void)
 {
 	const char *battery_cap = "battery";
-	char match_string[128];
 	int ret;
 
 	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
 
-	if (!dbus_connection_add_filter(connection, signal_filter,
-					NULL, NULL)) {
-		error("telephony-ofono: Can't add signal filter");
-		return -EIO;
-	}
+	registration_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+					OFONO_NETWORKREG_INTERFACE,
+					"PropertyChanged",
+					handle_registration_property_changed,
+					NULL, NULL);
 
-	snprintf(match_string, sizeof(match_string), "type=signal,interface=%s",
-				OFONO_NETWORKREG_INTERFACE);
-	dbus_bus_add_match(connection, match_string, NULL);
-
-	snprintf(match_string, sizeof(match_string), "type=signal,interface=%s",
-				OFONO_VCMANAGER_INTERFACE);
-	dbus_bus_add_match(connection, match_string, NULL);
-
-	snprintf(match_string, sizeof(match_string), "type=signal,interface=%s",
-				OFONO_VC_INTERFACE);
-	dbus_bus_add_match(connection, match_string, NULL);
+	voice_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+					OFONO_VCMANAGER_INTERFACE,
+					"PropertyChanged",
+					handle_vcmanager_property_changed,
+					NULL, NULL);
 
 	ret = send_method_call(OFONO_BUS_NAME, OFONO_PATH,
 				OFONO_MANAGER_INTERFACE, "GetProperties",
@@ -1087,7 +1097,7 @@
 	if (ret < 0)
 		return ret;
 
-	debug("telephony_init() successfully");
+	DBG("telephony_init() successfully");
 
 	return ret;
 }
@@ -1103,7 +1113,9 @@
 	g_slist_free(calls);
 	calls = NULL;
 
-	dbus_connection_remove_filter(connection, signal_filter, NULL);
+	g_dbus_remove_watch(connection, registration_watch);
+	g_dbus_remove_watch(connection, voice_watch);
+	g_dbus_remove_watch(connection, device_watch);
 
 	dbus_connection_unref(connection);
 	connection = NULL;
diff --git a/audio/telephony.h b/audio/telephony.h
index 9bc5ee2..5343e8c 100644
--- a/audio/telephony.h
+++ b/audio/telephony.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -155,6 +155,7 @@
 void telephony_operator_selection_req(void *telephony_device);
 void telephony_call_hold_req(void *telephony_device, const char *cmd);
 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable);
+void telephony_voice_dial_req(void *telephony_device, gboolean enable);
 void telephony_key_press_req(void *telephony_device, const char *keys);
 
 /* AG responses to HF requests. These are implemented by headset.c */
@@ -170,6 +171,7 @@
 int telephony_operator_selection_rsp(void *telephony_device, cme_error_t err);
 int telephony_call_hold_rsp(void *telephony_device, cme_error_t err);
 int telephony_nr_and_ec_rsp(void *telephony_device, cme_error_t err);
+int telephony_voice_dial_rsp(void *telephony_device, cme_error_t err);
 int telephony_key_press_rsp(void *telephony_device, cme_error_t err);
 
 /* Event indications by AG. These are implemented by headset.c */
@@ -205,10 +207,10 @@
 	if (!ind)
 		return -ENOENT;
 
-	debug("Telephony indicator \"%s\" %d->%d", desc, ind->val, new_val);
+	DBG("Telephony indicator \"%s\" %d->%d", desc, ind->val, new_val);
 
 	if (ind->ignore_redundant && ind->val == new_val) {
-		debug("Ignoring no-change indication");
+		DBG("Ignoring no-change indication");
 		return 0;
 	}
 
diff --git a/audio/unix.c b/audio/unix.c
index b04cc59..cf2704c 100644
--- a/audio/unix.c
+++ b/audio/unix.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -39,7 +39,7 @@
 #include <dbus/dbus.h>
 #include <glib.h>
 
-#include "logging.h"
+#include "log.h"
 #include "ipc.h"
 #include "device.h"
 #include "manager.h"
@@ -97,7 +97,7 @@
 
 static void client_free(struct unix_client *client)
 {
-	debug("client_free(%p)", client);
+	DBG("client_free(%p)", client);
 
 	if (client->cancel && client->dev && client->req_id > 0)
 		client->cancel(client->dev, client->req_id);
@@ -147,7 +147,7 @@
 	const char *type = bt_audio_strtype(msg->type);
 	const char *name = bt_audio_strname(msg->name);
 
-	debug("Audio API: %s -> %s", type, name);
+	DBG("Audio API: %s -> %s", type, name);
 
 	if (send(client->sock, msg, msg->length, 0) < 0)
 		error("Error %s(%d)", strerror(errno), errno);
@@ -168,6 +168,7 @@
 
 	rsp->posix_errno = err;
 
+	DBG("sending error %s(%d)", strerror(err), err);
 	unix_ipc_sendmsg(client, &rsp->h);
 }
 
@@ -176,13 +177,20 @@
 	if (!interface) {
 		if (dev->sink && avdtp_is_connected(&dev->src, &dev->dst))
 			return TYPE_SINK;
+		else if (dev->source && avdtp_is_connected(&dev->src,
+								&dev->dst))
+			return TYPE_SOURCE;
 		else if (dev->headset && headset_is_active(dev))
 			return TYPE_HEADSET;
 		else if (dev->sink)
 			return TYPE_SINK;
+		else if (dev->source)
+			return TYPE_SOURCE;
 		else if (dev->headset)
 			return TYPE_HEADSET;
-	} else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink)
+	} else if (!strcmp(interface, AUDIO_SOURCE_INTERFACE) && dev->source)
+		return TYPE_SOURCE;
+	else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink)
 		return TYPE_SINK;
 	else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset)
 		return TYPE_HEADSET;
@@ -310,14 +318,14 @@
 	unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
 }
 
-static void gateway_setup_complete(struct audio_device *dev, void *user_data)
+static void gateway_setup_complete(struct audio_device *dev, GError *err, void *user_data)
 {
 	struct unix_client *client = user_data;
 	char buf[BT_SUGGESTED_BUFFER_SIZE];
 	struct bt_set_configuration_rsp *rsp = (void *) buf;
 
-	if (!dev) {
-		unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
+	if (err) {
+		unix_ipc_error(client, BT_SET_CONFIGURATION, err->code);
 		return;
 	}
 
@@ -380,13 +388,18 @@
 	unix_ipc_error(client, BT_START_STREAM, EIO);
 }
 
-static void gateway_resume_complete(struct audio_device *dev, void *user_data)
+static void gateway_resume_complete(struct audio_device *dev, GError *err, void *user_data)
 {
 	struct unix_client *client = user_data;
 	char buf[BT_SUGGESTED_BUFFER_SIZE];
 	struct bt_start_stream_rsp *rsp = (void *) buf;
 	struct bt_new_stream_ind *ind = (void *) buf;
 
+	if (err) {
+		unix_ipc_error(client, BT_START_STREAM, err->code);
+		return;
+	}
+
 	memset(buf, 0, sizeof(buf));
 	rsp->h.type = BT_RESPONSE;
 	rsp->h.name = BT_START_STREAM;
@@ -435,7 +448,7 @@
 
 static void print_mpeg12(struct mpeg_codec_cap *mpeg)
 {
-	debug("Media Codec: MPEG12"
+	DBG("Media Codec: MPEG12"
 		" Channel Modes: %s%s%s%s"
 		" Frequencies: %s%s%s%s%s%s"
 		" Layers: %s%s%s"
@@ -460,7 +473,7 @@
 
 static void print_sbc(struct sbc_codec_cap *sbc)
 {
-	debug("Media Codec: SBC"
+	DBG("Media Codec: SBC"
 		" Channel Modes: %s%s%s%s"
 		" Frequencies: %s%s%s%s"
 		" Subbands: %s%s"
@@ -487,6 +500,7 @@
 static int a2dp_append_codec(struct bt_get_capabilities_rsp *rsp,
 				struct avdtp_service_capability *cap,
 				uint8_t seid,
+				uint8_t type,
 				uint8_t configured,
 				uint8_t lock)
 {
@@ -507,6 +521,13 @@
 		if (space_left < sizeof(sbc_capabilities_t))
 			return -ENOMEM;
 
+		if (type == AVDTP_SEP_TYPE_SINK)
+			codec->type = BT_A2DP_SBC_SINK;
+		else if (type == AVDTP_SEP_TYPE_SOURCE)
+			codec->type = BT_A2DP_SBC_SOURCE;
+		else
+			return -EINVAL;
+
 		codec->length = sizeof(sbc_capabilities_t);
 
 		sbc->channel_mode = sbc_cap->channel_mode;
@@ -518,7 +539,6 @@
 		sbc->max_bitpool = sbc_cap->max_bitpool;
 
 		print_sbc(sbc_cap);
-		codec->type = BT_A2DP_SBC_SINK;
 	} else if (codec_cap->media_codec_type == A2DP_CODEC_MPEG12) {
 		struct mpeg_codec_cap *mpeg_cap = (void *) codec_cap;
 		mpeg_capabilities_t *mpeg = (void *) codec;
@@ -526,6 +546,13 @@
 		if (space_left < sizeof(mpeg_capabilities_t))
 			return -ENOMEM;
 
+		if (type == AVDTP_SEP_TYPE_SINK)
+			codec->type = BT_A2DP_MPEG12_SINK;
+		else if (type == AVDTP_SEP_TYPE_SOURCE)
+			codec->type = BT_A2DP_MPEG12_SOURCE;
+		else
+			return -EINVAL;
+
 		codec->length = sizeof(mpeg_capabilities_t);
 
 		mpeg->channel_mode = mpeg_cap->channel_mode;
@@ -536,7 +563,6 @@
 		mpeg->bitrate = mpeg_cap->bitrate;
 
 		print_mpeg12(mpeg_cap);
-		codec->type = BT_A2DP_MPEG12_SINK;
 	} else {
 		size_t codec_length, type_length, total_length;
 
@@ -549,11 +575,17 @@
 		if (space_left < total_length)
 			return -ENOMEM;
 
+		if (type == AVDTP_SEP_TYPE_SINK)
+			codec->type = BT_A2DP_UNKNOWN_SINK;
+		else if (type == AVDTP_SEP_TYPE_SOURCE)
+			codec->type = BT_A2DP_UNKNOWN_SOURCE;
+		else
+			return -EINVAL;
+
 		codec->length = total_length;
 		memcpy(codec->data, &codec_cap->media_codec_type, type_length);
 		memcpy(codec->data + type_length, codec_cap->data,
 			codec_length);
-		codec->type = BT_A2DP_UNKNOWN_SINK;
 	}
 
 	codec->seid = seid;
@@ -561,7 +593,7 @@
 	codec->lock = lock;
 	rsp->h.length += codec->length;
 
-	debug("Append %s seid %d - length %d - total %d",
+	DBG("Append %s seid %d - length %d - total %d",
 		configured ? "configured" : "", seid, codec->length,
 		rsp->h.length);
 
@@ -579,7 +611,7 @@
 	GSList *l;
 
 	if (!g_slist_find(clients, client)) {
-		debug("Client disconnected during discovery");
+		DBG("Client disconnected during discovery");
 		return;
 	}
 
@@ -606,7 +638,8 @@
 
 		type = avdtp_get_type(rsep);
 
-		if (type != AVDTP_SEP_TYPE_SINK)
+		if (type != AVDTP_SEP_TYPE_SINK &&
+						type != AVDTP_SEP_TYPE_SOURCE)
 			continue;
 
 		cap = avdtp_get_codec(rsep);
@@ -630,8 +663,7 @@
 			struct unix_client *c = cl->data;
 			struct a2dp_data *ca2dp = &c->d.a2dp;
 
-			if (ca2dp && ca2dp->session == session &&
-					c->seid == seid) {
+			if (ca2dp->session == session && c->seid == seid) {
 				lock = c->lock;
 				break;
 			}
@@ -641,7 +673,7 @@
 		if (sep && a2dp_sep_get_lock(sep))
 			lock = BT_WRITE_LOCK;
 
-		a2dp_append_codec(rsp, cap, seid, configured, lock);
+		a2dp_append_codec(rsp, cap, seid, type, configured, lock);
 	}
 
 	unix_ipc_sendmsg(client, &rsp->h);
@@ -819,6 +851,7 @@
 
 	switch (client->type) {
 	case TYPE_SINK:
+	case TYPE_SOURCE:
 		a2dp = &client->d.a2dp;
 
 		if (!a2dp->session)
@@ -875,8 +908,6 @@
 	strncpy(rsp->object, dev->path, sizeof(rsp->object));
 
 	unix_ipc_sendmsg(client, &rsp->h);
-
-	return;
 }
 
 static void start_open(struct audio_device *dev, struct unix_client *client)
@@ -1254,6 +1285,7 @@
 	struct audio_device *dev;
 	bdaddr_t src, dst;
 	int err = EIO;
+	const char *interface;
 
 	if (!check_nul(req->source) || !check_nul(req->destination) ||
 			!check_nul(req->object)) {
@@ -1264,29 +1296,33 @@
 	str2ba(req->source, &src);
 	str2ba(req->destination, &dst);
 
-	if (req->transport == BT_CAPABILITIES_TRANSPORT_SCO)
-		client->interface = g_strdup(AUDIO_HEADSET_INTERFACE);
-	else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
-		client->interface = g_strdup(AUDIO_SINK_INTERFACE);
-
 	if (!manager_find_device(req->object, &src, &dst, NULL, FALSE))
 		goto failed;
 
-	dev = manager_find_device(req->object, &src, &dst, client->interface,
-				TRUE);
+	if (req->transport == BT_CAPABILITIES_TRANSPORT_SCO)
+		interface = AUDIO_HEADSET_INTERFACE;
+	else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
+		interface = AUDIO_SINK_INTERFACE;
+	else
+		interface = client->interface;
+
+	dev = manager_find_device(req->object, &src, &dst, interface, TRUE);
 	if (!dev && (req->flags & BT_FLAG_AUTOCONNECT))
 		dev = manager_find_device(req->object, &src, &dst,
-					client->interface, FALSE);
+							interface, FALSE);
 
-	if (!dev && req->transport == BT_CAPABILITIES_TRANSPORT_SCO) {
-		g_free(client->interface);
-		client->interface = g_strdup(AUDIO_GATEWAY_INTERFACE);
-
+	if (!dev) {
+		if (req->transport == BT_CAPABILITIES_TRANSPORT_SCO)
+			interface = AUDIO_GATEWAY_INTERFACE;
+		else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
+			interface = AUDIO_SOURCE_INTERFACE;
+		else
+			interface = NULL;
 		dev = manager_find_device(req->object, &src, &dst,
-				client->interface, TRUE);
+							interface, TRUE);
 		if (!dev && (req->flags & BT_FLAG_AUTOCONNECT))
 			dev = manager_find_device(req->object, &src, &dst,
-					client->interface, FALSE);
+							interface, FALSE);
 	}
 
 	if (!dev) {
@@ -1294,12 +1330,17 @@
 		goto failed;
 	}
 
-	client->type = select_service(dev, client->interface);
+	client->type = select_service(dev, interface);
 	if (client->type == TYPE_NONE) {
 		error("No matching service found");
 		goto failed;
 	}
 
+	if (g_strcmp0(interface, client->interface) != 0) {
+		g_free(client->interface);
+		client->interface = g_strdup(interface);
+	}
+
 	client->seid = req->seid;
 
 	start_discovery(dev, client);
@@ -1318,7 +1359,7 @@
 		!g_str_equal(client->interface, AUDIO_GATEWAY_INTERFACE))
 		return -EIO;
 
-	debug("open sco - object=%s source=%s destination=%s lock=%s%s",
+	DBG("open sco - object=%s source=%s destination=%s lock=%s%s",
 			strcmp(req->object, "") ? req->object : "ANY",
 			strcmp(req->source, "") ? req->source : "ANY",
 			strcmp(req->destination, "") ? req->destination : "ANY",
@@ -1331,11 +1372,13 @@
 static int handle_a2dp_open(struct unix_client *client, struct bt_open_req *req)
 {
 	if (!client->interface)
+		/* FIXME: are we treating a sink or a source? */
 		client->interface = g_strdup(AUDIO_SINK_INTERFACE);
-	else if (!g_str_equal(client->interface, AUDIO_SINK_INTERFACE))
+	else if (!g_str_equal(client->interface, AUDIO_SINK_INTERFACE) &&
+			!g_str_equal(client->interface, AUDIO_SOURCE_INTERFACE))
 		return -EIO;
 
-	debug("open a2dp - object=%s source=%s destination=%s lock=%s%s",
+	DBG("open a2dp - object=%s source=%s destination=%s lock=%s%s",
 			strcmp(req->object, "") ? req->object : "ANY",
 			strcmp(req->source, "") ? req->source : "ANY",
 			strcmp(req->destination, "") ? req->destination : "ANY",
@@ -1424,8 +1467,10 @@
 	struct mpeg_codec_cap mpeg_cap;
 
 	if (!client->interface)
+		/* FIXME: are we treating a sink or a source? */
 		client->interface = g_strdup(AUDIO_SINK_INTERFACE);
-	else if (!g_str_equal(client->interface, AUDIO_SINK_INTERFACE))
+	else if (!g_str_equal(client->interface, AUDIO_SINK_INTERFACE) &&
+			!g_str_equal(client->interface, AUDIO_SOURCE_INTERFACE))
 		return -EIO;
 
 	if (client->caps) {
@@ -1439,7 +1484,8 @@
 
 	client->caps = g_slist_append(client->caps, media_transport);
 
-	if (req->codec.type == BT_A2DP_MPEG12_SINK) {
+	if (req->codec.type == BT_A2DP_MPEG12_SINK ||
+		req->codec.type == BT_A2DP_MPEG12_SOURCE) {
 		mpeg_capabilities_t *mpeg = (void *) &req->codec;
 
 		memset(&mpeg_cap, 0, sizeof(mpeg_cap));
@@ -1457,7 +1503,8 @@
 							sizeof(mpeg_cap));
 
 		print_mpeg12(&mpeg_cap);
-	} else if (req->codec.type == BT_A2DP_SBC_SINK) {
+	} else if (req->codec.type == BT_A2DP_SBC_SINK ||
+			req->codec.type == BT_A2DP_SBC_SOURCE) {
 		sbc_capabilities_t *sbc = (void *) &req->codec;
 
 		memset(&sbc_cap, 0, sizeof(sbc_cap));
@@ -1491,7 +1538,7 @@
 
 	if (req->codec.seid != client->seid) {
 		error("Unable to set configuration: seid %d not opened",
-				client->seid);
+				req->codec.seid);
 		goto failed;
 	}
 
@@ -1577,6 +1624,56 @@
 	unix_ipc_sendmsg(client, &rsp->h);
 }
 
+static void handle_delay_report_req(struct unix_client *client,
+					struct bt_delay_report_req *req)
+{
+	char buf[BT_SUGGESTED_BUFFER_SIZE];
+	struct bt_set_configuration_rsp *rsp = (void *) buf;
+	struct a2dp_data *a2dp;
+	int err;
+
+	if (!client->dev) {
+		err = -ENODEV;
+		goto failed;
+	}
+
+	switch (client->type) {
+	case TYPE_HEADSET:
+        case TYPE_GATEWAY:
+		err = -EINVAL;
+		goto failed;
+	case TYPE_SOURCE:
+	case TYPE_SINK:
+		a2dp = &client->d.a2dp;
+		if (a2dp->session && a2dp->stream) {
+			err = avdtp_delay_report(a2dp->session, a2dp->stream,
+								req->delay);
+			if (err < 0)
+				goto failed;
+		} else {
+			err = -EINVAL;
+			goto failed;
+		}
+		break;
+	default:
+		error("No known services for device");
+		err = -EINVAL;
+		goto failed;
+	}
+
+	memset(buf, 0, sizeof(buf));
+	rsp->h.type = BT_RESPONSE;
+	rsp->h.name = BT_DELAY_REPORT;
+	rsp->h.length = sizeof(*rsp);
+
+	unix_ipc_sendmsg(client, &rsp->h);
+
+	return;
+
+failed:
+	unix_ipc_error(client, BT_DELAY_REPORT, -err);
+}
+
 static gboolean client_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
 {
 	char buf[BT_SUGGESTED_BUFFER_SIZE];
@@ -1589,7 +1686,7 @@
 		return FALSE;
 
 	if (cond & (G_IO_HUP | G_IO_ERR)) {
-		debug("Unix client disconnected (fd=%d)", client->sock);
+		DBG("Unix client disconnected (fd=%d)", client->sock);
 
 		goto failed;
 	}
@@ -1605,7 +1702,7 @@
 	type = bt_audio_strtype(msghdr->type);
 	name = bt_audio_strname(msghdr->name);
 
-	debug("Audio API: %s <- %s", type, name);
+	DBG("Audio API: %s <- %s", type, name);
 
 	if (msghdr->length != len) {
 		error("Invalid message: length mismatch");
@@ -1641,6 +1738,10 @@
 		handle_control_req(client,
 				(struct bt_control_req *) msghdr);
 		break;
+	case BT_DELAY_REPORT:
+		handle_delay_report_req(client,
+				(struct bt_delay_report_req *) msghdr);
+		break;
 	default:
 		error("Audio API: received unexpected message name %d",
 				msghdr->name);
@@ -1682,7 +1783,7 @@
 		return TRUE;
 	}
 
-	debug("Accepted new client connection on unix socket (fd=%d)", cli_sk);
+	DBG("Accepted new client connection on unix socket (fd=%d)", cli_sk);
 	set_nonblocking(cli_sk);
 
 	client = g_new0(struct unix_client, 1);
@@ -1701,7 +1802,7 @@
 {
 	GSList *l;
 
-	debug("unix_device_removed(%p)", dev);
+	DBG("unix_device_removed(%p)", dev);
 
 	l = clients;
 	while (l) {
@@ -1717,6 +1818,29 @@
 	}
 }
 
+void unix_delay_report(struct audio_device *dev, uint8_t seid, uint16_t delay)
+{
+	GSList *l;
+	struct bt_delay_report_ind ind;
+
+	DBG("unix_delay_report(%p): %u.%ums", dev, delay / 10, delay % 10);
+
+	memset(&ind, 0, sizeof(ind));
+	ind.h.type = BT_INDICATION;
+	ind.h.name = BT_DELAY_REPORT;
+	ind.h.length = sizeof(ind);
+	ind.delay = delay;
+
+	for (l = clients; l != NULL; l = g_slist_next(l)) {
+		struct unix_client *client = l->data;
+
+		if (client->dev != dev || client->seid != seid)
+			continue;
+
+		unix_ipc_sendmsg(client, (void *) &ind);
+	}
+}
+
 int unix_init(void)
 {
 	GIOChannel *io;
@@ -1756,7 +1880,7 @@
 							server_cb, NULL);
 	g_io_channel_unref(io);
 
-	debug("Unix socket created: %d", sk);
+	DBG("Unix socket created: %d", sk);
 
 	return 0;
 }
diff --git a/audio/unix.h b/audio/unix.h
index 12cf3ef..74ca16d 100644
--- a/audio/unix.h
+++ b/audio/unix.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -24,5 +24,7 @@
 
 void unix_device_removed(struct audio_device *dev);
 
+void unix_delay_report(struct audio_device *dev, uint8_t seid, uint16_t delay);
+
 int unix_init(void);
 void unix_exit(void);
diff --git a/bluez.m4 b/bluez.m4
deleted file mode 100644
index 0257a3f..0000000
--- a/bluez.m4
+++ /dev/null
@@ -1,40 +0,0 @@
-AC_DEFUN([AM_PATH_BLUEZ], [
-	if (test "${prefix}" = "NONE"); then
-		bluez_prefix=${ac_default_prefix}
-	else
-		bluez_prefix=${prefix}
-	fi
-
-	AC_ARG_WITH(bluez, AC_HELP_STRING([--with-bluez=DIR], [BlueZ library is installed in DIR]), [
-		if (test "${withval}" != "yes"); then
-			bluez_prefix=${withval}
-		fi
-	])
-
-	ac_save_CPPFLAGS=$CPPFLAGS
-	ac_save_LDFLAGS=$LDFLAGS
-
-	BLUEZ_CFLAGS=""
-	test -d "${bluez_prefix}/include" && BLUEZ_CFLAGS="$BLUEZ_CFLAGS -I${bluez_prefix}/include"
-
-	CPPFLAGS="$CPPFLAGS $BLUEZ_CFLAGS"
-	AC_CHECK_HEADER(bluetooth/bluetooth.h,, AC_MSG_ERROR(Bluetooth header files not found))
-
-	BLUEZ_LIBS=""
-	if (test "${ac_default_prefix}" = "${bluez_prefix}"); then
-		test -d "${libdir}" && BLUEZ_LIBS="$BLUEZ_LIBS -L${libdir}"
-	else
-		test -d "${bluez_prefix}/lib64" && BLUEZ_LIBS="$BLUEZ_LIBS -L${bluez_prefix}/lib64"
-		test -d "${bluez_prefix}/lib" && BLUEZ_LIBS="$BLUEZ_LIBS -L${bluez_prefix}/lib"
-	fi
-
-	LDFLAGS="$LDFLAGS $BLUEZ_LIBS"
-	AC_CHECK_LIB(bluetooth, hci_open_dev, BLUEZ_LIBS="$BLUEZ_LIBS -lbluetooth", AC_MSG_ERROR(Bluetooth library not found))
-	AC_CHECK_LIB(bluetooth, sdp_connect,, AC_CHECK_LIB(sdp, sdp_connect, BLUEZ_LIBS="$BLUEZ_LIBS -lsdp"))
-
-	CPPFLAGS=$ac_save_CPPFLAGS
-	LDFLAGS=$ac_save_LDFLAGS
-
-	AC_SUBST(BLUEZ_CFLAGS)
-	AC_SUBST(BLUEZ_LIBS)
-])
diff --git a/bootstrap-configure b/bootstrap-configure
index 15b3ba7..7456103 100755
--- a/bootstrap-configure
+++ b/bootstrap-configure
@@ -17,6 +17,8 @@
 		--localstatedir=/var \
 		--libexecdir=/lib \
 		--enable-netlink \
+		--enable-capng \
+		--enable-tracer \
 		--enable-tools \
 		--enable-bccmd \
 		--enable-dfutool \
@@ -27,6 +29,5 @@
 		--enable-test \
 		--enable-cups \
 		--disable-pcmcia \
-		--disable-manpages \
 		--disable-udevrules \
 		--disable-configfiles $*
diff --git a/client/Makefile.am b/client/Makefile.am
deleted file mode 100644
index 0274292..0000000
--- a/client/Makefile.am
+++ /dev/null
@@ -1,2 +0,0 @@
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/common/Android.mk b/common/Android.mk
deleted file mode 100755
index 74c0bec..0000000
--- a/common/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	btio.c \
-	glib-helper.c \
-	logging.c \
-	oui.c \
-	sdp-xml.c \
-	textfile.c \
-	test_textfile.c \
-	android_bluez.c
-
-LOCAL_CFLAGS+= \
-	-O3 \
-	-DNEED_DBUS_WATCH_GET_UNIX_FD
-
-ifeq ($(BOARD_HAVE_BLUETOOTH_BCM),true)
-LOCAL_CFLAGS += \
-	-DBOARD_HAVE_BLUETOOTH_BCM
-endif
-
-LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-	$(call include-path-for, glib) \
-	$(call include-path-for, glib)/glib \
-	$(call include-path-for, dbus)
-
-LOCAL_MODULE:=libbluez-common-static
-
-LOCAL_STATIC_LIBRARY:= \
-	libglib_static
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/common/Makefile.am b/common/Makefile.am
deleted file mode 100644
index 8fe1547..0000000
--- a/common/Makefile.am
+++ /dev/null
@@ -1,15 +0,0 @@
-
-noinst_LIBRARIES = libhelper.a
-
-libhelper_a_SOURCES = oui.h oui.c textfile.h textfile.c logging.h logging.c \
-		glib-helper.h glib-helper.c sdp-xml.h sdp-xml.c btio.h btio.c
-
-noinst_PROGRAMS = test_textfile
-
-test_textfile_LDADD = libhelper.a
-
-AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
-
-EXTRA_DIST = ppoll.h uinput.h
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/common/logging.c b/common/logging.c
deleted file mode 100644
index 6c6f925..0000000
--- a/common/logging.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <syslog.h>
-
-#include "logging.h"
-
-static volatile int debug_enabled = 0;
-
-static inline void vinfo(const char *format, va_list ap)
-{
-	vsyslog(LOG_INFO, format, ap);
-}
-
-void info(const char *format, ...)
-{
-	va_list ap;
-
-	va_start(ap, format);
-
-	vinfo(format, ap);
-
-	va_end(ap);
-}
-
-void error(const char *format, ...)
-{
-	va_list ap;
-
-	va_start(ap, format);
-
-	vsyslog(LOG_ERR, format, ap);
-
-	va_end(ap);
-}
-
-void debug(const char *format, ...)
-{
-	va_list ap;
-
-	if (!debug_enabled)
-		return;
-
-	va_start(ap, format);
-
-	vsyslog(LOG_DEBUG, format, ap);
-
-	va_end(ap);
-}
-
-void toggle_debug(void)
-{
-	debug_enabled = (debug_enabled + 1) % 2;
-}
-
-void enable_debug(void)
-{
-	debug_enabled = 1;
-}
-
-void disable_debug(void)
-{
-	debug_enabled = 0;
-}
-
-void start_logging(const char *ident, const char *message, ...)
-{
-	va_list ap;
-
-	openlog(ident, LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
-
-	va_start(ap, message);
-
-	vinfo(message, ap);
-
-	va_end(ap);
-}
-
-void stop_logging(void)
-{
-	closelog();
-}
diff --git a/common/logging.h b/common/logging.h
deleted file mode 100644
index 9508733..0000000
--- a/common/logging.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2009  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
- *
- */
-
-#ifndef __LOGGING_H
-#define __LOGGING_H
-
-void info(const char *format, ...) __attribute__((format(printf, 1, 2)));
-void error(const char *format, ...) __attribute__((format(printf, 1, 2)));
-void debug(const char *format, ...) __attribute__((format(printf, 1, 2)));
-void toggle_debug(void);
-void enable_debug(void);
-void disable_debug(void);
-void start_logging(const char *ident, const char *message, ...);
-void stop_logging(void);
-
-#define DBG(fmt, arg...)  debug("%s: " fmt "\n" , __FUNCTION__ , ## arg)
-
-#endif /* __LOGGING_H */
diff --git a/compat/Android.mk b/compat/Android.mk
index 3de66b4..2f99d65 100755
--- a/compat/Android.mk
+++ b/compat/Android.mk
@@ -13,17 +13,16 @@
 	pand.c bnep.c sdp.c
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\" -DSTORAGEDIR=\"/data/misc/bluetoothd\" -DNEED_PPOLL -D__ANDROID__
+	-DVERSION=\"4.69\" -DSTORAGEDIR=\"/data/misc/bluetoothd\" -DNEED_PPOLL -D__ANDROID__
 
 LOCAL_C_INCLUDES:=\
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common \
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src \
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth libcutils
-
-LOCAL_STATIC_LIBRARIES := \
-	libbluez-common-static
+	libbluetoothd \
+	libbluetooth \
+	libcutils
 
 LOCAL_MODULE_TAGS :=
 LOCAL_MODULE:=pand
diff --git a/compat/Makefile.am b/compat/Makefile.am
deleted file mode 100644
index 58254ad..0000000
--- a/compat/Makefile.am
+++ /dev/null
@@ -1,47 +0,0 @@
-
-bin_PROGRAMS =
-man_MANS =
-
-if HIDD
-bin_PROGRAMS += hidd
-
-hidd_SOURCES = hidd.c hidd.h sdp.h sdp.c fakehid.c
-
-hidd_LDADD = $(top_builddir)/common/libhelper.a @BLUEZ_LIBS@ -lm
-
-if MANPAGES
-man_MANS += hidd.1
-endif
-endif
-
-if PAND
-bin_PROGRAMS += pand
-
-pand_SOURCES = pand.c pand.h bnep.c sdp.h sdp.c
-
-pand_LDADD = $(top_builddir)/common/libhelper.a @BLUEZ_LIBS@
-
-if MANPAGES
-man_MANS += pand.1
-endif
-endif
-
-if DUND
-bin_PROGRAMS += dund
-
-dund_SOURCES = dund.c dund.h lib.h sdp.h sdp.c dun.c msdun.c
-
-dund_LDADD = $(top_builddir)/common/libhelper.a @BLUEZ_LIBS@
-
-if MANPAGES
-man_MANS += dund.1
-endif
-endif
-
-AM_CFLAGS = @BLUEZ_CFLAGS@
-
-INCLUDES = -I$(top_srcdir)/common
-
-EXTRA_DIST = fakehid.txt hidd.1 pand.1 dund.1
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/compat/bnep.c b/compat/bnep.c
index 0498c78..2e4fb9d 100644
--- a/compat/bnep.c
+++ b/compat/bnep.c
@@ -3,7 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -93,7 +93,7 @@
 	}
 
 	/* Temporary ioctl compatibility hack */
-	{ 
+	{
 		struct bnep_connlist_req req;
 		struct bnep_conninfo ci[1];
 
@@ -194,19 +194,19 @@
 	return 0;
 }
 
-struct __service_16 { 
+struct __service_16 {
 	uint16_t dst;
 	uint16_t src;
 } __attribute__ ((packed));
 
-struct __service_32 { 
+struct __service_32 {
 	uint16_t unused1;
 	uint16_t dst;
 	uint16_t unused2;
 	uint16_t src;
 } __attribute__ ((packed));
 
-struct __service_128 { 
+struct __service_128 {
 	uint16_t unused1;
 	uint16_t dst;
 	uint16_t unused2[8];
@@ -246,7 +246,7 @@
 	return bnep_connadd(sk, role, dev);
 }
 
-/* Create BNEP connection 
+/* Create BNEP connection
  * sk      - Connect L2CAP socket
  * role    - Local role
  * service - Remote service
diff --git a/compat/dun.c b/compat/dun.c
index c74e5ee..59f036f 100644
--- a/compat/dun.c
+++ b/compat/dun.c
@@ -3,7 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -86,6 +86,7 @@
 	}
 
 	close(sk);
+	free(dl);
 	return r;
 }
 
@@ -106,8 +107,10 @@
 		int  len = readlink(de->d_name, link, sizeof(link));
 		if (len > 0) {
 			link[len] = 0;
-			if (strstr(link, dev))
+			if (strstr(link, dev)) {
+				closedir(dir);
 				return 1;
+			}
 		}
 	}
 
@@ -155,7 +158,7 @@
 {
 	int pid = fork();
 	int fd;
-	
+
 	switch (pid) {
 	case -1:
 		return -1;
@@ -241,7 +244,7 @@
 static int show_conn(struct rfcomm_dev_info *di, unsigned long arg)
 {
 	pid_t pid;
-	
+
 	if (di->state == BT_CONNECTED &&
 		(di->flags & (1<<RFCOMM_REUSE_DLC)) &&
 		(di->flags & (1<<RFCOMM_TTY_ATTACHED)) &&
diff --git a/compat/dund.c b/compat/dund.c
index fc8ba30..af1b536 100644
--- a/compat/dund.c
+++ b/compat/dund.c
@@ -3,7 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -192,7 +192,7 @@
 		}
 
 		ba2str(&sa.rc_bdaddr, ba);
-		sprintf(ch, "%d", channel);
+		snprintf(ch, sizeof(ch), "%d", channel);
 
 		/* Setup environment */
 		setenv("DUN_BDADDR",  ba, 1);
@@ -247,7 +247,7 @@
 	sa.rc_bdaddr  = src_addr;
 
 	if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)))
-		syslog(LOG_ERR, "Bind failed. %s(%d)", 
+		syslog(LOG_ERR, "Bind failed. %s(%d)",
 			strerror(errno), errno);
 
 	sa.rc_channel = ch;
@@ -337,7 +337,7 @@
 		for (i = 0; i < n; i++) {
 			char dst[40];
 			ba2str(&ii[i].bdaddr, dst);
-			
+
 			r = create_connection(dst, &ii[i].bdaddr, 0);
 			if (r < 0) {
 				terminate = 1;
@@ -405,7 +405,7 @@
 
 static const char *main_sopts = "hsc:k:Kr:i:lnp::DQ::AESMP:C::P:Xam:u";
 
-static const char *main_help = 
+static const char *main_help =
 	"Bluetooth LAP (LAN Access over PPP) daemon version %s\n"
 	"Usage:\n"
 	"\tdund <options> [pppd options]\n"
@@ -568,21 +568,26 @@
 
 	io_init();
 
-	if (dun_init())
+	if (dun_init()) {
+		free(dst);
 		return -1;
+	}
 
 	/* Check non daemon modes first */
 	switch (mode) {
 	case SHOW:
 		do_show();
+		free(dst);
 		return 0;
 
 	case KILL:
 		do_kill(dst);
+		free(dst);
 		return 0;
 
 	case NONE:
 		printf(main_help, VERSION);
+		free(dst);
 		return 0;
 	}
 
@@ -612,6 +617,7 @@
 		src_dev = hci_devid(src);
 		if (src_dev < 0 || hci_devba(src_dev, &src_addr) < 0) {
 			syslog(LOG_ERR, "Invalid source. %s(%d)", strerror(errno), errno);
+			free(dst);
 			return -1;
 		}
 	}
@@ -634,5 +640,6 @@
 		break;
 	}
 
+	free(dst);
 	return 0;
 }
diff --git a/compat/dund.h b/compat/dund.h
index 0408e09..e3a4ef6 100644
--- a/compat/dund.h
+++ b/compat/dund.h
@@ -3,7 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/compat/fakehid.c b/compat/fakehid.c
index 438185d..b996d10 100644
--- a/compat/fakehid.c
+++ b/compat/fakehid.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/compat/hidd.c b/compat/hidd.c
index 212c092..88944cf 100644
--- a/compat/hidd.c
+++ b/compat/hidd.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -453,6 +453,7 @@
 	int csk, isk, err;
 
 	memset(&req, 0, sizeof(req));
+	name[0] = '\0';
 
 	err = get_sdp_device_info(src, dst, &req);
 	if (err < 0 && fakehid)
@@ -572,7 +573,7 @@
 
 	for (i = 0; i < num_rsp; i++) {
 		memcpy(class, (info+i)->dev_class, 3);
-		if ((class[0] == 0x00 && class[2] == 0x00 && 
+		if ((class[0] == 0x00 && class[2] == 0x00 &&
 				(class[1] == 0x40 || class[1] == 0x1f)) ||
 				(class[0] == 0x10 && class[1] == 0x02 && class[2] == 0x40)) {
 			bacpy(&dst, &(info+i)->bdaddr);
diff --git a/compat/hidd.h b/compat/hidd.h
index 362815a..0536967 100644
--- a/compat/hidd.h
+++ b/compat/hidd.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/compat/lib.h b/compat/lib.h
index d6373a7..3b3aeb5 100644
--- a/compat/lib.h
+++ b/compat/lib.h
@@ -3,7 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/compat/msdun.c b/compat/msdun.c
index 1759ef6..ae88c0c 100644
--- a/compat/msdun.c
+++ b/compat/msdun.c
@@ -3,7 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -58,7 +58,7 @@
 	char buf[40];
 	unsigned len = 0;
 	int r;
-	
+
 	while (1) {
 		r = read(fd, buf + len, sizeof(buf) - len - 1);
 		if (r < 0) {
@@ -92,7 +92,7 @@
 		write_n(fd, "CLIENTSERVER", 12);
 	case MS_PPP:
 		return MS_SUCCESS;
-	default:	
+	default:
 		return MS_FAILED;
 	}
 }
@@ -123,7 +123,7 @@
 
 			alarm(0);
 			signal(SIGALRM, osig);
-		
+
 			switch (r) {
 			case MS_SUCCESS:
 			case MS_PPP:
@@ -142,7 +142,7 @@
 		}
 
 		alarm(timeout);
-		
+
 		if (server)
 			r = ms_server(fd);
 		else
diff --git a/compat/pand.c b/compat/pand.c
index 747661f..6554e50 100644
--- a/compat/pand.c
+++ b/compat/pand.c
@@ -3,7 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -367,7 +367,7 @@
 	bacpy(&l2a.l2_bdaddr, bdaddr);
 	l2a.l2_psm = htobs(BNEP_PSM);
 
-	if (!connect(sk, (struct sockaddr *) &l2a, sizeof(l2a)) && 
+	if (!connect(sk, (struct sockaddr *) &l2a, sizeof(l2a)) &&
 			!bnep_create_connection(sk, role, service, netdev)) {
 
 		syslog(LOG_INFO, "%s connected", netdev);
@@ -454,7 +454,7 @@
 			ba2str(&ii[i].bdaddr, dst);
 
 			if (use_sdp) {
-				syslog(LOG_INFO, "Searching for %s on %s", 
+				syslog(LOG_INFO, "Searching for %s on %s",
 						bnep_svc2str(service), dst);
 
 				if (bnep_sdp_search(&src_addr, &ii[i].bdaddr, service) <= 0)
@@ -512,7 +512,7 @@
 							strerror(errno), errno);
 				return -1;
 			}
-			
+
 			/* We're already running; send a SIGHUP (we presume that they
 			 * are calling ifup for a reason, so they probably want to
 			 * rescan) and then exit cleanly and let things go on in the
@@ -595,7 +595,7 @@
 
 static const char *main_sopts = "hsc:k:Kr:d:e:i:lnp::DQ::AESMC::P:u:o:z";
 
-static const char *main_help = 
+static const char *main_help =
 	"Bluetooth PAN daemon version %s\n"
 	"Usage:\n"
 	"\tpand <options>\n"
@@ -745,21 +745,26 @@
 	argv += optind;
 	optind = 0;
 
-	if (bnep_init())
+	if (bnep_init()) {
+		free(dst);
 		return -1;
+	}
 
 	/* Check non daemon modes first */
 	switch (mode) {
 	case SHOW:
 		do_show();
+		free(dst);
 		return 0;
 
 	case KILL:
 		do_kill(dst);
+		free(dst);
 		return 0;
 
 	case NONE:
 		printf(main_help, VERSION);
+		free(dst);
 		return 0;
 	}
 
@@ -790,12 +795,15 @@
 		if (src_dev < 0 || hci_devba(src_dev, &src_addr) < 0) {
 			syslog(LOG_ERR, "Invalid source. %s(%d)",
 						strerror(errno), errno);
+			free(dst);
 			return -1;
 		}
 	}
 
-	if (pidfile && write_pidfile())
+	if (pidfile && write_pidfile()) {
+		free(dst);
 		return -1;
+	}
 
 	if (dst) {
 		/* Disable cache invalidation */
diff --git a/compat/pand.h b/compat/pand.h
index 4819178..08b5bdc 100644
--- a/compat/pand.h
+++ b/compat/pand.h
@@ -3,7 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/compat/sdp.c b/compat/sdp.c
index d411c05..8898136 100644
--- a/compat/sdp.c
+++ b/compat/sdp.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -368,7 +368,7 @@
 	return -EIO;
 }
 
-void bnep_sdp_unregister(void) 
+void bnep_sdp_unregister(void)
 {
 	if (record && sdp_record_unregister(session, record))
 		syslog(LOG_ERR, "Service record unregistration failed.");
@@ -424,7 +424,7 @@
 
 	/* Supported protocols */
 	{
-		uint16_t ptype[4] = { 
+		uint16_t ptype[4] = {
 			0x0800,  /* IPv4 */
 			0x0806,  /* ARP */
 		};
@@ -483,7 +483,7 @@
 		profile[0].version = 0x0100;
 		pfseq = sdp_list_append(NULL, &profile[0]);
 		sdp_set_profile_descs(record, pfseq);
-		
+
 		sdp_set_info_attr(record, "Group Network Service", name, desc);
 		break;
 
@@ -558,7 +558,7 @@
 static unsigned char async_uuid[] = {	0x03, 0x50, 0x27, 0x8F, 0x3D, 0xCA, 0x4E, 0x62,
 					0x83, 0x1D, 0xA4, 0x11, 0x65, 0xFF, 0x90, 0x6C };
 
-void dun_sdp_unregister(void) 
+void dun_sdp_unregister(void)
 {
 	if (record && sdp_record_unregister(session, record))
 		syslog(LOG_ERR, "Service record unregistration failed.");
@@ -575,7 +575,7 @@
 
 	session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
 	if (!session) {
-		syslog(LOG_ERR, "Failed to connect to the local SDP server. %s(%d)", 
+		syslog(LOG_ERR, "Failed to connect to the local SDP server. %s(%d)",
 				strerror(errno), errno);
 		return -1;
 	}
@@ -670,7 +670,7 @@
 
 	s = sdp_connect(src, dst, 0);
 	if (!s) {
-		syslog(LOG_ERR, "Failed to connect to the SDP server. %s(%d)", 
+		syslog(LOG_ERR, "Failed to connect to the SDP server. %s(%d)",
 				strerror(errno), errno);
 		return -1;
 	}
diff --git a/compat/sdp.h b/compat/sdp.h
index bec58a2..6ca975f 100644
--- a/compat/sdp.h
+++ b/compat/sdp.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/configure.ac b/configure.ac
index 85e1dae..b004f6e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
 AC_PREREQ(2.60)
-AC_INIT()
+AC_INIT(bluez, 4.69)
 
-AM_INIT_AUTOMAKE(bluez, 4.47)
+AM_INIT_AUTOMAKE([foreign subdir-objects])
 AM_CONFIG_HEADER(config.h)
 
 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
@@ -17,10 +17,12 @@
 AC_LANG_C
 
 AC_PROG_CC
+AM_PROG_CC_C_O
 AC_PROG_CC_PIE
 AC_PROG_INSTALL
 AC_PROG_YACC
 AM_PROG_LEX
+AM_PROG_MKDIR_P
 
 m4_define([_LT_AC_TAGCONFIG], [])
 m4_ifdef([AC_LIBTOOL_TAGS], [AC_LIBTOOL_TAGS([])])
@@ -28,8 +30,6 @@
 AC_DISABLE_STATIC
 AC_PROG_LIBTOOL
 
-GTK_DOC_CHECK
-
 AC_FUNC_PPOLL
 
 AC_CHECK_LIB(dl, dlopen, dummy=yes,
@@ -40,35 +40,29 @@
 AC_PATH_ALSA
 AC_PATH_GSTREAMER
 AC_PATH_USB
-AC_PATH_NETLINK
 AC_PATH_SNDFILE
 
 AC_ARG_BLUEZ
 
-AC_OUTPUT([
-	Makefile
-	include/Makefile
-	lib/Makefile
-	gdbus/Makefile
-	common/Makefile
-	sbc/Makefile
-	src/Makefile
-	test/Makefile
-	cups/Makefile
-	tools/Makefile
-	client/Makefile
-	rfcomm/Makefile
-	compat/Makefile
-	plugins/Makefile
-	network/Makefile
-	serial/Makefile
-	input/Makefile
-	audio/Makefile
-	scripts/Makefile
-	scripts/bluetooth.rules
-	doc/Makefile
-	doc/version.xml
-	src/bluetoothd.8
-	src/hcid.conf.5
-	bluez.pc
-])
+AC_ARG_ENABLE(capng, AC_HELP_STRING([--enable-capng],
+		[enable capabilities support]), [enable_capng=${enableval}])
+if (test "${enable_capng}" = "yes"); then
+	PKG_CHECK_MODULES(CAPNG, libcap-ng, dummy=yes,
+				AC_MSG_ERROR(Capabilities library is required))
+	AC_SUBST(CAPNG_CFLAGS)
+	AC_SUBST(CAPNG_LIBS)
+	AC_DEFINE(HAVE_CAPNG, 1, [Define to 1 if you have capabilities library.])
+fi
+
+AC_ARG_ENABLE(netlink, AC_HELP_STRING([--enable-netlink],
+		[enable netlink support]), [enable_netlink=${enableval}])
+if (test "${enable_netlink}" = "yes"); then
+	PKG_CHECK_MODULES(NETLINK, libnl-1, dummy=yes,
+				AC_MSG_ERROR(Netlink library is required))
+	AC_SUBST(NETLINK_CFLAGS)
+	AC_SUBST(NETLINK_LIBS)
+fi
+AM_CONDITIONAL(NETLINK, test "${enable_netlink}" = "yes")
+
+AC_OUTPUT(Makefile scripts/bluetooth.rules doc/version.xml
+					src/bluetoothd.8 bluez.pc)
diff --git a/cups/Makefile.am b/cups/Makefile.am
deleted file mode 100644
index 70a8ba8..0000000
--- a/cups/Makefile.am
+++ /dev/null
@@ -1,16 +0,0 @@
-
-if CUPS
-cupsdir = $(libdir)/cups/backend
-
-cups_PROGRAMS = bluetooth
-
-bluetooth_SOURCES = main.c cups.h sdp.c spp.c hcrp.c
-
-bluetooth_LDADD = @GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
-endif
-
-AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
-
-INCLUDES = -I$(top_srcdir)/common
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/cups/cups.h b/cups/cups.h
index 2cbac98..f4e0c01 100644
--- a/cups/cups.h
+++ b/cups/cups.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/cups/hcrp.c b/cups/hcrp.c
index 155236d..7aafcdc 100644
--- a/cups/hcrp.c
+++ b/cups/hcrp.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/cups/main.c b/cups/main.c
index 2fbfe7e..9659a11 100644
--- a/cups/main.c
+++ b/cups/main.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -185,6 +185,27 @@
 	return id;
 }
 
+static void print_printer_details(const char *name, const char *bdaddr, const char *id)
+{
+	char *uri, *escaped;
+
+	escaped = g_strdelimit(g_strdup(name), "\"", '\'');
+	uri = g_strdup_printf("bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c",
+		 bdaddr[0], bdaddr[1],
+		 bdaddr[3], bdaddr[4],
+		 bdaddr[6], bdaddr[7],
+		 bdaddr[9], bdaddr[10],
+		 bdaddr[12], bdaddr[13],
+		 bdaddr[15], bdaddr[16]);
+	printf("direct %s \"%s\" \"%s (Bluetooth)\"", uri, escaped, escaped);
+	if (id != NULL)
+		printf(" \"%s\"\n", id);
+	else
+		printf("\n");
+	g_free(escaped);
+	g_free(uri);
+}
+
 static void add_device_to_list(const char *name, const char *bdaddr, const char *id)
 {
 	struct cups_device *device;
@@ -212,27 +233,7 @@
 	device->id = g_strdup(id);
 
 	device_list = g_slist_prepend(device_list, device);
-}
-
-static void print_printer_details(const char *name, const char *bdaddr, const char *id)
-{
-	char *uri, *escaped;
-
-	escaped = g_strdelimit(g_strdup(name), "\"", '\'');
-	uri = g_strdup_printf("bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c",
-		 bdaddr[0], bdaddr[1],
-		 bdaddr[3], bdaddr[4],
-		 bdaddr[6], bdaddr[7],
-		 bdaddr[9], bdaddr[10],
-		 bdaddr[12], bdaddr[13],
-		 bdaddr[15], bdaddr[16]);
-	printf("network %s \"Unknown\" \"%s (Bluetooth)\"", uri, escaped);
-	if (id != NULL)
-		printf(" \"%s\"\n", id);
-	else
-		printf("\n");
-	g_free(escaped);
-	g_free(uri);
+	print_printer_details(device->name, device->bdaddr, device->id);
 }
 
 static gboolean parse_device_properties(DBusMessageIter *reply_iter, char **name, char **bdaddr)
@@ -371,9 +372,10 @@
 
 		if (!reply)
 			return;
-	} else {
-		if (dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID) == FALSE)
-			return;
+	}
+	if (dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &object_path,
+				  DBUS_TYPE_INVALID) == FALSE) {
+		return;
 	}
 
 	id = device_get_ieee1284_id(adapter, object_path);
@@ -383,23 +385,6 @@
 
 static void discovery_completed(void)
 {
-	GSList *l;
-
-	for (l = device_list; l != NULL; l = l->next) {
-		struct cups_device *device = (struct cups_device *) l->data;
-
-		if (device->name == NULL)
-			device->name = g_strdelimit(g_strdup(device->bdaddr), ":", '-');
-		/* Give another try to getting an ID for the device */
-		if (device->id == NULL)
-			remote_device_found(NULL, device->bdaddr, device->name);
-		print_printer_details(device->name, device->bdaddr, device->id);
-		g_free(device->name);
-		g_free(device->bdaddr);
-		g_free(device->id);
-		g_free(device);
-	}
-
 	g_slist_free(device_list);
 	device_list = NULL;
 
@@ -441,7 +426,7 @@
 
 	dbus_message_unref(message);
 
-	if (&error != NULL && dbus_error_is_set(&error))
+	if (dbus_error_is_set(&error))
 		return FALSE;
 
 	dbus_message_iter_init(reply, &reply_iter);
@@ -506,6 +491,8 @@
 
 		dbus_message_iter_init(message, &iter);
 		dbus_message_iter_get_basic(&iter, &name);
+		if (name == NULL || strcmp(name, "Discovering") != 0)
+			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 		dbus_message_iter_next(&iter);
 		dbus_message_iter_recurse(&iter, &value_iter);
 		dbus_message_iter_get_basic(&value_iter, &discovering);
@@ -540,7 +527,7 @@
 
 	dbus_error_init(&error);
 	hcid_exists = dbus_bus_name_has_owner(conn, "org.bluez", &error);
-	if (&error != NULL && dbus_error_is_set(&error))
+	if (dbus_error_is_set(&error))
 		return TRUE;
 
 	if (!hcid_exists)
@@ -560,7 +547,7 @@
 
 	dbus_message_unref(message);
 
-	if (&error != NULL && dbus_error_is_set(&error)) {
+	if (dbus_error_is_set(&error)) {
 		dbus_connection_unref(conn);
 		/* No adapter */
 		return TRUE;
@@ -612,6 +599,7 @@
 	loop = g_main_loop_new(NULL, TRUE);
 	g_main_loop_run(loop);
 
+	g_free(adapter);
 	dbus_connection_unref(conn);
 
 	return TRUE;
@@ -635,6 +623,9 @@
 	/* Make sure status messages are not buffered */
 	setbuf(stderr, NULL);
 
+	/* Make sure output is not buffered */
+	setbuf(stdout, NULL);
+
 	/* Ignore SIGPIPE signals */
 #ifdef HAVE_SIGSET
 	sigset(SIGPIPE, SIG_IGN);
diff --git a/cups/sdp.c b/cups/sdp.c
index 8bf6d32..c7f17a4 100644
--- a/cups/sdp.c
+++ b/cups/sdp.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/cups/spp.c b/cups/spp.c
index 3370218..d906ed2 100644
--- a/cups/spp.c
+++ b/cups/spp.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/doc/Makefile.am b/doc/Makefile.am
deleted file mode 100644
index 6277dcc..0000000
--- a/doc/Makefile.am
+++ /dev/null
@@ -1,31 +0,0 @@
-
-DOC_MODULE = bluez
-
-DOC_MAIN_SGML_FILE = $(DOC_MODULE)-docs.xml
-
-DOC_SOURCE_DIR = ../src
-
-SCAN_OPTIONS = --rebuild-sections
-
-MKDB_OPTIONS = --sgml-mode --output-format=xml --tmpl-dir=. \
-					--source-suffixes=c,h
-
-MKTMPL_OPTIONS = --output-dir=.
-
-HFILE_GLOB = $(top_srcdir)/src/*.h
-CFILE_GLOB = $(top_srcdir)/src/*.c
-
-IGNORE_HFILES =
-
-MAINTAINERCLEANFILES = Makefile.in \
-	$(DOC_MODULE).types $(DOC_MODULE)-*.txt *.sgml
-
-if ENABLE_GTK_DOC
-include $(top_srcdir)/doc/gtk-doc.make
-else
-EXTRA_DIST = $(DOC_MAIN_SGML_FILE) $(content_files)
-endif
-
-EXTRA_DIST += manager-api.txt adapter-api.txt device-api.txt \
-		service-api.txt agent-api.txt serial-api.txt \
-		network-api.txt input-api.txt audio-api.txt control-api.txt
diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt
index 1e03b4e..6098c76 100644
--- a/doc/adapter-api.txt
+++ b/doc/adapter-api.txt
@@ -1,7 +1,7 @@
 BlueZ D-Bus Adapter API description
 ***********************************
 
-Copyright (C) 2004-2008  Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
 Copyright (C) 2005-2006  Johan Hedberg <johan.hedberg@nokia.com>
 Copyright (C) 2005-2006  Claudio Takahasi <claudio.takahasi@indt.org.br>
 Copyright (C) 2006-2007  Luiz von Dentz <luiz.dentz@indt.org.br>
@@ -80,9 +80,11 @@
 			Possible Errors: org.bluez.Error.DoesNotExist
 					 org.bluez.Error.InvalidArguments
 
-		array{object} ListDevices()
+		array{object} ListDevices() {deprecated}
 
 			Returns list of device object paths.
+			This method is deprecated, instead use the Devices
+			Property to get the list of devices object paths.
 
 			Possible errors: org.bluez.Error.InvalidArguments
 					 org.bluez.Error.Failed
@@ -268,3 +270,8 @@
 		array{object} Devices [readonly]
 
 			List of device object paths.
+
+		array{string} UUIDs [readonly]
+
+			List of 128-bit UUIDs that represents the available
+			local services.
diff --git a/doc/agent-api.txt b/doc/agent-api.txt
index dbfc08a..c927a55 100644
--- a/doc/agent-api.txt
+++ b/doc/agent-api.txt
@@ -1,7 +1,7 @@
 BlueZ D-Bus Agent API description
 **********************************
 
-Copyright (C) 2004-2008  Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
 Copyright (C) 2005-2006  Johan Hedberg <johan.hedberg@nokia.com>
 
 
diff --git a/doc/attribute-api.txt b/doc/attribute-api.txt
new file mode 100644
index 0000000..ee91f93
--- /dev/null
+++ b/doc/attribute-api.txt
@@ -0,0 +1,97 @@
+BlueZ D-Bus Attribute API description
+*************************************
+
+Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+
+
+Attribute hierarchy
+===================
+
+Service		org.bluez
+Interface	org.bluez.Service
+		org.bluez.Characteristic
+Object path	[prefix]/{hci0}/{service0}
+		[prefix]/{hci0}/{device0}/{service0}/{characteristic0,...}
+		[prefix]/{hci0}/{device0}/{service1}/{characteristic0,...}
+
+Service details
+---------------
+
+One service object path for every remote SDP record or service in the
+attribute database. One service object path for every local SDP record
+or service from attribute database.
+
+Local services are children of the adapter object path. Remote services
+are children of the remote device object path. This doesn't solve the
+problem where local atttributes can have different instances based on
+the remote device.
+
+In general the idea is to also represent SDP records as services so that
+new style application can just use the service interfaces to retrieve the
+needed information. That way the usage of SDP and GATT would be mostly
+fully transparent and a differentiation becomes unimportant in the future.
+
+A service consists of some generic service information and a set of
+characteristics. All characteristic are presented as object path as well.
+
+Properties
+----------
+	string Name (mandatory)
+
+		General name of service
+
+	string Description (optional)
+
+		Description of service
+
+	string UUID (mandatory)
+
+		UUID of service. Service class value for SDP and GATT UUID
+		for attribute based services.
+
+	array{object} Characteristics
+
+		This list contains the characteristics owned by this specific
+		service and other characteristics from service includes. That
+		way no complicated service includes array is needed.
+
+		string UUID
+		string Name
+		string Description
+		struct Format (type, name, exponet etc.)
+
+		array{byte} Value
+		string Representation (of the binary Value)
+
+		object Service (the original service in case of includes)
+
+		At this point only GetProperties() method call should be
+		supported for simplicity. Changing characteristics is up
+		to future support.
+
+		The object path of the characteristics might be split
+		over multiple service objects, because of includes.
+
+	array[(object, dict)] GetCharacteristics()
+
+		Array of tuples with object path as identifier. An alternativ
+		is doing dict of dict since the object path is unique and the
+		order of characteristics is irrelevant. However it might be
+		good to actually present an order here.
+
+		See Characteristics properties for dictionary details.
+
+	RegisterCharacteristicsWatcher(object path)
+
+		Register a watcher for changes in specific characteristics
+		to monitor changes.
+
+		A watcher will be registered for this service and will
+		notifier about any changed characteristics in the service.
+		This also notifies about any included characteristics.
+
+		Method for the watch objects still need to be defined.
+
+	UnregisterCharacteristicsWatcher(object path)
+
+		Unregister a watcher.
diff --git a/doc/audio-api.txt b/doc/audio-api.txt
index 1f09cd5..e7991f3 100644
--- a/doc/audio-api.txt
+++ b/doc/audio-api.txt
@@ -1,7 +1,7 @@
 BlueZ D-Bus Audio API description
 *********************************
 
-Copyright (C) 2004-2008  Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
 Copyright (C) 2005-2007  Johan Hedberg <johan.hedberg@nokia.com>
 Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
 
diff --git a/doc/control-api.txt b/doc/control-api.txt
index ffc0fc0..1a42846 100644
--- a/doc/control-api.txt
+++ b/doc/control-api.txt
@@ -1,7 +1,7 @@
 BlueZ D-Bus Control API description
 ***********************************
 
-Copyright (C) 2004-2008  Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
 Copyright (C) 2007-2008  David Stockwell <dstockwell@frequency-one.com>
 
 
diff --git a/doc/device-api.txt b/doc/device-api.txt
index 698f9ce..b818299 100644
--- a/doc/device-api.txt
+++ b/doc/device-api.txt
@@ -1,7 +1,7 @@
 BlueZ D-Bus Device API description
 **********************************
 
-Copyright (C) 2004-2008  Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
 Copyright (C) 2005-2006  Johan Hedberg <johan.hedberg@nokia.com>
 Copyright (C) 2005-2006  Claudio Takahasi <claudio.takahasi@indt.org.br>
 Copyright (C) 2006-2007  Luiz von Dentz <luiz.dentz@indt.org.br>
@@ -154,6 +154,13 @@
 			Indicates if the remote is seen as trusted. This
 			setting can be changed by the application.
 
+		boolean Blocked [readwrite]
+
+			If set to true any incoming connections from the
+			device will be immediately rejected. Any device
+			drivers will also be removed and no new ones will
+			be probed as long as the device is blocked.
+
 		string Alias [readwrite]
 
 			The name alias for the remote device. The alias can
diff --git a/doc/health-api.txt b/doc/health-api.txt
new file mode 100644
index 0000000..f469df3
--- /dev/null
+++ b/doc/health-api.txt
@@ -0,0 +1,168 @@
+BlueZ D-Bus Health API description
+**********************************
+
+	Santiago Carot-Nemesio <sancane@gmail.com>
+	José Antonio Santos-Cadenas <santoscadenas@gmail.com>
+	Elvis Pfützenreuter <epx@signove.com>
+
+Health Device Profile hierarchy
+===============================
+
+Service		org.bluez
+Interface	org.bluez.HealthManager
+Object path	/org/bluez/
+
+Methods:
+
+	object	CreateApplication(dict config, object agent)
+
+		Returns the path of the new registered application. The agent
+		parameter is the path of the object with the callbacks to
+		notify events (see org.bluez.HealthAgent at the end
+		of this document).
+
+		Dict is defined as bellow:
+		{
+			"DataType": uint16, (mandatory)
+			"Role" : ("Source" or "Sink"), (mandatory)
+			"Description" : string, (optional)
+			"ChannelType" : ("Reliable" or "Streaming")
+						(just for Sources, optional)
+		}
+
+		Application will be closed by the call or implicitly when the
+		programs leaves the bus.
+
+		Possible errors: org.bluez.Error.InvalidArguments
+
+	void	DestroyApplication(object application)
+
+		Closes the HDP application identified by the object path. Also
+		application will be closed if the process that started it leaves
+		the bus.
+
+		Possible errors: org.bluez.Error.InvalidArguments
+				org.bluez.Error.NotFound
+
+--------------------------------------------------------------------------------
+
+Service		org.bluez
+Interface	org.bluez.HealthApplication
+Object path	[variable prefix]/health_app_ZZZZ
+
+Methods:
+
+	void Echo(object service)
+
+		Sends an echo petition to the remote service. Returns True if
+		response matches with the buffer sent. If some error is detected
+		False value is returned and the associated MCL is closed.
+
+		Possible errors: org.bluez.Error.InvalidArguments
+				org.bluez.Error.OutOfRange
+
+	object CreateChannel(object service, string type)
+
+		Creates a new data channel with the indicated config to the
+		remote Service.
+		The configuration should indicate the channel quality of
+		service using one of this values "Reliable", "Streaming", "Any".
+
+		Returns the object path that identifies the data channel that
+		is already connected.
+
+		Possible errors: org.bluez.Error.InvalidArguments
+				org.bluez.Error.HealthError
+
+	void DestroyChannel(object channel)
+
+		Destroys the data channel object.
+
+		Possible errors: org.bluez.Error.InvalidArguments
+				orb.bluez.Error.NotFound
+
+--------------------------------------------------------------------------------
+
+Service		org.bluez
+Interface	org.bluez.HealthService
+Object path	[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/hdp_YYYY
+
+--------------------------------------------------------------------------------
+
+Service		org.bluez
+Interface	org.bluez.HealthChannel
+Object path	[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/
+							hdp_YYYY/channel_ZZ
+
+Methods:
+
+	dict GetProperties()
+
+		Returns all properties for the interface. See the properties
+		section for available properties.
+
+	fd Acquire()
+
+		Returns the file descriptor for this data channel. If the data
+		channel is not connected it will also reconnect.
+
+		Possible errors: org.bluez.Error.NotConnected
+
+	void Release()
+
+		Releases the fd. Application should also need to close() it.
+
+Properties:
+
+	string Type (read only)
+
+		The quality of service of the data channel. ("Reliable" or
+		"Streaming")
+
+	object Service (read only)
+
+		Identifies the Remote Service that is connected with. Maps with
+		a HealthService object.
+
+HealthAgent hierarchy
+=====================
+
+(this object is implemented by the HDP user in order to receive notifications)
+
+Service		unique name
+Interface	org.bluez.HealthAgent
+Object path	freely definable
+
+Methods:
+
+	void Release()
+
+		This method gets called when the service daemon unregisters the
+		agent. An agent can use it to do cleanup tasks. There is no need
+		to unregister the agent, because when this method gets called it
+		has already been unregistered.
+
+	void ServiceDiscovered(object service)
+
+		This method is called when a device containing an HDP
+		application is paired or when the method Update of the
+		HealthManager is called and new HealthServices are discovered.
+		The method will be called once for each HealthService.
+
+	void ServiceRemoved(object service)
+
+		This is called if during an Update some HealthServices
+		have disappeared. The method is called once for each removed
+		HealthService.
+
+	void ChannelConnected(object channel)
+
+		This method is called when a new data channel is created or when
+		a known data channel is reconnected.
+
+	void ChannelDeleted(object channel)
+
+		This method is called when a data channel is deleted.
+
+		After this call the data channel path will not be valid and can
+		be reused for future creation of data channels.
diff --git a/doc/hfp-api.txt b/doc/hfp-api.txt
new file mode 100644
index 0000000..93251e8
--- /dev/null
+++ b/doc/hfp-api.txt
@@ -0,0 +1,86 @@
+Gateway hierarchy
+========================
+
+Service		org.bluez
+Interface	org.bluez.HandsfreeGateway
+Object path	[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+This interface is available for remote devices which can function in the Audio
+Gateway role of the HFP profiles.  It is intended to be used with external
+telephony stacks / handlers of the HFP protocol.
+
+Methods		void Connect()
+
+			Connect to the AG service on the remote device.
+
+		void Disconnect()
+
+			Disconnect from the AG service on the remote device
+
+		dict GetProperties()
+
+			Returns all properties for the interface. See the
+			properties section for available properties.
+
+		void RegisterAgent(object path)
+
+			The object path defines the path the of the agent
+			that will be called when a new Handsfree connection
+			is established.
+
+			If an application disconnects from the bus all of its
+			registered agents will be removed.
+
+		void UnregisterAgent(object path)
+
+			This unregisters the agent that has been previously
+			registered. The object path parameter must match the
+			same value that has been used on registration.
+
+			Possible Errors: org.bluez.Error.Failed
+					 org.bluez.Error.InvalidArguments
+
+
+Signals		PropertyChanged(string name, variant value)
+
+			This signal indicates a changed value of the given
+			property.
+
+Properties	string State [readonly]
+
+			Indicates the state of the connection.  Possible
+			values are:
+				"disconnected"
+				"connecting"
+				"connected"
+				"playing"
+
+HandsfreeAgent hierarchy
+===============
+
+Service         unique name
+Interface       org.bluez.HandsfreeAgent
+Object path     freely definable
+
+Methods		void NewConnection(filedescriptor fd)
+
+			This method gets called whenever a new handsfree
+			connection has been established.  The objectpath
+			contains the object path of the remote device.  This
+			method assumes that DBus daemon with file descriptor
+			passing capability is being used.
+
+			The agent should only return successfully once the
+			establishment of the service level connection (SLC)
+			has been completed.  In the case of Handsfree this
+			means that BRSF exchange has been performed and
+			necessary initialization has been done.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+					 org.bluez.Error.Failed
+
+		void Release()
+
+			This method gets called whenever the service daemon
+			unregisters the agent or whenever the Adapter where
+			the HandsfreeAgent registers itself is removed.
diff --git a/doc/input-api.txt b/doc/input-api.txt
index 38310ce..7c3a4b2 100644
--- a/doc/input-api.txt
+++ b/doc/input-api.txt
@@ -1,7 +1,7 @@
 BlueZ D-Bus Input API description
 *********************************
 
-Copyright (C) 2004-2008  Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
 
 
 Input hierarchy
diff --git a/doc/manager-api.txt b/doc/manager-api.txt
index e045cad..d2c1caf 100644
--- a/doc/manager-api.txt
+++ b/doc/manager-api.txt
@@ -1,7 +1,7 @@
 BlueZ D-Bus Manager API description
 ***********************************
 
-Copyright (C) 2004-2008  Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
 Copyright (C) 2005-2006  Johan Hedberg <johan.hedberg@nokia.com>
 Copyright (C) 2005-2006  Claudio Takahasi <claudio.takahasi@indt.org.br>
 Copyright (C) 2006-2007  Luiz von Dentz <luiz.dentz@indt.org.br>
@@ -37,9 +37,11 @@
 			Possible errors: org.bluez.Error.InvalidArguments
 					 org.bluez.Error.NoSuchAdapter
 
-		array{object} ListAdapters()
+		array{object} ListAdapters() {deprecated}
 
-			Returns list of adapter object paths under /org/bluez
+			Returns list of adapter object paths under /org/bluez.
+			This method is deprecated, instead use the Adapters
+			Property to get the list of adapter object paths.
 
 			Possible errors: org.bluez.Error.InvalidArguments
 					 org.bluez.Error.Failed
diff --git a/doc/network-api.txt b/doc/network-api.txt
index 7271193..4dd3e58 100644
--- a/doc/network-api.txt
+++ b/doc/network-api.txt
@@ -1,7 +1,7 @@
 BlueZ D-Bus Network API description
 ***********************************
 
-Copyright (C) 2004-2008  Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
 
 
 Network hierarchy
@@ -14,8 +14,16 @@
 Methods		string Connect(string uuid)
 
 			Connect to the network device and return the network
-			device name. Examples of the device name are bnep0,
-			bnep1 etc.
+			interface name. Examples of the interface name are
+			bnep0, bnep1 etc.
+
+			uuid can be either one of "gn", "panu" or "nap" (case
+			insensitive) or a traditional string representation of
+			UUID or a hexadecimal number.
+
+			The connection will be closed and network device
+			released either upon calling Disconnect() or when
+			the client disappears from the message bus.
 
 			Possible errors: org.bluez.Error.AlreadyConnected
 					 org.bluez.Error.ConnectionAttemptFailed
@@ -43,7 +51,7 @@
 
 			Indicates if the device is connected.
 
-		string Device [readonly]
+		string Interface [readonly]
 
 			Indicates the network interface name when available.
 
@@ -52,35 +60,29 @@
 			Indicates the connection role when available.
 
 
-Network Hub/Peer/Router hierarchy
-=================
+Network server hierarchy
+========================
 
 Service		org.bluez
-Interface	org.bluez.network.{Hub, Peer, Router}
+Interface	org.bluez.NetworkServer
 Object path	/org/bluez/{hci0,hci1,...}
 
-Methods		dict GetProperties()
+Methods		void Register(string uuid, string bridge)
 
-			Returns all properties for the GN/PANU/NAP server. See the
-			properties section for available properties.
+			Register server for the provided UUID. Every new
+			connection to this server will be added the bridge
+			interface.
 
-		void SetProperty(string name, variant value)
+			Valid UUIDs are "gn", "panu" or "nap".
 
-			Changes the value of the specified property. Only
-			properties that are listed a read-write are changeable.
-			On success this will emit a PropertyChanged signal.
+			Initially no network server SDP is provided. Only
+			after this method a SDP record will be available
+			and the BNEP server will be ready for incoming
+			connections.
 
-			Possible Errors: org.bluez.Error.DoesNotExist
-					 org.bluez.Error.InvalidArguments
+		void Unregister(string uuid)
 
-Properties	string Name[readwrite]
+			Unregister the server for provided UUID.
 
-			The Bluetooth network server name.
-
-		boolean Enable[readwrite]
-
-			Indicates if the server is Enabled/Disabled.
-
-		string Uuid[readonly]
-
-			The Bluetooth network server UUID 128 identification.
+			All servers will be automatically unregistered when
+			the calling application terminates.
diff --git a/doc/node-api.txt b/doc/node-api.txt
index 7a33dab..3ae4dee 100644
--- a/doc/node-api.txt
+++ b/doc/node-api.txt
@@ -1,7 +1,7 @@
 BlueZ D-Bus Node API description
 ********************************
 
-Copyright (C) 2004-2008  Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
 
 
 Node hierarchy
diff --git a/doc/serial-api.txt b/doc/serial-api.txt
index b4c806a..5f9bd5f 100644
--- a/doc/serial-api.txt
+++ b/doc/serial-api.txt
@@ -1,7 +1,7 @@
 BlueZ D-Bus Serial API description
 **********************************
 
-Copyright (C) 2004-2008  Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
 
 
 Serial hierarchy
diff --git a/doc/service-api.txt b/doc/service-api.txt
index c9489fb..5c8c7f3 100644
--- a/doc/service-api.txt
+++ b/doc/service-api.txt
@@ -1,7 +1,7 @@
 BlueZ D-Bus Adapter API description
 ***********************************
 
-Copyright (C) 2004-2008  Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
 Copyright (C) 2005-2006  Johan Hedberg <johan.hedberg@nokia.com>
 Copyright (C) 2005-2006  Claudio Takahasi <claudio.takahasi@indt.org.br>
 Copyright (C) 2006-2007  Luiz von Dentz <luiz.dentz@indt.org.br>
diff --git a/gdbus/Makefile.am b/gdbus/Makefile.am
deleted file mode 100644
index 9447555..0000000
--- a/gdbus/Makefile.am
+++ /dev/null
@@ -1,8 +0,0 @@
-
-noinst_LTLIBRARIES = libgdbus.la
-
-libgdbus_la_SOURCES = gdbus.h mainloop.c object.c watch.c
-
-AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
index fa618a5..47e18cf 100644
--- a/gdbus/gdbus.h
+++ b/gdbus/gdbus.h
@@ -2,7 +2,7 @@
  *
  *  D-Bus helper library
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -40,10 +40,11 @@
 DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name,
 							DBusError *error);
 
-gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
+DBusConnection *g_dbus_setup_private(DBusBusType type, const char *name,
 							DBusError *error);
 
-gboolean g_dbus_check_service(DBusConnection *connection, const char *name);
+gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
+							DBusError *error);
 
 gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
 				GDBusWatchFunction function,
@@ -90,9 +91,9 @@
 
 gboolean g_dbus_register_interface(DBusConnection *connection,
 					const char *path, const char *name,
-					GDBusMethodTable *methods,
-					GDBusSignalTable *signals,
-					GDBusPropertyTable *properties,
+					const GDBusMethodTable *methods,
+					const GDBusSignalTable *signals,
+					const GDBusPropertyTable *properties,
 					void *user_data,
 					GDBusDestroyFunction destroy);
 gboolean g_dbus_unregister_interface(DBusConnection *connection,
@@ -127,8 +128,10 @@
 				GDBusWatchFunction function,
 				void *user_data, GDBusDestroyFunction destroy);
 guint g_dbus_add_signal_watch(DBusConnection *connection,
-				const char *rule, GDBusSignalFunction function,
-				void *user_data, GDBusDestroyFunction destroy);
+				const char *sender, const char *path,
+				const char *interface, const char *member,
+				GDBusSignalFunction function, void *user_data,
+				GDBusDestroyFunction destroy);
 gboolean g_dbus_remove_watch(DBusConnection *connection, guint tag);
 void g_dbus_remove_all_watches(DBusConnection *connection);
 
diff --git a/gdbus/mainloop.c b/gdbus/mainloop.c
index eaba42e..ec10ab0 100644
--- a/gdbus/mainloop.c
+++ b/gdbus/mainloop.c
@@ -2,7 +2,7 @@
  *
  *  D-Bus helper library
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -25,8 +25,6 @@
 #include <config.h>
 #endif
 
-#include <stdint.h>
-
 #include <glib.h>
 #include <dbus/dbus.h>
 
@@ -42,116 +40,131 @@
 #define error(fmt...)
 #define debug(fmt...)
 
-typedef struct {
-	uint32_t id;
+struct timeout_handler {
+	guint id;
 	DBusTimeout *timeout;
-} timeout_handler_t;
+};
 
 struct watch_info {
-	guint watch_id;
-	GIOChannel *io;
+	guint id;
+	DBusWatch *watch;
 	DBusConnection *conn;
 };
 
-struct server_info {
-	guint watch_id;
-	GIOChannel *io;
-	DBusServer *server;
-};
-
 struct disconnect_data {
-	GDBusWatchFunction disconnect_cb;
+	GDBusWatchFunction function;
 	void *user_data;
 };
 
-static DBusHandlerResult disconnect_filter(DBusConnection *conn,
+static gboolean disconnected_signal(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
 	struct disconnect_data *dc_data = data;
 
-	if (dbus_message_is_signal(msg,
-			DBUS_INTERFACE_LOCAL, "Disconnected") == TRUE) {
-		error("Got disconnected from the system message bus");
-		dc_data->disconnect_cb(conn, dc_data->user_data);
-		dbus_connection_unref(conn);
-	}
+	error("Got disconnected from the system message bus");
 
-	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+	dc_data->function(conn, dc_data->user_data);
+
+	dbus_connection_unref(conn);
+
+	return TRUE;
 }
 
-static gboolean message_dispatch_cb(void *data)
+static gboolean message_dispatch(void *data)
 {
-	DBusConnection *connection = data;
+	DBusConnection *conn = data;
 
-	dbus_connection_ref(connection);
+	dbus_connection_ref(conn);
 
 	/* Dispatch messages */
-	while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS);
+	while (dbus_connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS);
 
-	dbus_connection_unref(connection);
+	dbus_connection_unref(conn);
 
 	return FALSE;
 }
 
+static inline void queue_dispatch(DBusConnection *conn,
+						DBusDispatchStatus status)
+{
+	if (status == DBUS_DISPATCH_DATA_REMAINS)
+		g_timeout_add(DISPATCH_TIMEOUT, message_dispatch, conn);
+}
+
 static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data)
 {
-	DBusWatch *watch = data;
-	struct watch_info *info = dbus_watch_get_data(watch);
-	int flags = 0;
+	struct watch_info *info = data;
+	unsigned int flags = 0;
+
+	dbus_connection_ref(info->conn);
 
 	if (cond & G_IO_IN)  flags |= DBUS_WATCH_READABLE;
 	if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE;
 	if (cond & G_IO_HUP) flags |= DBUS_WATCH_HANGUP;
 	if (cond & G_IO_ERR) flags |= DBUS_WATCH_ERROR;
 
-	dbus_watch_handle(watch, flags);
+	dbus_watch_handle(info->watch, flags);
 
-	if (dbus_connection_get_dispatch_status(info->conn) == DBUS_DISPATCH_DATA_REMAINS)
-		g_timeout_add(DISPATCH_TIMEOUT, message_dispatch_cb, info->conn);
+	dbus_connection_unref(info->conn);
 
 	return TRUE;
 }
 
+static void watch_info_free(void *data)
+{
+	struct watch_info *info = data;
+
+	if (info->id > 0) {
+		g_source_remove(info->id);
+		info->id = 0;
+	}
+
+	dbus_connection_unref(info->conn);
+
+	g_free(info);
+}
+
 static dbus_bool_t add_watch(DBusWatch *watch, void *data)
 {
-	GIOCondition cond = G_IO_HUP | G_IO_ERR;
 	DBusConnection *conn = data;
+	GIOCondition cond = G_IO_HUP | G_IO_ERR;
+	GIOChannel *chan;
 	struct watch_info *info;
-	int fd, flags;
+	unsigned int flags;
+	int fd;
 
 	if (!dbus_watch_get_enabled(watch))
 		return TRUE;
 
-	info = g_new(struct watch_info, 1);
+	info = g_new0(struct watch_info, 1);
 
 	fd = dbus_watch_get_unix_fd(watch);
-	info->io = g_io_channel_unix_new(fd);
+	chan = g_io_channel_unix_new(fd);
+
+	info->watch = watch;
 	info->conn = dbus_connection_ref(conn);
 
-	dbus_watch_set_data(watch, info, NULL);
+	dbus_watch_set_data(watch, info, watch_info_free);
 
 	flags = dbus_watch_get_flags(watch);
 
 	if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN;
 	if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT;
 
-	info->watch_id = g_io_add_watch(info->io, cond, watch_func, watch);
+	info->id = g_io_add_watch(chan, cond, watch_func, info);
+
+	g_io_channel_unref(chan);
 
 	return TRUE;
 }
 
 static void remove_watch(DBusWatch *watch, void *data)
 {
-	struct watch_info *info = dbus_watch_get_data(watch);
+	if (dbus_watch_get_enabled(watch))
+		return;
 
+	/* will trigger watch_info_free() */
 	dbus_watch_set_data(watch, NULL, NULL);
-
-	if (info) {
-		g_source_remove(info->watch_id);
-		g_io_channel_unref(info->io);
-		dbus_connection_unref(info->conn);
-		g_free(info);
-	}
 }
 
 static void watch_toggled(DBusWatch *watch, void *data)
@@ -166,10 +179,12 @@
 
 static gboolean timeout_handler_dispatch(gpointer data)
 {
-	timeout_handler_t *handler = data;
+	struct timeout_handler *handler = data;
+
+	handler->id = 0;
 
 	/* if not enabled should not be polled by the main loop */
-	if (dbus_timeout_get_enabled(handler->timeout) != TRUE)
+	if (!dbus_timeout_get_enabled(handler->timeout))
 		return FALSE;
 
 	dbus_timeout_handle(handler->timeout);
@@ -179,34 +194,43 @@
 
 static void timeout_handler_free(void *data)
 {
-	timeout_handler_t *handler = data;
-	if (!handler)
-		return;
+	struct timeout_handler *handler = data;
 
-	g_source_remove(handler->id);
+	if (handler->id > 0) {
+		g_source_remove(handler->id);
+		handler->id = 0;
+	}
+
 	g_free(handler);
 }
 
 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
 {
-	timeout_handler_t *handler;
+	int interval = dbus_timeout_get_interval(timeout);
+	struct timeout_handler *handler;
 
 	if (!dbus_timeout_get_enabled(timeout))
 		return TRUE;
 
-	handler = g_new0(timeout_handler_t, 1);
+	handler = g_new0(struct timeout_handler, 1);
 
 	handler->timeout = timeout;
-	handler->id = g_timeout_add(dbus_timeout_get_interval(timeout),
-					timeout_handler_dispatch, handler);
 
 	dbus_timeout_set_data(timeout, handler, timeout_handler_free);
 
+	handler->id = g_timeout_add(interval, timeout_handler_dispatch,
+								handler);
+
 	return TRUE;
 }
 
 static void remove_timeout(DBusTimeout *timeout, void *data)
 {
+	if (dbus_timeout_get_enabled(timeout))
+		return;
+
+	/* will trigger timeout_handler_free() */
+	dbus_timeout_set_data(timeout, NULL, NULL);
 }
 
 static void timeout_toggled(DBusTimeout *timeout, void *data)
@@ -217,26 +241,51 @@
 		remove_timeout(timeout, data);
 }
 
-static void dispatch_status_cb(DBusConnection *conn,
-				DBusDispatchStatus new_status, void *data)
+static void dispatch_status(DBusConnection *conn,
+					DBusDispatchStatus status, void *data)
 {
 	if (!dbus_connection_get_is_connected(conn))
 		return;
 
-	if (new_status == DBUS_DISPATCH_DATA_REMAINS)
-		g_timeout_add(DISPATCH_TIMEOUT, message_dispatch_cb, data);
+	queue_dispatch(conn, status);
 }
 
-static void setup_dbus_with_main_loop(DBusConnection *conn)
+static inline void setup_dbus_with_main_loop(DBusConnection *conn)
 {
 	dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
 						watch_toggled, conn, NULL);
 
 	dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout,
-						timeout_toggled, conn, NULL);
+						timeout_toggled, NULL, NULL);
 
-	dbus_connection_set_dispatch_status_function(conn, dispatch_status_cb,
-								conn, NULL);
+	dbus_connection_set_dispatch_status_function(conn, dispatch_status,
+								NULL, NULL);
+}
+
+static gboolean setup_bus(DBusConnection *conn, const char *name,
+						DBusError *error)
+{
+	gboolean result;
+	DBusDispatchStatus status;
+
+	if (name != NULL) {
+		result = g_dbus_request_name(conn, name, error);
+
+		if (error != NULL) {
+			if (dbus_error_is_set(error) == TRUE)
+				return FALSE;
+		}
+
+		if (result == FALSE)
+			return FALSE;
+	}
+
+	setup_dbus_with_main_loop(conn);
+
+	status = dbus_connection_get_dispatch_status(conn);
+	queue_dispatch(conn, status);
+
+	return TRUE;
 }
 
 DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name,
@@ -254,23 +303,33 @@
 	if (conn == NULL)
 		return NULL;
 
-	if (name != NULL) {
-		if (dbus_bus_request_name(conn, name,
-				DBUS_NAME_FLAG_DO_NOT_QUEUE, error) !=
-				DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER ) {
-			dbus_connection_unref(conn);
-			return NULL;
-		}
-
-		if (error != NULL) {
-			if (dbus_error_is_set(error) == TRUE) {
-				dbus_connection_unref(conn);
-				return NULL;
-			}
-		}
+	if (setup_bus(conn, name, error) == FALSE) {
+		dbus_connection_unref(conn);
+		return NULL;
 	}
 
-	setup_dbus_with_main_loop(conn);
+	return conn;
+}
+
+DBusConnection *g_dbus_setup_private(DBusBusType type, const char *name,
+							DBusError *error)
+{
+	DBusConnection *conn;
+
+	conn = dbus_bus_get_private(type, error);
+
+	if (error != NULL) {
+		if (dbus_error_is_set(error) == TRUE)
+			return NULL;
+	}
+
+	if (conn == NULL)
+		return NULL;
+
+	if (setup_bus(conn, name, error) == FALSE) {
+		dbus_connection_unref(conn);
+		return NULL;
+	}
 
 	return conn;
 }
@@ -278,68 +337,43 @@
 gboolean g_dbus_request_name(DBusConnection *connection, const char *name,
 							DBusError *error)
 {
+	int result;
+
+	result = dbus_bus_request_name(connection, name,
+					DBUS_NAME_FLAG_DO_NOT_QUEUE, error);
+
+	if (error != NULL) {
+		if (dbus_error_is_set(error) == TRUE)
+			return FALSE;
+	}
+
+	if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+		if (error != NULL)
+			dbus_set_error(error, name, "Name already in use");
+
+		return FALSE;
+	}
+
 	return TRUE;
 }
 
-gboolean g_dbus_check_service(DBusConnection *connection, const char *name)
-{
-	DBusMessage *message, *reply;
-	const char **names;
-	int i, count;
-	gboolean result = FALSE;
-
-	message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
-			DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "ListNames");
-	if (message == NULL) {
-		error("Can't allocate new message");
-		return FALSE;
-	}
-
-	reply = dbus_connection_send_with_reply_and_block(connection,
-							message, -1, NULL);
-
-	dbus_message_unref(message);
-
-	if (reply == NULL) {
-		error("Failed to execute method call");
-		return FALSE;
-	}
-
-	if (dbus_message_get_args(reply, NULL,
-				DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
-				&names, &count, DBUS_TYPE_INVALID) == FALSE) {
-		error("Failed to read name list");
-		goto done;
-	}
-
-	for (i = 0; i < count; i++)
-		if (g_str_equal(names[i], name) == TRUE) {
-			result = TRUE;
-			break;
-		}
-
-done:
-	dbus_message_unref(reply);
-
-	return result;
-}
-
 gboolean g_dbus_set_disconnect_function(DBusConnection *connection,
 				GDBusWatchFunction function,
 				void *user_data, DBusFreeFunction destroy)
 {
 	struct disconnect_data *dc_data;
 
-	dc_data = g_new(struct disconnect_data, 1);
+	dc_data = g_new0(struct disconnect_data, 1);
 
-	dc_data->disconnect_cb = function;
+	dc_data->function = function;
 	dc_data->user_data = user_data;
 
 	dbus_connection_set_exit_on_disconnect(connection, FALSE);
 
-	if (dbus_connection_add_filter(connection, disconnect_filter,
-						dc_data, g_free) == FALSE) {
-		error("Can't add D-Bus disconnect filter");
+	if (g_dbus_add_signal_watch(connection, NULL, NULL,
+				DBUS_INTERFACE_LOCAL, "Disconnected",
+				disconnected_signal, dc_data, g_free) == 0) {
+		error("Failed to add watch for D-Bus Disconnected signal");
 		g_free(dc_data);
 		return FALSE;
 	}
diff --git a/gdbus/object.c b/gdbus/object.c
index 3186921..ff69641 100644
--- a/gdbus/object.c
+++ b/gdbus/object.c
@@ -2,7 +2,7 @@
  *
  *  D-Bus helper library
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -45,9 +45,9 @@
 
 struct interface_data {
 	char *name;
-	GDBusMethodTable *methods;
-	GDBusSignalTable *signals;
-	GDBusPropertyTable *properties;
+	const GDBusMethodTable *methods;
+	const GDBusSignalTable *signals;
+	const GDBusPropertyTable *properties;
 	void *user_data;
 	GDBusDestroyFunction destroy;
 };
@@ -114,8 +114,8 @@
 
 static void generate_interface_xml(GString *gstr, struct interface_data *iface)
 {
-	GDBusMethodTable *method;
-	GDBusSignalTable *signal;
+	const GDBusMethodTable *method;
+	const GDBusSignalTable *signal;
 
 	for (method = iface->methods; method && method->name; method++) {
 		if (!strlen(method->signature) && !strlen(method->reply))
@@ -183,14 +183,15 @@
 	data->introspect = g_string_free(gstr, FALSE);
 }
 
-static DBusHandlerResult introspect(DBusConnection *connection,
-				DBusMessage *message, struct generic_data *data)
+static DBusMessage *introspect(DBusConnection *connection,
+				DBusMessage *message, void *user_data)
 {
+	struct generic_data *data = user_data;
 	DBusMessage *reply;
 
 	if (!dbus_message_has_signature(message, DBUS_TYPE_INVALID_AS_STRING)) {
 		error("Unexpected signature to introspect call");
-		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+		return NULL;
 	}
 
 	if (!data->introspect)
@@ -199,16 +200,12 @@
 
 	reply = dbus_message_new_method_return(message);
 	if (!reply)
-		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+		return NULL;
 
 	dbus_message_append_args(reply, DBUS_TYPE_STRING, &data->introspect,
 					DBUS_TYPE_INVALID);
 
-	dbus_connection_send(connection, reply, NULL);
-
-	dbus_message_unref(reply);
-
-	return DBUS_HANDLER_RESULT_HANDLED;
+	return reply;
 }
 
 static void generic_unregister(DBusConnection *connection, void *user_data)
@@ -241,14 +238,9 @@
 {
 	struct generic_data *data = user_data;
 	struct interface_data *iface;
-	GDBusMethodTable *method;
+	const GDBusMethodTable *method;
 	const char *interface;
 
-	if (dbus_message_is_method_call(message,
-					DBUS_INTERFACE_INTROSPECTABLE,
-								"Introspect"))
-		return introspect(connection, message, data);
-
 	interface = dbus_message_get_interface(message);
 
 	iface = find_interface(data->interfaces, interface);
@@ -316,8 +308,10 @@
 		goto done;
 
 	if (!dbus_connection_get_object_path_data(conn, parent_path,
-							(void *) &data))
+							(void *) &data)) {
+		invalidate_parent_data(conn, parent_path);
 		goto done;
+	}
 
 	if (!data)
 		goto done;
@@ -329,6 +323,31 @@
 	g_free(parent_path);
 }
 
+static GDBusMethodTable introspect_methods[] = {
+	{ "Introspect",	"",	"s", introspect	},
+	{ }
+};
+
+static void add_interface(struct generic_data *data, const char *name,
+				const GDBusMethodTable *methods,
+				const GDBusSignalTable *signals,
+				const GDBusPropertyTable *properties,
+				void *user_data,
+				GDBusDestroyFunction destroy)
+{
+	struct interface_data *iface;
+
+	iface = g_new0(struct interface_data, 1);
+	iface->name = g_strdup(name);
+	iface->methods = methods;
+	iface->signals = signals;
+	iface->properties = properties;
+	iface->user_data = user_data;
+	iface->destroy = destroy;
+
+	data->interfaces = g_slist_append(data->interfaces, iface);
+}
+
 static struct generic_data *object_path_ref(DBusConnection *connection,
 							const char *path)
 {
@@ -357,9 +376,31 @@
 
 	invalidate_parent_data(connection, path);
 
+	add_interface(data, DBUS_INTERFACE_INTROSPECTABLE,
+			introspect_methods, NULL, NULL, data, NULL);
+
 	return data;
 }
 
+static gboolean remove_interface(struct generic_data *data, const char *name)
+{
+	struct interface_data *iface;
+
+	iface = find_interface(data->interfaces, name);
+	if (!iface)
+		return FALSE;
+
+	data->interfaces = g_slist_remove(data->interfaces, iface);
+
+	if (iface->destroy)
+		iface->destroy(iface->user_data);
+
+	g_free(iface->name);
+	g_free(iface);
+
+	return TRUE;
+}
+
 static void object_path_unref(DBusConnection *connection, const char *path)
 {
 	struct generic_data *data = NULL;
@@ -376,6 +417,8 @@
 	if (data->refcount > 0)
 		return;
 
+	remove_interface(data, DBUS_INTERFACE_INTROSPECTABLE);
+
 	invalidate_parent_data(connection, path);
 
 	dbus_connection_unregister_object_path(connection, path);
@@ -387,7 +430,7 @@
 {
 	struct generic_data *data = NULL;
 	struct interface_data *iface;
-	GDBusSignalTable *signal;
+	const GDBusSignalTable *signal;
 
 	*args = NULL;
 	if (!dbus_connection_get_object_path_data(conn, path,
@@ -461,32 +504,25 @@
 
 gboolean g_dbus_register_interface(DBusConnection *connection,
 					const char *path, const char *name,
-					GDBusMethodTable *methods,
-					GDBusSignalTable *signals,
-					GDBusPropertyTable *properties,
+					const GDBusMethodTable *methods,
+					const GDBusSignalTable *signals,
+					const GDBusPropertyTable *properties,
 					void *user_data,
 					GDBusDestroyFunction destroy)
 {
 	struct generic_data *data;
-	struct interface_data *iface;
 
 	data = object_path_ref(connection, path);
 	if (data == NULL)
 		return FALSE;
 
-	if (find_interface(data->interfaces, name))
+	if (find_interface(data->interfaces, name)) {
+		object_path_unref(connection, path);
 		return FALSE;
+	}
 
-	iface = g_new0(struct interface_data, 1);
-
-	iface->name = g_strdup(name);
-	iface->methods = methods;
-	iface->signals = signals;
-	iface->properties = properties;
-	iface->user_data = user_data;
-	iface->destroy = destroy;
-
-	data->interfaces = g_slist_append(data->interfaces, iface);
+	add_interface(data, name, methods, signals,
+			properties, user_data, destroy);
 
 	g_free(data->introspect);
 	data->introspect = NULL;
@@ -498,7 +534,6 @@
 					const char *path, const char *name)
 {
 	struct generic_data *data = NULL;
-	struct interface_data *iface;
 
 	if (!path)
 		return FALSE;
@@ -510,18 +545,9 @@
 	if (data == NULL)
 		return FALSE;
 
-	iface = find_interface(data->interfaces, name);
-	if (!iface)
+	if (remove_interface(data, name) == FALSE)
 		return FALSE;
 
-	data->interfaces = g_slist_remove(data->interfaces, iface);
-
-	if (iface->destroy)
-		iface->destroy(iface->user_data);
-
-	g_free(iface->name);
-	g_free(iface);
-
 	g_free(data->introspect);
 	data->introspect = NULL;
 
diff --git a/gdbus/watch.c b/gdbus/watch.c
index c7a4e69..1d479fa 100644
--- a/gdbus/watch.c
+++ b/gdbus/watch.c
@@ -2,7 +2,7 @@
  *
  *  D-Bus helper library
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -37,52 +37,198 @@
 #define error(fmt...)
 #define debug(fmt...)
 
-static DBusHandlerResult name_exit_filter(DBusConnection *connection,
+static DBusHandlerResult message_filter(DBusConnection *connection,
 					DBusMessage *message, void *user_data);
 
 static guint listener_id = 0;
-static GSList *name_listeners = NULL;
+static GSList *listeners = NULL;
 
-struct name_callback {
+struct filter_callback {
 	GDBusWatchFunction conn_func;
 	GDBusWatchFunction disc_func;
+	GDBusSignalFunction signal_func;
+	GDBusDestroyFunction destroy_func;
 	void *user_data;
 	guint id;
 };
 
-struct name_data {
+struct filter_data {
 	DBusConnection *connection;
-	char *name;
+	DBusHandleMessageFunction handle_func;
+	char *sender;
+	char *path;
+	char *interface;
+	char *member;
+	char *argument;
 	GSList *callbacks;
 	GSList *processed;
 	gboolean lock;
+	gboolean registered;
 };
 
-static struct name_data *name_data_find(DBusConnection *connection,
-							const char *name)
+static struct filter_data *filter_data_find(DBusConnection *connection,
+							const char *sender,
+							const char *path,
+							const char *interface,
+							const char *member,
+							const char *argument)
 {
 	GSList *current;
 
-	for (current = name_listeners;
+	for (current = listeners;
 			current != NULL; current = current->next) {
-		struct name_data *data = current->data;
+		struct filter_data *data = current->data;
 
 		if (connection != data->connection)
 			continue;
 
-		if (name == NULL || g_str_equal(name, data->name))
-			return data;
+		if (sender && data->sender &&
+				g_str_equal(sender, data->sender) == FALSE)
+			continue;
+
+		if (path && data->path &&
+				g_str_equal(path, data->path) == FALSE)
+			continue;
+
+		if (interface && data->interface &&
+				g_str_equal(interface, data->interface) == FALSE)
+			continue;
+
+		if (member && data->member &&
+				g_str_equal(member, data->member) == FALSE)
+			continue;
+
+		if (argument && data->argument &&
+				g_str_equal(argument, data->argument) == FALSE)
+			continue;
+
+		return data;
 	}
 
 	return NULL;
 }
 
-static struct name_callback *name_callback_find(GSList *callbacks, guint id)
+static void format_rule(struct filter_data *data, char *rule, size_t size)
 {
-	GSList *current;
+	int offset;
 
-	for (current = callbacks; current != NULL; current = current->next) {
-		struct name_callback *cb = current->data;
+	offset = snprintf(rule, size, "type='signal'");
+
+	if (data->sender)
+		offset += snprintf(rule + offset, size - offset,
+				",sender='%s'", data->sender);
+	if (data->path)
+		offset += snprintf(rule + offset, size - offset,
+				",path='%s'", data->path);
+	if (data->interface)
+		offset += snprintf(rule + offset, size - offset,
+				",interface='%s'", data->interface);
+	if (data->member)
+		offset += snprintf(rule + offset, size - offset,
+				",member='%s'", data->member);
+	if (data->argument)
+		snprintf(rule + offset, size - offset,
+				",arg0='%s'", data->argument);
+}
+
+static gboolean add_match(struct filter_data *data,
+				DBusHandleMessageFunction filter)
+{
+	DBusError err;
+	char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
+
+	format_rule(data, rule, sizeof(rule));
+	dbus_error_init(&err);
+
+	dbus_bus_add_match(data->connection, rule, &err);
+	if (dbus_error_is_set(&err)) {
+		error("Adding match rule \"%s\" failed: %s", rule,
+				err.message);
+		dbus_error_free(&err);
+		return FALSE;
+	}
+
+	data->handle_func = filter;
+	data->registered = TRUE;
+
+	return TRUE;
+}
+
+static gboolean remove_match(struct filter_data *data)
+{
+	DBusError err;
+	char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
+
+	format_rule(data, rule, sizeof(rule));
+
+	dbus_error_init(&err);
+
+	dbus_bus_remove_match(data->connection, rule, &err);
+	if (dbus_error_is_set(&err)) {
+		error("Removing owner match rule for %s failed: %s",
+				rule, err.message);
+		dbus_error_free(&err);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static struct filter_data *filter_data_get(DBusConnection *connection,
+					DBusHandleMessageFunction filter,
+					const char *sender,
+					const char *path,
+					const char *interface,
+					const char *member,
+					const char *argument)
+{
+	struct filter_data *data;
+
+	if (!filter_data_find(connection, NULL, NULL, NULL, NULL, NULL)) {
+		if (!dbus_connection_add_filter(connection,
+					message_filter, NULL, NULL)) {
+			error("dbus_connection_add_filter() failed");
+			return NULL;
+		}
+	}
+
+	data = filter_data_find(connection, sender, path, interface, member,
+					argument);
+	if (data)
+		return data;
+
+	data = g_new0(struct filter_data, 1);
+
+	data->connection = dbus_connection_ref(connection);
+	data->sender = g_strdup(sender);
+	data->path = g_strdup(path);
+	data->interface = g_strdup(interface);
+	data->member = g_strdup(member);
+	data->argument = g_strdup(argument);
+
+	if (!add_match(data, filter)) {
+		g_free(data);
+		return NULL;
+	}
+
+	listeners = g_slist_append(listeners, data);
+
+	return data;
+}
+
+static struct filter_callback *filter_data_find_callback(
+						struct filter_data *data,
+						guint id)
+{
+	GSList *l;
+
+	for (l = data->callbacks; l; l = l->next) {
+		struct filter_callback *cb = l->data;
+		if (cb->id == id)
+			return cb;
+	}
+	for (l = data->processed; l; l = l->next) {
+		struct filter_callback *cb = l->data;
 		if (cb->id == id)
 			return cb;
 	}
@@ -90,23 +236,7 @@
 	return NULL;
 }
 
-static void name_data_call_and_free(struct name_data *data)
-{
-	GSList *l;
-
-	for (l = data->callbacks; l != NULL; l = l->next) {
-		struct name_callback *cb = l->data;
-		if (cb->disc_func)
-			cb->disc_func(data->connection, cb->user_data);
-		g_free(cb);
-	}
-
-	g_slist_free(data->callbacks);
-	g_free(data->name);
-	g_free(data);
-}
-
-static void name_data_free(struct name_data *data)
+static void filter_data_free(struct filter_data *data)
 {
 	GSList *l;
 
@@ -114,134 +244,127 @@
 		g_free(l->data);
 
 	g_slist_free(data->callbacks);
-	g_free(data->name);
+	g_free(data->sender);
+	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 int name_data_add(DBusConnection *connection, const char *name,
+static void filter_data_call_and_free(struct filter_data *data)
+{
+	GSList *l;
+
+	for (l = data->callbacks; l != NULL; l = l->next) {
+		struct filter_callback *cb = l->data;
+		if (cb->disc_func)
+			cb->disc_func(data->connection, cb->user_data);
+		if (cb->destroy_func)
+			cb->destroy_func(cb->user_data);
+		g_free(cb);
+	}
+
+	filter_data_free(data);
+}
+
+static struct filter_callback *filter_data_add_callback(
+						struct filter_data *data,
 						GDBusWatchFunction connect,
 						GDBusWatchFunction disconnect,
-						void *user_data, guint id)
+						GDBusSignalFunction signal,
+						GDBusDestroyFunction destroy,
+						void *user_data)
 {
-	int first = 1;
-	struct name_data *data = NULL;
-	struct name_callback *cb = NULL;
+	struct filter_callback *cb = NULL;
 
-	cb = g_new(struct name_callback, 1);
+	cb = g_new(struct filter_callback, 1);
 
 	cb->conn_func = connect;
 	cb->disc_func = disconnect;
+	cb->signal_func = signal;
+	cb->destroy_func = destroy;
 	cb->user_data = user_data;
-	cb->id = id;
+	cb->id = ++listener_id;
 
-	data = name_data_find(connection, name);
-	if (data) {
-		first = 0;
-		goto done;
-	}
-
-	data = g_new0(struct name_data, 1);
-
-	data->connection = connection;
-	data->name = g_strdup(name);
-
-	name_listeners = g_slist_append(name_listeners, data);
-
-done:
 	if (data->lock)
 		data->processed = g_slist_append(data->processed, cb);
 	else
 		data->callbacks = g_slist_append(data->callbacks, cb);
 
-	return first;
+	return cb;
 }
 
-static void name_data_remove(DBusConnection *connection,
-					const char *name, guint id)
+static gboolean filter_data_remove_callback(struct filter_data *data,
+						struct filter_callback *cb)
 {
-	struct name_data *data;
-	struct name_callback *cb = NULL;
+	DBusConnection *connection;
 
-	data = name_data_find(connection, name);
-	if (!data)
-		return;
+	data->callbacks = g_slist_remove(data->callbacks, cb);
+	data->processed = g_slist_remove(data->processed, cb);
 
-	cb = name_callback_find(data->callbacks, id);
-	if (cb) {
-		data->callbacks = g_slist_remove(data->callbacks, cb);
-		g_free(cb);
-	}
+	if (cb->destroy_func)
+		cb->destroy_func(cb->user_data);
 
-	if (data->callbacks)
-		return;
+	g_free(cb);
 
-	name_listeners = g_slist_remove(name_listeners, data);
-	name_data_free(data);
+	/* Don't remove the filter if other callbacks exist or data is lock
+	 * processing callbacks */
+	if (data->callbacks || data->lock)
+		return TRUE;
+
+	if (data->registered && !remove_match(data))
+		return FALSE;
+
+	connection = dbus_connection_ref(data->connection);
+	listeners = g_slist_remove(listeners, data);
+	filter_data_free(data);
 
 	/* Remove filter if there are no listeners left for the connection */
-	data = name_data_find(connection, NULL);
+	data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL);
 	if (!data)
-		dbus_connection_remove_filter(connection,
-						name_exit_filter,
+		dbus_connection_remove_filter(connection, message_filter,
 						NULL);
-}
 
-static gboolean add_match(DBusConnection *connection, const char *name)
-{
-	DBusError err;
-	char match_string[128];
-
-	snprintf(match_string, sizeof(match_string),
-			"interface=%s,member=NameOwnerChanged,arg0=%s",
-			DBUS_INTERFACE_DBUS, name);
-
-	dbus_error_init(&err);
-
-	dbus_bus_add_match(connection, match_string, &err);
-
-	if (dbus_error_is_set(&err)) {
-		error("Adding match rule \"%s\" failed: %s", match_string,
-				err.message);
-		dbus_error_free(&err);
-		return FALSE;
-	}
+	dbus_connection_unref(connection);
 
 	return TRUE;
 }
 
-static gboolean remove_match(DBusConnection *connection, const char *name)
-{
-	DBusError err;
-	char match_string[128];
-
-	snprintf(match_string, sizeof(match_string),
-			"interface=%s,member=NameOwnerChanged,arg0=%s",
-			DBUS_INTERFACE_DBUS, name);
-
-	dbus_error_init(&err);
-
-	dbus_bus_remove_match(connection, match_string, &err);
-
-	if (dbus_error_is_set(&err)) {
-		error("Removing owner match rule for %s failed: %s",
-				name, err.message);
-		dbus_error_free(&err);
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static DBusHandlerResult name_exit_filter(DBusConnection *connection,
+static DBusHandlerResult signal_filter(DBusConnection *connection,
 					DBusMessage *message, void *user_data)
 {
-	struct name_data *data;
-	struct name_callback *cb;
-	char *name, *old, *new;
+	struct filter_data *data = user_data;
+	struct filter_callback *cb;
 
-	if (!dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
-							"NameOwnerChanged"))
-		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+	while (data->callbacks) {
+		cb = data->callbacks->data;
+
+		if (cb->signal_func && !cb->signal_func(connection, message,
+							cb->user_data)) {
+			filter_data_remove_callback(data, cb);
+			continue;
+		}
+
+		/* Check if the watch was removed/freed by the callback
+		 * function */
+		if (!g_slist_find(data->callbacks, cb))
+			continue;
+
+		data->callbacks = g_slist_remove(data->callbacks, cb);
+		data->processed = g_slist_append(data->processed, cb);
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult service_filter(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct filter_data *data = user_data;
+	struct filter_callback *cb;
+	char *name, *old, *new;
 
 	if (!dbus_message_get_args(message, NULL,
 				DBUS_TYPE_STRING, &name,
@@ -252,14 +375,6 @@
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 	}
 
-	data = name_data_find(connection, name);
-	if (!data) {
-		error("Got NameOwnerChanged signal for %s which has no listeners", name);
-		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-	}
-
-	data->lock = TRUE;
-
 	while (data->callbacks) {
 		cb = data->callbacks->data;
 
@@ -286,60 +401,172 @@
 		data->processed = g_slist_append(data->processed, cb);
 	}
 
-	data->callbacks = data->processed;
-	data->processed = NULL;
-	data->lock = FALSE;
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
+static DBusHandlerResult message_filter(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct filter_data *data;
+	const char *sender, *path, *iface, *member, *arg = NULL;
+
+	/* Only filter signals */
+	if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+	sender = dbus_message_get_sender(message);
+	path = dbus_message_get_path(message);
+	iface = dbus_message_get_interface(message);
+	member = dbus_message_get_member(message);
+	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
+
+	data = filter_data_find(connection, sender, path, iface, member, arg);
+	if (!data) {
+		error("Got %s.%s signal which has no listeners", iface, member);
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+	}
+
+	if (data->handle_func) {
+		data->lock = TRUE;
+
+		data->handle_func(connection, message, data);
+
+		data->callbacks = data->processed;
+		data->processed = NULL;
+		data->lock = FALSE;
+	}
 
 	if (data->callbacks)
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
-	name_listeners = g_slist_remove(name_listeners, data);
-	name_data_free(data);
+	remove_match(data);
+
+	listeners = g_slist_remove(listeners, data);
+	filter_data_free(data);
 
 	/* Remove filter if there no listener left for the connection */
-	data = name_data_find(connection, NULL);
+	data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL);
 	if (!data)
-		dbus_connection_remove_filter(connection, name_exit_filter,
+		dbus_connection_remove_filter(connection, message_filter,
 						NULL);
 
-	remove_match(connection, name);
-
 	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
+struct service_data {
+	DBusConnection *conn;
+	GDBusWatchFunction conn_func;
+	void *user_data;
+};
+
+static void service_reply(DBusPendingCall *call, void *user_data)
+{
+	struct service_data *data = user_data;
+	DBusMessage *reply;
+	DBusError error;
+	dbus_bool_t has_owner;
+
+	reply = dbus_pending_call_steal_reply(call);
+	if (reply == NULL)
+		return;
+
+	dbus_error_init(&error);
+
+	if (dbus_message_get_args(reply, &error,
+					DBUS_TYPE_BOOLEAN, &has_owner,
+						DBUS_TYPE_INVALID) == FALSE) {
+		if (dbus_error_is_set(&error) == TRUE) {
+			error("%s", error.message);
+			dbus_error_free(&error);
+		} else {
+			error("Wrong arguments for NameHasOwner reply");
+		}
+		goto done;
+	}
+
+	if (has_owner && data->conn_func)
+		data->conn_func(data->conn, data->user_data);
+
+done:
+	dbus_message_unref(reply);
+}
+
+static void check_service(DBusConnection *connection, const char *name,
+				GDBusWatchFunction connect, void *user_data)
+{
+	DBusMessage *message;
+	DBusPendingCall *call;
+	struct service_data *data;
+
+	data = g_try_malloc0(sizeof(*data));
+	if (data == NULL) {
+		error("Can't allocate data structure");
+		return;
+	}
+
+	data->conn = connection;
+	data->conn_func = connect;
+	data->user_data = user_data;
+
+	message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
+			DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameHasOwner");
+	if (message == NULL) {
+		error("Can't allocate new message");
+		g_free(data);
+		return;
+	}
+
+	dbus_message_append_args(message, DBUS_TYPE_STRING, &name,
+							DBUS_TYPE_INVALID);
+
+	if (dbus_connection_send_with_reply(connection, message,
+							&call, -1) == FALSE) {
+		error("Failed to execute method call");
+		g_free(data);
+		goto done;
+	}
+
+	if (call == NULL) {
+		error("D-Bus connection not available");
+		g_free(data);
+		goto done;
+	}
+
+	dbus_pending_call_set_notify(call, service_reply, data, NULL);
+
+	dbus_pending_call_unref(call);
+
+done:
+	dbus_message_unref(message);
+}
+
 guint g_dbus_add_service_watch(DBusConnection *connection, const char *name,
 				GDBusWatchFunction connect,
 				GDBusWatchFunction disconnect,
 				void *user_data, GDBusDestroyFunction destroy)
 {
-	int first;
+	struct filter_data *data;
+	struct filter_callback *cb;
 
-	if (!name_data_find(connection, NULL)) {
-		if (!dbus_connection_add_filter(connection,
-					name_exit_filter, NULL, NULL)) {
-			error("dbus_connection_add_filter() failed");
-			return 0;
-		}
-	}
+	if (!name)
+		return 0;
 
-	listener_id++;
-	first = name_data_add(connection, name, connect, disconnect,
-						user_data, listener_id);
-	/* The filter is already added if this is not the first callback
-	 * registration for the name */
-	if (!first)
-		return listener_id;
+	data = filter_data_get(connection, service_filter, NULL, NULL,
+				DBUS_INTERFACE_DBUS, "NameOwnerChanged",
+				name);
+	if (!data)
+		return 0;
 
-	if (name) {
-		debug("name_listener_add(%s)", name);
+	cb = filter_data_add_callback(data, connect, disconnect, NULL, NULL,
+					user_data);
+	if (!cb)
+		return 0;
 
-		if (!add_match(connection, name)) {
-			name_data_remove(connection, name, listener_id);
-			return 0;
-		}
-	}
+	if (connect)
+		check_service(connection, name, connect, user_data);
 
-	return listener_id;
+	return cb->id;
 }
 
 guint g_dbus_add_disconnect_watch(DBusConnection *connection, const char *name,
@@ -351,72 +578,57 @@
 }
 
 guint g_dbus_add_signal_watch(DBusConnection *connection,
-				const char *rule, GDBusSignalFunction function,
-				void *user_data, GDBusDestroyFunction destroy)
+				const char *sender, const char *path,
+				const char *interface, const char *member,
+				GDBusSignalFunction function, void *user_data,
+				GDBusDestroyFunction destroy)
 {
-	return 0;
+	struct filter_data *data;
+	struct filter_callback *cb;
+
+	data = filter_data_get(connection, signal_filter, sender, path,
+				interface, member, NULL);
+	if (!data)
+		return 0;
+
+	cb = filter_data_add_callback(data, NULL, NULL, function, destroy,
+					user_data);
+	if (!cb)
+		return 0;
+
+	return cb->id;
 }
 
 gboolean g_dbus_remove_watch(DBusConnection *connection, guint id)
 {
-	struct name_data *data;
-	struct name_callback *cb;
-	GSList *ldata, *lcb;
+	struct filter_data *data;
+	struct filter_callback *cb;
+	GSList *ldata;
 
 	if (id == 0)
 		return FALSE;
 
-	for (ldata = name_listeners; ldata; ldata = ldata->next) {
+	for (ldata = listeners; ldata; ldata = ldata->next) {
 		data = ldata->data;
-		for (lcb = data->callbacks; lcb; lcb = lcb->next) {
-			cb = lcb->data;
-			if (cb->id == id)
-				goto remove;
-		}
-		for (lcb = data->processed; lcb; lcb = lcb->next) {
-			cb = lcb->data;
-			if (cb->id == id)
-				goto remove;
+
+		cb = filter_data_find_callback(data, id);
+		if (cb) {
+			filter_data_remove_callback(data, cb);
+			return TRUE;
 		}
 	}
 
 	return FALSE;
-
-remove:
-	data->callbacks = g_slist_remove(data->callbacks, cb);
-	data->processed = g_slist_remove(data->processed, cb);
-	g_free(cb);
-
-	/* Don't remove the filter if other callbacks exist or data is lock
-	 * processing callbacks */
-	if (data->callbacks || data->lock)
-		return TRUE;
-
-	if (data->name) {
-		if (!remove_match(data->connection, data->name))
-			return FALSE;
-	}
-
-	name_listeners = g_slist_remove(name_listeners, data);
-	name_data_free(data);
-
-	/* Remove filter if there are no listeners left for the connection */
-	data = name_data_find(connection, NULL);
-	if (!data)
-		dbus_connection_remove_filter(connection, name_exit_filter,
-						NULL);
-
-	return TRUE;
 }
 
 void g_dbus_remove_all_watches(DBusConnection *connection)
 {
-	struct name_data *data;
+	struct filter_data *data;
 
-	while ((data = name_data_find(connection, NULL))) {
-		name_listeners = g_slist_remove(name_listeners, data);
-		name_data_call_and_free(data);
+	while ((data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL))) {
+		listeners = g_slist_remove(listeners, data);
+		filter_data_call_and_free(data);
 	}
 
-	dbus_connection_remove_filter(connection, name_exit_filter, NULL);
+	dbus_connection_remove_filter(connection, message_filter, NULL);
 }
diff --git a/include/bluetooth/Makefile.am b/include/bluetooth/Makefile.am
deleted file mode 100644
index 992e987..0000000
--- a/include/bluetooth/Makefile.am
+++ /dev/null
@@ -1,14 +0,0 @@
-
-includedir = @includedir@/bluetooth
-
-include_HEADERS = \
-	bluetooth.h hci.h hci_lib.h sco.h l2cap.h \
-	sdp.h sdp_lib.h rfcomm.h bnep.h cmtp.h hidp.h
-
-MAINTAINERCLEANFILES = Makefile.in
-
-all-local:
-	@if [ ! -e bluetooth ] ; then $(LN_S) $(top_srcdir)/include bluetooth ; fi
-
-clean-local:
-	@rm -f bluetooth
diff --git a/input/Android.mk b/input/Android.mk
index 935afb9..8f8f4f5 100755
--- a/input/Android.mk
+++ b/input/Android.mk
@@ -12,13 +12,12 @@
 	server.c
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\" \
+	-DVERSION=\"4.69\" \
 	-DSTORAGEDIR=\"/data/misc/bluetoothd\" \
 	-DCONFIGDIR=\"/etc/bluetooth\"
 
 LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common \
+	$(LOCAL_PATH)/../lib \
 	$(LOCAL_PATH)/../src \
 	$(LOCAL_PATH)/../gdbus \
 	$(call include-path-for, glib) \
diff --git a/input/Makefile.am b/input/Makefile.am
deleted file mode 100644
index 98ce928..0000000
--- a/input/Makefile.am
+++ /dev/null
@@ -1,24 +0,0 @@
-
-if INPUTPLUGIN
-plugindir = $(libdir)/bluetooth/plugins
-
-plugin_LTLIBRARIES = input.la
-
-input_la_SOURCES = main.c manager.h manager.c \
-			server.h server.c device.h device.c \
-						fakehid.c fakehid.h
-
-LDADD = $(top_builddir)/common/libhelper.a \
-		@GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
-endif
-
-AM_LDFLAGS = -module -avoid-version -no-undefined
-
-AM_CFLAGS = -fvisibility=hidden \
-		@BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
-
-INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/src
-
-EXTRA_DIST = input.conf sixpair.c
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/input/device.c b/input/device.c
index 2cfc5d8..f06b229 100644
--- a/input/device.c
+++ b/input/device.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -46,7 +46,7 @@
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 #include "textfile.h"
 #include "uinput.h"
 
@@ -298,7 +298,7 @@
 		goto failed;
 	}
 
-	debug("Received: %s", buf);
+	DBG("Received: %s", buf);
 
 	if (g_io_channel_write(chan, ok, 6, &bwritten) != G_IO_ERROR_NONE) {
 		error("IO Channel write error");
@@ -596,8 +596,7 @@
 	close(req->ctrl_sock);
 
 cleanup:
-	if (req->rd_data)
-		free(req->rd_data);
+	free(req->rd_data);
 
 	g_free(req);
 }
@@ -659,17 +658,10 @@
 		}
 	}
 
-	if (req->vendor == 0x054c && req->product == 0x0268) {
-		unsigned char buf[] = { 0x53, 0xf4,  0x42, 0x03, 0x00, 0x00 };
-		int sk = g_io_channel_unix_get_fd(iconn->ctrl_io);
-		err = write(sk, buf, sizeof(buf));
-	}
-
 	err = ioctl_connadd(req);
 
 cleanup:
-	if (req->rd_data)
-		free(req->rd_data);
+	free(req->rd_data);
 	g_free(req);
 
 	return err;
@@ -892,6 +884,7 @@
 				BT_IO_OPT_SOURCE_BDADDR, &idev->src,
 				BT_IO_OPT_DEST_BDADDR, &idev->dst,
 				BT_IO_OPT_PSM, L2CAP_PSM_HIDP_INTR,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
 				BT_IO_OPT_INVALID);
 	if (!io) {
 		error("%s", err->message);
@@ -970,6 +963,7 @@
 					BT_IO_OPT_SOURCE_BDADDR, &idev->src,
 					BT_IO_OPT_DEST_BDADDR, &idev->dst,
 					BT_IO_OPT_PSM, L2CAP_PSM_HIDP_CTRL,
+					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
 					BT_IO_OPT_INVALID);
 		iconn->ctrl_io = io;
 	}
@@ -1008,7 +1002,7 @@
 {
 	struct input_device *idev = data;
 
-	debug("Unregistered interface %s on path %s", INPUT_DEVICE_INTERFACE,
+	DBG("Unregistered interface %s on path %s", INPUT_DEVICE_INTERFACE,
 								idev->path);
 
 	devices = g_slist_remove(devices, idev);
@@ -1095,7 +1089,7 @@
 		return NULL;
 	}
 
-	debug("Registered interface %s on path %s",
+	DBG("Registered interface %s on path %s",
 			INPUT_DEVICE_INTERFACE, idev->path);
 
 	return idev;
diff --git a/input/device.h b/input/device.h
index f9ec7c2..3390a0b 100644
--- a/input/device.h
+++ b/input/device.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/input/fakehid.c b/input/fakehid.c
index 6c9a715..ee1f77a 100644
--- a/input/fakehid.c
+++ b/input/fakehid.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -43,7 +43,7 @@
 #include "../src/adapter.h"
 #include "../src/device.h"
 
-#include "logging.h"
+#include "log.h"
 #include "device.h"
 #include "fakehid.h"
 #include "uinput.h"
diff --git a/input/fakehid.h b/input/fakehid.h
index 90aacb4..33b1e70 100644
--- a/input/fakehid.h
+++ b/input/fakehid.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/input/main.c b/input/main.c
index 913ea7b..e165ab4 100644
--- a/input/main.c
+++ b/input/main.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -32,7 +32,7 @@
 #include <gdbus.h>
 
 #include "plugin.h"
-#include "logging.h"
+#include "log.h"
 #include "manager.h"
 
 static GKeyFile *load_config_file(const char *file)
diff --git a/input/manager.c b/input/manager.c
index 567075b..a98a080 100644
--- a/input/manager.c
+++ b/input/manager.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,7 @@
 
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 #include "../src/adapter.h"
 #include "../src/device.h"
 
@@ -45,7 +45,7 @@
 static int idle_timeout = 0;
 
 static DBusConnection *connection = NULL;
-GSList *adapters = NULL;
+static GSList *adapters = NULL;
 
 static void input_remove(struct btd_device *device, const char *uuid)
 {
@@ -179,7 +179,7 @@
 		idle_timeout = g_key_file_get_integer(config, "General",
 						"IdleTimeout", &err);
 		if (err) {
-			debug("input.conf: %s", err->message);
+			DBG("input.conf: %s", err->message);
 			g_error_free(err);
 		}
 	}
diff --git a/input/manager.h b/input/manager.h
index 754c57a..7b93c5b 100644
--- a/input/manager.h
+++ b/input/manager.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/input/server.c b/input/server.c
index 5ae9f8c..d98018b 100644
--- a/input/server.c
+++ b/input/server.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,7 @@
 #include <glib.h>
 #include <dbus/dbus.h>
 
-#include "logging.h"
+#include "log.h"
 
 #include "glib-helper.h"
 #include "btio.h"
@@ -82,7 +82,7 @@
 		return;
 	}
 
-	debug("Incoming connection on PSM %d", psm);
+	DBG("Incoming connection on PSM %d", psm);
 
 	ret = input_device_set_channel(&src, &dst, psm, chan);
 	if (ret == 0)
@@ -187,6 +187,7 @@
 				server, NULL, &err,
 				BT_IO_OPT_SOURCE_BDADDR, src,
 				BT_IO_OPT_PSM, L2CAP_PSM_HIDP_CTRL,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
 				BT_IO_OPT_INVALID);
 	if (!server->ctrl) {
 		error("Failed to listen on control channel");
@@ -199,6 +200,7 @@
 				server, NULL, &err,
 				BT_IO_OPT_SOURCE_BDADDR, src,
 				BT_IO_OPT_PSM, L2CAP_PSM_HIDP_INTR,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
 				BT_IO_OPT_INVALID);
 	if (!server->intr) {
 		error("Failed to listen on interrupt channel");
diff --git a/input/server.h b/input/server.h
index c3dee07..74159bb 100644
--- a/input/server.h
+++ b/input/server.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/lib/Android.mk b/lib/Android.mk
index a0dc4d0..0d645aa 100755
--- a/lib/Android.mk
+++ b/lib/Android.mk
@@ -6,8 +6,8 @@
 	sdp.c \
 	hci.c
 
-LOCAL_C_INCLUDES+= \
-	 $(LOCAL_PATH)/../include/
+LOCAL_C_INCLUDES:= \
+        $(LOCAL_PATH)/bluetooth \
 
 LOCAL_MODULE:=libbluetooth
 
diff --git a/lib/Makefile.am b/lib/Makefile.am
deleted file mode 100644
index f7a8ffb..0000000
--- a/lib/Makefile.am
+++ /dev/null
@@ -1,9 +0,0 @@
-
-lib_LTLIBRARIES = libbluetooth.la
-
-libbluetooth_la_SOURCES = bluetooth.c hci.c sdp.c
-libbluetooth_la_LDFLAGS = -version-info 5:7:2
-
-INCLUDES = -I$(top_builddir)/include
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/lib/bluetooth.c b/lib/bluetooth.c
index 1c34f25..4ed03e9 100644
--- a/lib/bluetooth.c
+++ b/lib/bluetooth.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2000-2001  Qualcomm Incorporated
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -35,8 +35,8 @@
 #include <string.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
+#include "bluetooth.h"
+#include "hci.h"
 
 void baswap(bdaddr_t *dst, const bdaddr_t *src)
 {
@@ -55,7 +55,7 @@
 		return NULL;
 
 	sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
-		ba->b[0], ba->b[1], ba->b[2], 
+		ba->b[0], ba->b[1], ba->b[2],
 		ba->b[3], ba->b[4], ba->b[5]);
 
 	return str;
@@ -429,7 +429,7 @@
 	case 70:
 		return "MediaTek, Inc.";
 	case 71:
-		return "Bluegiga";	/* (tentative) */
+		return "Bluegiga";
 	case 72:
 		return "Marvell Technology Group Ltd.";
 	case 73:
@@ -462,6 +462,24 @@
 		return "Sony Ericsson Mobile Communications";
 	case 87:
 		return "Harman International Industries, Inc.";
+	case 88:
+		return "Vizio, Inc.";
+	case 89:
+		return "Nordic Semiconductor ASA";
+	case 90:
+		return "EM Microelectronic-Marin SA";
+	case 91:
+		return "Ralink Technology Corporation";
+	case 92:
+		return "Belkin International, Inc.";
+	case 93:
+		return "Realtek Semiconductor Corporation";
+	case 94:
+		return "Stonestreet One, LLC";
+	case 95:
+		return "Wicentric, Inc.";
+	case 96:
+		return "RivieraWaves S.A.S";
 	case 65535:
 		return "internal use";
 	default:
diff --git a/include/bluetooth/bluetooth.h b/lib/bluetooth/bluetooth.h
similarity index 98%
rename from include/bluetooth/bluetooth.h
rename to lib/bluetooth/bluetooth.h
index b0b23a4..a0486c7 100644
--- a/include/bluetooth/bluetooth.h
+++ b/lib/bluetooth/bluetooth.h
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2000-2001  Qualcomm Incorporated
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/include/bluetooth/bnep.h b/lib/bluetooth/bnep.h
similarity index 97%
rename from include/bluetooth/bnep.h
rename to lib/bluetooth/bnep.h
index a022c8e..2bbfb17 100644
--- a/include/bluetooth/bnep.h
+++ b/lib/bluetooth/bnep.h
@@ -3,7 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/include/bluetooth/cmtp.h b/lib/bluetooth/cmtp.h
similarity index 95%
rename from include/bluetooth/cmtp.h
rename to lib/bluetooth/cmtp.h
index b7439ac..ce937bd 100644
--- a/include/bluetooth/cmtp.h
+++ b/lib/bluetooth/cmtp.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/include/bluetooth/hci.h b/lib/bluetooth/hci.h
similarity index 84%
rename from include/bluetooth/hci.h
rename to lib/bluetooth/hci.h
index aaee296..57b6150 100644
--- a/include/bluetooth/hci.h
+++ b/lib/bluetooth/hci.h
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2000-2001  Qualcomm Incorporated
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -47,7 +47,7 @@
 #define HCI_DEV_SUSPEND	5
 #define HCI_DEV_RESUME	6
 
-/* HCI device types */
+/* HCI bus types */
 #define HCI_VIRTUAL	0
 #define HCI_USB		1
 #define HCI_PCCARD	2
@@ -56,6 +56,10 @@
 #define HCI_PCI		5
 #define HCI_SDIO	6
 
+/* HCI controller types */
+#define HCI_BREDR	0x00
+#define HCI_80211	0x01
+
 /* HCI device flags */
 enum {
 	HCI_UP,
@@ -93,6 +97,9 @@
 #define HCISETACLMTU	_IOW('H', 227, int)
 #define HCISETSCOMTU	_IOW('H', 228, int)
 
+#define HCIBLOCKADDR	_IOW('H', 230, int)
+#define HCIUNBLOCKADDR	_IOW('H', 231, int)
+
 #define HCIINQUIRY	_IOR('H', 240, int)
 
 #ifndef __NO_HCI_DEFS
@@ -253,6 +260,8 @@
 #define LMP_EV5		0x02
 #define LMP_AFH_CAP_SLV	0x08
 #define LMP_AFH_CLS_SLV	0x10
+#define LMP_NO_BREDR	0x20
+#define LMP_LE		0x40
 #define LMP_EDR_3SLOT	0x80
 
 #define LMP_EDR_5SLOT	0x01
@@ -265,6 +274,7 @@
 #define LMP_EDR_3S_ESCO	0x80
 
 #define LMP_EXT_INQ	0x01
+#define LMP_LE_BREDR	0x02
 #define LMP_SIMPLE_PAIR	0x08
 #define LMP_ENCAPS_PDU	0x10
 #define LMP_ERR_DAT_REP	0x20
@@ -272,6 +282,7 @@
 
 #define LMP_LSTO	0x01
 #define LMP_INQ_TX_PWR	0x02
+#define LMP_EPC		0x04
 #define LMP_EXT_FEAT	0x80
 
 /* Link policies */
@@ -742,14 +753,14 @@
 typedef struct {
 	uint8_t		name[248];
 } __attribute__ ((packed)) change_local_name_cp;
-#define CHANGE_LOCAL_NAME_CP_SIZE 248 
+#define CHANGE_LOCAL_NAME_CP_SIZE 248
 
 #define OCF_READ_LOCAL_NAME		0x0014
 typedef struct {
 	uint8_t		status;
 	uint8_t		name[248];
 } __attribute__ ((packed)) read_local_name_rp;
-#define READ_LOCAL_NAME_RP_SIZE 249 
+#define READ_LOCAL_NAME_RP_SIZE 249
 
 #define OCF_READ_CONN_ACCEPT_TIMEOUT	0x0015
 typedef struct {
@@ -837,7 +848,7 @@
 	uint8_t		status;
 	uint8_t		dev_class[3];
 } __attribute__ ((packed)) read_class_of_dev_rp;
-#define READ_CLASS_OF_DEV_RP_SIZE 4 
+#define READ_CLASS_OF_DEV_RP_SIZE 4
 
 #define OCF_WRITE_CLASS_OF_DEV		0x0024
 typedef struct {
@@ -1070,6 +1081,13 @@
 } __attribute__ ((packed)) read_local_oob_data_rp;
 #define READ_LOCAL_OOB_DATA_RP_SIZE 33
 
+#define OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL	0x0058
+typedef struct {
+	uint8_t		status;
+	int8_t		level;
+} __attribute__ ((packed)) read_inq_response_tx_power_level_rp;
+#define READ_INQ_RESPONSE_TX_POWER_LEVEL_RP_SIZE 2
+
 #define OCF_READ_INQUIRY_TRANSMIT_POWER_LEVEL	0x0058
 typedef struct {
 	uint8_t		status;
@@ -1258,6 +1276,250 @@
 } __attribute__ ((packed)) write_simple_pairing_debug_mode_rp;
 #define WRITE_SIMPLE_PAIRING_DEBUG_MODE_RP_SIZE 1
 
+/* LE commands */
+#define OGF_LE_CTL		0x08
+
+#define OCF_LE_SET_EVENT_MASK			0x0001
+typedef struct {
+	uint8_t		mask[8];
+} __attribute__ ((packed)) le_set_event_mask_cp;
+#define LE_SET_EVENT_MASK_CP_SIZE 8
+
+#define OCF_LE_READ_BUFFER_SIZE			0x0002
+typedef struct {
+	uint8_t		status;
+	uint16_t	pkt_len;
+	uint8_t		max_pkt;
+} __attribute__ ((packed)) le_read_buffer_size_rp;
+#define LE_READ_BUFFER_SIZE_RP_SIZE 4
+
+#define OCF_LE_READ_LOCAL_SUPPORTED_FEATURES	0x0003
+typedef struct {
+	uint8_t		status;
+	uint8_t		features[8];
+} __attribute__ ((packed)) le_read_local_supported_features_rp;
+#define LE_READ_LOCAL_SUPPORTED_FEATURES_RP_SIZE 9
+
+#define OCF_LE_SET_RANDOM_ADDRESS		0x0005
+typedef struct {
+	bdaddr_t	bdaddr;
+} __attribute__ ((packed)) le_set_random_address_cp;
+#define LE_SET_RANDOM_ADDRESS_CP_SIZE 6
+
+#define OCF_LE_SET_ADVERTISING_PARAMETERS	0x0006
+typedef struct {
+	uint16_t	min_interval;
+	uint16_t	max_interval;
+	uint8_t		advtype;
+	uint8_t		own_bdaddr_type;
+	uint8_t		direct_bdaddr_type;
+	bdaddr_t	direct_bdaddr;
+	uint8_t		chan_map;
+	uint8_t		filter;
+} __attribute__ ((packed)) le_set_advertising_parameters_cp;
+#define LE_SET_ADVERTISING_PARAMETERS_CP_SIZE 15
+
+#define OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER	0x0007
+typedef struct {
+	uint8_t		status;
+	uint8_t		level;
+} __attribute__ ((packed)) le_read_advertising_channel_tx_power_rp;
+#define LE_READ_ADVERTISING_CHANNEL_TX_POWER_RP_SIZE 2
+
+#define OCF_LE_SET_ADVERTISING_DATA		0x0008
+typedef struct {
+	uint8_t		length;
+	uint8_t		data[31];
+} __attribute__ ((packed)) le_set_advertising_data_cp;
+#define LE_SET_ADVERTISING_DATA_CP_SIZE 32
+
+#define OCF_LE_SET_SCAN_RESPONSE_DATA		0x0009
+typedef struct {
+	uint8_t		length;
+	uint8_t		data[31];
+} __attribute__ ((packed)) le_set_scan_response_data_cp;
+#define LE_SET_SCAN_RESPONSE_DATA_CP_SIZE 32
+
+#define OCF_LE_SET_ADVERTISE_ENABLE		0x000A
+typedef struct {
+	uint8_t		enable;
+} __attribute__ ((packed)) le_set_advertise_enable_cp;
+#define LE_SET_ADVERTISE_ENABLE_CP_SIZE 1
+
+#define OCF_LE_SET_SCAN_PARAMETERS		0x000B
+typedef struct {
+	uint8_t		type;
+	uint16_t	interval;
+	uint16_t	window;
+	uint8_t		own_bdaddr_type;
+	uint8_t		filter;
+} __attribute__ ((packed)) le_set_scan_parameters_cp;
+#define LE_SET_SCAN_PARAMETERS_CP_SIZE 7
+
+#define OCF_LE_SET_SCAN_ENABLE			0x000C
+typedef struct {
+	uint8_t		enable;
+	uint8_t		filter_dup;
+} __attribute__ ((packed)) le_set_scan_enable_cp;
+#define LE_SET_SCAN_ENABLE_CP_SIZE 2
+
+#define OCF_LE_CREATE_CONN			0x000D
+typedef struct {
+	uint16_t	interval;
+	uint16_t	window;
+	uint8_t		initiator_filter;
+	uint8_t		peer_bdaddr_type;
+	bdaddr_t	peer_bdaddr;
+	uint8_t		own_bdaddr_type;
+	uint16_t	min_interval;
+	uint16_t	max_interval;
+	uint16_t	latency;
+	uint16_t	supervision_timeout;
+	uint16_t	min_ce_length;
+	uint16_t	max_ce_length;
+} __attribute__ ((packed)) le_create_connection_cp;
+#define LE_CREATE_CONN_CP_SIZE 25
+
+#define OCF_LE_CREATE_CONN_CANCEL		0x000E
+
+#define OCF_LE_READ_WHITE_LIST_SIZE		0x000F
+typedef struct {
+	uint8_t		status;
+	uint8_t		size;
+} __attribute__ ((packed)) le_read_white_list_size_rp;
+#define LE_READ_WHITE_LIST_SIZE_RP_SIZE 2
+
+#define OCF_LE_CLEAR_WHITE_LIST			0x0010
+
+#define OCF_LE_ADD_DEVICE_TO_WHITE_LIST		0x0011
+typedef struct {
+	uint8_t		bdaddr_type;
+	bdaddr_t	bdaddr;
+} __attribute__ ((packed)) le_add_device_to_white_list_cp;
+#define LE_ADD_DEVICE_TO_WHITE_LIST_CP_SIZE 7
+
+#define OCF_LE_REMOVE_DEVICE_FROM_WHITE_LIST	0x0012
+typedef struct {
+	uint8_t		bdaddr_type;
+	bdaddr_t	bdaddr;
+} __attribute__ ((packed)) le_remove_device_from_white_list_cp;
+#define LE_REMOVE_DEVICE_FROM_WHITE_LIST_CP_SIZE 7
+
+#define OCF_LE_CONN_UPDATE			0x0013
+typedef struct {
+	uint16_t	handle;
+	uint16_t	min_interval;
+	uint16_t	max_interval;
+	uint16_t	latency;
+	uint16_t	supervision_timeout;
+	uint16_t	min_ce_length;
+	uint16_t	max_ce_length;
+} __attribute__ ((packed)) le_connection_update_cp;
+#define LE_CONN_UPDATE_CP_SIZE 14
+
+#define OCF_LE_SET_HOST_CHANNEL_CLASSIFICATION	0x0014
+typedef struct {
+	uint8_t		map[5];
+} __attribute__ ((packed)) le_set_host_channel_classification_cp;
+#define LE_SET_HOST_CHANNEL_CLASSIFICATION_CP_SIZE 5
+
+#define OCF_LE_READ_CHANNEL_MAP			0x0015
+typedef struct {
+	uint16_t	handle;
+} __attribute__ ((packed)) le_read_channel_map_cp;
+#define LE_READ_CHANNEL_MAP_CP_SIZE 2
+typedef struct {
+	uint8_t		status;
+	uint16_t	handle;
+	uint8_t		map[5];
+} __attribute__ ((packed)) le_read_channel_map_rp;
+#define LE_READ_CHANNEL_MAP_RP_SIZE 8
+
+#define OCF_LE_READ_REMOTE_USED_FEATURES	0x0016
+typedef struct {
+	uint16_t	handle;
+} __attribute__ ((packed)) le_read_remote_used_features_cp;
+#define LE_READ_REMOTE_USED_FEATURES_CP_SIZE 2
+
+#define OCF_LE_ENCRYPT				0x0017
+typedef struct {
+	uint8_t		key[16];
+	uint8_t		plaintext[16];
+} __attribute__ ((packed)) le_encrypt_cp;
+#define LE_ENCRYPT_CP_SIZE 32
+typedef struct {
+	uint8_t		status;
+	uint8_t		data[16];
+} __attribute__ ((packed)) le_encrypt_rp;
+#define LE_ENCRYPT_RP_SIZE 17
+
+#define OCF_LE_RAND				0x0018
+typedef struct {
+	uint8_t		status;
+	uint64_t	random;
+} __attribute__ ((packed)) le_rand_rp;
+#define LE_RAND_RP_SIZE 9
+
+#define OCF_LE_START_ENCRYPTION			0x0019
+typedef struct {
+	uint16_t	handle;
+	uint64_t	random;
+	uint16_t	diversifier;
+	uint8_t		key[16];
+} __attribute__ ((packed)) le_start_encryption_cp;
+#define LE_START_ENCRYPTION_CP_SIZE 28
+
+#define OCF_LE_LTK_REPLY			0x001A
+typedef struct {
+	uint16_t	handle;
+	uint8_t		key[16];
+} __attribute__ ((packed)) le_ltk_reply_cp;
+#define LE_LTK_REPLY_CP_SIZE 18
+typedef struct {
+	uint8_t		status;
+	uint16_t	handle;
+} __attribute__ ((packed)) le_ltk_reply_rp;
+#define LE_LTK_REPLY_RP_SIZE 3
+
+#define OCF_LE_LTK_NEG_REPLY			0x001B
+typedef struct {
+	uint16_t	handle;
+} __attribute__ ((packed)) le_ltk_neg_reply_cp;
+#define LE_LTK_NEG_REPLY_CP_SIZE 2
+typedef struct {
+	uint8_t		status;
+	uint16_t	handle;
+} __attribute__ ((packed)) le_ltk_neg_reply_rp;
+#define LE_LTK_NEG_REPLY_RP_SIZE 3
+
+#define OCF_LE_READ_SUPPORTED_STATES		0x001C
+typedef struct {
+	uint8_t		status;
+	uint64_t	states;
+} __attribute__ ((packed)) le_read_supported_states_rp;
+#define LE_READ_SUPPORTED_STATES_RP_SIZE 9
+
+#define OCF_LE_RECEIVER_TEST			0x001D
+typedef struct {
+	uint8_t		frequency;
+} __attribute__ ((packed)) le_receiver_test_cp;
+#define LE_RECEIVER_TEST_CP_SIZE 1
+
+#define OCF_LE_TRANSMITTER_TEST			0x001E
+typedef struct {
+	uint8_t		frequency;
+	uint8_t		length;
+	uint8_t		payload;
+} __attribute__ ((packed)) le_transmitter_test_cp;
+#define LE_TRANSMITTER_TEST_CP_SIZE 3
+
+#define OCF_LE_TEST_END				0x001F
+typedef struct {
+	uint8_t		status;
+	uint16_t	num_pkts;
+} __attribute__ ((packed)) le_test_end_rp;
+#define LE_TEST_END_RP_SIZE 3
+
 /* Vendor specific commands */
 #define OGF_VENDOR_CMD		0x3f
 
@@ -1660,6 +1922,64 @@
 } __attribute__ ((packed)) evt_remote_host_features_notify;
 #define EVT_REMOTE_HOST_FEATURES_NOTIFY_SIZE 14
 
+#define EVT_LE_META_EVENT	0x3E
+typedef struct {
+	uint8_t		subevent;
+	uint8_t		data[0];
+} __attribute__ ((packed)) evt_le_meta_event;
+#define EVT_LE_META_EVENT_SIZE 1
+
+#define EVT_LE_CONN_COMPLETE	0x01
+typedef struct {
+	uint8_t		status;
+	uint16_t	handle;
+	uint8_t		role;
+	uint8_t		peer_bdaddr_type;
+	bdaddr_t	peer_bdaddr;
+	uint16_t	interval;
+	uint16_t	latency;
+	uint16_t	supervision_timeout;
+	uint8_t		master_clock_accuracy;
+} __attribute__ ((packed)) evt_le_connection_complete;
+#define EVT_LE_CONN_COMPLETE_SIZE 18
+
+#define EVT_LE_ADVERTISING_REPORT	0x02
+typedef struct {
+	uint8_t		evt_type;
+	uint8_t		bdaddr_type;
+	bdaddr_t	bdaddr;
+	uint8_t		length;
+	uint8_t		data[31];
+	uint8_t		rssi;
+} __attribute__ ((packed)) le_advertising_info;
+#define LE_ADVERTISING_INFO_SIZE 41
+
+#define EVT_LE_CONN_UPDATE_COMPLETE	0x03
+typedef struct {
+	uint8_t		status;
+	uint16_t	handle;
+	uint16_t	interval;
+	uint16_t	latency;
+	uint16_t	supervision_timeout;
+} __attribute__ ((packed)) evt_le_connection_update_complete;
+#define EVT_LE_CONN_UPDATE_COMPLETE_SIZE 9
+
+#define EVT_LE_READ_REMOTE_USED_FEATURES_COMPLETE	0x04
+typedef struct {
+	uint8_t		status;
+	uint16_t	handle;
+	uint8_t		features[8];
+} __attribute__ ((packed)) evt_le_read_remote_used_features_complete;
+#define EVT_LE_READ_REMOTE_USED_FEATURES_COMPLETE_SIZE 11
+
+#define EVT_LE_LTK_REQUEST	0x05
+typedef struct {
+	uint16_t	handle;
+	uint64_t	random;
+	uint16_t	diversifier;
+} __attribute__ ((packed)) evt_le_long_term_key_request;
+#define EVT_LE_LTK_REQUEST_SIZE 12
+
 #define EVT_TESTING			0xFE
 
 #define EVT_VENDOR			0xFF
diff --git a/include/bluetooth/hci_lib.h b/lib/bluetooth/hci_lib.h
similarity index 91%
rename from include/bluetooth/hci_lib.h
rename to lib/bluetooth/hci_lib.h
index bd50785..b63a2a4 100644
--- a/include/bluetooth/hci_lib.h
+++ b/lib/bluetooth/hci_lib.h
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2000-2001  Qualcomm Incorporated
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -101,6 +101,7 @@
 int hci_read_simple_pairing_mode(int dd, uint8_t *mode, int to);
 int hci_write_simple_pairing_mode(int dd, uint8_t mode, int to);
 int hci_read_local_oob_data(int dd, uint8_t *hash, uint8_t *randomizer, int to);
+int hci_read_inq_response_tx_power_level(int dd, int8_t *level, int to);
 int hci_read_inquiry_transmit_power_level(int dd, int8_t *level, int to);
 int hci_write_inquiry_transmit_power_level(int dd, int8_t level, int to);
 int hci_read_transmit_power_level(int dd, uint16_t handle, uint8_t type, int8_t *level, int to);
@@ -114,9 +115,24 @@
 int hci_read_afh_map(int dd, uint16_t handle, uint8_t *mode, uint8_t *map, int to);
 int hci_read_clock(int dd, uint16_t handle, uint8_t which, uint32_t *clock, uint16_t *accuracy, int to);
 
+int hci_le_set_scan_enable(int dev_id, uint8_t enable, uint8_t filter_dup);
+int hci_le_set_scan_parameters(int dev_id, uint8_t type, uint16_t interval,
+					uint16_t window, uint8_t own_type,
+					uint8_t filter);
+int hci_le_set_advertise_enable(int dev_id, uint8_t enable);
+int hci_le_create_conn(int dd, uint16_t interval, uint16_t window,
+		uint8_t initiator_filter, uint8_t peer_bdaddr_type,
+		bdaddr_t peer_bdaddr, uint8_t own_bdaddr_type,
+		uint16_t min_interval, 	uint16_t max_interval,
+		uint16_t latency, uint16_t supervision_timeout,
+		uint16_t min_ce_length, uint16_t max_ce_length,
+		uint16_t *handle, int to);
+
 int hci_for_each_dev(int flag, int(*func)(int dd, int dev_id, long arg), long arg);
 int hci_get_route(bdaddr_t *bdaddr);
 
+char *hci_bustostr(int bus);
+char *hci_typetostr(int type);
 char *hci_dtypetostr(int type);
 char *hci_dflagstostr(uint32_t flags);
 char *hci_ptypetostr(unsigned int ptype);
diff --git a/include/bluetooth/hidp.h b/lib/bluetooth/hidp.h
similarity index 96%
rename from include/bluetooth/hidp.h
rename to lib/bluetooth/hidp.h
index 7ae56c8..c5e6a78 100644
--- a/include/bluetooth/hidp.h
+++ b/lib/bluetooth/hidp.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/include/bluetooth/l2cap.h b/lib/bluetooth/l2cap.h
similarity index 97%
rename from include/bluetooth/l2cap.h
rename to lib/bluetooth/l2cap.h
index be2bebf..17ad554 100644
--- a/include/bluetooth/l2cap.h
+++ b/lib/bluetooth/l2cap.h
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2000-2001  Qualcomm Incorporated
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -51,6 +51,9 @@
 	uint16_t	imtu;
 	uint16_t	flush_to;
 	uint8_t		mode;
+	uint8_t		fcs;
+	uint8_t		max_tx;
+	uint16_t	txwin_size;
 };
 
 #define L2CAP_CONNINFO	0x02
diff --git a/include/bluetooth/rfcomm.h b/lib/bluetooth/rfcomm.h
similarity index 96%
rename from include/bluetooth/rfcomm.h
rename to lib/bluetooth/rfcomm.h
index 0765af3..ad6c0e1 100644
--- a/include/bluetooth/rfcomm.h
+++ b/lib/bluetooth/rfcomm.h
@@ -3,7 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/include/bluetooth/sco.h b/lib/bluetooth/sco.h
similarity index 95%
rename from include/bluetooth/sco.h
rename to lib/bluetooth/sco.h
index ff71829..82cd77c 100644
--- a/include/bluetooth/sco.h
+++ b/lib/bluetooth/sco.h
@@ -3,7 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/include/bluetooth/sdp.h b/lib/bluetooth/sdp.h
similarity index 94%
rename from include/bluetooth/sdp.h
rename to lib/bluetooth/sdp.h
index 63cfcf0..2e1f6b5 100644
--- a/include/bluetooth/sdp.h
+++ b/lib/bluetooth/sdp.h
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2001-2002  Nokia Corporation
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com>
  *
  *
@@ -141,9 +141,9 @@
 #define VIDEO_SOURCE_SVCLASS_ID		0x1303
 #define VIDEO_SINK_SVCLASS_ID		0x1304
 #define VIDEO_DISTRIBUTION_SVCLASS_ID	0x1305
-#define MDP_SVCLASS_ID			0x1400
-#define MDP_SOURCE_SVCLASS_ID		0x1401
-#define MDP_SINK_SVCLASS_ID		0x1402
+#define HDP_SVCLASS_ID			0x1400
+#define HDP_SOURCE_SVCLASS_ID		0x1401
+#define HDP_SINK_SVCLASS_ID		0x1402
 #define APPLE_AGENT_SVCLASS_ID		0x2112
 
 /*
@@ -213,12 +213,22 @@
 #define VIDEO_SOURCE_PROFILE_ID		VIDEO_SOURCE_SVCLASS_ID
 #define VIDEO_SINK_PROFILE_ID		VIDEO_SINK_SVCLASS_ID
 #define VIDEO_DISTRIBUTION_PROFILE_ID	VIDEO_DISTRIBUTION_SVCLASS_ID
-#define MDP_PROFILE_ID			MDP_SVCLASS_ID
-#define MDP_SOURCE_PROFILE_ID		MDP_SROUCE_SVCLASS_ID
-#define MDP_SINK_PROFILE_ID		MDP_SINK_SVCLASS_ID
+#define HDP_PROFILE_ID			HDP_SVCLASS_ID
+#define HDP_SOURCE_PROFILE_ID		HDP_SOURCE_SVCLASS_ID
+#define HDP_SINK_PROFILE_ID		HDP_SINK_SVCLASS_ID
 #define APPLE_AGENT_PROFILE_ID		APPLE_AGENT_SVCLASS_ID
 
 /*
+ * Compatibility macros for the old MDP acronym
+ */
+#define MDP_SVCLASS_ID			HDP_SVCLASS_ID
+#define MDP_SOURCE_SVCLASS_ID		HDP_SOURCE_SVCLASS_ID
+#define MDP_SINK_SVCLASS_ID		HDP_SINK_SVCLASS_ID
+#define MDP_PROFILE_ID			HDP_PROFILE_ID
+#define MDP_SOURCE_PROFILE_ID		HDP_SOURCE_PROFILE_ID
+#define MDP_SINK_PROFILE_ID		HDP_SINK_PROFILE_ID
+
+/*
  * Attribute identifier codes
  */
 #define SDP_SERVER_RECORD_HANDLE		0x0000
@@ -245,13 +255,16 @@
 #define SDP_ATTR_GROUP_ID			0x0200
 #define SDP_ATTR_IP_SUBNET			0x0200
 #define SDP_ATTR_VERSION_NUM_LIST		0x0200
+#define SDP_ATTR_SUPPORTED_FEATURES_LIST	0x0200
 #define SDP_ATTR_SVCDB_STATE			0x0201
 
 #define SDP_ATTR_SERVICE_VERSION		0x0300
 #define SDP_ATTR_EXTERNAL_NETWORK		0x0301
 #define SDP_ATTR_SUPPORTED_DATA_STORES_LIST	0x0301
+#define SDP_ATTR_DATA_EXCHANGE_SPEC		0x0301
 #define SDP_ATTR_FAX_CLASS1_SUPPORT		0x0302
 #define SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL	0x0302
+#define SDP_ATTR_MCAP_SUPPORTED_PROCEDURES	0x0302
 #define SDP_ATTR_FAX_CLASS20_SUPPORT		0x0303
 #define SDP_ATTR_SUPPORTED_FORMATS_LIST		0x0303
 #define SDP_ATTR_FAX_CLASS2_SUPPORT		0x0304
@@ -295,7 +308,7 @@
 #define SDP_ATTR_HID_BOOT_DEVICE		0x020e
 
 /*
- * These identifiers are based on the SDP spec stating that 
+ * These identifiers are based on the SDP spec stating that
  * "base attribute id of the primary (universal) language must be 0x0100"
  *
  * Other languages should have their own offset; e.g.:
diff --git a/include/bluetooth/sdp_lib.h b/lib/bluetooth/sdp_lib.h
similarity index 91%
rename from include/bluetooth/sdp_lib.h
rename to lib/bluetooth/sdp_lib.h
index f3f4357..e506ac1 100644
--- a/include/bluetooth/sdp_lib.h
+++ b/lib/bluetooth/sdp_lib.h
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2001-2002  Nokia Corporation
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com>
  *
  *
@@ -47,7 +47,7 @@
 sdp_list_t *sdp_list_insert_sorted(sdp_list_t *list, void *data, sdp_comp_func_t f);
 void        sdp_list_free(sdp_list_t *list, sdp_free_func_t f);
 
-static inline int sdp_list_len(const sdp_list_t *list) 
+static inline int sdp_list_len(const sdp_list_t *list)
 {
 	int n = 0;
 	for (; list; list = list->next)
@@ -118,9 +118,9 @@
 
 /*
  * create an L2CAP connection to a Bluetooth device
- * 
+ *
  * INPUT:
- *  
+ *
  *  bdaddr_t *src:
  *	Address of the local device to use to make the connection
  *	(or BDADDR_ANY)
@@ -174,29 +174,29 @@
 int sdp_get_uuidseq_attr(const sdp_record_t *rec, uint16_t attr, sdp_list_t **seqp);
 
 /*
- * NOTE that none of the functions below will update the SDP server, 
+ * NOTE that none of the functions below will update the SDP server,
  * unless the {register, update}sdp_record_t() function is invoked.
- * All functions which return an integer value, return 0 on success 
+ * All functions which return an integer value, return 0 on success
  * or -1 on failure.
  */
 
 /*
  * Create an attribute and add it to the service record's attribute list.
- * This consists of the data type descriptor of the attribute, 
+ * This consists of the data type descriptor of the attribute,
  * the value of the attribute and the attribute identifier.
  */
 int sdp_attr_add_new(sdp_record_t *rec, uint16_t attr, uint8_t dtd, const void *p);
 
 /*
  * Set the information attributes of the service record.
- * The set of attributes comprises service name, description 
+ * The set of attributes comprises service name, description
  * and provider name
  */
 void sdp_set_info_attr(sdp_record_t *rec, const char *name, const char *prov, const char *desc);
 
 /*
  * Set the ServiceClassID attribute to the sequence specified by seq.
- * Note that the identifiers need to be in sorted order from the most 
+ * Note that the identifiers need to be in sorted order from the most
  * specific to the most generic service class that this service
  * conforms to.
  */
@@ -207,8 +207,8 @@
 
 /*
  * Get the service classes to which the service conforms.
- * 
- * When set, the list contains elements of ServiceClassIdentifer(uint16_t) 
+ *
+ * When set, the list contains elements of ServiceClassIdentifer(uint16_t)
  * ordered from most specific to most generic
  */
 static inline int sdp_get_service_classes(const sdp_record_t *rec, sdp_list_t **seqp)
@@ -218,8 +218,8 @@
 
 /*
  * Set the BrowseGroupList attribute to the list specified by seq.
- * 
- * A service can belong to one or more service groups 
+ *
+ * A service can belong to one or more service groups
  * and the list comprises such group identifiers (UUIDs)
  */
 static inline int sdp_set_browse_groups(sdp_record_t *rec, sdp_list_t *seq)
@@ -238,24 +238,24 @@
 int sdp_set_add_access_protos(sdp_record_t *rec, const sdp_list_t *proto);
 
 /*
- * Get protocol port (i.e. PSM for L2CAP, Channel for RFCOMM) 
+ * Get protocol port (i.e. PSM for L2CAP, Channel for RFCOMM)
  */
 int sdp_get_proto_port(const sdp_list_t *list, int proto);
 
 /*
- * Get protocol descriptor. 
+ * Get protocol descriptor.
  */
 sdp_data_t *sdp_get_proto_desc(sdp_list_t *list, int proto);
 
 /*
- * Set the LanguageBase attributes to the values specified in list 
- * (a linked list of sdp_lang_attr_t objects, one for each language in 
+ * Set the LanguageBase attributes to the values specified in list
+ * (a linked list of sdp_lang_attr_t objects, one for each language in
  * which user-visible attributes are present).
  */
 int sdp_set_lang_attr(sdp_record_t *rec, const sdp_list_t *list);
 
 /*
- * Set the ServiceInfoTimeToLive attribute of the service.  
+ * Set the ServiceInfoTimeToLive attribute of the service.
  * This is the number of seconds that this record is guaranteed
  * not to change after being obtained by a client.
  */
@@ -266,8 +266,8 @@
 
 /*
  * Set the ServiceRecordState attribute of a service. This is
- * guaranteed to change if there is any kind of modification to 
- * the record. 
+ * guaranteed to change if there is any kind of modification to
+ * the record.
  */
 static inline int sdp_set_record_state(sdp_record_t *rec, uint32_t state)
 {
@@ -275,7 +275,7 @@
 }
 
 /*
- * Set the ServiceID attribute of a service. 
+ * Set the ServiceID attribute of a service.
  */
 void sdp_set_service_id(sdp_record_t *rec, uuid_t uuid);
 
@@ -286,7 +286,7 @@
 
 /*
  * Set the ServiceAvailability attribute of a service.
- * 
+ *
  * Note that this represents the relative availability
  * of the service: 0x00 means completely unavailable;
  * 0xFF means maximum availability.
@@ -298,7 +298,7 @@
 
 /*
  * Set the profile descriptor list attribute of a record.
- * 
+ *
  * Each element in the list is an object of type
  * sdp_profile_desc_t which is a definition of the
  * Bluetooth profile that this service conforms to.
@@ -307,41 +307,41 @@
 
 /*
  * Set URL attributes of a record.
- * 
- * ClientExecutableURL: a URL to a client's platform specific (WinCE, 
+ *
+ * ClientExecutableURL: a URL to a client's platform specific (WinCE,
  * PalmOS) executable code that can be used to access this service.
- * 
+ *
  * DocumentationURL: a URL pointing to service documentation
- * 
+ *
  * IconURL: a URL to an icon that can be used to represent this service.
- * 
+ *
  * Note: pass NULL for any URLs that you don't want to set or remove
  */
 void sdp_set_url_attr(sdp_record_t *rec, const char *clientExecURL, const char *docURL, const char *iconURL);
 
 /*
- * a service search request. 
- * 
+ * a service search request.
+ *
  *  INPUT :
- * 
+ *
  *    sdp_list_t *search
  *      list containing elements of the search
  *      pattern. Each entry in the list is a UUID
  *      of the service to be searched
- * 
+ *
  *    uint16_t max_rec_num
  *       An integer specifying the maximum number of
  *       entries that the client can handle in the response.
- * 
+ *
  *  OUTPUT :
- * 
+ *
  *    int return value
- *      0 
+ *      0
  *        The request completed successfully. This does not
  *        mean the requested services were found
  *      -1
  *        The request completed unsuccessfully
- * 
+ *
  *    sdp_list_t *rsp_list
  *      This variable is set on a successful return if there are
  *      non-zero service handles. It is a singly linked list of
@@ -350,33 +350,33 @@
 int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search, uint16_t max_rec_num, sdp_list_t **rsp_list);
 
 /*
- *  a service attribute request. 
- * 
+ *  a service attribute request.
+ *
  *  INPUT :
- * 
+ *
  *    uint32_t handle
  *      The handle of the service for which the attribute(s) are
  *      requested
- * 
+ *
  *    sdp_attrreq_type_t reqtype
  *      Attribute identifiers are 16 bit unsigned integers specified
  *      in one of 2 ways described below :
  *      SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers
  *         They are the actual attribute identifiers in ascending order
- * 
+ *
  *      SDP_ATTR_REQ_RANGE - 32bit identifier range
  *         The high-order 16bits is the start of range
  *         the low-order 16bits are the end of range
  *         0x0000 to 0xFFFF gets all attributes
- * 
+ *
  *    sdp_list_t *attrid_list
  *      Singly linked list containing attribute identifiers desired.
- *      Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)  
+ *      Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
  *      or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
- * 
+ *
  *  OUTPUT :
  *    int return value
- *      0 
+ *      0
  *        The request completed successfully. This does not
  *        mean the requested services were found
  *      -1
@@ -388,38 +388,38 @@
  *  This is a service search request combined with the service
  *  attribute request. First a service class match is done and
  *  for matching service, requested attributes are extracted
- * 
+ *
  *  INPUT :
- * 
+ *
  *    sdp_list_t *search
  *      Singly linked list containing elements of the search
  *      pattern. Each entry in the list is a UUID(DataTypeSDP_UUID16)
  *      of the service to be searched
- * 
+ *
  *    AttributeSpecification attrSpec
  *      Attribute identifiers are 16 bit unsigned integers specified
  *      in one of 2 ways described below :
  *      SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers
  *         They are the actual attribute identifiers in ascending order
- * 
+ *
  *      SDP_ATTR_REQ_RANGE - 32bit identifier range
  *         The high-order 16bits is the start of range
  *         the low-order 16bits are the end of range
  *         0x0000 to 0xFFFF gets all attributes
- * 
+ *
  *    sdp_list_t *attrid_list
  *      Singly linked list containing attribute identifiers desired.
- *      Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)  
+ *      Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
  *      or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
- * 
+ *
  *  OUTPUT :
  *    int return value
- *      0 
+ *      0
  *        The request completed successfully. This does not
  *        mean the requested services were found
  *      -1
  *        The request completed unsuccessfully due to a timeout
- * 
+ *
  *    sdp_list_t *rsp_list
  *      This variable is set on a successful return to point to
  *      service(s) found. Each element of this list is of type
@@ -434,12 +434,12 @@
 void sdp_record_free(sdp_record_t *rec);
 
 /*
- * Register a service record. 
- * 
- * Note: It is the responsbility of the Service Provider to create the 
+ * Register a service record.
+ *
+ * Note: It is the responsbility of the Service Provider to create the
  * record first and set its attributes using setXXX() methods.
- * 
- * The service provider must then call sdp_record_register() to make 
+ *
+ * The service provider must then call sdp_record_register() to make
  * the service record visible to SDP clients.  This function returns 0
  * on success or -1 on failure (and sets errno).
  */
@@ -473,9 +473,10 @@
 uuid_t *sdp_uuid128_create(uuid_t *uuid, const void *data);
 int sdp_uuid16_cmp(const void *p1, const void *p2);
 int sdp_uuid128_cmp(const void *p1, const void *p2);
-uuid_t *sdp_uuid_to_uuid128(uuid_t *uuid);
-void sdp_uuid16_to_uuid128(uuid_t *uuid128, uuid_t *uuid16);
-void sdp_uuid32_to_uuid128(uuid_t *uuid128, uuid_t *uuid32);
+int sdp_uuid_cmp(const void *p1, const void *p2);
+uuid_t *sdp_uuid_to_uuid128(const uuid_t *uuid);
+void sdp_uuid16_to_uuid128(uuid_t *uuid128, const uuid_t *uuid16);
+void sdp_uuid32_to_uuid128(uuid_t *uuid128, const uuid_t *uuid32);
 int sdp_uuid128_to_uuid(uuid_t *uuid);
 int sdp_uuid_to_proto(uuid_t *uuid);
 int sdp_uuid_extract(const uint8_t *buffer, int bufsize, uuid_t *uuid, int *scanned);
@@ -492,14 +493,14 @@
 int sdp_profile_uuid2strn(const uuid_t *uuid, char *str, size_t n);
 
 /*
- * In all the sdp_get_XXX(handle, XXX *xxx) functions below, 
+ * In all the sdp_get_XXX(handle, XXX *xxx) functions below,
  * the XXX * is set to point to the value, should it exist
  * and 0 is returned. If the value does not exist, -1 is
  * returned and errno set to ENODATA.
  *
  * In all the methods below, the memory management rules are
  * simple. Don't free anything! The pointer returned, in the
- * case of constructed types, is a pointer to the contents 
+ * case of constructed types, is a pointer to the contents
  * of the sdp_record_t.
  */
 
@@ -515,7 +516,7 @@
 
 /*
  * Extract the list of browse groups to which the service belongs.
- * When set, seqp contains elements of GroupID (uint16_t) 
+ * When set, seqp contains elements of GroupID (uint16_t)
  */
 static inline int sdp_get_browse_groups(const sdp_record_t *rec, sdp_list_t **seqp)
 {
@@ -523,9 +524,9 @@
 }
 
 /*
- * Extract language attribute meta-data of the service record. 
+ * Extract language attribute meta-data of the service record.
  * For each language in the service record, LangSeq has a struct of type
- * sdp_lang_attr_t. 
+ * sdp_lang_attr_t.
  */
 int sdp_get_lang_attr(const sdp_record_t *rec, sdp_list_t **langSeq);
 
@@ -539,8 +540,8 @@
 int sdp_get_profile_descs(const sdp_record_t *rec, sdp_list_t **profDesc);
 
 /*
- * Extract SDP server version numbers 
- * 
+ * Extract SDP server version numbers
+ *
  * Note: that this is an attribute of the SDP server only and
  * contains a list of uint16_t each of which represent the
  * major and minor SDP version numbers supported by this server
@@ -584,6 +585,20 @@
 	return sdp_get_string_attr(rec, SDP_ATTR_ICON_URL, str, len);
 }
 
+/*
+ * Set the supported features
+ * sf should be a list of list with each feature data
+ * Returns 0 on success -1 on fail
+ */
+int sdp_set_supp_feat(sdp_record_t *rec, const sdp_list_t *sf);
+
+/*
+ * Get the supported features
+ * seqp is set to a list of list with each feature data
+ * Returns 0 on success, if an error occurred -1 is returned and errno is set
+ */
+int sdp_get_supp_feat(const sdp_record_t *rec, sdp_list_t **seqp);
+
 sdp_record_t *sdp_extract_pdu(const uint8_t *pdata, int bufsize, int *scanned);
 sdp_record_t *sdp_copy_record(sdp_record_t *rec);
 
diff --git a/lib/hci.c b/lib/hci.c
index 6d25a8b..1c455c5 100644
--- a/lib/hci.c
+++ b/lib/hci.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2000-2001  Qualcomm Incorporated
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -41,9 +41,9 @@
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "bluetooth.h"
+#include "hci.h"
+#include "hci_lib.h"
 
 #ifndef MIN
 #define MIN(x, y) ((x) < (y) ? (x) : (y))
@@ -54,7 +54,7 @@
 	unsigned int val;
 } hci_map;
 
-static char *hci_bit2str(hci_map *m, unsigned int val) 
+static char *hci_bit2str(hci_map *m, unsigned int val)
 {
 	char *str = malloc(120);
 	char *ptr = str;
@@ -95,7 +95,7 @@
 	return set;
 }
 
-static char *hci_uint2str(hci_map *m, unsigned int val) 
+static char *hci_uint2str(hci_map *m, unsigned int val)
 {
 	char *str = malloc(50);
 	char *ptr = str;
@@ -138,9 +138,9 @@
 	return set;
 }
 
-char *hci_dtypetostr(int type)
+char *hci_bustostr(int bus)
 {
-	switch (type) {
+	switch (bus) {
 	case HCI_VIRTUAL:
 		return "VIRTUAL";
 	case HCI_USB:
@@ -160,6 +160,23 @@
 	}
 }
 
+char *hci_dtypetostr(int type)
+{
+	return hci_bustostr(type & 0x0f);
+}
+
+char *hci_typetostr(int type)
+{
+	switch (type) {
+	case HCI_BREDR:
+		return "BR/EDR";
+	case HCI_80211:
+		return "802.11";
+	default:
+		return "UNKNOWN";
+	}
+}
+
 /* HCI dev flags mapping */
 static hci_map dev_flags_map[] = {
 	{ "UP",      HCI_UP      },
@@ -192,7 +209,7 @@
 		if (hci_test_bit(m->val, &flags))
 			ptr += sprintf(ptr, "%s ", m->str);
 		m++;
-	} 	
+	}
 	return str;
 }
 
@@ -473,7 +490,7 @@
 	{ "Write Simple Pairing Mode",			142 },
 	{ "Read Local OOB Data",			143 },
 
-	{ "Read Inquiry Transmit Power Level",		144 },
+	{ "Read Inquiry Response Transmit Power Level",	144 },
 	{ "Write Inquiry Transmit Power Level",		145 },
 	{ "Read Default Erroneous Data Reporting",	146 },
 	{ "Write Default Erroneous Data Reporting",	147 },
@@ -494,12 +511,84 @@
 	{ "Reserved",					160 },
 	{ "Reserved",					161 },
 	{ "Send Keypress Notification",			162 },
-	{ "IO Capabilities Response Negative Reply",	163 },
-	{ "Reserved",					164 },
+	{ "IO Capability Request Negative Reply",	163 },
+	{ "Read Encryption Key Size",			164 },
 	{ "Reserved",					165 },
 	{ "Reserved",					166 },
 	{ "Reserved",					167 },
 
+	{ "Create Physical Link",			168 },
+	{ "Accept Physical Link",			169 },
+	{ "Disconnect Physical Link",			170 },
+	{ "Create Logical Link",			171 },
+	{ "Accept Logical Link",			172 },
+	{ "Disconnect Logical Link",			173 },
+	{ "Logical Link Cancel",			174 },
+	{ "Flow Specification Modify",			175 },
+
+	{ "Read Logical Link Accept Timeout",		176 },
+	{ "Write Logical Link Accept Timeout",		177 },
+	{ "Set Event Mask Page 2",			178 },
+	{ "Read Location Data",				179 },
+	{ "Write Location Data",			180 },
+	{ "Read Local AMP Info",			181 },
+	{ "Read Local AMP_ASSOC",			182 },
+	{ "Write Remote AMP_ASSOC",			183 },
+
+	{ "Read Flow Control Mode",			184 },
+	{ "Write Flow Control Mode",			185 },
+	{ "Read Data Block Size",			186 },
+	{ "Reserved",					187 },
+	{ "Reserved",					188 },
+	{ "Enable AMP Receiver Reports",		189 },
+	{ "AMP Test End",				190 },
+	{ "AMP Test Command",				191 },
+
+	{ "Read Enhanced Transmit Power Level",		192 },
+	{ "Reserved",					193 },
+	{ "Read Best Effort Flush Timeout",		194 },
+	{ "Write Best Effort Flush Timeout",		195 },
+	{ "Short Range Mode",				196 },
+	{ "Read LE Host Support",			197 },
+	{ "Write LE Host Support",			198 },
+	{ "Reserved",					199 },
+
+	{ "LE Set Event Mask",				200 },
+	{ "LE Read Buffer Size",			201 },
+	{ "LE Read Local Supported Features",		202 },
+	{ "Reserved",					203 },
+	{ "LE Set Random Address",			204 },
+	{ "LE Set Advertising Parameters",		205 },
+	{ "LE Read Advertising Channel TX Power",	206 },
+	{ "LE Set Advertising Data",			207 },
+
+	{ "LE Set Scan Response Data",			208 },
+	{ "LE Set Advertise Enable",			209 },
+	{ "LE Set Scan Parameters",			210 },
+	{ "LE Set Scan Enable",				211 },
+	{ "LE Create Connection",			212 },
+	{ "LE Create Connection Cancel",		213 },
+	{ "LE Read White List Size",			214 },
+	{ "LE Clear White List",			215 },
+
+	{ "LE Add Device To White List",		216 },
+	{ "LE Remove Device From White List",		217 },
+	{ "LE Connection Update",			218 },
+	{ "LE Set Host Channel Classification",		219 },
+	{ "LE Read Channel Map",			220 },
+	{ "LE Read Remote Used Features",		221 },
+	{ "LE Encrypt",					222 },
+	{ "LE Rand",					223 },
+
+	{ "LE Start Encryption",			224 },
+	{ "LE Long Term Key Request Reply",		225 },
+	{ "LE Long Term Key Request Negative Reply",	226 },
+	{ "LE Read Supported States",			227 },
+	{ "LE Receiver Test",				228 },
+	{ "LE Transmitter Test",			229 },
+	{ "LE Test End",				230 },
+	{ "Reserved",					231 },
+
 	{ NULL }
 };
 
@@ -558,6 +647,7 @@
 	{ "2.0",	0x03 },
 	{ "2.1",	0x04 },
 	{ "3.0",	0x05 },
+	{ "4.0",	0x06 },
 	{ NULL }
 };
 
@@ -630,8 +720,8 @@
 		{ "<no. 34>",		0x04		},	/* Bit 2 */
 		{ "<AFH cap. slave>",	LMP_AFH_CAP_SLV	},	/* Bit 3 */
 		{ "<AFH class. slave>",	LMP_AFH_CLS_SLV	},	/* Bit 4 */
-		{ "<no. 37>",		0x20		},	/* Bit 5 */
-		{ "<no. 38>",		0x40		},	/* Bit 6 */
+		{ "<BR/EDR not supp.>",	LMP_NO_BREDR	},	/* Bit 5 */
+		{ "<LE support>",	LMP_LE		},	/* Bit 6 */
 		{ "<3-slot EDR ACL>",	LMP_EDR_3SLOT	},	/* Bit 7 */
 		{ NULL }
 	},
@@ -648,7 +738,7 @@
 	},
 	{	/* Byte 6 */
 		{ "<extended inquiry>",	LMP_EXT_INQ	},	/* Bit 0 */
-		{ "<no. 49>",		0x02		},	/* Bit 1 */
+		{ "<LE and BR/EDR>",	LMP_LE_BREDR	},	/* Bit 1 */
 		{ "<no. 50>",		0x04		},	/* Bit 2 */
 		{ "<simple pairing>",	LMP_SIMPLE_PAIR	},	/* Bit 3 */
 		{ "<encapsulated PDU>",	LMP_ENCAPS_PDU	},	/* Bit 4 */
@@ -660,7 +750,7 @@
 	{	/* Byte 7 */
 		{ "<LSTO>",		LMP_LSTO	},	/* Bit 1 */
 		{ "<inquiry TX power>",	LMP_INQ_TX_PWR	},	/* Bit 1 */
-		{ "<no. 58>",		0x04		},	/* Bit 2 */
+		{ "<EPC>",		LMP_EPC		},	/* Bit 2 */
 		{ "<no. 59>",		0x08		},	/* Bit 3 */
 		{ "<no. 60>",		0x10		},	/* Bit 4 */
 		{ "<no. 61>",		0x20		},	/* Bit 5 */
@@ -869,7 +959,7 @@
 			errno = ENODEV;
 			return -1;
 		}
-	}	
+	}
 
 	dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
 	if (dd < 0)
@@ -919,7 +1009,7 @@
 	return ret;
 }
 
-/* Open HCI device. 
+/* Open HCI device.
  * Returns device descriptor (dd). */
 int hci_open_dev(int dev_id)
 {
@@ -1003,6 +1093,7 @@
 	hci_filter_set_ptype(HCI_EVENT_PKT,  &nf);
 	hci_filter_set_event(EVT_CMD_STATUS, &nf);
 	hci_filter_set_event(EVT_CMD_COMPLETE, &nf);
+	hci_filter_set_event(EVT_LE_META_EVENT, &nf);
 	hci_filter_set_event(r->event, &nf);
 	hci_filter_set_opcode(opcode, &nf);
 	if (setsockopt(dd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0)
@@ -1016,6 +1107,7 @@
 		evt_cmd_complete *cc;
 		evt_cmd_status *cs;
 		evt_remote_name_req_complete *rn;
+		evt_le_meta_event *me;
 		remote_name_req_cp *cp;
 		int len;
 
@@ -1096,6 +1188,17 @@
 			memcpy(r->rparam, ptr, r->rlen);
 			goto done;
 
+		case EVT_LE_META_EVENT:
+			me = (void *) ptr;
+
+			if (me->subevent != r->event)
+				continue;
+
+			len -= 1;
+			r->rlen = MIN(len, r->rlen);
+			memcpy(r->rparam, me->data, r->rlen);
+			goto done;
+
 		default:
 			if (hdr->evt != r->event)
 				break;
@@ -2173,16 +2276,16 @@
 	return 0;
 }
 
-int hci_read_inquiry_transmit_power_level(int dd, int8_t *level, int to)
+int hci_read_inq_response_tx_power_level(int dd, int8_t *level, int to)
 {
-	read_inquiry_transmit_power_level_rp rp;
+	read_inq_response_tx_power_level_rp rp;
 	struct hci_request rq;
 
 	memset(&rq, 0, sizeof(rq));
 	rq.ogf    = OGF_HOST_CTL;
-	rq.ocf    = OCF_READ_INQUIRY_TRANSMIT_POWER_LEVEL;
+	rq.ocf    = OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL;
 	rq.rparam = &rp;
-	rq.rlen   = READ_INQUIRY_TRANSMIT_POWER_LEVEL_RP_SIZE;
+	rq.rlen   = READ_INQ_RESPONSE_TX_POWER_LEVEL_RP_SIZE;
 
 	if (hci_send_req(dd, &rq, to) < 0)
 		return -1;
@@ -2196,6 +2299,11 @@
 	return 0;
 }
 
+int hci_read_inquiry_transmit_power_level(int dd, int8_t *level, int to)
+{
+	return hci_read_inq_response_tx_power_level(dd, level, to);
+}
+
 int hci_write_inquiry_transmit_power_level(int dd, int8_t level, int to)
 {
 	write_inquiry_transmit_power_level_cp cp;
@@ -2496,3 +2604,143 @@
 	*accuracy = rp.accuracy;
 	return 0;
 }
+
+int hci_le_set_scan_enable(int dd, uint8_t enable, uint8_t filter_dup)
+{
+	struct hci_request rq;
+	le_set_scan_enable_cp scan_cp;
+	uint8_t status;
+
+	memset(&scan_cp, 0, sizeof(scan_cp));
+	scan_cp.enable = enable;
+	scan_cp.filter_dup = filter_dup;
+
+	memset(&rq, 0, sizeof(rq));
+	rq.ogf = OGF_LE_CTL;
+	rq.ocf = OCF_LE_SET_SCAN_ENABLE;
+	rq.cparam = &scan_cp;
+	rq.clen = LE_SET_SCAN_ENABLE_CP_SIZE;
+	rq.rparam = &status;
+	rq.rlen = 1;
+
+	if (hci_send_req(dd, &rq, 100) < 0)
+		return -1;
+
+	if (status) {
+		errno = EIO;
+		return -1;
+	}
+
+	return 0;
+}
+
+int hci_le_set_scan_parameters(int dd, uint8_t type,
+					uint16_t interval, uint16_t window,
+					uint8_t own_type, uint8_t filter)
+{
+	struct hci_request rq;
+	le_set_scan_parameters_cp param_cp;
+	uint8_t status;
+
+	memset(&param_cp, 0, sizeof(param_cp));
+	param_cp.type = type;
+	param_cp.interval = interval;
+	param_cp.window = window;
+	param_cp.own_bdaddr_type = own_type;
+	param_cp.filter = filter;
+
+	memset(&rq, 0, sizeof(rq));
+	rq.ogf = OGF_LE_CTL;
+	rq.ocf = OCF_LE_SET_SCAN_PARAMETERS;
+	rq.cparam = &param_cp;
+	rq.clen = LE_SET_SCAN_PARAMETERS_CP_SIZE;
+	rq.rparam = &status;
+	rq.rlen = 1;
+
+	if (hci_send_req(dd, &rq, 100) < 0)
+		return -1;
+
+	if (status) {
+		errno = EIO;
+		return -1;
+	}
+
+	return 0;
+}
+
+int hci_le_set_advertise_enable(int dd, uint8_t enable)
+{
+	struct hci_request rq;
+	le_set_advertise_enable_cp adv_cp;
+	uint8_t status;
+
+	memset(&adv_cp, 0, sizeof(adv_cp));
+	adv_cp.enable = enable;
+
+	memset(&rq, 0, sizeof(rq));
+	rq.ogf = OGF_LE_CTL;
+	rq.ocf = OCF_LE_SET_ADVERTISE_ENABLE;
+	rq.cparam = &adv_cp;
+	rq.clen = LE_SET_ADVERTISE_ENABLE_CP_SIZE;
+	rq.rparam = &status;
+	rq.rlen = 1;
+
+	if (hci_send_req(dd, &rq, 100) < 0)
+		return -1;
+
+	if (status) {
+		errno = EIO;
+		return -1;
+	}
+
+	return 0;
+}
+
+int hci_le_create_conn(int dd, uint16_t interval, uint16_t window,
+		uint8_t initiator_filter, uint8_t peer_bdaddr_type,
+		bdaddr_t peer_bdaddr, uint8_t own_bdaddr_type,
+		uint16_t min_interval, 	uint16_t max_interval,
+		uint16_t latency, uint16_t supervision_timeout,
+		uint16_t min_ce_length, uint16_t max_ce_length,
+		uint16_t *handle, int to)
+{
+	struct hci_request rq;
+	le_create_connection_cp create_conn_cp;
+	evt_le_connection_complete conn_complete_rp;
+
+	memset(&create_conn_cp, 0, sizeof(create_conn_cp));
+	create_conn_cp.interval = interval;
+	create_conn_cp.window = window;
+	create_conn_cp.initiator_filter = initiator_filter;
+	create_conn_cp.peer_bdaddr_type = peer_bdaddr_type;
+	create_conn_cp.peer_bdaddr = peer_bdaddr;
+	create_conn_cp.own_bdaddr_type = own_bdaddr_type;
+	create_conn_cp.min_interval = min_interval;
+	create_conn_cp.max_interval = max_interval;
+	create_conn_cp.latency = latency;
+	create_conn_cp.supervision_timeout = supervision_timeout;
+	create_conn_cp.min_ce_length = min_ce_length;
+	create_conn_cp.max_ce_length = max_ce_length;
+
+	memset(&rq, 0, sizeof(rq));
+	rq.ogf = OGF_LE_CTL;
+	rq.ocf = OCF_LE_CREATE_CONN;
+	rq.event = EVT_LE_CONN_COMPLETE;
+	rq.cparam = &create_conn_cp;
+	rq.clen = LE_CREATE_CONN_CP_SIZE;
+	rq.rparam = &conn_complete_rp;
+	rq.rlen = EVT_CONN_COMPLETE_SIZE;
+
+	if (hci_send_req(dd, &rq, to) < 0)
+		return -1;
+
+	if (conn_complete_rp.status) {
+		errno = EIO;
+		return -1;
+	}
+
+	if (handle)
+		*handle = conn_complete_rp.handle;
+
+	return 0;
+}
diff --git a/lib/sdp.c b/lib/sdp.c
index bf34c3c..17745ac 100644
--- a/lib/sdp.c
+++ b/lib/sdp.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2001-2002  Nokia Corporation
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com>
  *
  *
@@ -40,16 +40,15 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/un.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
 #include <netinet/in.h>
 
+#include "bluetooth.h"
+#include "hci.h"
+#include "hci_lib.h"
+#include "l2cap.h"
+#include "sdp.h"
+#include "sdp_lib.h"
+
 #define SDPINF(fmt, arg...) syslog(LOG_INFO, fmt "\n", ## arg)
 #define SDPERR(fmt, arg...) syslog(LOG_ERR, "%s: " fmt "\n", __func__ , ## arg)
 
@@ -202,9 +201,9 @@
 	{ VIDEO_SOURCE_SVCLASS_ID,		"Video Source"			},
 	{ VIDEO_SINK_SVCLASS_ID,		"Video Sink"			},
 	{ VIDEO_DISTRIBUTION_SVCLASS_ID,	"Video Distribution"		},
-	{ MDP_SVCLASS_ID,			"MDP"				},
-	{ MDP_SOURCE_SVCLASS_ID,		"MDP Source"			},
-	{ MDP_SINK_SVCLASS_ID,			"MDP Sink"			},
+	{ HDP_SVCLASS_ID,			"HDP"				},
+	{ HDP_SOURCE_SVCLASS_ID,		"HDP Source"			},
+	{ HDP_SINK_SVCLASS_ID,			"HDP Sink"			},
 	{ APPLE_AGENT_SVCLASS_ID,		"Apple Agent"			},
 	{ 0 }
 };
@@ -638,14 +637,14 @@
 
 void sdp_set_seq_len(uint8_t *ptr, uint32_t length)
 {
-	uint8_t dtd = *(uint8_t *) ptr++;
+	uint8_t dtd = *ptr++;
 
 	switch (dtd) {
 	case SDP_SEQ8:
 	case SDP_ALT8:
 	case SDP_TEXT_STR8:
 	case SDP_URL_STR8:
-		*(uint8_t *)ptr = (uint8_t) length;
+		*ptr = (uint8_t) length;
 		break;
 	case SDP_SEQ16:
 	case SDP_ALT16:
@@ -1079,6 +1078,8 @@
 	}
 
 	d = malloc(sizeof(sdp_data_t));
+	if (!d)
+		return NULL;
 
 	SDPDBG("Extracting integer\n");
 	memset(d, 0, sizeof(sdp_data_t));
@@ -1153,13 +1154,16 @@
 {
 	sdp_data_t *d = malloc(sizeof(sdp_data_t));
 
+	if (!d)
+		return NULL;
+
 	SDPDBG("Extracting UUID");
 	memset(d, 0, sizeof(sdp_data_t));
 	if (sdp_uuid_extract(p, bufsize, &d->val.uuid, len) < 0) {
 		free(d);
 		return NULL;
 	}
-	d->dtd = *(uint8_t *) p;
+	d->dtd = *p;
 	if (rec)
 		sdp_pattern_add_uuid(rec, &d->val.uuid);
 	return d;
@@ -1180,6 +1184,8 @@
 	}
 
 	d = malloc(sizeof(sdp_data_t));
+	if (!d)
+		return NULL;
 
 	memset(d, 0, sizeof(sdp_data_t));
 	d->dtd = *(uint8_t *) p;
@@ -1215,7 +1221,7 @@
 	default:
 		SDPERR("Sizeof text string > UINT16_MAX\n");
 		free(d);
-		return 0;
+		return NULL;
 	}
 
 	if (bufsize < n) {
@@ -1303,6 +1309,9 @@
 	sdp_data_t *curr, *prev;
 	sdp_data_t *d = malloc(sizeof(sdp_data_t));
 
+	if (!d)
+		return NULL;
+
 	SDPDBG("Extracting SEQ");
 	memset(d, 0, sizeof(sdp_data_t));
 	*len = sdp_extract_seqtype(p, bufsize, &d->dtd, &seqlen);
@@ -1575,7 +1584,7 @@
 
 		value = sdp_data_value(tmp, NULL);
 		datatmp = sdp_data_alloc_with_length(tmp->dtd, value,
-					tmp->unitSize);
+								tmp->unitSize);
 
 		if (cur)
 			cur->next = datatmp;
@@ -1601,7 +1610,7 @@
 		sdp_attr_add_new(rec, data->attrId, data->dtd, val);
 	else
 		sdp_attr_add_new_with_length(rec, data->attrId,
-			data->dtd, val, len);
+							data->dtd, val, len);
 }
 
 sdp_record_t *sdp_copy_record(sdp_record_t *rec)
@@ -1703,7 +1712,7 @@
 		sdpTemplate.attrId = attrId;
 		p = sdp_list_find(rec->attrlist, &sdpTemplate, sdp_attrid_comp_func);
 		if (p)
-			return (sdp_data_t *)p->data;
+			return p->data;
 	}
 	return NULL;
 }
@@ -1744,8 +1753,8 @@
 			uint8_t *rspbuf, uint32_t reqsize, uint32_t *rspsize)
 {
 	int n;
-	sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *)reqbuf;
-	sdp_pdu_hdr_t *rsphdr = (sdp_pdu_hdr_t *)rspbuf;
+	sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *) reqbuf;
+	sdp_pdu_hdr_t *rsphdr = (sdp_pdu_hdr_t *) rspbuf;
 
 	SDPDBG("");
 	if (0 > sdp_send_req(session, reqbuf, reqsize)) {
@@ -1772,7 +1781,7 @@
 	sdp_list_t *q, *n = malloc(sizeof(sdp_list_t));
 
 	if (!n)
-		return 0;
+		return NULL;
 
 	n->data = d;
 	n->next = 0;
@@ -1810,7 +1819,7 @@
 
 	n = malloc(sizeof(sdp_list_t));
 	if (!n)
-		return 0;
+		return NULL;
 	n->data = d;
 	for (q = 0, p = list; p; q = p, p = p->next)
 		if (f(p->data, d) >= 0)
@@ -1867,7 +1876,7 @@
 	for (; list; list = list->next) {
 		sdp_list_t *p;
 		for (p = list->data; p; p = p->next) {
-			sdp_data_t *seq = (sdp_data_t *) p->data;
+			sdp_data_t *seq = p->data;
 			int port = __find_port(seq, proto);
 			if (port)
 				return port;
@@ -1881,7 +1890,7 @@
 	for (; list; list = list->next) {
 		sdp_list_t *p;
 		for (p = list->data; p; p = p->next) {
-			sdp_data_t *seq = (sdp_data_t *) p->data;
+			sdp_data_t *seq = p->data;
 			if (SDP_IS_UUID(seq->dtd) &&
 					sdp_uuid_to_proto(&seq->val.uuid) == proto)
 				return seq->next;
@@ -1946,10 +1955,15 @@
 		sdp_data_t *d;
 		for (d = sdpdata->val.dataseq; d; d = d->next) {
 			uuid_t *u;
-			if (d->dtd < SDP_UUID16 || d->dtd > SDP_UUID128)
+			if (d->dtd < SDP_UUID16 || d->dtd > SDP_UUID128) {
+				errno = EINVAL;
 				goto fail;
+			}
 
 			u = malloc(sizeof(uuid_t));
+			if (!u)
+				goto fail;
+
 			memset(u, 0, sizeof(uuid_t));
 			*u = d->val.uuid;
 			*seqp = sdp_list_append(*seqp, u);
@@ -1958,7 +1972,7 @@
 	}
 fail:
 	sdp_list_free(*seqp, free);
-	errno = EINVAL;
+	*seqp = NULL;
 	return -1;
 }
 
@@ -1974,10 +1988,18 @@
 	len = sdp_list_len(seq);
 	if (!seq || len == 0)
 		return -1;
-	dtds = (void **)malloc(len * sizeof(void *));
-	values = (void **)malloc(len * sizeof(void *));
+	dtds = malloc(len * sizeof(void *));
+	if (!dtds)
+		return -1;
+
+	values = malloc(len * sizeof(void *));
+	if (!values) {
+		free(dtds);
+		return -1;
+	}
+
 	for (p = seq, i = 0; i < len; i++, p = p->next) {
-		uuid_t *uuid = (uuid_t *)p->data;
+		uuid_t *uuid = p->data;
 		if (uuid)
 			switch (uuid->type) {
 			case SDP_UUID16:
@@ -2027,8 +2049,13 @@
 		sdp_data_t *pCode = curr_data;
 		sdp_data_t *pEncoding = pCode->next;
 		sdp_data_t *pOffset = pEncoding->next;
-		if (pCode && pEncoding && pOffset) {
+		if (pEncoding && pOffset) {
 			lang = malloc(sizeof(sdp_lang_attr_t));
+			if (!lang) {
+				sdp_list_free(*langSeq, free);
+				*langSeq = NULL;
+				return -1;
+			}
 			lang->code_ISO639 = pCode->val.uint16;
 			lang->encoding = pEncoding->val.uint16;
 			lang->base_offset = pOffset->val.uint16;
@@ -2070,6 +2097,11 @@
 
 		if (uuid != NULL) {
 			profDesc = malloc(sizeof(sdp_profile_desc_t));
+			if (!profDesc) {
+				sdp_list_free(*profDescSeq, free);
+				*profDescSeq = NULL;
+				return -1;
+			}
 			profDesc->uuid = *uuid;
 			profDesc->version = version;
 #ifdef SDP_DEBUG
@@ -2212,14 +2244,14 @@
 							const char *desc)
 {
 	if (name)
-		sdp_attr_add_new(rec, SDP_ATTR_SVCNAME_PRIMARY, SDP_TEXT_STR8,
-								(void *)name);
+		sdp_attr_add_new(rec, SDP_ATTR_SVCNAME_PRIMARY,
+							SDP_TEXT_STR8, name);
 	if (prov)
-		sdp_attr_add_new(rec, SDP_ATTR_PROVNAME_PRIMARY, SDP_TEXT_STR8,
-								(void *)prov);
+		sdp_attr_add_new(rec, SDP_ATTR_PROVNAME_PRIMARY,
+							SDP_TEXT_STR8, prov);
 	if (desc)
-		sdp_attr_add_new(rec, SDP_ATTR_SVCDESC_PRIMARY, SDP_TEXT_STR8,
-								(void *)desc);
+		sdp_attr_add_new(rec, SDP_ATTR_SVCDESC_PRIMARY,
+							SDP_TEXT_STR8, desc);
 }
 
 static sdp_data_t *access_proto_to_dataseq(sdp_record_t *rec, sdp_list_t *proto)
@@ -2231,15 +2263,23 @@
 	sdp_list_t *p;
 
 	seqlen = sdp_list_len(proto);
-	seqDTDs = (void **)malloc(seqlen * sizeof(void *));
-	seqs = (void **)malloc(seqlen * sizeof(void *));
+	seqDTDs = malloc(seqlen * sizeof(void *));
+	if (!seqDTDs)
+		return NULL;
+
+	seqs = malloc(seqlen * sizeof(void *));
+	if (!seqs) {
+		free(seqDTDs);
+		return NULL;
+	}
+
 	for (i = 0, p = proto; p; p = p->next, i++) {
-		sdp_list_t *elt = (sdp_list_t *)p->data;
+		sdp_list_t *elt = p->data;
 		sdp_data_t *s;
 		uuid_t *uuid = NULL;
 		unsigned int pslen = 0;
 		for (; elt && pslen < ARRAY_SIZE(dtds); elt = elt->next, pslen++) {
-			sdp_data_t *d = (sdp_data_t *)elt->data;
+			sdp_data_t *d = elt->data;
 			dtds[pslen] = &d->dtd;
 			switch (d->dtd) {
 			case SDP_UUID16:
@@ -2304,8 +2344,7 @@
 	sdp_data_t *protos = NULL;
 
 	for (p = ap; p; p = p->next) {
-		sdp_data_t *seq = access_proto_to_dataseq(rec,
-						(sdp_list_t *) p->data);
+		sdp_data_t *seq = access_proto_to_dataseq(rec, p->data);
 		protos = sdp_seq_append(protos, seq);
 	}
 
@@ -2320,8 +2359,7 @@
 	sdp_data_t *protos = NULL;
 
 	for (p = ap; p; p = p->next) {
-		sdp_data_t *seq = access_proto_to_dataseq(rec,
-						(sdp_list_t *) p->data);
+		sdp_data_t *seq = access_proto_to_dataseq(rec, p->data);
 		protos = sdp_seq_append(protos, seq);
 	}
 
@@ -2351,12 +2389,21 @@
 {
 	uint8_t uint16 = SDP_UINT16;
 	int status = 0, i = 0, seqlen = sdp_list_len(seq);
-	void **dtds = (void **)malloc(3 * seqlen * sizeof(void *));
-	void **values = (void **)malloc(3 * seqlen * sizeof(void *));
+	void **dtds, **values;
 	const sdp_list_t *p;
 
+	dtds = malloc(3 * seqlen * sizeof(void *));
+	if (!dtds)
+		return -1;
+
+	values = malloc(3 * seqlen * sizeof(void *));
+	if (!values) {
+		free(dtds);
+		return -1;
+	}
+
 	for (p = seq; p; p = p->next) {
-		sdp_lang_attr_t *lang = (sdp_lang_attr_t *)p->data;
+		sdp_lang_attr_t *lang = p->data;
 		if (!lang) {
 			status = -1;
 			break;
@@ -2456,14 +2503,23 @@
 	uint8_t uuid128 = SDP_UUID128;
 	uint8_t uint16 = SDP_UINT16;
 	int i = 0, seqlen = sdp_list_len(profiles);
-	void **seqDTDs = (void **)malloc(seqlen * sizeof(void *));
-	void **seqs = (void **)malloc(seqlen * sizeof(void *));
+	void **seqDTDs, **seqs;
 	const sdp_list_t *p;
 
+	seqDTDs = malloc(seqlen * sizeof(void *));
+	if (!seqDTDs)
+		return -1;
+
+	seqs = malloc(seqlen * sizeof(void *));
+	if (!seqs) {
+		free(seqDTDs);
+		return -1;
+	}
+
 	for (p = profiles; p; p = p->next) {
 		sdp_data_t *seq;
 		void *dtds[2], *values[2];
-		sdp_profile_desc_t *profile = (sdp_profile_desc_t *)p->data;
+		sdp_profile_desc_t *profile = p->data;
 		if (!profile) {
 			status = -1;
 			break;
@@ -2556,10 +2612,28 @@
  * UUID comparison function
  * returns 0 if uuidValue1 == uuidValue2 else -1
  */
+int sdp_uuid_cmp(const void *p1, const void *p2)
+{
+	uuid_t *u1 = sdp_uuid_to_uuid128(p1);
+	uuid_t *u2 = sdp_uuid_to_uuid128(p2);
+	int ret;
+
+	ret = sdp_uuid128_cmp(u1, u2);
+
+	bt_free(u1);
+	bt_free(u2);
+
+	return ret;
+}
+
+/*
+ * UUID comparison function
+ * returns 0 if uuidValue1 == uuidValue2 else -1
+ */
 int sdp_uuid16_cmp(const void *p1, const void *p2)
 {
-	const uuid_t *u1 = (const uuid_t *)p1;
-	const uuid_t *u2 = (const uuid_t *)p2;
+	const uuid_t *u1 = p1;
+	const uuid_t *u2 = p2;
 	return memcmp(&u1->value.uuid16, &u2->value.uuid16, sizeof(uint16_t));
 }
 
@@ -2569,8 +2643,8 @@
  */
 int sdp_uuid128_cmp(const void *p1, const void *p2)
 {
-	const uuid_t *u1 = (const uuid_t *)p1;
-	const uuid_t *u2 = (const uuid_t *)p2;
+	const uuid_t *u1 = p1;
+	const uuid_t *u2 = p2;
 	return memcmp(&u1->value.uuid128, &u2->value.uuid128, sizeof(uint128_t));
 }
 
@@ -2579,7 +2653,7 @@
  * yet to be implemented. Note that the input is in NBO in
  * both 32 and 128 bit UUIDs and conversion is needed
  */
-void sdp_uuid16_to_uuid128(uuid_t *uuid128, uuid_t *uuid16)
+void sdp_uuid16_to_uuid128(uuid_t *uuid128, const uuid_t *uuid16)
 {
 	/*
 	 * We have a 16 bit value, which needs to be added to
@@ -2601,7 +2675,7 @@
 	memcpy(&uuid128->value.uuid128.data[2], &data1, 2);
 }
 
-void sdp_uuid32_to_uuid128(uuid_t *uuid128, uuid_t *uuid32)
+void sdp_uuid32_to_uuid128(uuid_t *uuid128, const uuid_t *uuid32)
 {
 	/*
 	 * We have a 32 bit value, which needs to be added to
@@ -2623,9 +2697,13 @@
 	memcpy(&uuid128->value.uuid128.data[0], &data0, 4);
 }
 
-uuid_t *sdp_uuid_to_uuid128(uuid_t *uuid)
+uuid_t *sdp_uuid_to_uuid128(const uuid_t *uuid)
 {
 	uuid_t *uuid128 = bt_malloc(sizeof(uuid_t));
+
+	if (!uuid128)
+		return NULL;
+
 	memset(uuid128, 0, sizeof(uuid_t));
 	switch (uuid->type) {
 	case SDP_UUID128:
@@ -2697,14 +2775,14 @@
 void sdp_append_to_buf(sdp_buf_t *dst, uint8_t *data, uint32_t len)
 {
 	uint8_t *p = dst->data;
-	uint8_t dtd = *(uint8_t *) p;
+	uint8_t dtd = *p;
 
 	SDPDBG("Append src size: %d\n", len);
 	SDPDBG("Append dst size: %d\n", dst->data_size);
 	SDPDBG("Dst buffer size: %d\n", dst->buf_size);
 	if (dst->data_size == 0 && dtd == 0) {
 		/* create initial sequence */
-		*(uint8_t *)p = SDP_SEQ8;
+		*p = SDP_SEQ8;
 		p += sizeof(uint8_t);
 		dst->data_size += sizeof(uint8_t);
 		/* reserve space for sequence size */
@@ -2715,13 +2793,13 @@
 	memcpy(dst->data + dst->data_size, data, len);
 	dst->data_size += len;
 
-	dtd = *(uint8_t *)dst->data;
+	dtd = *(uint8_t *) dst->data;
 	if (dst->data_size > UCHAR_MAX && dtd == SDP_SEQ8) {
 		short offset = sizeof(uint8_t) + sizeof(uint8_t);
 		memmove(dst->data + offset + 1, dst->data + offset,
 						dst->data_size - offset);
 		p = dst->data;
-		*(uint8_t *) p = SDP_SEQ16;
+		*p = SDP_SEQ16;
 		p += sizeof(uint8_t);
 		dst->data_size += 1;
 	}
@@ -2837,11 +2915,8 @@
 	}
 
 end:
-	if (req)
-		free(req);
-
-	if (rsp)
-		free(rsp);
+	free(req);
+	free(rsp);
 
 	return status;
 }
@@ -2947,11 +3022,8 @@
 		status = -1;
 	}
 end:
-	if (reqbuf)
-		free(reqbuf);
-
-	if (rspbuf)
-		free(rspbuf);
+	free(reqbuf);
+	free(rspbuf);
 
 	return status;
 }
@@ -3055,10 +3127,8 @@
 		status = -1;
 	}
 end:
-	if (reqbuf)
-		free(reqbuf);
-	if (rspbuf)
-		free(rspbuf);
+	free(reqbuf);
+	free(rspbuf);
 	return status;
 }
 
@@ -3070,7 +3140,11 @@
 sdp_record_t *sdp_record_alloc()
 {
 	sdp_record_t *rec = malloc(sizeof(sdp_record_t));
-	memset((void *)rec, 0, sizeof(sdp_record_t));
+
+	if (!rec)
+		return NULL;
+
+	memset(rec, 0, sizeof(sdp_record_t));
 	rec->handle = 0xffffffff;
 	return rec;
 }
@@ -3080,7 +3154,7 @@
  */
 void sdp_record_free(sdp_record_t *rec)
 {
-	sdp_list_free(rec->attrlist, (sdp_free_func_t)sdp_data_free);
+	sdp_list_free(rec->attrlist, (sdp_free_func_t) sdp_data_free);
 	sdp_list_free(rec->pattern, free);
 	free(rec);
 }
@@ -3089,9 +3163,8 @@
 {
 	uuid_t *uuid128 = sdp_uuid_to_uuid128(uuid);
 
-	SDPDBG("SvcRec : 0x%lx\n", (unsigned long)rec);
 	SDPDBG("Elements in target pattern : %d\n", sdp_list_len(rec->pattern));
-	SDPDBG("Trying to add : 0x%lx\n", (unsigned long)uuid128);
+	SDPDBG("Trying to add : 0x%lx\n", (unsigned long) uuid128);
 
 	if (sdp_list_find(rec->pattern, uuid128, sdp_uuid128_cmp) == NULL)
 		rec->pattern = sdp_list_insert_sorted(rec->pattern, uuid128, sdp_uuid128_cmp);
@@ -3206,7 +3279,7 @@
 
 static int gen_searchseq_pdu(uint8_t *dst, const sdp_list_t *seq)
 {
-	uuid_t *uuid = (uuid_t *) seq->data;
+	uuid_t *uuid = seq->data;
 	return gen_dataseq_pdu(dst, seq, uuid->type);
 }
 
@@ -3237,7 +3310,7 @@
 }
 
 /*
- * This is a service search request. 
+ * This is a service search request.
  *
  * INPUT :
  *
@@ -3391,16 +3464,14 @@
 	} while (cstate);
 
 end:
-	if (reqbuf)
-		free(reqbuf);
-	if (rspbuf)
-		free(rspbuf);
+	free(reqbuf);
+	free(rspbuf);
 
 	return status;
 }
 
 /*
- * This is a service attribute request. 
+ * This is a service attribute request.
  *
  * INPUT :
  *
@@ -3421,7 +3492,7 @@
  *
  *   sdp_list_t *attrid
  *     Singly linked list containing attribute identifiers desired.
- *     Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)  
+ *     Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
  *     or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
  *
  * OUTPUT :
@@ -3431,7 +3502,7 @@
  *     !0:
  *	 The service record
  */
-sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle, 
+sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle,
 			sdp_attrreq_type_t reqtype, const sdp_list_t *attrids)
 {
 	uint32_t reqsize = 0, _reqsize;
@@ -3449,16 +3520,17 @@
 
 	if (reqtype != SDP_ATTR_REQ_INDIVIDUAL && reqtype != SDP_ATTR_REQ_RANGE) {
 		errno = EINVAL;
-		return 0;
+		return NULL;
 	}
 
+	memset(&rsp_concat_buf, 0, sizeof(sdp_buf_t));
+
 	reqbuf = malloc(SDP_REQ_BUFFER_SIZE);
 	rspbuf = malloc(SDP_RSP_BUFFER_SIZE);
 	if (!reqbuf || !rspbuf) {
 		errno = ENOMEM;
 		goto end;
 	}
-	memset((char *) &rsp_concat_buf, 0, sizeof(sdp_buf_t));
 	reqhdr = (sdp_pdu_hdr_t *) reqbuf;
 	reqhdr->pdu_id = SDP_SVC_ATTR_REQ;
 
@@ -3476,7 +3548,7 @@
 	pdata += sizeof(uint16_t);
 
 	// get attr seq PDU form
-	seqlen = gen_attridseq_pdu(pdata, attrids, 
+	seqlen = gen_attridseq_pdu(pdata, attrids,
 		reqtype == SDP_ATTR_REQ_INDIVIDUAL? SDP_UINT16 : SDP_UINT32);
 	if (seqlen == -1) {
 		errno = EINVAL;
@@ -3540,7 +3612,7 @@
 		SDPDBG("sdp_cstate_t length : %d\n", cstate_len);
 
 		/*
-		 * a split response: concatenate intermediate responses 
+		 * a split response: concatenate intermediate responses
 		 * and the last one (which has cstate_len == 0)
 		 */
 		if (cstate_len > 0 || rsp_concat_buf.data_size != 0) {
@@ -3565,14 +3637,11 @@
 		}
 		rec = sdp_extract_pdu(pdata, pdata_len, &scanned);
 	}
-	
+
 end:
-	if (reqbuf)
-		free(reqbuf);
-	if (rsp_concat_buf.data)
-		free(rsp_concat_buf.data);
-	if (rspbuf)
-		free(rspbuf);
+	free(reqbuf);
+	free(rsp_concat_buf.data);
+	free(rspbuf);
 	return rec;
 }
 
@@ -3658,7 +3727,7 @@
 
 /*
  * This function starts an asynchronous service search request.
- * The incomming and outgoing data are stored in the transaction structure 
+ * The incomming and outgoing data are stored in the transaction structure
  * buffers. When there is incomming data the sdp_process function must be
  * called to get the data and handle the continuation state.
  *
@@ -3695,9 +3764,8 @@
 
 	t = session->priv;
 
-	/* check if the buffer is already allocated */
-	if (t->rsp_concat_buf.data)
-		free(t->rsp_concat_buf.data);
+	/* clean possible allocated buffer */
+	free(t->rsp_concat_buf.data);
 	memset(&t->rsp_concat_buf, 0, sizeof(sdp_buf_t));
 
 	if (!t->reqbuf) {
@@ -3743,17 +3811,15 @@
 	return 0;
 end:
 
-	if (t->reqbuf) {
-		free(t->reqbuf);
-		t->reqbuf = NULL;
-	}
+	free(t->reqbuf);
+	t->reqbuf = NULL;
 
 	return -1;
 }
 
 /*
  * This function starts an asynchronous service attribute request.
- * The incomming and outgoing data are stored in the transaction structure 
+ * The incomming and outgoing data are stored in the transaction structure
  * buffers. When there is incomming data the sdp_process function must be
  * called to get the data and handle the continuation state.
  *
@@ -3778,7 +3844,7 @@
  *
  *   sdp_list_t *attrid_list
  *     Singly linked list containing attribute identifiers desired.
- *     Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)  
+ *     Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
  *     or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
  *
  * OUTPUT :
@@ -3799,9 +3865,8 @@
 
 	t = session->priv;
 
-	/* check if the buffer is already allocated */
-	if (t->rsp_concat_buf.data)
-		free(t->rsp_concat_buf.data);
+	/* clean possible allocated buffer */
+	free(t->rsp_concat_buf.data);
 	memset(&t->rsp_concat_buf, 0, sizeof(sdp_buf_t));
 
 	if (!t->reqbuf) {
@@ -3857,10 +3922,8 @@
 	return 0;
 end:
 
-	if (t->reqbuf) {
-		free(t->reqbuf);
-		t->reqbuf = NULL;
-	}
+	free(t->reqbuf);
+	t->reqbuf = NULL;
 
 	return -1;
 }
@@ -3894,7 +3957,7 @@
  *
  *   sdp_list_t *attrid_list
  *     Singly linked list containing attribute identifiers desired.
- *     Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)  
+ *     Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
  *     or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
  *
 
@@ -3914,9 +3977,8 @@
 
 	t = session->priv;
 
-	/* check if the buffer is already allocated */
-	if (t->rsp_concat_buf.data)
-		free(t->rsp_concat_buf.data);
+	/* clean possible allocated buffer */
+	free(t->rsp_concat_buf.data);
 	memset(&t->rsp_concat_buf, 0, sizeof(sdp_buf_t));
 
 	if (!t->reqbuf) {
@@ -3976,10 +4038,8 @@
 	return 0;
 end:
 
-	if (t->reqbuf) {
-		free(t->reqbuf);
-		t->reqbuf = NULL;
-	}
+	free(t->reqbuf);
+	t->reqbuf = NULL;
 
 	return -1;
 }
@@ -4112,7 +4172,7 @@
 			pdata += sizeof(uint16_t); /* point to csrc */
 
 			/* the first csrc contains the sum of partial csrc responses */
-			*pcsrc += bt_get_unaligned((uint16_t *) pdata); 
+			*pcsrc += bt_get_unaligned((uint16_t *) pdata);
 
 			pdata += sizeof(uint16_t); /* point to the first handle */
 			rsp_count = csrc * 4;
@@ -4123,8 +4183,8 @@
 	case SDP_SVC_SEARCH_ATTR_RSP:
 		rsp_count = ntohs(bt_get_unaligned((uint16_t *) pdata));
 		SDPDBG("Attrlist byte count : %d\n", rsp_count);
-	
-		/* 
+
+		/*
 		 * Number of bytes in the AttributeLists parameter(without
 		 * continuation state) + AttributeListsByteCount field size.
 		 */
@@ -4150,7 +4210,7 @@
 
 	SDPDBG("Cstate length : %d\n", pcstate->length);
 
-	/* 
+	/*
 	 * Check out of bound. Continuation state must have at least
 	 * 1 byte: ZERO to indicate that it is not a partial response.
 	 */
@@ -4184,7 +4244,7 @@
 
 		// set the request header's param length
 		reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));
-	
+
 		if (sdp_send_req(session, t->reqbuf, reqsize) < 0) {
 			SDPERR("Error sendind data:%s(%d)", strerror(errno), errno);
 			status = 0xffff;
@@ -4204,8 +4264,7 @@
 			t->cb(pdu_id, status, pdata, size, t->udata);
 	}
 
-	if (rspbuf)
-		free(rspbuf);
+	free(rspbuf);
 
 	return err;
 }
@@ -4235,7 +4294,7 @@
  *
  *   sdp_list_t *attrids
  *     Singly linked list containing attribute identifiers desired.
- *     Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)  
+ *     Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
  *     or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
  *
  * OUTPUT :
@@ -4271,6 +4330,9 @@
 		errno = EINVAL;
 		return -1;
 	}
+
+	memset(&rsp_concat_buf, 0, sizeof(sdp_buf_t));
+
 	reqbuf = malloc(SDP_REQ_BUFFER_SIZE);
 	rspbuf = malloc(SDP_RSP_BUFFER_SIZE);
 	if (!reqbuf || !rspbuf) {
@@ -4279,7 +4341,6 @@
 		goto end;
 	}
 
-	memset((char *)&rsp_concat_buf, 0, sizeof(sdp_buf_t));
 	reqhdr = (sdp_pdu_hdr_t *) reqbuf;
 	reqhdr->pdu_id = SDP_SVC_SEARCH_ATTR_REQ;
 
@@ -4437,12 +4498,9 @@
 		}
 	}
 end:
-	if (rsp_concat_buf.data)
-		free(rsp_concat_buf.data);
-	if (reqbuf)
-		free(reqbuf);
-	if (rspbuf)
-		free(rspbuf);
+	free(rsp_concat_buf.data);
+	free(reqbuf);
+	free(rspbuf);
 	return status;
 }
 
@@ -4473,11 +4531,9 @@
 	t = session->priv;
 
 	if (t) {
-		if (t->reqbuf)
-			free(t->reqbuf);
+		free(t->reqbuf);
 
-		if (t->rsp_concat_buf.data)
-			free(t->rsp_concat_buf.data);
+		free(t->rsp_concat_buf.data);
 
 		free(t);
 	}
@@ -4502,7 +4558,7 @@
 	sa.sun_family = AF_UNIX;
 	strcpy(sa.sun_path, SDP_UNIX_PATH);
 
-	return connect(session->sock, (struct sockaddr *)&sa, sizeof(sa));
+	return connect(session->sock, (struct sockaddr *) &sa, sizeof(sa));
 }
 
 static int sdp_connect_l2cap(const bdaddr_t *src,
@@ -4584,8 +4640,7 @@
 	err = errno;
 	if (session->sock >= 0)
 		close(session->sock);
-	if (session->priv)
-		free(session->priv);
+	free(session->priv);
 	free(session);
 	errno = err;
 
@@ -4601,3 +4656,162 @@
 {
 	return session->tid++;
 }
+
+/*
+ * Set the supported features
+ */
+int sdp_set_supp_feat(sdp_record_t *rec, const sdp_list_t *sf)
+{
+	const sdp_list_t *p, *r;
+	sdp_data_t *feat, *seq_feat;
+	int seqlen, i;
+	void **seqDTDs, **seqVals;
+
+	seqlen = sdp_list_len(sf);
+	seqDTDs = malloc(seqlen * sizeof(void *));
+	if (!seqDTDs)
+		return -1;
+	seqVals = malloc(seqlen * sizeof(void *));
+	if (!seqVals) {
+		free(seqDTDs);
+		return -1;
+	}
+
+	for (p = sf, i = 0; p; p = p->next, i++) {
+		int plen, j;
+		void **dtds, **vals;
+		int *lengths;
+
+		plen = sdp_list_len(p->data);
+		dtds = malloc(plen * sizeof(void *));
+		if (!dtds)
+			goto fail;
+		vals = malloc(plen * sizeof(void *));
+		if (!vals) {
+			free(dtds);
+			goto fail;
+		}
+		lengths = malloc(plen * sizeof(int *));
+		if (!lengths) {
+			free(dtds);
+			free(vals);
+			goto fail;
+		}
+		for (r = p->data, j = 0; r; r = r->next, j++) {
+			sdp_data_t *data = (sdp_data_t*)r->data;
+			dtds[j] = &data->dtd;
+			switch (data->dtd) {
+			case SDP_URL_STR8:
+			case SDP_URL_STR16:
+			case SDP_TEXT_STR8:
+			case SDP_TEXT_STR16:
+				vals[j] = data->val.str;
+				lengths[j] = data->unitSize - sizeof(uint8_t);
+				break;
+			case SDP_ALT8:
+			case SDP_ALT16:
+			case SDP_ALT32:
+			case SDP_SEQ8:
+			case SDP_SEQ16:
+			case SDP_SEQ32:
+				vals[j] = data->val.dataseq;
+				lengths[j] = 0;
+				break;
+			default:
+				vals[j] = &data->val;
+				lengths[j] = 0;
+				break;
+			}
+		}
+		feat = sdp_seq_alloc_with_length(dtds, vals, lengths, plen);
+		free(dtds);
+		free(vals);
+		free(lengths);
+		if (!feat)
+			goto fail;
+		seqDTDs[i] = &feat->dtd;
+		seqVals[i] = feat;
+	}
+	seq_feat = sdp_seq_alloc(seqDTDs, seqVals, seqlen);
+	if (!seq_feat)
+		goto fail;
+	sdp_attr_replace(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST, seq_feat);
+
+	free(seqVals);
+	free(seqDTDs);
+	return 0;
+
+fail:
+	free(seqVals);
+	free(seqDTDs);
+	return -1;
+}
+
+/*
+ * Get the supported features
+ * If an error occurred -1 is returned and errno is set
+ */
+int sdp_get_supp_feat(const sdp_record_t *rec, sdp_list_t **seqp)
+{
+	sdp_data_t *sdpdata, *d;
+	sdp_list_t *tseq;
+	tseq = NULL;
+
+	sdpdata = sdp_data_get(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST);
+
+	if (!sdpdata || sdpdata->dtd < SDP_SEQ8 || sdpdata->dtd > SDP_SEQ32)
+		return sdp_get_uuidseq_attr(rec,
+					SDP_ATTR_SUPPORTED_FEATURES_LIST, seqp);
+
+	for (d = sdpdata->val.dataseq; d; d = d->next) {
+		sdp_data_t *dd;
+		sdp_list_t *subseq;
+
+		if (d->dtd < SDP_SEQ8 || d->dtd > SDP_SEQ32)
+			goto fail;
+
+		subseq = NULL;
+
+		for (dd = d->val.dataseq; dd; dd = dd->next) {
+			sdp_data_t *data;
+			void *val;
+			int length;
+
+			switch (dd->dtd) {
+			case SDP_URL_STR8:
+			case SDP_URL_STR16:
+			case SDP_TEXT_STR8:
+			case SDP_TEXT_STR16:
+				val = dd->val.str;
+				length = dd->unitSize - sizeof(uint8_t);
+				break;
+			case SDP_UINT8:
+			case SDP_UINT16:
+				val = &dd->val;
+				length = 0;
+				break;
+			default:
+				goto fail;
+			}
+
+			data = sdp_data_alloc_with_length(dd->dtd, val, length);
+			if (data)
+				subseq = sdp_list_append(subseq, data);
+		}
+		tseq = sdp_list_append(tseq, subseq);
+	}
+	*seqp = tseq;
+	return 0;
+
+fail:
+	while (tseq) {
+		sdp_list_t * next;
+
+		next = tseq->next;
+		sdp_list_free(tseq, free);
+		tseq = next;
+	}
+	errno = EINVAL;
+	return -1;
+}
+
diff --git a/network/Makefile.am b/network/Makefile.am
deleted file mode 100644
index f5cb320..0000000
--- a/network/Makefile.am
+++ /dev/null
@@ -1,24 +0,0 @@
-
-if NETWORKPLUGIN
-plugindir = $(libdir)/bluetooth/plugins
-
-plugin_LTLIBRARIES = network.la
-
-network_la_SOURCES = main.c manager.h manager.c \
-				server.h server.c bridge.h bridge.c \
-				connection.h connection.c common.h common.c
-
-LDADD = $(top_builddir)/common/libhelper.a \
-		@GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
-endif
-
-AM_LDFLAGS = -module -avoid-version -no-undefined
-
-AM_CFLAGS = -fvisibility=hidden \
-		@BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
-
-INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/src
-
-EXTRA_DIST = network.conf
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/network/bridge.c b/network/bridge.c
deleted file mode 100644
index 995da5c..0000000
--- a/network/bridge.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <net/if.h>
-#include <linux/sockios.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/bnep.h>
-
-#include "logging.h"
-#include "bridge.h"
-#include "common.h"
-
-static int bridge_socket = -1;
-static const char *gn_bridge = NULL;
-static const char *nap_bridge = NULL;
-
-int bridge_init(const char *gn_iface, const char *nap_iface)
-{
-#if 0
-	struct stat st;
-
-	if (stat("/sys/module/bridge", &st) < 0)
-		return -EOPNOTSUPP;
-#endif
-	bridge_socket = socket(AF_INET, SOCK_STREAM, 0);
-	if (bridge_socket < 0) {
-		error("Failed to open bridge socket: %s (%d)",
-				strerror(errno), errno);
-		return -errno;
-	}
-
-	gn_bridge = gn_iface;
-	nap_bridge = nap_iface;
-
-	return 0;
-}
-
-void bridge_cleanup(void)
-{
-	close(bridge_socket);
-
-	bridge_socket = -1;
-}
-
-int bridge_create(int id)
-{
-	int err;
-	const char *name = bridge_get_name(id);
-
-	err = ioctl(bridge_socket, SIOCBRADDBR, name);
-	if (err < 0)
-		return -errno;
-
-	info("bridge %s created", name);
-
-	return 0;
-}
-
-int bridge_remove(int id)
-{
-	int err;
-	const char *name = bridge_get_name(id);
-
-	err = bnep_if_down(name);
-	if (err < 0)
-		return err;
-
-	err = ioctl(bridge_socket, SIOCBRDELBR, name);
-	if (err < 0)
-		return -errno;
-
-	info("bridge %s removed", name);
-
-	return 0;
-}
-
-int bridge_add_interface(int id, const char *dev)
-{
-	struct ifreq ifr;
-	int err;
-	int ifindex = if_nametoindex(dev);
-	const char *name = bridge_get_name(id);
-
-	if (!name)
-		return -EINVAL;
-
-	if (ifindex == 0)
-		return -ENODEV;
-
-	memset(&ifr, 0, sizeof(ifr));
-	strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
-	ifr.ifr_ifindex = ifindex;
-
-	err = ioctl(bridge_socket, SIOCBRADDIF, &ifr);
-	if (err < 0)
-		return err;
-
-	info("bridge %s: interface %s added", name, dev);
-
-	err = bnep_if_up(name, id);
-	if (err < 0)
-		return err;
-
-	return 0;
-}
-
-const char *bridge_get_name(int id)
-{
-	if (id == BNEP_SVC_GN)
-		return gn_bridge;
-
-	if (id == BNEP_SVC_NAP)
-		return nap_bridge;
-
-	return NULL;
-}
diff --git a/network/bridge.h b/network/bridge.h
deleted file mode 100644
index 272afe2..0000000
--- a/network/bridge.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-int bridge_init(const char *gn_iface, const char *nap_iface);
-void bridge_cleanup(void);
-
-int bridge_create(int id);
-int bridge_remove(int id);
-int bridge_add_interface(int id, const char *dev);
-const char *bridge_get_name(int id);
diff --git a/network/common.c b/network/common.c
index 479716a..ef72679 100644
--- a/network/common.c
+++ b/network/common.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -34,6 +34,7 @@
 #include <sys/socket.h>
 #include <sys/wait.h>
 #include <net/if.h>
+#include <linux/sockios.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/l2cap.h>
@@ -41,11 +42,10 @@
 
 #include <glib.h>
 
-#include "logging.h"
+#include "log.h"
 #include "common.h"
 
 static int ctl;
-static GSList *pids;
 
 static struct {
 	const char	*name;		/* Friendly name */
@@ -58,34 +58,6 @@
 	{ NULL }
 };
 
-static const char *panu = NULL;
-static const char *gn = NULL;
-static const char *nap = NULL;
-
-struct bnep_data {
-	char *devname;
-	char *script;
-	int pid;
-};
-
-static gint find_devname(gconstpointer a, gconstpointer b)
-{
-	struct bnep_data *data = (struct bnep_data *) a;
-	const char *devname = b;
-
-	return strcmp(data->devname, devname);
-}
-
-static void script_exited(GPid pid, gint status, gpointer data)
-{
-	if (WIFEXITED(status))
-		debug("%d exited with status %d", pid, WEXITSTATUS(status));
-	else
-		debug("%d was killed by signal %d", pid, WTERMSIG(status));
-
-	g_spawn_close_pid(pid);
-}
-
 uint16_t bnep_service_id(const char *svc)
 {
 	int i;
@@ -131,8 +103,7 @@
 	return NULL;
 }
 
-int bnep_init(const char *panu_script, const char *gn_script,
-		const char *nap_script)
+int bnep_init(void)
 {
 	ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
 
@@ -143,9 +114,6 @@
 		return -err;
 	}
 
-	panu = panu_script;
-	gn = gn_script;
-	nap = nap_script;
 	return 0;
 }
 
@@ -219,155 +187,76 @@
 	return 0;
 }
 
-static void bnep_setup(gpointer data)
+int bnep_if_up(const char *devname)
 {
-}
-
-static int bnep_exec(const char **argv)
-{
-	int pid;
-	GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH;
-
-	if (!g_spawn_async(NULL, (char **) argv, NULL, flags, bnep_setup, NULL,
-				&pid, NULL)) {
-		error("Unable to execute %s %s", argv[0], argv[1]);
-		return -EINVAL;
-	}
-
-	return pid;
-}
-
-int bnep_if_up(const char *devname, uint16_t id)
-{
-	int sd, err;
 	struct ifreq ifr;
-	const char *argv[5];
-	struct bnep_data *bnep = NULL;
-	GSList *l;
+	int sk, err;
 
-	/* Check if a script is running */
-	l = g_slist_find_custom(pids, devname, find_devname);
-	if (l) {
-		bnep = l->data;
+	sk = socket(AF_INET, SOCK_DGRAM, 0);
 
-		if (bnep->script && !strcmp(bnep->script, "avahi-autoipd")) {
-			argv[0] = bnep->script;
-			argv[1] = devname;
-			argv[2] = "--refresh";
-			argv[3] = NULL;
-
-			bnep->pid = bnep_exec(argv);
-		}
-	}
-
-	sd = socket(AF_INET, SOCK_DGRAM, 0);
 	memset(&ifr, 0, sizeof(ifr));
 	strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
 
 	ifr.ifr_flags |= IFF_UP;
 	ifr.ifr_flags |= IFF_MULTICAST;
 
-	if ((ioctl(sd, SIOCSIFFLAGS, (caddr_t) &ifr)) < 0) {
-		err = errno;
-		error("Could not bring up %s. %s(%d)", devname, strerror(err),
-			err);
-		return -err;
+	err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr);
+
+	close(sk);
+
+	if (err < 0) {
+		error("Could not bring up %s", devname);
+		return err;
 	}
 
-	if (bnep)
-		return bnep->pid;
-
-	bnep = g_new0(struct bnep_data, 1);
-	bnep->devname = g_strdup(devname);
-
-	if (!id)
-		goto done;
-
-	if (id == BNEP_SVC_PANU)
-		bnep->script = g_strdup(panu);
-	else if (id == BNEP_SVC_GN)
-		bnep->script = g_strdup(gn);
-	else
-		bnep->script = g_strdup(nap);
-
-	if (!bnep->script)
-		goto done;
-
-	argv[0] = bnep->script;
-	argv[1] = devname;
-
-	if (!strcmp(bnep->script, "avahi-autoipd")) {
-		argv[2] = "--no-drop-root";
-		argv[3] = "--no-chroot";
-		argv[4] = NULL;
-	} else
-		argv[2] = NULL;
-
-	bnep->pid = bnep_exec(argv);
-	g_child_watch_add(bnep->pid, script_exited, bnep);
-
-done:
-	pids = g_slist_append(pids, bnep);
-
-	return bnep->pid;
+	return 0;
 }
 
 int bnep_if_down(const char *devname)
 {
-	int sd, err, pid;
 	struct ifreq ifr;
-	struct bnep_data *bnep;
-	GSList *l;
-	GSpawnFlags flags;
-	const char *argv[4];
+	int sk, err;
 
-	l = g_slist_find_custom(pids, devname, find_devname);
-	if (!l)
-		return 0;
+	sk = socket(AF_INET, SOCK_DGRAM, 0);
 
-	bnep = l->data;
-
-	if (!bnep->pid)
-		goto done;
-
-	if (bnep->script && !strcmp(bnep->script, "avahi-autoipd")) {
-		argv[0] = bnep->script;
-		argv[1] = devname;
-		argv[2] = "--kill";
-		argv[3] = NULL;
-
-		flags = G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH;
-		g_spawn_async(NULL, (char **) argv, NULL, flags, bnep_setup,
-				(gpointer) devname, &pid, NULL);
-
-		goto done;
-	}
-
-	/* Kill script */
-	err = kill(bnep->pid, SIGTERM);
-	if (err < 0)
-		error("kill(%d, SIGTERM): %s (%d)", bnep->pid,
-			strerror(errno), errno);
-
-done:
-	sd = socket(AF_INET, SOCK_DGRAM, 0);
 	memset(&ifr, 0, sizeof(ifr));
 	strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
 
 	ifr.ifr_flags &= ~IFF_UP;
 
 	/* Bring down the interface */
-	ioctl(sd, SIOCSIFFLAGS, (caddr_t) &ifr);
+	err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr);
 
-	pids = g_slist_remove(pids, bnep);
+	close(sk);
 
-	if (bnep->devname)
-		g_free(bnep->devname);
+	return 0;
+}
 
-	if (bnep->script)
-		g_free(bnep->script);
+int bnep_add_to_bridge(const char *devname, const char *bridge)
+{
+	int ifindex = if_nametoindex(devname);
+	struct ifreq ifr;
+	int sk, err;
 
-	g_free(bnep);
+	if (!devname || !bridge)
+		return -EINVAL;
+
+	sk = socket(AF_INET, SOCK_STREAM, 0);
+	if (sk < 0)
+		return -1;
+
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
+	ifr.ifr_ifindex = ifindex;
+
+	err = ioctl(sk, SIOCBRADDIF, &ifr);
+
+	close(sk);
+
+	if (err < 0)
+		return err;
+
+	info("bridge %s: interface %s added", bridge, devname);
 
 	return 0;
 }
diff --git a/network/common.h b/network/common.h
index 424d618..fefb754 100644
--- a/network/common.h
+++ b/network/common.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -26,8 +26,7 @@
 #define GN_UUID		"00001117-0000-1000-8000-00805f9b34fb"
 #define BNEP_SVC_UUID	"0000000f-0000-1000-8000-00805f9b34fb"
 
-int bnep_init(const char *panu_script, const char *gn_script,
-		const char *nap_script);
+int bnep_init(void);
 int bnep_cleanup(void);
 
 uint16_t bnep_service_id(const char *svc);
@@ -38,5 +37,6 @@
 int bnep_kill_all_connections(void);
 
 int bnep_connadd(int sk, uint16_t role, char *dev);
-int bnep_if_up(const char *devname, uint16_t id);
+int bnep_if_up(const char *devname);
 int bnep_if_down(const char *devname);
+int bnep_add_to_bridge(const char *devname, const char *bridge);
diff --git a/network/connection.c b/network/connection.c
index 7a82467..a255c79 100644
--- a/network/connection.c
+++ b/network/connection.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -38,7 +38,7 @@
 #include <glib.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 #include "glib-helper.h"
 #include "btio.h"
 #include "dbus-common.h"
@@ -82,7 +82,6 @@
 } __attribute__ ((packed));
 
 static DBusConnection *connection = NULL;
-static const char *prefix = NULL;
 static GSList *peers = NULL;
 
 static struct network_peer *find_peer(GSList *list, const char *path)
@@ -157,7 +156,7 @@
 					NETWORK_PEER_INTERFACE, "Connected",
 					DBUS_TYPE_BOOLEAN, &connected);
 		emit_property_changed(connection, nc->peer->path,
-					NETWORK_PEER_INTERFACE, "Device",
+					NETWORK_PEER_INTERFACE, "Interface",
 					DBUS_TYPE_STRING, &property);
 		emit_property_changed(connection, nc->peer->path,
 					NETWORK_PEER_INTERFACE, "UUID",
@@ -174,8 +173,8 @@
 
 	bnep_if_down(nc->dev);
 	nc->state = DISCONNECTED;
-	memset(nc->dev, 0, 16);
-	strncpy(nc->dev, prefix, sizeof(nc->dev) - 1);
+	memset(nc->dev, 0, sizeof(nc->dev));
+	strcpy(nc->dev, "bnep%d");
 
 	return FALSE;
 }
@@ -289,7 +288,7 @@
 		goto failed;
 	}
 
-	bnep_if_up(nc->dev, nc->id);
+	bnep_if_up(nc->dev);
 	pdev = nc->dev;
 	uuid = bnep_uuid(nc->id);
 
@@ -302,7 +301,7 @@
 				NETWORK_PEER_INTERFACE, "Connected",
 				DBUS_TYPE_BOOLEAN, &connected);
 	emit_property_changed(connection, nc->peer->path,
-				NETWORK_PEER_INTERFACE, "Device",
+				NETWORK_PEER_INTERFACE, "Interface",
 				DBUS_TYPE_STRING, &pdev);
 	emit_property_changed(connection, nc->peer->path,
 				NETWORK_PEER_INTERFACE, "UUID",
@@ -502,9 +501,9 @@
 	connected = nc ? TRUE : FALSE;
 	dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &connected);
 
-	/* Device */
+	/* Interface */
 	property = nc ? nc->dev : "";
-	dict_append_entry(&dict, "Device", DBUS_TYPE_STRING, &property);
+	dict_append_entry(&dict, "Interface", DBUS_TYPE_STRING, &property);
 
 	/* UUID */
 	property = nc ? bnep_uuid(nc->id) : "";
@@ -539,7 +538,7 @@
 {
 	struct network_peer *peer = data;
 
-	debug("Unregistered interface %s on path %s",
+	DBG("Unregistered interface %s on path %s",
 		NETWORK_PEER_INTERFACE, peer->path);
 
 	peers = g_slist_remove(peers, peer);
@@ -603,7 +602,7 @@
 		return NULL;
 	}
 
-	debug("Registered interface %s on path %s",
+	DBG("Registered interface %s on path %s",
 		NETWORK_PEER_INTERFACE, path);
 
 	return peer;
@@ -632,8 +631,8 @@
 
 	nc = g_new0(struct network_conn, 1);
 	nc->id = id;
-	memset(nc->dev, 0, 16);
-	strncpy(nc->dev, prefix, sizeof(nc->dev) - 1);
+	memset(nc->dev, 0, sizeof(nc->dev));
+	strcpy(nc->dev, "bnep%d");
 	nc->state = DISCONNECTED;
 	nc->peer = peer;
 
@@ -642,17 +641,15 @@
 	return 0;
 }
 
-int connection_init(DBusConnection *conn, const char *iface_prefix)
+int connection_init(DBusConnection *conn)
 {
 	connection = dbus_connection_ref(conn);
-	prefix = iface_prefix;
 
 	return 0;
 }
 
-void connection_exit()
+void connection_exit(void)
 {
 	dbus_connection_unref(connection);
 	connection = NULL;
-	prefix = NULL;
 }
diff --git a/network/connection.h b/network/connection.h
index ba1fdf6..5ea4147 100644
--- a/network/connection.h
+++ b/network/connection.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -21,8 +21,8 @@
  *
  */
 
-int connection_init(DBusConnection *conn, const char *iface_prefix);
-void connection_exit();
+int connection_init(DBusConnection *conn);
+void connection_exit(void);
 int connection_register(struct btd_device *device, const char *path,
 			bdaddr_t *src, bdaddr_t *dst, uint16_t id);
 void connection_unregister(const char *path, uint16_t id);
diff --git a/network/main.c b/network/main.c
index 97838a2..88e77ee 100644
--- a/network/main.c
+++ b/network/main.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/network/manager.c b/network/manager.c
index bd52279..c910148 100644
--- a/network/manager.c
+++ b/network/manager.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -33,156 +33,43 @@
 #include <glib.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 
 #include "adapter.h"
 #include "device.h"
-#include "bridge.h"
 #include "manager.h"
 #include "common.h"
 #include "connection.h"
 #include "server.h"
 
-#define IFACE_PREFIX "bnep%d"
-#define GN_IFACE  "pan0"
-#define NAP_IFACE "pan1"
-
-static struct btd_adapter_driver network_panu_server_driver;
-static struct btd_adapter_driver network_gn_server_driver;
-static struct btd_adapter_driver network_nap_server_driver;
-
 static DBusConnection *connection = NULL;
 
-static struct network_conf {
-	gboolean connection_enabled;
-	gboolean server_enabled;
-	gboolean security;
-	char *iface_prefix;
-	char *panu_script;
-	char *gn_script;
-	char *nap_script;
-	char *gn_iface;
-	char *nap_iface;
-} conf = {
-	.connection_enabled = TRUE,
-	.server_enabled = TRUE,
-	.security = TRUE,
-	.iface_prefix = NULL,
-	.panu_script = NULL,
-	.gn_script = NULL,
-	.nap_script = NULL,
-	.gn_iface = NULL,
-	.nap_iface = NULL
-};
-
-static void conf_cleanup(void)
-{
-	g_free(conf.iface_prefix);
-	g_free(conf.panu_script);
-	g_free(conf.gn_script);
-	g_free(conf.nap_script);
-	g_free(conf.gn_iface);
-	g_free(conf.nap_iface);
-}
+static gboolean conf_security = TRUE;
 
 static void read_config(const char *file)
 {
 	GKeyFile *keyfile;
 	GError *err = NULL;
-	char **disabled;
 
 	keyfile = g_key_file_new();
 
 	if (!g_key_file_load_from_file(keyfile, file, 0, &err)) {
-		error("Parsing %s failed: %s", file, err->message);
 		g_clear_error(&err);
 		goto done;
 	}
 
-	disabled = g_key_file_get_string_list(keyfile, "General",
-						"Disable", NULL, &err);
-	if (err) {
-		debug("%s: %s", file, err->message);
-		g_clear_error(&err);
-	} else {
-		int i;
-		for (i = 0; disabled[i] != NULL; i++) {
-			if (g_str_equal(disabled[i], "Connection"))
-				conf.connection_enabled = FALSE;
-			else if (g_str_equal(disabled[i], "Server"))
-				conf.server_enabled = FALSE;
-		}
-		g_strfreev(disabled);
-	}
-
-	conf.security = !g_key_file_get_boolean(keyfile, "General",
+	conf_security = !g_key_file_get_boolean(keyfile, "General",
 						"DisableSecurity", &err);
 	if (err) {
-		debug("%s: %s", file, err->message);
-		g_clear_error(&err);
-	}
-
-#if 0
-	conf.panu_script = g_key_file_get_string(keyfile, "PANU Role",
-						"Script", &err);
-	if (err) {
-		debug("%s: %s", file, err->message);
-		g_clear_error(&err);
-	}
-
-	conf.gn_script = g_key_file_get_string(keyfile, "GN Role",
-						"Script", &err);
-	if (err) {
-		debug("%s: %s", file, err->message);
-		g_clear_error(&err);
-	}
-
-	conf.nap_script = g_key_file_get_string(keyfile, "NAP Role",
-						"Script", &err);
-	if (err) {
-		debug("%s: %s", file, err->message);
-		g_clear_error(&err);
-	}
-#endif
-
-	conf.iface_prefix = g_key_file_get_string(keyfile, "PANU Role",
-						"Interface", &err);
-	if (err) {
-		debug("%s: %s", file, err->message);
-		g_clear_error(&err);
-	}
-
-	conf.gn_iface = g_key_file_get_string(keyfile, "GN Role",
-						"Interface", &err);
-	if (err) {
-		debug("%s: %s", file, err->message);
-		g_clear_error(&err);
-	}
-
-	conf.nap_iface = g_key_file_get_string(keyfile, "NAP Role",
-						"Interface", &err);
-	if (err) {
-		debug("%s: %s", file, err->message);
+		DBG("%s: %s", file, err->message);
 		g_clear_error(&err);
 	}
 
 done:
 	g_key_file_free(keyfile);
 
-	if (!conf.iface_prefix)
-		conf.iface_prefix = g_strdup(IFACE_PREFIX);
-
-	if (!conf.gn_iface)
-		conf.gn_iface = g_strdup(GN_IFACE);
-	if (!conf.nap_iface)
-		conf.nap_iface = g_strdup(NAP_IFACE);
-
-	debug("Config options: InterfacePrefix=%s, PANU_Script=%s, "
-		"GN_Script=%s, NAP_Script=%s, GN_Interface=%s, "
-		"NAP_Interface=%s, Security=%s",
-		conf.iface_prefix, conf.panu_script, conf.gn_script,
-		conf.nap_script, conf.gn_iface, conf.nap_iface,
-		conf.security ? "true" : "false");
+	DBG("Config options: Security=%s",
+				conf_security ? "true" : "false");
 }
 
 static int network_probe(struct btd_device *device, GSList *uuids, uint16_t id)
@@ -238,55 +125,22 @@
 	network_remove(device, BNEP_SVC_NAP);
 }
 
-static int network_server_probe(struct btd_adapter *adapter, uint16_t id)
+static int network_server_probe(struct btd_adapter *adapter)
 {
 	const gchar *path = adapter_get_path(adapter);
 
 	DBG("path %s", path);
 
-	if (!conf.server_enabled)
-		return 0;
-
-	return server_register(adapter, id);
+	return server_register(adapter);
 }
 
-static void network_server_remove(struct btd_adapter *adapter, uint16_t id)
+static void network_server_remove(struct btd_adapter *adapter)
 {
 	const gchar *path = adapter_get_path(adapter);
 
 	DBG("path %s", path);
 
-	server_unregister(adapter, id);
-}
-
-static int panu_server_probe(struct btd_adapter *adapter)
-{
-	return network_server_probe(adapter, BNEP_SVC_PANU);
-}
-
-static int gn_server_probe(struct btd_adapter *adapter)
-{
-	return network_server_probe(adapter, BNEP_SVC_GN);
-}
-
-static int nap_server_probe(struct btd_adapter *adapter)
-{
-	return network_server_probe(adapter, BNEP_SVC_NAP);
-}
-
-static void panu_server_remove(struct btd_adapter *adapter)
-{
-	network_server_remove(adapter, BNEP_SVC_PANU);
-}
-
-static void gn_server_remove(struct btd_adapter *adapter)
-{
-	network_server_remove(adapter, BNEP_SVC_GN);
-}
-
-static void nap_server_remove(struct btd_adapter *adapter)
-{
-	network_server_remove(adapter, BNEP_SVC_NAP);
+	server_unregister(adapter);
 }
 
 static struct btd_device_driver network_panu_driver = {
@@ -310,29 +164,17 @@
 	.remove	= nap_remove,
 };
 
-static struct btd_adapter_driver network_panu_server_driver = {
-	.name	= "network-panu-server",
-	.probe	= panu_server_probe,
-	.remove	= panu_server_remove,
-};
-
-static struct btd_adapter_driver network_gn_server_driver = {
-	.name	= "network-gn-server",
-	.probe	= gn_server_probe,
-	.remove	= gn_server_remove,
-};
-
-static struct btd_adapter_driver network_nap_server_driver = {
-	.name	= "network-nap-server",
-	.probe	= nap_server_probe,
-	.remove	= nap_server_remove,
+static struct btd_adapter_driver network_server_driver = {
+	.name	= "network-server",
+	.probe	= network_server_probe,
+	.remove	= network_server_remove,
 };
 
 int network_manager_init(DBusConnection *conn)
 {
 	read_config(CONFIGDIR "/network.conf");
 
-	if (bnep_init(conf.panu_script, conf.gn_script, conf.nap_script)) {
+	if (bnep_init()) {
 		error("Can't init bnep module");
 		return -1;
 	}
@@ -343,20 +185,14 @@
 	 * (setup connection request) contains the destination service
 	 * field that defines which service the source is connecting to.
 	 */
-	if (bridge_init(conf.gn_iface, conf.nap_iface) < 0) {
-		error("Can't init bridge module");
-		return -1;
-	}
 
-	if (server_init(conn, conf.iface_prefix, conf.security) < 0)
+	if (server_init(conn, conf_security) < 0)
 		return -1;
 
-	/* Register PANU, GN and NAP servers if they don't exist */
-	btd_register_adapter_driver(&network_panu_server_driver);
-	btd_register_adapter_driver(&network_gn_server_driver);
-	btd_register_adapter_driver(&network_nap_server_driver);
+	/* Register network server if it doesn't exist */
+	btd_register_adapter_driver(&network_server_driver);
 
-	if (connection_init(conn, conf.iface_prefix) < 0)
+	if (connection_init(conn) < 0)
 		return -1;
 
 	btd_register_device_driver(&network_panu_driver);
@@ -370,24 +206,18 @@
 
 void network_manager_exit(void)
 {
-	if (conf.server_enabled)
-		server_exit();
+	server_exit();
 
-	if (conf.connection_enabled) {
-		btd_unregister_device_driver(&network_panu_driver);
-		btd_unregister_device_driver(&network_gn_driver);
-		btd_unregister_device_driver(&network_nap_driver);
-		connection_exit();
-	}
+	btd_unregister_device_driver(&network_panu_driver);
+	btd_unregister_device_driver(&network_gn_driver);
+	btd_unregister_device_driver(&network_nap_driver);
 
-	btd_unregister_adapter_driver(&network_panu_server_driver);
-	btd_unregister_adapter_driver(&network_gn_server_driver);
-	btd_unregister_adapter_driver(&network_nap_server_driver);
+	connection_exit();
+
+	btd_unregister_adapter_driver(&network_server_driver);
 
 	dbus_connection_unref(connection);
 	connection = NULL;
 
 	bnep_cleanup();
-	bridge_cleanup();
-	conf_cleanup();
 }
diff --git a/network/manager.h b/network/manager.h
index e26d60b..27bc13f 100644
--- a/network/manager.h
+++ b/network/manager.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/network/network.conf b/network/network.conf
index 4c24c8d..5f11639 100644
--- a/network/network.conf
+++ b/network/network.conf
@@ -1,33 +1,6 @@
 # Configuration file for the network service
 
-# This section contains options which are not specific to any
-# particular interface
 [General]
 
 # Disable link encryption: default=false
 #DisableSecurity=true
-
-[PANU Role]
-
-# Network interface name for PANU for connections. default:bnep%d
-# (up to 16 characters)
-#Interface=
-
-# PAN user connection interface up script. default:none
-Script=avahi-autoipd
-
-[GN Role]
-
-# Network Interface name for Group Network server. default:pan0
-#Interface=
-
-# Group Network connection interface up script. default:none
-Script=avahi-autoipd
-
-[NAP Role]
-
-# Network Interface name for Network Access Point server. default:pan1
-#Interface=
-
-# Network Access Point connection interface up script. default:none
-Script=dhclient
diff --git a/network/server.c b/network/server.c
index 23d3b64..9a5bd38 100644
--- a/network/server.c
+++ b/network/server.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -44,19 +44,16 @@
 #include "../src/dbus-common.h"
 #include "../src/adapter.h"
 
-#include "logging.h"
+#include "log.h"
 #include "error.h"
 #include "sdpd.h"
 #include "btio.h"
 #include "glib-helper.h"
 
-#include "bridge.h"
 #include "common.h"
 #include "server.h"
 
-#define NETWORK_PEER_INTERFACE "org.bluez.NetworkPeer"
-#define NETWORK_HUB_INTERFACE "org.bluez.NetworkHub"
-#define NETWORK_ROUTER_INTERFACE "org.bluez.NetworkRouter"
+#define NETWORK_SERVER_INTERFACE "org.bluez.NetworkServer"
 #define SETUP_TIMEOUT		1
 
 /* Pending Authorization */
@@ -78,17 +75,16 @@
 	bdaddr_t	src;		/* Bluetooth Local Address */
 	char		*iface;		/* DBus interface */
 	char		*name;		/* Server service name */
-	char		*range;		/* IP Address range */
-	gboolean	enable;		/* Enable flag */
+	char		*bridge;	/* Bridge name */
 	uint32_t	record_id;	/* Service record id */
 	uint16_t	id;		/* Service class identifier */
 	GSList		*sessions;	/* Active connections */
 	struct network_adapter *na;	/* Adapter reference */
+	guint		watch_id;	/* Client service watch */
 };
 
 static DBusConnection *connection = NULL;
 static GSList *adapters = NULL;
-static const char *prefix = NULL;
 static gboolean security = TRUE;
 
 static struct network_adapter *find_adapter(GSList *list,
@@ -145,7 +141,7 @@
 	uint16_t security_desc = (security ? 0x0001 : 0x0000);
 	uint16_t net_access_type = 0xfffe;
 	uint32_t max_net_access_rate = 0;
-	const char *desc = "BlueZ PAN service";
+	const char *desc = "Network service";
 	sdp_record_t *record;
 
 	record = sdp_record_alloc();
@@ -276,15 +272,10 @@
 				uint16_t dst_role)
 {
 	char devname[16];
-	const char *bridge;
 	int err, nsk;
 
-	/* Server can be disabled in the meantime */
-	if (ns->enable == FALSE)
-		return -EPERM;
-
-	memset(devname, 0, 16);
-	strncpy(devname, prefix, sizeof(devname) - 1);
+	memset(devname, 0, sizeof(devname));
+	strcpy(devname, "bnep%d");
 
 	nsk = g_io_channel_unix_get_fd(session->io);
 	err = bnep_connadd(nsk, dst_role, devname);
@@ -293,18 +284,13 @@
 
 	info("Added new connection: %s", devname);
 
-	bridge = bridge_get_name(ns->id);
-	if (bridge) {
-		if (bridge_add_interface(ns->id, devname) < 0) {
-			error("Can't add %s to the bridge %s: %s(%d)",
-					devname, bridge, strerror(errno),
-					errno);
-			return -EPERM;
-		}
+	if (bnep_add_to_bridge(devname, ns->bridge) < 0) {
+		error("Can't add %s to the bridge %s: %s(%d)",
+				devname, ns->bridge, strerror(errno), errno);
+		return -EPERM;
+	}
 
-		bnep_if_up(devname, 0);
-	} else
-		bnep_if_up(devname, ns->id);
+	bnep_if_up(devname);
 
 	ns->sessions = g_slist_append(ns->sessions, session);
 
@@ -322,8 +308,8 @@
 		return BNEP_CONN_INVALID_SRC;
 	case BNEP_SVC_PANU:
 		if (src_role == BNEP_SVC_PANU ||
-			src_role == BNEP_SVC_GN ||
-			src_role == BNEP_SVC_NAP)
+				src_role == BNEP_SVC_GN ||
+				src_role == BNEP_SVC_NAP)
 			return 0;
 
 		return BNEP_CONN_INVALID_SRC;
@@ -422,11 +408,21 @@
 		goto reply;
 
 	ns = find_server(na->servers, dst_role);
-	if (!ns || ns->enable == FALSE) {
+	if (!ns) {
 		error("Server unavailable: (0x%x)", dst_role);
 		goto reply;
 	}
 
+	if (!ns->record_id) {
+		error("Service record not available");
+		goto reply;
+	}
+
+	if (!ns->bridge) {
+		error("Bridge interface not configured");
+		goto reply;
+	}
+
 	if (server_connadd(ns, na->setup, dst_role) < 0)
 		goto reply;
 
@@ -484,6 +480,7 @@
 static void confirm_event(GIOChannel *chan, gpointer user_data)
 {
 	struct network_adapter *na = user_data;
+	struct network_server *ns;
 	int perr;
 	bdaddr_t src, dst;
 	char address[18];
@@ -500,13 +497,23 @@
 		goto drop;
 	}
 
-	debug("BNEP: incoming connect from %s", address);
+	DBG("BNEP: incoming connect from %s", address);
 
 	if (na->setup) {
 		error("Refusing connect from %s: setup in progress", address);
 		goto drop;
 	}
 
+	ns = find_server(na->servers, BNEP_SVC_NAP);
+	if (!ns)
+		goto drop;
+
+	if (!ns->record_id)
+		goto drop;
+
+	if (!ns->bridge)
+		goto drop;
+
 	na->setup = g_new0(struct network_session, 1);
 	bacpy(&na->setup->dst, &dst);
 	na->setup->io = g_io_channel_ref(chan);
@@ -526,24 +533,16 @@
 	g_io_channel_shutdown(chan, TRUE, NULL);
 }
 
-int server_init(DBusConnection *conn, const char *iface_prefix,
-		gboolean secure)
+int server_init(DBusConnection *conn, gboolean secure)
 {
 	security = secure;
 	connection = dbus_connection_ref(conn);
-	prefix = iface_prefix;
-
-	if (bridge_create(BNEP_SVC_GN) < 0)
-		error("Can't create GN bridge");
 
 	return 0;
 }
 
-void server_exit()
+void server_exit(void)
 {
-	if (bridge_remove(BNEP_SVC_GN) < 0)
-		error("Can't remove GN bridge");
-
 	dbus_connection_unref(connection);
 	connection = NULL;
 }
@@ -564,7 +563,7 @@
 		return 0;
 	}
 
-	debug("register_server_record: got record id 0x%x", record->handle);
+	DBG("got record id 0x%x", record->handle);
 
 	return record->handle;
 }
@@ -583,164 +582,79 @@
 				description);
 }
 
-static DBusMessage *enable(DBusConnection *conn,
-			DBusMessage *msg, void *data)
+static void server_disconnect(DBusConnection *conn, void *user_data)
 {
-	struct network_server *ns = data;
-	DBusMessage *reply;
+	struct network_server *ns = user_data;
 
-	if (ns->enable)
-		return g_dbus_create_error(msg, ERROR_INTERFACE
-						".AlreadyExist",
-						"Server already enabled");
+	ns->watch_id = 0;
 
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
-		return NULL;
-
-	/* Add the service record */
-	ns->record_id = register_server_record(ns);
-	if (!ns->record_id) {
-		dbus_message_unref(reply);
-		return failed(msg, "Service record registration failed");
-	}
-
-	ns->enable = TRUE;
-
-	return reply;
-}
-
-static DBusMessage *disable(DBusConnection *conn,
-				DBusMessage *msg, void *data)
-{
-	struct network_server *ns = data;
-	DBusMessage *reply;
-
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
-		return NULL;
-
-	if (!ns->enable)
-		return failed(msg, "Not enabled");
-
-	/* Remove the service record */
 	if (ns->record_id) {
 		remove_record_from_server(ns->record_id);
 		ns->record_id = 0;
 	}
 
-	ns->enable = FALSE;
-
-	g_slist_foreach(ns->sessions, (GFunc) session_free, NULL);
-	g_slist_free(ns->sessions);
-
-	return reply;
+	g_free(ns->bridge);
+	ns->bridge = NULL;
 }
 
-static DBusMessage *set_name(DBusConnection *conn, DBusMessage *msg,
-				const char *name, void *data)
-{
-	struct network_server *ns = data;
-	DBusMessage *reply;
-
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
-		return NULL;
-
-	if (!name || (strlen(name) == 0))
-		return invalid_arguments(msg, "Invalid name");
-
-	if (ns->name)
-		g_free(ns->name);
-	ns->name = g_strdup(name);
-
-	if (ns->enable && ns->record_id) {
-		uint32_t handle = register_server_record(ns);
-		if (!handle) {
-			dbus_message_unref(reply);
-			return failed(msg,
-				"Service record attribute update failed");
-		}
-
-		remove_record_from_server(ns->record_id);
-		ns->record_id = handle;
-	}
-
-	return reply;
-}
-
-static DBusMessage *get_properties(DBusConnection *conn,
+static DBusMessage *register_server(DBusConnection *conn,
 				DBusMessage *msg, void *data)
 {
 	struct network_server *ns = data;
 	DBusMessage *reply;
-	DBusMessageIter iter;
-	DBusMessageIter dict;
-	const char *uuid;
+	const char *uuid, *bridge;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &uuid,
+				DBUS_TYPE_STRING, &bridge, DBUS_TYPE_INVALID))
+		return NULL;
+
+	if (g_strcmp0(uuid, "nap"))
+		return failed(msg, "Invalid UUID");
+
+	if (ns->record_id)
+		return failed(msg, "Already registered");
 
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
 		return NULL;
 
-	dbus_message_iter_init_append(reply, &iter);
+	ns->record_id = register_server_record(ns);
+	if (!ns->record_id)
+		return failed(msg, "SDP record registration failed");
 
-	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+	g_free(ns->bridge);
+	ns->bridge = g_strdup(bridge);
 
-	dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &ns->name);
-
-	uuid = bnep_uuid(ns->id);
-	dict_append_entry(&dict, "Uuid", DBUS_TYPE_STRING, &uuid);
-
-	dict_append_entry(&dict, "Enabled", DBUS_TYPE_BOOLEAN, &ns->enable);
-
-	dbus_message_iter_close_container(&iter, &dict);
+	ns->watch_id = g_dbus_add_disconnect_watch(conn,
+					dbus_message_get_sender(msg),
+					server_disconnect, ns, NULL);
 
 	return reply;
 }
 
-static DBusMessage *set_property(DBusConnection *conn,
+static DBusMessage *unregister_server(DBusConnection *conn,
 					DBusMessage *msg, void *data)
 {
-	DBusMessageIter iter;
-	DBusMessageIter sub;
-	const char *property;
+	struct network_server *ns = data;
+	DBusMessage *reply;
+	const char *uuid;
 
-	if (!dbus_message_iter_init(msg, &iter))
-		return invalid_arguments(msg, "Not a dict");
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &uuid,
+							DBUS_TYPE_INVALID))
+		return NULL;
 
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-		return invalid_arguments(msg, "Key not a string");
+	if (g_strcmp0(uuid, "nap"))
+		return failed(msg, "Invalid UUID");
 
-	dbus_message_iter_get_basic(&iter, &property);
-	dbus_message_iter_next(&iter);
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return NULL;
 
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
-		return invalid_arguments(msg, "Value not a variant");
-	dbus_message_iter_recurse(&iter, &sub);
+	g_dbus_remove_watch(conn, ns->watch_id);
 
-	if (g_str_equal("Name", property)) {
-		const char *name;
+	server_disconnect(conn, ns);
 
-		if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
-			return invalid_arguments(msg, "Value not string");
-		dbus_message_iter_get_basic(&sub, &name);
-
-		return set_name(conn, msg, name, data);
-	} else if (g_str_equal("Enabled", property)) {
-		gboolean enabled;
-
-		if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
-			return invalid_arguments(msg, "Value not boolean");
-		dbus_message_iter_get_basic(&sub, &enabled);
-
-		return enabled ? enable(conn, msg, data) :
-				disable(conn, msg, data);
-	}
-
-	return invalid_arguments(msg, "Property does not exist");
+	return reply;
 }
 
 static void adapter_free(struct network_adapter *na)
@@ -764,14 +678,9 @@
 	if (ns->record_id)
 		remove_record_from_server(ns->record_id);
 
-	if (ns->iface)
-		g_free(ns->iface);
-
-	if (ns->name)
-		g_free(ns->name);
-
-	if (ns->range)
-		g_free(ns->range);
+	g_free(ns->iface);
+	g_free(ns->name);
+	g_free(ns->bridge);
 
 	if (ns->sessions) {
 		g_slist_foreach(ns->sessions, (GFunc) session_free, NULL);
@@ -786,7 +695,7 @@
 	struct network_server *ns = data;
 	struct network_adapter *na = ns->na;
 
-	debug("Unregistered interface %s on path %s",
+	DBG("Unregistered interface %s on path %s",
 		ns->iface, adapter_get_path(na->adapter));
 
 	na->servers = g_slist_remove(na->servers, ns);
@@ -800,13 +709,8 @@
 }
 
 static GDBusMethodTable server_methods[] = {
-	{ "SetProperty",	"sv",	"",	set_property },
-	{ "GetProperties",	"",	"a{sv}",get_properties },
-	{ }
-};
-
-static GDBusSignalTable server_signals[] = {
-	{ "PropertyChanged",		"sv"		},
+	{ "Register",	"ss",	"",	register_server		},
+	{ "Unregister",	"s",	"",	unregister_server	},
 	{ }
 };
 
@@ -840,7 +744,7 @@
 	return na;
 }
 
-int server_register(struct btd_adapter *adapter, uint16_t id)
+int server_register(struct btd_adapter *adapter)
 {
 	struct network_adapter *na;
 	struct network_server *ns;
@@ -854,31 +758,19 @@
 		adapters = g_slist_append(adapters, na);
 	}
 
-	ns = find_server(na->servers, id);
+	ns = find_server(na->servers, BNEP_SVC_NAP);
 	if (ns)
 		return 0;
 
 	ns = g_new0(struct network_server, 1);
 
-	switch (id) {
-	case BNEP_SVC_PANU:
-		ns->iface = g_strdup(NETWORK_PEER_INTERFACE);
-		ns->name = g_strdup("BlueZ PANU service");
-		break;
-	case BNEP_SVC_GN:
-		ns->iface = g_strdup(NETWORK_HUB_INTERFACE);
-		ns->name = g_strdup("BlueZ GN service");
-		break;
-	case BNEP_SVC_NAP:
-		ns->iface = g_strdup(NETWORK_ROUTER_INTERFACE);
-		ns->name = g_strdup("BlueZ NAP service");
-		break;
-	}
+	ns->iface = g_strdup(NETWORK_SERVER_INTERFACE);
+	ns->name = g_strdup("Network service");
 
 	path = adapter_get_path(adapter);
 
 	if (!g_dbus_register_interface(connection, path, ns->iface,
-					server_methods, server_signals, NULL,
+					server_methods, NULL, NULL,
 					ns, path_unregister)) {
 		error("D-Bus failed to register %s interface",
 				ns->iface);
@@ -887,21 +779,21 @@
 	}
 
 	adapter_get_address(adapter, &ns->src);
-	ns->id = id;
+	ns->id = BNEP_SVC_NAP;
 	ns->na = na;
-	ns->record_id = register_server_record(ns);
-	ns->enable = TRUE;
+	ns->record_id = 0;
 	na->servers = g_slist_append(na->servers, ns);
 
-	debug("Registered interface %s on path %s", ns->iface, path);
+	DBG("Registered interface %s on path %s", ns->iface, path);
 
 	return 0;
 }
 
-int server_unregister(struct btd_adapter *adapter, uint16_t id)
+int server_unregister(struct btd_adapter *adapter)
 {
 	struct network_adapter *na;
 	struct network_server *ns;
+	uint16_t id = BNEP_SVC_NAP;
 
 	na = find_adapter(adapters, adapter);
 	if (!na)
diff --git a/network/server.h b/network/server.h
index 5072c47..d88acab 100644
--- a/network/server.h
+++ b/network/server.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -21,14 +21,9 @@
  *
  */
 
-int server_init(DBusConnection *conn, const char *iface_prefix,
-		gboolean secure);
-void server_exit();
-int server_register(struct btd_adapter *adapter, uint16_t id);
-int server_unregister(struct btd_adapter *adapter, uint16_t id);
-int server_register_from_file(const char *path, const bdaddr_t *src,
-		uint16_t id, const char *filename);
-
-int server_store(const char *path);
+int server_init(DBusConnection *conn, gboolean secure);
+void server_exit(void);
+int server_register(struct btd_adapter *adapter);
+int server_unregister(struct btd_adapter *adapter);
 
 int server_find_data(const char *path, const char *pattern);
diff --git a/plugins/Android.mk b/plugins/Android.mk
index 6302d00..da2b4a6 100755
--- a/plugins/Android.mk
+++ b/plugins/Android.mk
@@ -10,12 +10,11 @@
 	hciops.c \
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\" \
+	-DVERSION=\"4.69\" \
 	-DBLUETOOTH_PLUGIN_BUILTIN \
 
 LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-        $(LOCAL_PATH)/../common \
+	$(LOCAL_PATH)/../lib \
         $(LOCAL_PATH)/../gdbus \
         $(LOCAL_PATH)/../src \
         $(call include-path-for, glib) \
@@ -28,7 +27,6 @@
 	libdbus
 
 LOCAL_STATIC_LIBRARIES := \
-	libbluez-common-static \
 	libglib_static
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/bluez-plugin
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
deleted file mode 100644
index 9d9f970..0000000
--- a/plugins/Makefile.am
+++ /dev/null
@@ -1,71 +0,0 @@
-
-plugindir = $(libdir)/bluetooth/plugins
-
-plugin_LTLIBRARIES =
-
-builtin_modules =
-builtin_sources =
-builtin_cflags =
-
-if SERVICEPLUGIN
-builtin_modules += service
-builtin_sources += service.c
-endif
-
-builtin_modules += hciops
-builtin_sources += hciops.c
-
-if NETLINK
-plugin_LTLIBRARIES += netlink.la
-netlink_la_LIBADD = @NETLINK_LIBS@
-endif
-
-builtin_modules += hal
-builtin_sources += hal.c
-
-builtin_modules += storage
-builtin_sources += storage.c
-
-noinst_LTLIBRARIES = libbuiltin.la echo.la
-
-libbuiltin_la_SOURCES = $(builtin_sources)
-libbuiltin_la_LDFLAGS =
-libbuiltin_la_CFLAGS = $(AM_CFLAGS) \
-			$(builtin_cflags) -DBLUETOOTH_PLUGIN_BUILTIN
-
-BUILT_SOURCES = builtin.h
-
-nodist_libbuiltin_la_SOURCES = $(BUILT_SOURCES)
-
-AM_LDFLAGS = -module -avoid-version -no-undefined
-
-AM_CFLAGS = -fvisibility=hidden @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ \
-			@GLIB_CFLAGS@ @GDBUS_CFLAGS@ @NETLINK_CFLAGS@
-
-INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/src
-
-CLEANFILES = $(BUILT_SOURCES)
-
-MAINTAINERCLEANFILES = Makefile.in
-
-builtin.h:
-	echo "" > $@
-	list='$(builtin_modules)'; for i in $$list; \
-	  do echo "extern struct bluetooth_plugin_desc __bluetooth_builtin_$$i;" >> $@; done
-	echo "" >> $@
-	echo "static struct bluetooth_plugin_desc *__bluetooth_builtin[] = {" >> $@
-	list='$(builtin_modules)'; for i in $$list; \
-	  do echo "&__bluetooth_builtin_$$i," >> $@; done
-	echo "NULL };" >> $@
-
-all-local:
-	@$(LN_S) -f $(top_srcdir)/input/.libs/input.so
-	@$(LN_S) -f $(top_srcdir)/audio/.libs/audio.so
-	@$(LN_S) -f $(top_srcdir)/serial/.libs/serial.so
-	@$(LN_S) -f $(top_srcdir)/network/.libs/network.so
-
-clean-local:
-	@rm -f network.so
-	@rm -f serial.so
-	@rm -f audio.so
-	@rm -f input.so
diff --git a/plugins/echo.c b/plugins/echo.c
index 919d085..23f6e49 100644
--- a/plugins/echo.c
+++ b/plugins/echo.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -38,7 +38,7 @@
 
 #include "plugin.h"
 #include "adapter.h"
-#include "logging.h"
+#include "log.h"
 
 static gboolean session_event(GIOChannel *chan,
 					GIOCondition cond, gpointer data)
@@ -151,14 +151,14 @@
 
 static int echo_init(void)
 {
-	debug("Setup echo plugin");
+	DBG("Setup echo plugin");
 
 	return btd_register_adapter_driver(&echo_server);
 }
 
 static void echo_exit(void)
 {
-	debug("Cleanup echo plugin");
+	DBG("Cleanup echo plugin");
 
 	btd_unregister_adapter_driver(&echo_server);
 }
diff --git a/plugins/hal.c b/plugins/hal.c
index 6815f28..f6121c5 100644
--- a/plugins/hal.c
+++ b/plugins/hal.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,7 @@
 
 #include "plugin.h"
 #include "adapter.h"
-#include "logging.h"
+#include "log.h"
 #include "dbus-hci.h"
 
 static void formfactor_reply(DBusPendingCall *call, void *user_data)
@@ -42,8 +42,7 @@
 	struct btd_adapter *adapter = user_data;
 	const char *formfactor = NULL;
 	DBusMessage *reply;
-	uint8_t cls[3], minor = 0;
-	int dd;
+	uint8_t minor = 0;
 
 	reply = dbus_pending_call_steal_reply(call);
 
@@ -60,7 +59,7 @@
 		return;
 	}
 
-	debug("Computer is classified as %s", formfactor);
+	DBG("Computer is classified as %s", formfactor);
 
 	if (formfactor != NULL) {
 		if (g_str_equal(formfactor, "laptop") == TRUE)
@@ -75,24 +74,10 @@
 
 	dbus_message_unref(reply);
 
-	dd = hci_open_dev(adapter_get_dev_id(adapter));
-	if (dd < 0)
-		return;
-
-	if (hci_read_class_of_dev(dd, cls, 500) < 0) {
-		hci_close_dev(dd);
-		return;
-	}
-
-	debug("Current device class is 0x%02x%02x%02x\n",
-						cls[2], cls[1], cls[0]);
-
 	/* Computer major class */
-	debug("Setting 0x%06x for major/minor device class", (1 << 8) | minor);
+	DBG("Setting 0x%06x for major/minor device class", (1 << 8) | minor);
 
-	hci_close_dev(dd);
-
-	set_major_and_minor_class(adapter, 0x01, minor);
+	btd_adapter_set_class(adapter, 0x01, minor);
 }
 
 static DBusConnection *connection;
diff --git a/plugins/hciops.c b/plugins/hciops.c
index 4df799b..5775cf1 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  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
@@ -26,13 +26,8 @@
 
 #include <stdio.h>
 #include <errno.h>
-#include <fcntl.h>
 #include <unistd.h>
 #include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/wait.h>
@@ -43,15 +38,12 @@
 
 #include <glib.h>
 
-#include <dbus/dbus.h>
-
 #include "hcid.h"
 #include "sdpd.h"
 #include "adapter.h"
 #include "plugin.h"
-#include "logging.h"
+#include "log.h"
 #include "manager.h"
-#include "storage.h"
 
 static int child_pipe[2] = { -1, -1 };
 
@@ -71,7 +63,7 @@
 	if (waitpid(child_pid, &status, 0) != child_pid)
 		error("waitpid(%d) failed", child_pid);
 	else
-		debug("child %d exited", child_pid);
+		DBG("child %d exited", child_pid);
 
 	return TRUE;
 }
@@ -84,11 +76,11 @@
 		error("unable to write to child pipe");
 }
 
-static void configure_device(int index)
+static void device_devup_setup(int index)
 {
 	struct hci_dev_info di;
 	uint16_t policy;
-	int dd;
+	int dd, err;
 
 	if (hci_devinfo(index, &di) < 0)
 		return;
@@ -98,44 +90,12 @@
 
 	dd = hci_open_dev(index);
 	if (dd < 0) {
+		err = errno;
 		error("Can't open device hci%d: %s (%d)",
-						index, strerror(errno), errno);
+						index, strerror(err), err);
 		return;
 	}
 
-	/* Set device name */
-	if ((main_opts.flags & (1 << HCID_SET_NAME)) && main_opts.name) {
-		change_local_name_cp cp;
-
-		memset(cp.name, 0, sizeof(cp.name));
-		expand_name((char *) cp.name, sizeof(cp.name),
-						main_opts.name, index);
-
-		hci_send_cmd(dd, OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME,
-					CHANGE_LOCAL_NAME_CP_SIZE, &cp);
-	}
-
-	/* Set device class */
-	if ((main_opts.flags & (1 << HCID_SET_CLASS))) {
-		write_class_of_dev_cp cp;
-		uint32_t class;
-		uint8_t cls[3];
-
-		if (read_local_class(&di.bdaddr, cls) < 0) {
-			class = htobl(main_opts.class);
-			cls[2] = get_service_classes(&di.bdaddr);
-			memcpy(cp.dev_class, &class, 3);
-		} else {
-			if (!(main_opts.scan & SCAN_INQUIRY))
-				cls[1] &= 0xdf; /* Clear discoverable bit */
-			cls[2] = get_service_classes(&di.bdaddr);
-			memcpy(cp.dev_class, cls, 3);
-		}
-
-		hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV,
-					WRITE_CLASS_OF_DEV_CP_SIZE, &cp);
-	}
-
 	/* Set page timeout */
 	if ((main_opts.flags & (1 << HCID_SET_PAGETO))) {
 		write_page_timeout_cp cp;
@@ -151,6 +111,12 @@
 				OCF_WRITE_DEFAULT_LINK_POLICY, 2, &policy);
 
 	hci_close_dev(dd);
+
+	start_security_manager(index);
+
+	/* Return value 1 means ioctl(DEVDOWN) was performed */
+	if (manager_start_adapter(index) == 1)
+		stop_security_manager(index);
 }
 
 static void init_device(int index)
@@ -158,7 +124,7 @@
 	struct hci_dev_req dr;
 	struct hci_dev_info di;
 	pid_t pid;
-	int dd;
+	int dd, err;
 
 	/* Do initialization in the separate process */
 	pid = fork();
@@ -167,17 +133,19 @@
 			atexit(at_child_exit);
 			break;
 		case -1:
+			err = errno;
 			error("Fork failed. Can't init device hci%d: %s (%d)",
-					index, strerror(errno), errno);
+					index, strerror(err), err);
 		default:
-			debug("child %d forked", pid);
+			DBG("child %d forked", pid);
 			return;
 	}
 
 	dd = hci_open_dev(index);
 	if (dd < 0) {
+		err = errno;
 		error("Can't open device hci%d: %s (%d)",
-					index, strerror(errno), errno);
+					index, strerror(err), err);
 		exit(1);
 	}
 
@@ -187,8 +155,9 @@
 	/* Set link mode */
 	dr.dev_opt = main_opts.link_mode;
 	if (ioctl(dd, HCISETLINKMODE, (unsigned long) &dr) < 0) {
+		err = errno;
 		error("Can't set link mode on hci%d: %s (%d)",
-					index, strerror(errno), errno);
+					index, strerror(err), err);
 	}
 
 	/* Set link policy */
@@ -239,17 +208,6 @@
 		manager_register_adapter(index, devup);
 }
 
-static void device_devup_setup(int index)
-{
-	configure_device(index);
-
-	start_security_manager(index);
-
-	/* Return value 1 means ioctl(DEVDOWN) was performed */
-	if (manager_start_adapter(index) == 1)
-		stop_security_manager(index);
-}
-
 static void device_event(int event, int index)
 {
 	switch (event) {
@@ -284,29 +242,27 @@
 
 	dl = g_try_malloc0(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
 	if (!dl) {
-		err = -errno;
+		err = errno;
 		error("Can't allocate devlist buffer: %s (%d)",
-							strerror(errno), errno);
-		return err;
+							strerror(err), err);
+		return -err;
 	}
 
 	dl->dev_num = HCI_MAX_DEV;
 	dr = dl->dev_req;
 
 	if (ioctl(ctl, HCIGETDEVLIST, (void *) dl) < 0) {
-		err = -errno;
+		err = errno;
 		error("Can't get device list: %s (%d)",
-							strerror(errno), errno);
-		return err;
+							strerror(err), err);
+		g_free(dl);
+		return -err;
 	}
 
 	for (i = 0; i < dl->dev_num; i++, dr++) {
-		gboolean devup;
-
 		device_event(HCI_DEV_REG, dr->dev_id);
 
-		devup = hci_test_bit(HCI_UP, &dr->dev_opt);
-		if (devup)
+		if (hci_test_bit(HCI_UP, &dr->dev_opt))
 			device_event(HCI_DEV_UP, dr->dev_id);
 	}
 
@@ -370,9 +326,9 @@
 		return -EALREADY;
 
 	if (pipe(child_pipe) < 0) {
-		err = -errno;
-		error("pipe(): %s (%d)", strerror(errno), errno);
-		return err;
+		err = errno;
+		error("pipe(): %s (%d)", strerror(err), err);
+		return -err;
 	}
 
 	child_io = g_io_channel_unix_new(child_pipe[0]);
@@ -385,10 +341,10 @@
 	/* Create and bind HCI socket */
 	sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
 	if (sock < 0) {
-		err = -errno;
-		error("Can't open HCI socket: %s (%d)", strerror(errno),
-								errno);
-		return err;
+		err = errno;
+		error("Can't open HCI socket: %s (%d)", strerror(err),
+								err);
+		return -err;
 	}
 
 	/* Set filter */
@@ -397,9 +353,9 @@
 	hci_filter_set_event(EVT_STACK_INTERNAL, &flt);
 	if (setsockopt(sock, SOL_HCI, HCI_FILTER, &flt,
 							sizeof(flt)) < 0) {
-		err = -errno;
-		error("Can't set filter: %s (%d)", strerror(errno), errno);
-		return err;
+		err = errno;
+		error("Can't set filter: %s (%d)", strerror(err), err);
+		return -err;
 	}
 
 	memset(&addr, 0, sizeof(addr));
@@ -407,10 +363,10 @@
 	addr.hci_dev = HCI_DEV_NONE;
 	if (bind(sock, (struct sockaddr *) &addr,
 							sizeof(addr)) < 0) {
-		err = -errno;
+		err = errno;
 		error("Can't bind HCI socket: %s (%d)",
-							strerror(errno), errno);
-		return err;
+							strerror(err), err);
+		return -err;
 	}
 
 	ctl_io = g_io_channel_unix_new(sock);
@@ -460,14 +416,14 @@
 		goto done; /* on success */
 
 	if (errno != EALREADY) {
-		err = -errno;
+		err = errno;
 		error("Can't init device hci%d: %s (%d)",
-				index, strerror(errno), errno);
+				index, strerror(err), err);
 	}
 
 done:
 	hci_close_dev(dd);
-	return err;
+	return -err;
 }
 
 static int hciops_stop(int index)
@@ -483,19 +439,19 @@
 		goto done; /* on success */
 
 	if (errno != EALREADY) {
-		err = -errno;
+		err = errno;
 		error("Can't stop device hci%d: %s (%d)",
-				index, strerror(errno), errno);
+				index, strerror(err), err);
 	}
 
 done:
 	hci_close_dev(dd);
-	return err;
+	return -err;
 }
 
 static int hciops_powered(int index, gboolean powered)
 {
-	int dd;
+	int dd, err;
 	uint8_t mode = SCAN_DISABLED;
 
 	if (powered)
@@ -505,8 +461,13 @@
 	if (dd < 0)
 		return -EIO;
 
-	hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
+	err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
 					1, &mode);
+	if (err < 0) {
+		err = -errno;
+		hci_close_dev(dd);
+		return err;
+	}
 
 	hci_close_dev(dd);
 
@@ -515,45 +476,72 @@
 
 static int hciops_connectable(int index)
 {
-	int dd;
+	int dd, err;
 	uint8_t mode = SCAN_PAGE;
 
 	dd = hci_open_dev(index);
 	if (dd < 0)
 		return -EIO;
 
-	hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
+	err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
 					1, &mode);
+	if (err < 0)
+		err = -errno;
 
 	hci_close_dev(dd);
 
-	return 0;
+	return err;
 }
 
 static int hciops_discoverable(int index)
 {
-	int dd;
+	int dd, err;
 	uint8_t mode = (SCAN_PAGE | SCAN_INQUIRY);
 
 	dd = hci_open_dev(index);
 	if (dd < 0)
 		return -EIO;
 
-	hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
+	err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
 					1, &mode);
+	if (err < 0)
+		err = -errno;
 
 	hci_close_dev(dd);
 
-	return 0;
+	return err;
 }
 
-static int hciops_set_limited_discoverable(int index, const uint8_t *cls,
+static int hciops_set_class(int index, uint32_t class)
+{
+	int dd, err;
+	write_class_of_dev_cp cp;
+
+	dd = hci_open_dev(index);
+	if (dd < 0)
+		return -EIO;
+
+	memcpy(cp.dev_class, &class, 3);
+
+	err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV,
+					WRITE_CLASS_OF_DEV_CP_SIZE, &cp);
+
+	if (err < 0)
+		err = -errno;
+
+	hci_close_dev(dd);
+
+	return err;
+}
+
+static int hciops_set_limited_discoverable(int index, uint32_t class,
 							gboolean limited)
 {
-	int dd, err = 0;
-	uint32_t dev_class;
+	int dd, err;
 	int num = (limited ? 2 : 1);
 	uint8_t lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
+	write_current_iac_lap_cp cp;
+
 	/*
 	 * 1: giac
 	 * 2: giac + liac
@@ -562,40 +550,27 @@
 	if (dd < 0)
 		return -EIO;
 
-	if (hci_write_current_iac_lap(dd, num, lap, HCI_REQ_TIMEOUT) < 0) {
+	memset(&cp, 0, sizeof(cp));
+	cp.num_current_iac = num;
+	memcpy(&cp.lap, lap, num * 3);
+
+	err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_CURRENT_IAC_LAP,
+			(num * 3 + 1), &cp);
+	if (err < 0) {
 		err = -errno;
-		error("Can't write current IAC LAP: %s(%d)",
-						strerror(errno), errno);
-		goto done;
+		hci_close_dev(dd);
+		return err;
 	}
 
-	if (limited) {
-		if (cls[1] & 0x20)
-			goto done; /* Already limited */
-
-		dev_class = (cls[2] << 16) | ((cls[1] | 0x20) << 8) | cls[0];
-	} else {
-		if (!(cls[1] & 0x20))
-			goto done; /* Already clear */
-
-		dev_class = (cls[2] << 16) | ((cls[1] & 0xdf) << 8) | cls[0];
-	}
-
-	if (hci_write_class_of_dev(dd, dev_class, HCI_REQ_TIMEOUT) < 0) {
-		err = -errno;
-		error("Can't write class of device: %s (%d)",
-						strerror(errno), errno);
-		goto done;
-	}
-done:
 	hci_close_dev(dd);
-	return err;
+
+	return hciops_set_class(index, class);
 }
 
 static int hciops_start_discovery(int index, gboolean periodic)
 {
 	uint8_t lap[3] = { 0x33, 0x8b, 0x9e };
-	int dd, err = 0;
+	int dd, err;
 
 	dd = hci_open_dev(index);
 	if (dd < 0)
@@ -636,7 +611,7 @@
 static int hciops_stop_discovery(int index)
 {
 	struct hci_dev_info di;
-	int dd, err = 0;
+	int dd, err;
 
 	if (hci_devinfo(index, &di) < 0)
 		return -errno;
@@ -662,7 +637,7 @@
 static int hciops_resolve_name(int index, bdaddr_t *bdaddr)
 {
 	remote_name_req_cp cp;
-	int dd, err = 0;
+	int dd, err;
 
 	dd = hci_open_dev(index);
 	if (dd < 0)
@@ -685,7 +660,7 @@
 static int hciops_set_name(int index, const char *name)
 {
 	change_local_name_cp cp;
-	int dd, err = 0;
+	int dd, err;
 
 	dd = hci_open_dev(index);
 	if (dd < 0)
@@ -706,7 +681,7 @@
 
 static int hciops_read_name(int index)
 {
-	int dd, err = 0;
+	int dd, err;
 
 	dd = hci_open_dev(index);
 	if (dd < 0)
@@ -724,7 +699,7 @@
 static int hciops_cancel_resolve_name(int index, bdaddr_t *bdaddr)
 {
 	remote_name_req_cancel_cp cp;
-	int dd, err = 0;
+	int dd, err;
 
 	dd = hci_open_dev(index);
 	if (dd < 0)
@@ -758,6 +733,7 @@
 	.cancel_resolve_name = hciops_cancel_resolve_name,
 	.set_name = hciops_set_name,
 	.read_name = hciops_read_name,
+	.set_class = hciops_set_class,
 };
 
 static int hciops_init(void)
diff --git a/plugins/maemo6.c b/plugins/maemo6.c
new file mode 100644
index 0000000..2ed5f12
--- /dev/null
+++ b/plugins/maemo6.c
@@ -0,0 +1,176 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#include "adapter.h"
+#include "plugin.h"
+#include "log.h"
+#include "gdbus.h"
+
+/* from mce/mode-names.h */
+#define MCE_RADIO_STATE_BLUETOOTH	(1 << 3)
+
+/* from mce/dbus-names.h */
+#define MCE_SERVICE			"com.nokia.mce"
+#define MCE_REQUEST_IF			"com.nokia.mce.request"
+#define MCE_SIGNAL_IF			"com.nokia.mce.signal"
+#define MCE_REQUEST_PATH		"/com/nokia/mce/request"
+#define MCE_SIGNAL_PATH			"/com/nokia/mce/signal"
+#define MCE_RADIO_STATES_GET		"get_radio_states"
+#define MCE_RADIO_STATES_SIG		"radio_states_ind"
+
+static guint watch_id;
+static DBusConnection *conn = NULL;
+
+static gboolean mce_signal_callback(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	DBusMessageIter args;
+	uint32_t sigvalue;
+	struct btd_adapter *adapter = user_data;
+
+	DBG("received mce signal");
+
+	if (!dbus_message_iter_init(message, &args))
+		error("message has no arguments");
+	else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args))
+		error("argument is not uint32");
+	else {
+		dbus_message_iter_get_basic(&args, &sigvalue);
+		DBG("got signal with value %u", sigvalue);
+
+		if (sigvalue & MCE_RADIO_STATE_BLUETOOTH)
+			btd_adapter_switch_online(adapter);
+		else
+			btd_adapter_switch_offline(adapter);
+	}
+
+	return TRUE;
+}
+
+static void read_radio_states_cb(DBusPendingCall *call, void *user_data)
+{
+	DBusError err;
+	DBusMessage *reply;
+	dbus_uint32_t radio_states;
+	struct btd_adapter *adapter = user_data;
+
+	reply = dbus_pending_call_steal_reply(call);
+
+	dbus_error_init(&err);
+	if (dbus_set_error_from_message(&err, reply)) {
+		error("mce replied with an error: %s, %s",
+				err.name, err.message);
+		dbus_error_free(&err);
+		goto done;
+	}
+
+	dbus_error_init(&err);
+	if (dbus_message_get_args(reply, &err,
+				DBUS_TYPE_UINT32, &radio_states,
+				DBUS_TYPE_INVALID) == FALSE) {
+		error("unable to parse get_radio_states reply: %s, %s",
+							err.name, err.message);
+		dbus_error_free(&err);
+		goto done;
+	}
+
+	if (radio_states & MCE_RADIO_STATE_BLUETOOTH)
+		btd_adapter_switch_online(adapter);
+
+done:
+	dbus_message_unref(reply);
+}
+
+static int mce_probe(struct btd_adapter *adapter)
+{
+	DBusMessage *msg;
+	DBusPendingCall *call;
+
+	DBG("path %s", adapter_get_path(adapter));
+
+	msg = dbus_message_new_method_call(MCE_SERVICE, MCE_REQUEST_PATH,
+					MCE_REQUEST_IF, MCE_RADIO_STATES_GET);
+
+	if (!dbus_connection_send_with_reply(conn, msg, &call, -1)) {
+		error("calling %s failed", MCE_RADIO_STATES_GET);
+		dbus_message_unref(msg);
+		return -1;
+	}
+
+	dbus_pending_call_set_notify(call, read_radio_states_cb, adapter, NULL);
+	dbus_pending_call_unref(call);
+	dbus_message_unref(msg);
+
+	watch_id = g_dbus_add_signal_watch(conn, NULL, MCE_SIGNAL_PATH,
+					MCE_SIGNAL_IF, MCE_RADIO_STATES_SIG,
+					mce_signal_callback, adapter, NULL);
+	return 0;
+}
+
+static void mce_remove(struct btd_adapter *adapter)
+{
+	DBG("path %s", adapter_get_path(adapter));
+
+	if (watch_id > 0)
+		g_dbus_remove_watch(conn, watch_id);
+}
+
+static struct btd_adapter_driver mce_driver = {
+	.name	= "mce",
+	.probe	= mce_probe,
+	.remove	= mce_remove,
+};
+
+static int maemo6_init(void)
+{
+	DBG("init maemo6 plugin");
+
+	conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+	if (conn == NULL) {
+		error("Unable to connect to D-Bus");
+		return -1;
+	}
+
+	return btd_register_adapter_driver(&mce_driver);
+}
+
+static void maemo6_exit(void)
+{
+	DBG("exit maemo6 plugin");
+
+	if (conn != NULL)
+		dbus_connection_unref(conn);
+
+	btd_unregister_adapter_driver(&mce_driver);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(maemo6, VERSION,
+		BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, maemo6_init, maemo6_exit)
diff --git a/plugins/netlink.c b/plugins/netlink.c
index e85d264..081ffa2 100644
--- a/plugins/netlink.c
+++ b/plugins/netlink.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -37,7 +37,7 @@
 #include <glib.h>
 
 #include "plugin.h"
-#include "logging.h"
+#include "log.h"
 
 static struct nl_handle *handle;
 static struct nl_cache *cache;
@@ -53,7 +53,7 @@
 	if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
 		return FALSE;
 
-	debug("Message available on netlink channel");
+	DBG("Message available on netlink channel");
 
 	err = nl_recvmsgs_default(handle);
 
@@ -91,8 +91,8 @@
 	cache = genl_ctrl_alloc_cache(handle);
 	if (!cache) {
 		error("Failed to allocate generic netlink cache");
-		return -ENOMEM;
 		nl_handle_destroy(handle);
+		return -ENOMEM;
 	}
 
 	family = genl_ctrl_search_by_name(cache, "bluetooth");
diff --git a/plugins/pnat.c b/plugins/pnat.c
new file mode 100644
index 0000000..f9136a4
--- /dev/null
+++ b/plugins/pnat.c
@@ -0,0 +1,522 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010  Nokia Corporation
+ *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+
+#include <gdbus.h>
+
+#include "plugin.h"
+#include "sdpd.h"
+#include "btio.h"
+#include "adapter.h"
+#include "log.h"
+
+/* FIXME: This location should be build-time configurable */
+#define PNATD "/usr/bin/phonet-at"
+
+#define DUN_CHANNEL 1
+#define DUN_UUID "00001103-0000-1000-8000-00805F9B34FB"
+
+#define TTY_TIMEOUT 100
+#define TTY_TRIES 10
+
+struct dun_client {
+	bdaddr_t bda;
+
+	GIOChannel *io;	/* Client socket */
+	guint io_watch;	/* Client IO watch id */
+
+	guint tty_timer;
+	int tty_tries;
+	gboolean tty_open;
+	int tty_id;
+	char tty_name[PATH_MAX];
+
+	GPid pnatd_pid;
+	guint pnatd_watch;
+};
+
+struct dun_server {
+	bdaddr_t bda;		/* Local adapter address */
+
+	uint32_t record_handle; /* Local SDP record handle */
+	GIOChannel *server;	/* Server socket */
+
+	int rfcomm_ctl;
+
+	struct dun_client client;
+};
+
+static GSList *servers = NULL;
+
+static void disconnect(struct dun_server *server)
+{
+	struct dun_client *client = &server->client;
+
+	if (!client->io)
+		return;
+
+	g_io_channel_unref(client->io);
+	client->io = NULL;
+
+	if (client->io_watch > 0) {
+		g_source_remove(client->io_watch);
+		client->io_watch = 0;
+	}
+
+	if (client->pnatd_watch > 0) {
+		g_source_remove(client->pnatd_watch);
+		client->pnatd_watch = 0;
+		if (client->pnatd_pid > 0)
+			kill(client->pnatd_pid, SIGTERM);
+	}
+
+	if (client->pnatd_pid > 0) {
+		g_spawn_close_pid(client->pnatd_pid);
+		client->pnatd_pid = 0;
+	}
+
+	if (client->tty_timer > 0) {
+		g_source_remove(client->tty_timer);
+		client->tty_timer = 0;
+	}
+
+	if (client->tty_id >= 0) {
+		struct rfcomm_dev_req req;
+
+		memset(&req, 0, sizeof(req));
+		req.dev_id = client->tty_id;
+		req.flags = (1 << RFCOMM_HANGUP_NOW);
+		ioctl(server->rfcomm_ctl, RFCOMMRELEASEDEV, &req);
+
+		client->tty_name[0] = '\0';
+		client->tty_open = FALSE;
+		client->tty_id = -1;
+	}
+}
+
+static gboolean client_event(GIOChannel *chan,
+					GIOCondition cond, gpointer data)
+{
+	struct dun_server *server = data;
+	struct dun_client *client = &server->client;
+	char addr[18];
+
+	ba2str(&client->bda, addr);
+
+	DBG("Disconnected DUN from %s (%s)", addr, client->tty_name);
+
+	client->io_watch = 0;
+	disconnect(server);
+
+	return FALSE;
+}
+
+static void pnatd_exit(GPid pid, gint status, gpointer user_data)
+{
+	struct dun_server *server = user_data;
+	struct dun_client *client = &server->client;
+
+        if (WIFEXITED(status))
+                DBG("pnatd (%d) exited with status %d", pid,
+							WEXITSTATUS(status));
+        else
+                DBG("pnatd (%d) was killed by signal %d", pid,
+							WTERMSIG(status));
+
+	client->pnatd_watch = 0;
+
+	disconnect(server);
+}
+
+static gboolean start_pnatd(struct dun_server *server)
+{
+	struct dun_client *client = &server->client;
+	GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH;
+	char *argv[] = { PNATD, client->tty_name, NULL };
+	GError *err = NULL;
+	GPid pid;
+
+	g_spawn_async(NULL, argv, NULL, flags, NULL, NULL, &pid, &err);
+	if (err != NULL) {
+		error("Unable to spawn pnatd: %s", err->message);
+		g_error_free(err);
+		return FALSE;
+	}
+
+	DBG("pnatd started for %s with pid %d", client->tty_name, pid);
+
+	client->pnatd_pid = pid;
+	client->pnatd_watch = g_child_watch_add(pid, pnatd_exit, server);
+
+	return TRUE;
+}
+
+static gboolean tty_try_open(gpointer user_data)
+{
+	struct dun_server *server = user_data;
+	struct dun_client *client = &server->client;
+	int tty_fd;
+
+	tty_fd = open(client->tty_name, O_RDONLY | O_NOCTTY);
+	if (tty_fd < 0) {
+		if (errno == EACCES)
+			goto disconnect;
+
+		client->tty_tries--;
+
+		if (client->tty_tries <= 0)
+			goto disconnect;
+
+		return TRUE;
+	}
+
+	DBG("%s created for DUN", client->tty_name);
+
+	client->tty_open = TRUE;
+	client->tty_timer = 0;
+
+	g_io_channel_unref(client->io);
+	g_source_remove(client->io_watch);
+
+	client->io = g_io_channel_unix_new(tty_fd);
+	client->io_watch = g_io_add_watch(client->io,
+					G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+					client_event, server);
+
+	if (!start_pnatd(server))
+		goto disconnect;
+
+	return FALSE;
+
+disconnect:
+	client->tty_timer = 0;
+	disconnect(server);
+	return FALSE;
+}
+
+static gboolean create_tty(struct dun_server *server)
+{
+	struct dun_client *client = &server->client;
+	struct rfcomm_dev_req req;
+	int dev, sk = g_io_channel_unix_get_fd(client->io);
+
+	memset(&req, 0, sizeof(req));
+	req.dev_id = -1;
+	req.flags = (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP);
+
+	bacpy(&req.src, &server->bda);
+	bacpy(&req.dst, &client->bda);
+
+	bt_io_get(client->io, BT_IO_RFCOMM, NULL,
+			BT_IO_OPT_DEST_CHANNEL, &req.channel,
+			BT_IO_OPT_INVALID);
+
+	dev = ioctl(sk, RFCOMMCREATEDEV, &req);
+	if (dev < 0) {
+		error("Can't create RFCOMM TTY: %s", strerror(errno));
+		return FALSE;
+	}
+
+	snprintf(client->tty_name, PATH_MAX - 1, "/dev/rfcomm%d", dev);
+
+	client->tty_tries = TTY_TRIES;
+
+	tty_try_open(server);
+	if (!client->tty_open && client->tty_tries > 0)
+		client->tty_timer = g_timeout_add(TTY_TIMEOUT,
+							tty_try_open, server);
+
+	return TRUE;
+}
+
+static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
+{
+	struct dun_server *server = user_data;
+
+	if (err) {
+		error("Accepting DUN connection failed: %s", err->message);
+		disconnect(server);
+		return;
+	}
+
+	if (!create_tty(server)) {
+		error("Device creation failed");
+		disconnect(server);
+	}
+}
+
+static void auth_cb(DBusError *derr, void *user_data)
+{
+	struct dun_server *server = user_data;
+	struct dun_client *client = &server->client;
+	GError *err = NULL;
+
+	if (derr && dbus_error_is_set(derr)) {
+		error("DUN access denied: %s", derr->message);
+		goto drop;
+	}
+
+	if (!bt_io_accept(client->io, connect_cb, server, NULL, &err)) {
+		error("bt_io_accept: %s", err->message);
+		g_error_free(err);
+		goto drop;
+	}
+
+	return;
+
+drop:
+	disconnect(server);
+}
+
+static gboolean auth_watch(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+	struct dun_server *server = data;
+	struct dun_client *client = &server->client;
+
+	error("DUN client disconnected while waiting for authorization");
+
+	btd_cancel_authorization(&server->bda, &client->bda);
+
+	disconnect(server);
+
+	return FALSE;
+}
+
+static void confirm_cb(GIOChannel *io, gpointer user_data)
+{
+	struct dun_server *server = user_data;
+	struct dun_client *client = &server->client;
+	GError *err = NULL;
+
+	if (client->io) {
+		error("Rejecting DUN connection since one already exists");
+		return;
+	}
+
+	bt_io_get(io, BT_IO_RFCOMM, &err,
+			BT_IO_OPT_DEST_BDADDR, &client->bda,
+			BT_IO_OPT_INVALID);
+	if (err != NULL) {
+		error("Unable to get DUN source and dest address: %s",
+								err->message);
+		g_error_free(err);
+		return;
+	}
+
+	if (btd_request_authorization(&server->bda, &client->bda, DUN_UUID,
+						auth_cb, user_data) < 0) {
+		error("Requesting DUN authorization failed");
+		return;
+	}
+
+	client->io_watch = g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+						(GIOFunc) auth_watch, server);
+	client->io = g_io_channel_ref(io);
+}
+
+static sdp_record_t *dun_record(uint8_t ch)
+{
+	sdp_list_t *svclass_id, *pfseq, *apseq, *root, *aproto;
+	uuid_t root_uuid, dun, gn, l2cap, rfcomm;
+	sdp_profile_desc_t profile;
+	sdp_list_t *proto[2];
+	sdp_record_t *record;
+	sdp_data_t *channel;
+
+	record = sdp_record_alloc();
+	if (!record)
+		return NULL;
+
+	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+	root = sdp_list_append(NULL, &root_uuid);
+	sdp_set_browse_groups(record, root);
+
+	sdp_uuid16_create(&dun, DIALUP_NET_SVCLASS_ID);
+	svclass_id = sdp_list_append(NULL, &dun);
+	sdp_uuid16_create(&gn,  GENERIC_NETWORKING_SVCLASS_ID);
+	svclass_id = sdp_list_append(svclass_id, &gn);
+	sdp_set_service_classes(record, svclass_id);
+
+	sdp_uuid16_create(&profile.uuid, DIALUP_NET_PROFILE_ID);
+	profile.version = 0x0100;
+	pfseq = sdp_list_append(NULL, &profile);
+	sdp_set_profile_descs(record, pfseq);
+
+	sdp_uuid16_create(&l2cap, L2CAP_UUID);
+	proto[0] = sdp_list_append(NULL, &l2cap);
+	apseq = sdp_list_append(NULL, proto[0]);
+
+	sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
+	proto[1] = sdp_list_append(NULL, &rfcomm);
+	channel = sdp_data_alloc(SDP_UINT8, &ch);
+	proto[1] = sdp_list_append(proto[1], channel);
+	apseq = sdp_list_append(apseq, proto[1]);
+
+	aproto = sdp_list_append(0, apseq);
+	sdp_set_access_protos(record, aproto);
+
+	sdp_set_info_attr(record, "Dial-Up Networking", 0, 0);
+
+	sdp_data_free(channel);
+	sdp_list_free(root, NULL);
+	sdp_list_free(svclass_id, NULL);
+	sdp_list_free(proto[0], NULL);
+	sdp_list_free(proto[1], NULL);
+	sdp_list_free(pfseq, NULL);
+	sdp_list_free(apseq, NULL);
+	sdp_list_free(aproto, NULL);
+
+	return record;
+}
+
+static gint server_cmp(gconstpointer a, gconstpointer b)
+{
+	const struct dun_server *server = a;
+	const bdaddr_t *src = b;
+
+	return bacmp(src, &server->bda);
+}
+
+static int pnat_probe(struct btd_adapter *adapter)
+{
+	struct dun_server *server;
+	GIOChannel *io;
+	GError *err = NULL;
+	sdp_record_t *record;
+	bdaddr_t src;
+
+	adapter_get_address(adapter, &src);
+
+	server = g_new0(struct dun_server, 1);
+
+	io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_cb, server, NULL, &err,
+				BT_IO_OPT_SOURCE_BDADDR, &src,
+				BT_IO_OPT_CHANNEL, DUN_CHANNEL,
+				BT_IO_OPT_INVALID);
+	if (err != NULL) {
+		error("Failed to start DUN server: %s", err->message);
+		g_error_free(err);
+		goto fail;
+	}
+
+	record = dun_record(DUN_CHANNEL);
+	if (!record) {
+		error("Unable to allocate new service record");
+		goto fail;
+	}
+
+	if (add_record_to_server(&src, record) < 0) {
+		error("Unable to register DUN service record");
+		goto fail;
+	}
+
+	server->rfcomm_ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM);
+	if (server->rfcomm_ctl < 0) {
+		error("Unable to create RFCOMM control socket: %s (%d)",
+						strerror(errno), errno);
+		goto fail;
+	}
+
+	server->server = io;
+	server->record_handle = record->handle;
+	bacpy(&server->bda, &src);
+
+	servers = g_slist_append(servers, server);
+
+	return 0;
+
+fail:
+	if (io != NULL)
+		g_io_channel_unref(io);
+	g_free(server);
+	return -EIO;
+}
+
+static void pnat_remove(struct btd_adapter *adapter)
+{
+	struct dun_server *server;
+	GSList *match;
+	bdaddr_t src;
+
+	adapter_get_address(adapter, &src);
+
+	match = g_slist_find_custom(servers, &src, server_cmp);
+	if (match == NULL)
+		return;
+
+	server = match->data;
+
+	servers = g_slist_delete_link(servers, match);
+
+	disconnect(server);
+
+	remove_record_from_server(server->record_handle);
+	close(server->rfcomm_ctl);
+	g_io_channel_shutdown(server->server, TRUE, NULL);
+	g_io_channel_unref(server->server);
+	g_free(server);
+}
+
+static struct btd_adapter_driver pnat_server = {
+	.name	= "pnat-server",
+	.probe	= pnat_probe,
+	.remove	= pnat_remove,
+};
+
+static int pnat_init(void)
+{
+	DBG("Setup Phonet AT (DUN) plugin");
+
+	return btd_register_adapter_driver(&pnat_server);
+}
+
+static void pnat_exit(void)
+{
+	DBG("Cleanup Phonet AT (DUN) plugin");
+
+	btd_unregister_adapter_driver(&pnat_server);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(pnat, VERSION,
+			BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+			pnat_init, pnat_exit)
diff --git a/plugins/service.c b/plugins/service.c
index f89a7d6..96280bd 100644
--- a/plugins/service.c
+++ b/plugins/service.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -43,7 +43,7 @@
 #include "plugin.h"
 #include "adapter.h"
 #include "error.h"
-#include "logging.h"
+#include "log.h"
 
 #define SERVICE_INTERFACE "org.bluez.Service"
 
@@ -107,7 +107,7 @@
 				break;
 			}
 		}
-		debug("New attribute 0x%04x", ctx_data->attr_id);
+		DBG("New attribute 0x%04x", ctx_data->attr_id);
 		return;
 	}
 
@@ -174,13 +174,13 @@
 			int ret = sdp_attr_add(ctx_data->record, ctx_data->attr_id,
 							ctx_data->stack_head->data);
 			if (ret == -1)
-				debug("Trouble adding attribute\n");
+				DBG("Trouble adding attribute\n");
 
 			ctx_data->stack_head->data = NULL;
 			sdp_xml_data_free(ctx_data->stack_head);
 			ctx_data->stack_head = NULL;
 		} else {
-			debug("No data for attribute 0x%04x\n", ctx_data->attr_id);
+			DBG("No data for attribute 0x%04x\n", ctx_data->attr_id);
 		}
 		return;
 	}
@@ -321,7 +321,7 @@
 	struct service_adapter *serv_adapter = user_record->serv_adapter;
 	struct pending_auth *auth;
 
-	debug("remove record");
+	DBG("remove record");
 
 	serv_adapter->records = g_slist_remove(serv_adapter->records,
 						user_record);
@@ -409,7 +409,7 @@
 	serv_adapter->records = g_slist_append(serv_adapter->records,
 								user_record);
 
-	debug("listener_id %d", user_record->listener_id);
+	DBG("listener_id %d", user_record->listener_id);
 
 	*handle = user_record->handle;
 
@@ -493,13 +493,13 @@
 {
 	struct record_data *user_record;
 
-	debug("remove record 0x%x", handle);
+	DBG("remove record 0x%x", handle);
 
 	user_record = find_record(serv_adapter, handle, sender);
 	if (!user_record)
 		return -1;
 
-	debug("listner_id %d", user_record->listener_id);
+	DBG("listner_id %d", user_record->listener_id);
 
 	g_dbus_remove_watch(conn, user_record->listener_id);
 
@@ -640,6 +640,8 @@
 	}
 
 	record = sdp_record_find(user_record->handle);
+	if (record == NULL)
+		return not_authorized(msg);
 
 	if (sdp_get_service_classes(record, &services) < 0) {
 		sdp_record_free(record);
@@ -787,7 +789,7 @@
 		return -EIO;
 	}
 
-	debug("Registered interface %s on path %s", SERVICE_INTERFACE, path);
+	DBG("Registered interface %s on path %s", SERVICE_INTERFACE, path);
 
 	if (serv_adapter->adapter == NULL)
 		serv_adapter_any = serv_adapter;
diff --git a/plugins/storage.c b/plugins/storage.c
index 99b4952..04a02c7 100644
--- a/plugins/storage.c
+++ b/plugins/storage.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,7 @@
 #include <bluetooth/bluetooth.h>
 
 #include "plugin.h"
-#include "logging.h"
+#include "log.h"
 
 static int storage_init(void)
 {
diff --git a/rfcomm/Android.mk b/rfcomm/Android.mk
deleted file mode 100755
index 18e0f8f..0000000
--- a/rfcomm/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	kword.c \
-	main.c \
-	parser.c \
-	lexer.c
-
-LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\" \
-	-DCONFIGDIR=\"/etc/bluetooth\" \
-	-DNEED_PPOLL
-
-LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../common \
-	$(LOCAL_PATH)/../include
-
-LOCAL_SHARED_LIBRARIES := \
-	libbluetooth
-
-LOCAL_STATIC_LIBRARIES := \
-	libbluez-common-static
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := eng
-LOCAL_MODULE:=rfcomm
-
-include $(BUILD_EXECUTABLE)
diff --git a/rfcomm/Makefile.am b/rfcomm/Makefile.am
deleted file mode 100644
index 9baa8e6..0000000
--- a/rfcomm/Makefile.am
+++ /dev/null
@@ -1,34 +0,0 @@
-
-if TOOLS
-if CONFIGFILES
-confdir = $(sysconfdir)/bluetooth
-
-conf_DATA = rfcomm.conf
-endif
-
-bin_PROGRAMS = rfcomm
-
-rfcomm_SOURCES = main.c parser.h parser.y lexer.l kword.h kword.c
-
-rfcomm_LDADD = @BLUEZ_LIBS@
-endif
-
-AM_CFLAGS = @BLUEZ_CFLAGS@
-
-INCLUDES = -I$(top_srcdir)/common
-
-BUILT_SOURCES = parser.h
-
-if TOOLS
-if MANPAGES
-man_MANS = rfcomm.1
-endif
-endif
-
-AM_YFLAGS = -d
-
-CLEANFILES = lexer.c parser.c parser.h
-
-EXTRA_DIST = rfcomm.1 rfcomm.conf
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/sbc/Makefile.am b/sbc/Makefile.am
deleted file mode 100644
index f870164..0000000
--- a/sbc/Makefile.am
+++ /dev/null
@@ -1,33 +0,0 @@
-
-if SNDFILE
-sndfile_programs = sbctester
-else
-sndfile_programs =
-endif
-
-if SBC
-noinst_LTLIBRARIES = libsbc.la
-
-libsbc_la_SOURCES = sbc.h sbc.c sbc_math.h sbc_tables.h \
-	sbc_primitives.h sbc_primitives_mmx.h sbc_primitives_neon.h \
-	sbc_primitives.c sbc_primitives_mmx.c sbc_primitives_neon.c
-
-libsbc_la_CFLAGS = -finline-functions -fgcse-after-reload \
-				-funswitch-loops -funroll-loops
-
-noinst_PROGRAMS = sbcinfo sbcdec sbcenc $(sndfile_programs)
-
-sbcdec_SOURCES = sbcdec.c formats.h
-sbcdec_LDADD = libsbc.la
-
-sbcenc_SOURCES = sbcenc.c formats.h
-sbcenc_LDADD = libsbc.la
-
-if SNDFILE
-sbctester_LDADD = @SNDFILE_LIBS@
-endif
-endif
-
-AM_CFLAGS = @SNDFILE_CFLAGS@
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/sbc/formats.h b/sbc/formats.h
index 6c1960d..3050b25 100644
--- a/sbc/formats.h
+++ b/sbc/formats.h
@@ -2,7 +2,7 @@
  *
  *  Bluetooth low-complexity, subband codec (SBC) library
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/sbc/sbc.c b/sbc/sbc.c
index 14e5869..a6391ae 100644
--- a/sbc/sbc.c
+++ b/sbc/sbc.c
@@ -2,7 +2,8 @@
  *
  *  Bluetooth low-complexity, subband codec (SBC) library
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
  *  Copyright (C) 2005-2008  Brad Midgley <bmidgley@xmission.com>
  *
@@ -77,7 +78,7 @@
 	uint8_t joint;
 
 	/* only the lower 4 bits of every element are to be used */
-	uint32_t scale_factor[2][8];
+	uint32_t SBC_ALIGNED scale_factor[2][8];
 
 	/* raw integer subband samples in the frame */
 	int32_t SBC_ALIGNED sb_sample_f[16][2][8];
@@ -159,7 +160,8 @@
  * Takes a pointer to the frame in question, a pointer to the bits array and
  * the sampling frequency (as 2 bit integer)
  */
-static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
+static SBC_ALWAYS_INLINE void sbc_calculate_bits_internal(
+		const struct sbc_frame *frame, int (*bits)[8], int subbands)
 {
 	uint8_t sf = frame->frequency;
 
@@ -170,17 +172,17 @@
 		for (ch = 0; ch < frame->channels; ch++) {
 			max_bitneed = 0;
 			if (frame->allocation == SNR) {
-				for (sb = 0; sb < frame->subbands; sb++) {
+				for (sb = 0; sb < subbands; sb++) {
 					bitneed[ch][sb] = frame->scale_factor[ch][sb];
 					if (bitneed[ch][sb] > max_bitneed)
 						max_bitneed = bitneed[ch][sb];
 				}
 			} else {
-				for (sb = 0; sb < frame->subbands; sb++) {
+				for (sb = 0; sb < subbands; sb++) {
 					if (frame->scale_factor[ch][sb] == 0)
 						bitneed[ch][sb] = -5;
 					else {
-						if (frame->subbands == 4)
+						if (subbands == 4)
 							loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
 						else
 							loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
@@ -201,7 +203,7 @@
 				bitslice--;
 				bitcount += slicecount;
 				slicecount = 0;
-				for (sb = 0; sb < frame->subbands; sb++) {
+				for (sb = 0; sb < subbands; sb++) {
 					if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
 						slicecount++;
 					else if (bitneed[ch][sb] == bitslice + 1)
@@ -214,7 +216,7 @@
 				bitslice--;
 			}
 
-			for (sb = 0; sb < frame->subbands; sb++) {
+			for (sb = 0; sb < subbands; sb++) {
 				if (bitneed[ch][sb] < bitslice + 2)
 					bits[ch][sb] = 0;
 				else {
@@ -224,7 +226,8 @@
 				}
 			}
 
-			for (sb = 0; bitcount < frame->bitpool && sb < frame->subbands; sb++) {
+			for (sb = 0; bitcount < frame->bitpool &&
+							sb < subbands; sb++) {
 				if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) {
 					bits[ch][sb]++;
 					bitcount++;
@@ -234,7 +237,8 @@
 				}
 			}
 
-			for (sb = 0; bitcount < frame->bitpool && sb < frame->subbands; sb++) {
+			for (sb = 0; bitcount < frame->bitpool &&
+							sb < subbands; sb++) {
 				if (bits[ch][sb] < 16) {
 					bits[ch][sb]++;
 					bitcount++;
@@ -250,7 +254,7 @@
 		max_bitneed = 0;
 		if (frame->allocation == SNR) {
 			for (ch = 0; ch < 2; ch++) {
-				for (sb = 0; sb < frame->subbands; sb++) {
+				for (sb = 0; sb < subbands; sb++) {
 					bitneed[ch][sb] = frame->scale_factor[ch][sb];
 					if (bitneed[ch][sb] > max_bitneed)
 						max_bitneed = bitneed[ch][sb];
@@ -258,11 +262,11 @@
 			}
 		} else {
 			for (ch = 0; ch < 2; ch++) {
-				for (sb = 0; sb < frame->subbands; sb++) {
+				for (sb = 0; sb < subbands; sb++) {
 					if (frame->scale_factor[ch][sb] == 0)
 						bitneed[ch][sb] = -5;
 					else {
-						if (frame->subbands == 4)
+						if (subbands == 4)
 							loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
 						else
 							loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
@@ -285,7 +289,7 @@
 			bitcount += slicecount;
 			slicecount = 0;
 			for (ch = 0; ch < 2; ch++) {
-				for (sb = 0; sb < frame->subbands; sb++) {
+				for (sb = 0; sb < subbands; sb++) {
 					if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
 						slicecount++;
 					else if (bitneed[ch][sb] == bitslice + 1)
@@ -300,7 +304,7 @@
 		}
 
 		for (ch = 0; ch < 2; ch++) {
-			for (sb = 0; sb < frame->subbands; sb++) {
+			for (sb = 0; sb < subbands; sb++) {
 				if (bitneed[ch][sb] < bitslice + 2) {
 					bits[ch][sb] = 0;
 				} else {
@@ -324,7 +328,8 @@
 			if (ch == 1) {
 				ch = 0;
 				sb++;
-				if (sb >= frame->subbands) break;
+				if (sb >= subbands)
+					break;
 			} else
 				ch = 1;
 		}
@@ -339,7 +344,8 @@
 			if (ch == 1) {
 				ch = 0;
 				sb++;
-				if (sb >= frame->subbands) break;
+				if (sb >= subbands)
+					break;
 			} else
 				ch = 1;
 		}
@@ -348,6 +354,14 @@
 
 }
 
+static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
+{
+	if (frame->subbands == 4)
+		sbc_calculate_bits_internal(frame, bits, 4);
+	else
+		sbc_calculate_bits_internal(frame, bits, 8);
+}
+
 /*
  * Unpacks a SBC frame at the beginning of the stream in data,
  * which has at most len bytes into frame.
@@ -742,9 +756,10 @@
  * -99 not implemented
  */
 
-static SBC_ALWAYS_INLINE int sbc_pack_frame_internal(uint8_t *data,
+static SBC_ALWAYS_INLINE ssize_t sbc_pack_frame_internal(uint8_t *data,
 					struct sbc_frame *frame, size_t len,
-					int frame_subbands, int frame_channels)
+					int frame_subbands, int frame_channels,
+					int joint)
 {
 	/* Bitstream writer starts from the fourth byte */
 	uint8_t *data_ptr = data + 4;
@@ -801,63 +816,6 @@
 	crc_pos = 16;
 
 	if (frame->mode == JOINT_STEREO) {
-		/* like frame->sb_sample but joint stereo */
-		int32_t sb_sample_j[16][2];
-		/* scalefactor and scale_factor in joint case */
-		uint32_t scalefactor_j[2];
-		uint8_t scale_factor_j[2];
-
-		uint8_t joint = 0;
-		frame->joint = 0;
-
-		for (sb = 0; sb < frame_subbands - 1; sb++) {
-			scale_factor_j[0] = 0;
-			scalefactor_j[0] = 2 << SCALE_OUT_BITS;
-			scale_factor_j[1] = 0;
-			scalefactor_j[1] = 2 << SCALE_OUT_BITS;
-
-			for (blk = 0; blk < frame->blocks; blk++) {
-				uint32_t tmp;
-				/* Calculate joint stereo signal */
-				sb_sample_j[blk][0] =
-					ASR(frame->sb_sample_f[blk][0][sb], 1) +
-					ASR(frame->sb_sample_f[blk][1][sb], 1);
-				sb_sample_j[blk][1] =
-					ASR(frame->sb_sample_f[blk][0][sb], 1) -
-					ASR(frame->sb_sample_f[blk][1][sb], 1);
-
-				/* calculate scale_factor_j and scalefactor_j for joint case */
-				tmp = fabs(sb_sample_j[blk][0]);
-				while (scalefactor_j[0] < tmp) {
-					scale_factor_j[0]++;
-					scalefactor_j[0] *= 2;
-				}
-				tmp = fabs(sb_sample_j[blk][1]);
-				while (scalefactor_j[1] < tmp) {
-					scale_factor_j[1]++;
-					scalefactor_j[1] *= 2;
-				}
-			}
-
-			/* decide whether to join this subband */
-			if ((frame->scale_factor[0][sb] +
-					frame->scale_factor[1][sb]) >
-					(scale_factor_j[0] +
-					scale_factor_j[1])) {
-				/* use joint stereo for this subband */
-				joint |= 1 << (frame_subbands - 1 - sb);
-				frame->joint |= 1 << sb;
-				frame->scale_factor[0][sb] = scale_factor_j[0];
-				frame->scale_factor[1][sb] = scale_factor_j[1];
-				for (blk = 0; blk < frame->blocks; blk++) {
-					frame->sb_sample_f[blk][0][sb] =
-							sb_sample_j[blk][0];
-					frame->sb_sample_f[blk][1][sb] =
-							sb_sample_j[blk][1];
-				}
-			}
-		}
-
 		PUT_BITS(data_ptr, bits_cache, bits_count,
 			joint, frame_subbands);
 		crc_header[crc_pos >> 3] = joint;
@@ -915,18 +873,23 @@
 	return data_ptr - data;
 }
 
-static int sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len)
+static ssize_t sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len,
+								int joint)
 {
 	if (frame->subbands == 4) {
 		if (frame->channels == 1)
-			return sbc_pack_frame_internal(data, frame, len, 4, 1);
+			return sbc_pack_frame_internal(
+				data, frame, len, 4, 1, joint);
 		else
-			return sbc_pack_frame_internal(data, frame, len, 4, 2);
+			return sbc_pack_frame_internal(
+				data, frame, len, 4, 2, joint);
 	} else {
 		if (frame->channels == 1)
-			return sbc_pack_frame_internal(data, frame, len, 8, 1);
+			return sbc_pack_frame_internal(
+				data, frame, len, 8, 1, joint);
 		else
-			return sbc_pack_frame_internal(data, frame, len, 8, 2);
+			return sbc_pack_frame_internal(
+				data, frame, len, 8, 2, joint);
 	}
 }
 
@@ -1055,10 +1018,11 @@
 }
 
 ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
-			void *output, size_t output_len, size_t *written)
+			void *output, size_t output_len, ssize_t *written)
 {
 	struct sbc_priv *priv;
-	int framelen, samples;
+	int samples;
+	ssize_t framelen;
 	int (*sbc_enc_process_input)(int position,
 			const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
 			int nsamples, int nchannels);
@@ -1120,11 +1084,18 @@
 
 	samples = sbc_analyze_audio(&priv->enc_state, &priv->frame);
 
-	priv->enc_state.sbc_calc_scalefactors(
-		priv->frame.sb_sample_f, priv->frame.scale_factor,
-		priv->frame.blocks, priv->frame.channels, priv->frame.subbands);
-
-	framelen = sbc_pack_frame(output, &priv->frame, output_len);
+	if (priv->frame.mode == JOINT_STEREO) {
+		int j = priv->enc_state.sbc_calc_scalefactors_j(
+			priv->frame.sb_sample_f, priv->frame.scale_factor,
+			priv->frame.blocks, priv->frame.subbands);
+		framelen = sbc_pack_frame(output, &priv->frame, output_len, j);
+	} else {
+		priv->enc_state.sbc_calc_scalefactors(
+			priv->frame.sb_sample_f, priv->frame.scale_factor,
+			priv->frame.blocks, priv->frame.channels,
+			priv->frame.subbands);
+		framelen = sbc_pack_frame(output, &priv->frame, output_len, 0);
+	}
 
 	if (written)
 		*written = framelen;
@@ -1137,8 +1108,7 @@
 	if (!sbc)
 		return;
 
-	if (sbc->priv_alloc_base)
-		free(sbc->priv_alloc_base);
+	free(sbc->priv_alloc_base);
 
 	memset(sbc, 0, sizeof(sbc_t));
 }
diff --git a/sbc/sbc.h b/sbc/sbc.h
index 0d834d6..2f830ad 100644
--- a/sbc/sbc.h
+++ b/sbc/sbc.h
@@ -2,7 +2,8 @@
  *
  *  Bluetooth low-complexity, subband codec (SBC) library
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
  *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
  *
@@ -91,7 +92,7 @@
 
 /* Encodes ONE input block into ONE output block */
 ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
-			void *output, size_t output_len, size_t *written);
+			void *output, size_t output_len, ssize_t *written);
 
 /* Returns the output block size in bytes */
 size_t sbc_get_frame_length(sbc_t *sbc);
diff --git a/sbc/sbc_math.h b/sbc/sbc_math.h
index b87bc81..9f126c6 100644
--- a/sbc/sbc_math.h
+++ b/sbc/sbc_math.h
@@ -2,7 +2,8 @@
  *
  *  Bluetooth low-complexity, subband codec (SBC) library
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
  *  Copyright (C) 2005-2008  Brad Midgley <bmidgley@xmission.com>
  *
diff --git a/sbc/sbc_primitives.c b/sbc/sbc_primitives.c
index 2105280..f87fb5a 100644
--- a/sbc/sbc_primitives.c
+++ b/sbc/sbc_primitives.c
@@ -2,7 +2,8 @@
  *
  *  Bluetooth low-complexity, subband codec (SBC) library
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
  *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
  *
@@ -33,6 +34,7 @@
 #include "sbc_primitives.h"
 #include "sbc_primitives_mmx.h"
 #include "sbc_primitives_neon.h"
+#include "sbc_primitives_armv6.h"
 
 /*
  * A reference C code of analysis filter with SIMD-friendly tables
@@ -439,6 +441,80 @@
 	}
 }
 
+static int sbc_calc_scalefactors_j(
+	int32_t sb_sample_f[16][2][8],
+	uint32_t scale_factor[2][8],
+	int blocks, int subbands)
+{
+	int blk, joint = 0;
+	int32_t tmp0, tmp1;
+	uint32_t x, y;
+
+	/* last subband does not use joint stereo */
+	int sb = subbands - 1;
+	x = 1 << SCALE_OUT_BITS;
+	y = 1 << SCALE_OUT_BITS;
+	for (blk = 0; blk < blocks; blk++) {
+		tmp0 = fabs(sb_sample_f[blk][0][sb]);
+		tmp1 = fabs(sb_sample_f[blk][1][sb]);
+		if (tmp0 != 0)
+			x |= tmp0 - 1;
+		if (tmp1 != 0)
+			y |= tmp1 - 1;
+	}
+	scale_factor[0][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(x);
+	scale_factor[1][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(y);
+
+	/* the rest of subbands can use joint stereo */
+	while (--sb >= 0) {
+		int32_t sb_sample_j[16][2];
+		x = 1 << SCALE_OUT_BITS;
+		y = 1 << SCALE_OUT_BITS;
+		for (blk = 0; blk < blocks; blk++) {
+			tmp0 = sb_sample_f[blk][0][sb];
+			tmp1 = sb_sample_f[blk][1][sb];
+			sb_sample_j[blk][0] = ASR(tmp0, 1) + ASR(tmp1, 1);
+			sb_sample_j[blk][1] = ASR(tmp0, 1) - ASR(tmp1, 1);
+			tmp0 = fabs(tmp0);
+			tmp1 = fabs(tmp1);
+			if (tmp0 != 0)
+				x |= tmp0 - 1;
+			if (tmp1 != 0)
+				y |= tmp1 - 1;
+		}
+		scale_factor[0][sb] = (31 - SCALE_OUT_BITS) -
+			sbc_clz(x);
+		scale_factor[1][sb] = (31 - SCALE_OUT_BITS) -
+			sbc_clz(y);
+		x = 1 << SCALE_OUT_BITS;
+		y = 1 << SCALE_OUT_BITS;
+		for (blk = 0; blk < blocks; blk++) {
+			tmp0 = fabs(sb_sample_j[blk][0]);
+			tmp1 = fabs(sb_sample_j[blk][1]);
+			if (tmp0 != 0)
+				x |= tmp0 - 1;
+			if (tmp1 != 0)
+				y |= tmp1 - 1;
+		}
+		x = (31 - SCALE_OUT_BITS) - sbc_clz(x);
+		y = (31 - SCALE_OUT_BITS) - sbc_clz(y);
+
+		/* decide whether to use joint stereo for this subband */
+		if ((scale_factor[0][sb] + scale_factor[1][sb]) > x + y) {
+			joint |= 1 << (subbands - 1 - sb);
+			scale_factor[0][sb] = x;
+			scale_factor[1][sb] = y;
+			for (blk = 0; blk < blocks; blk++) {
+				sb_sample_f[blk][0][sb] = sb_sample_j[blk][0];
+				sb_sample_f[blk][1][sb] = sb_sample_j[blk][1];
+			}
+		}
+	}
+
+	/* bitmask with the information about subbands using joint stereo */
+	return joint;
+}
+
 /*
  * Detect CPU features and setup function pointers
  */
@@ -456,6 +532,7 @@
 
 	/* Default implementation for scale factors calculation */
 	state->sbc_calc_scalefactors = sbc_calc_scalefactors;
+	state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j;
 	state->implementation_info = "Generic C";
 
 	/* X86/AMD64 optimizations */
@@ -464,6 +541,9 @@
 #endif
 
 	/* ARM optimizations */
+#ifdef SBC_BUILD_WITH_ARMV6_SUPPORT
+	sbc_init_primitives_armv6(state);
+#endif
 #ifdef SBC_BUILD_WITH_NEON_SUPPORT
 	sbc_init_primitives_neon(state);
 #endif
diff --git a/sbc/sbc_primitives.h b/sbc/sbc_primitives.h
index 3d01c11..3fec8d5 100644
--- a/sbc/sbc_primitives.h
+++ b/sbc/sbc_primitives.h
@@ -2,7 +2,8 @@
  *
  *  Bluetooth low-complexity, subband codec (SBC) library
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
  *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
  *
@@ -62,6 +63,10 @@
 	void (*sbc_calc_scalefactors)(int32_t sb_sample_f[16][2][8],
 			uint32_t scale_factor[2][8],
 			int blocks, int channels, int subbands);
+	/* Scale factors calculation with joint stereo support */
+	int (*sbc_calc_scalefactors_j)(int32_t sb_sample_f[16][2][8],
+			uint32_t scale_factor[2][8],
+			int blocks, int subbands);
 	const char *implementation_info;
 };
 
diff --git a/sbc/sbc_primitives_armv6.c b/sbc/sbc_primitives_armv6.c
new file mode 100644
index 0000000..9586098
--- /dev/null
+++ b/sbc/sbc_primitives_armv6.c
@@ -0,0 +1,299 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ *  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
+ *
+ */
+
+#include <stdint.h>
+#include <limits.h>
+#include "sbc.h"
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc_primitives_armv6.h"
+
+/*
+ * ARMv6 optimizations. The instructions are scheduled for ARM11 pipeline.
+ */
+
+#ifdef SBC_BUILD_WITH_ARMV6_SUPPORT
+
+static void __attribute__((naked)) sbc_analyze_four_armv6()
+{
+	/* r0 = in, r1 = out, r2 = consts */
+	asm volatile (
+		"push   {r1, r4-r7, lr}\n"
+		"push   {r8-r11}\n"
+		"ldrd   r4,  r5,  [r0, #0]\n"
+		"ldrd   r6,  r7,  [r2, #0]\n"
+		"ldrd   r8,  r9,  [r0, #16]\n"
+		"ldrd   r10, r11, [r2, #16]\n"
+		"mov    r14, #0x8000\n"
+		"smlad  r3,  r4,  r6,  r14\n"
+		"smlad  r12, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r0, #32]\n"
+		"ldrd   r6,  r7,  [r2, #32]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #48]\n"
+		"ldrd   r10, r11, [r2, #48]\n"
+		"smlad  r3,  r4,  r6,  r3\n"
+		"smlad  r12, r5,  r7,  r12\n"
+		"ldrd   r4,  r5,  [r0, #64]\n"
+		"ldrd   r6,  r7,  [r2, #64]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #8]\n"
+		"ldrd   r10, r11, [r2, #8]\n"
+		"smlad  r3,  r4,  r6,  r3\n"      /* t1[0] is done */
+		"smlad  r12, r5,  r7,  r12\n"     /* t1[1] is done */
+		"ldrd   r4,  r5,  [r0, #24]\n"
+		"ldrd   r6,  r7,  [r2, #24]\n"
+		"pkhtb  r3,  r12, r3, asr #16\n"  /* combine t1[0] and t1[1] */
+		"smlad  r12, r8,  r10, r14\n"
+		"smlad  r14, r9,  r11, r14\n"
+		"ldrd   r8,  r9,  [r0, #40]\n"
+		"ldrd   r10, r11, [r2, #40]\n"
+		"smlad  r12, r4,  r6,  r12\n"
+		"smlad  r14, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r0, #56]\n"
+		"ldrd   r6,  r7,  [r2, #56]\n"
+		"smlad  r12, r8,  r10, r12\n"
+		"smlad  r14, r9,  r11, r14\n"
+		"ldrd   r8,  r9,  [r0, #72]\n"
+		"ldrd   r10, r11, [r2, #72]\n"
+		"smlad  r12, r4,  r6,  r12\n"
+		"smlad  r14, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r2, #80]\n"    /* start loading cos table */
+		"smlad  r12, r8,  r10, r12\n"     /* t1[2] is done */
+		"smlad  r14, r9,  r11, r14\n"     /* t1[3] is done */
+		"ldrd   r6,  r7,  [r2, #88]\n"
+		"ldrd   r8,  r9,  [r2, #96]\n"
+		"ldrd   r10, r11, [r2, #104]\n"   /* cos table fully loaded */
+		"pkhtb  r12, r14, r12, asr #16\n" /* combine t1[2] and t1[3] */
+		"smuad  r4,  r3,  r4\n"
+		"smuad  r5,  r3,  r5\n"
+		"smlad  r4,  r12, r8,  r4\n"
+		"smlad  r5,  r12, r9,  r5\n"
+		"smuad  r6,  r3,  r6\n"
+		"smuad  r7,  r3,  r7\n"
+		"smlad  r6,  r12, r10, r6\n"
+		"smlad  r7,  r12, r11, r7\n"
+		"pop    {r8-r11}\n"
+		"stmia  r1, {r4, r5, r6, r7}\n"
+		"pop    {r1, r4-r7, pc}\n"
+	);
+}
+
+#define sbc_analyze_four(in, out, consts) \
+	((void (*)(int16_t *, int32_t *, const FIXED_T*)) \
+		sbc_analyze_four_armv6)((in), (out), (consts))
+
+static void __attribute__((naked)) sbc_analyze_eight_armv6()
+{
+	/* r0 = in, r1 = out, r2 = consts */
+	asm volatile (
+		"push   {r1, r4-r7, lr}\n"
+		"push   {r8-r11}\n"
+		"ldrd   r4,  r5,  [r0, #24]\n"
+		"ldrd   r6,  r7,  [r2, #24]\n"
+		"ldrd   r8,  r9,  [r0, #56]\n"
+		"ldrd   r10, r11, [r2, #56]\n"
+		"mov    r14, #0x8000\n"
+		"smlad  r3,  r4,  r6,  r14\n"
+		"smlad  r12, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r0, #88]\n"
+		"ldrd   r6,  r7,  [r2, #88]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #120]\n"
+		"ldrd   r10, r11, [r2, #120]\n"
+		"smlad  r3,  r4,  r6,  r3\n"
+		"smlad  r12, r5,  r7,  r12\n"
+		"ldrd   r4,  r5,  [r0, #152]\n"
+		"ldrd   r6,  r7,  [r2, #152]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #16]\n"
+		"ldrd   r10, r11, [r2, #16]\n"
+		"smlad  r3,  r4,  r6,  r3\n"      /* t1[6] is done */
+		"smlad  r12, r5,  r7,  r12\n"     /* t1[7] is done */
+		"ldrd   r4,  r5,  [r0, #48]\n"
+		"ldrd   r6,  r7,  [r2, #48]\n"
+		"pkhtb  r3,  r12, r3, asr #16\n"  /* combine t1[6] and t1[7] */
+		"str    r3,  [sp, #-4]!\n"        /* save to stack */
+		"smlad  r3,  r8,  r10, r14\n"
+		"smlad  r12, r9,  r11, r14\n"
+		"ldrd   r8,  r9,  [r0, #80]\n"
+		"ldrd   r10, r11, [r2, #80]\n"
+		"smlad  r3,  r4,  r6,  r3\n"
+		"smlad  r12, r5,  r7,  r12\n"
+		"ldrd   r4,  r5,  [r0, #112]\n"
+		"ldrd   r6,  r7,  [r2, #112]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #144]\n"
+		"ldrd   r10, r11, [r2, #144]\n"
+		"smlad  r3,  r4,  r6,  r3\n"
+		"smlad  r12, r5,  r7,  r12\n"
+		"ldrd   r4,  r5,  [r0, #0]\n"
+		"ldrd   r6,  r7,  [r2, #0]\n"
+		"smlad  r3,  r8,  r10, r3\n"      /* t1[4] is done */
+		"smlad  r12, r9,  r11, r12\n"     /* t1[5] is done */
+		"ldrd   r8,  r9,  [r0, #32]\n"
+		"ldrd   r10, r11, [r2, #32]\n"
+		"pkhtb  r3,  r12, r3, asr #16\n"  /* combine t1[4] and t1[5] */
+		"str    r3,  [sp, #-4]!\n"        /* save to stack */
+		"smlad  r3,  r4,  r6,  r14\n"
+		"smlad  r12, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r0, #64]\n"
+		"ldrd   r6,  r7,  [r2, #64]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #96]\n"
+		"ldrd   r10, r11, [r2, #96]\n"
+		"smlad  r3,  r4,  r6,  r3\n"
+		"smlad  r12, r5,  r7,  r12\n"
+		"ldrd   r4,  r5,  [r0, #128]\n"
+		"ldrd   r6,  r7,  [r2, #128]\n"
+		"smlad  r3,  r8,  r10, r3\n"
+		"smlad  r12, r9,  r11, r12\n"
+		"ldrd   r8,  r9,  [r0, #8]\n"
+		"ldrd   r10, r11, [r2, #8]\n"
+		"smlad  r3,  r4,  r6,  r3\n"      /* t1[0] is done */
+		"smlad  r12, r5,  r7,  r12\n"     /* t1[1] is done */
+		"ldrd   r4,  r5,  [r0, #40]\n"
+		"ldrd   r6,  r7,  [r2, #40]\n"
+		"pkhtb  r3,  r12, r3, asr #16\n"  /* combine t1[0] and t1[1] */
+		"smlad  r12, r8,  r10, r14\n"
+		"smlad  r14, r9,  r11, r14\n"
+		"ldrd   r8,  r9,  [r0, #72]\n"
+		"ldrd   r10, r11, [r2, #72]\n"
+		"smlad  r12, r4,  r6,  r12\n"
+		"smlad  r14, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r0, #104]\n"
+		"ldrd   r6,  r7,  [r2, #104]\n"
+		"smlad  r12, r8,  r10, r12\n"
+		"smlad  r14, r9,  r11, r14\n"
+		"ldrd   r8,  r9,  [r0, #136]\n"
+		"ldrd   r10, r11, [r2, #136]!\n"
+		"smlad  r12, r4,  r6,  r12\n"
+		"smlad  r14, r5,  r7,  r14\n"
+		"ldrd   r4,  r5,  [r2, #(160 - 136 + 0)]\n"
+		"smlad  r12, r8,  r10, r12\n"     /* t1[2] is done */
+		"smlad  r14, r9,  r11, r14\n"     /* t1[3] is done */
+		"ldrd   r6,  r7,  [r2, #(160 - 136 + 8)]\n"
+		"smuad  r4,  r3,  r4\n"
+		"smuad  r5,  r3,  r5\n"
+		"pkhtb  r12, r14, r12, asr #16\n" /* combine t1[2] and t1[3] */
+						  /* r3  = t2[0:1] */
+						  /* r12 = t2[2:3] */
+		"pop    {r0, r14}\n"              /* t2[4:5], t2[6:7] */
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 32)]\n"
+		"smuad  r6,  r3,  r6\n"
+		"smuad  r7,  r3,  r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 40)]\n"
+		"smlad  r4,  r12, r8,  r4\n"
+		"smlad  r5,  r12, r9,  r5\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 64)]\n"
+		"smlad  r6,  r12, r10, r6\n"
+		"smlad  r7,  r12, r11, r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 72)]\n"
+		"smlad  r4,  r0,  r8,  r4\n"
+		"smlad  r5,  r0,  r9,  r5\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 96)]\n"
+		"smlad  r6,  r0,  r10, r6\n"
+		"smlad  r7,  r0,  r11, r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 104)]\n"
+		"smlad  r4,  r14, r8,  r4\n"
+		"smlad  r5,  r14, r9,  r5\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 16 + 0)]\n"
+		"smlad  r6,  r14, r10, r6\n"
+		"smlad  r7,  r14, r11, r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 16 + 8)]\n"
+		"stmia  r1!, {r4, r5}\n"
+		"smuad  r4,  r3,  r8\n"
+		"smuad  r5,  r3,  r9\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 16 + 32)]\n"
+		"stmia  r1!, {r6, r7}\n"
+		"smuad  r6,  r3,  r10\n"
+		"smuad  r7,  r3,  r11\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 16 + 40)]\n"
+		"smlad  r4,  r12, r8,  r4\n"
+		"smlad  r5,  r12, r9,  r5\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 16 + 64)]\n"
+		"smlad  r6,  r12, r10, r6\n"
+		"smlad  r7,  r12, r11, r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 16 + 72)]\n"
+		"smlad  r4,  r0,  r8,  r4\n"
+		"smlad  r5,  r0,  r9,  r5\n"
+		"ldrd   r8,  r9,  [r2, #(160 - 136 + 16 + 96)]\n"
+		"smlad  r6,  r0,  r10, r6\n"
+		"smlad  r7,  r0,  r11, r7\n"
+		"ldrd   r10, r11, [r2, #(160 - 136 + 16 + 104)]\n"
+		"smlad  r4,  r14, r8,  r4\n"
+		"smlad  r5,  r14, r9,  r5\n"
+		"smlad  r6,  r14, r10, r6\n"
+		"smlad  r7,  r14, r11, r7\n"
+		"pop    {r8-r11}\n"
+		"stmia  r1!, {r4, r5, r6, r7}\n"
+		"pop    {r1, r4-r7, pc}\n"
+	);
+}
+
+#define sbc_analyze_eight(in, out, consts) \
+	((void (*)(int16_t *, int32_t *, const FIXED_T*)) \
+		sbc_analyze_eight_armv6)((in), (out), (consts))
+
+static void sbc_analyze_4b_4s_armv6(int16_t *x, int32_t *out, int out_stride)
+{
+	/* Analyze blocks */
+	sbc_analyze_four(x + 12, out, analysis_consts_fixed4_simd_odd);
+	out += out_stride;
+	sbc_analyze_four(x + 8, out, analysis_consts_fixed4_simd_even);
+	out += out_stride;
+	sbc_analyze_four(x + 4, out, analysis_consts_fixed4_simd_odd);
+	out += out_stride;
+	sbc_analyze_four(x + 0, out, analysis_consts_fixed4_simd_even);
+}
+
+static void sbc_analyze_4b_8s_armv6(int16_t *x, int32_t *out, int out_stride)
+{
+	/* Analyze blocks */
+	sbc_analyze_eight(x + 24, out, analysis_consts_fixed8_simd_odd);
+	out += out_stride;
+	sbc_analyze_eight(x + 16, out, analysis_consts_fixed8_simd_even);
+	out += out_stride;
+	sbc_analyze_eight(x + 8, out, analysis_consts_fixed8_simd_odd);
+	out += out_stride;
+	sbc_analyze_eight(x + 0, out, analysis_consts_fixed8_simd_even);
+}
+
+void sbc_init_primitives_armv6(struct sbc_encoder_state *state)
+{
+	state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_armv6;
+	state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_armv6;
+	state->implementation_info = "ARMv6 SIMD";
+}
+
+#endif
diff --git a/sbc/sbc_primitives_armv6.h b/sbc/sbc_primitives_armv6.h
new file mode 100644
index 0000000..1862aed
--- /dev/null
+++ b/sbc/sbc_primitives_armv6.h
@@ -0,0 +1,52 @@
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ *  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
+ *
+ */
+
+#ifndef __SBC_PRIMITIVES_ARMV6_H
+#define __SBC_PRIMITIVES_ARMV6_H
+
+#include "sbc_primitives.h"
+
+#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
+	defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \
+	defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) || \
+	defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_7__) || \
+	defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || \
+	defined(__ARM_ARCH_7M__)
+#define SBC_HAVE_ARMV6 1
+#endif
+
+#if !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15) && \
+	defined(__GNUC__) && defined(SBC_HAVE_ARMV6) && \
+	defined(__ARM_EABI__) && !defined(__thumb__) && \
+	!defined(__ARM_NEON__)
+
+#define SBC_BUILD_WITH_ARMV6_SUPPORT
+
+void sbc_init_primitives_armv6(struct sbc_encoder_state *encoder_state);
+
+#endif
+
+#endif
diff --git a/sbc/sbc_primitives_mmx.c b/sbc/sbc_primitives_mmx.c
index 08e9ca2..45c62ac 100644
--- a/sbc/sbc_primitives_mmx.c
+++ b/sbc/sbc_primitives_mmx.c
@@ -2,7 +2,8 @@
  *
  *  Bluetooth low-complexity, subband codec (SBC) library
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
  *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
  *
@@ -275,6 +276,59 @@
 	asm volatile ("emms\n");
 }
 
+static void sbc_calc_scalefactors_mmx(
+	int32_t sb_sample_f[16][2][8],
+	uint32_t scale_factor[2][8],
+	int blocks, int channels, int subbands)
+{
+	static const SBC_ALIGNED int32_t consts[2] = {
+		1 << SCALE_OUT_BITS,
+		1 << SCALE_OUT_BITS,
+	};
+	int ch, sb;
+	intptr_t blk;
+	for (ch = 0; ch < channels; ch++) {
+		for (sb = 0; sb < subbands; sb += 2) {
+			blk = (blocks - 1) * (((char *) &sb_sample_f[1][0][0] -
+				(char *) &sb_sample_f[0][0][0]));
+			asm volatile (
+				"movq         (%4), %%mm0\n"
+			"1:\n"
+				"movq     (%1, %0), %%mm1\n"
+				"pxor        %%mm2, %%mm2\n"
+				"pcmpgtd     %%mm2, %%mm1\n"
+				"paddd    (%1, %0), %%mm1\n"
+				"pcmpgtd     %%mm1, %%mm2\n"
+				"pxor        %%mm2, %%mm1\n"
+
+				"por         %%mm1, %%mm0\n"
+
+				"sub            %2, %0\n"
+				"jns            1b\n"
+
+				"movd        %%mm0, %k0\n"
+				"psrlq         $32, %%mm0\n"
+				"bsrl          %k0, %k0\n"
+				"subl           %5, %k0\n"
+				"movl          %k0, (%3)\n"
+
+				"movd        %%mm0, %k0\n"
+				"bsrl          %k0, %k0\n"
+				"subl           %5, %k0\n"
+				"movl          %k0, 4(%3)\n"
+			: "+r" (blk)
+			: "r" (&sb_sample_f[0][ch][sb]),
+				"i" ((char *) &sb_sample_f[1][0][0] -
+					(char *) &sb_sample_f[0][0][0]),
+				"r" (&scale_factor[ch][sb]),
+				"r" (&consts),
+				"i" (SCALE_OUT_BITS)
+			: "memory");
+		}
+	}
+	asm volatile ("emms\n");
+}
+
 static int check_mmx_support(void)
 {
 #ifdef __amd64__
@@ -313,6 +367,7 @@
 	if (check_mmx_support()) {
 		state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_mmx;
 		state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_mmx;
+		state->sbc_calc_scalefactors = sbc_calc_scalefactors_mmx;
 		state->implementation_info = "MMX";
 	}
 }
diff --git a/sbc/sbc_primitives_mmx.h b/sbc/sbc_primitives_mmx.h
index c1e44a5..e0e728b 100644
--- a/sbc/sbc_primitives_mmx.h
+++ b/sbc/sbc_primitives_mmx.h
@@ -2,7 +2,8 @@
  *
  *  Bluetooth low-complexity, subband codec (SBC) library
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
  *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
  *
diff --git a/sbc/sbc_primitives_neon.c b/sbc/sbc_primitives_neon.c
index f1bc7b4..0572158 100644
--- a/sbc/sbc_primitives_neon.c
+++ b/sbc/sbc_primitives_neon.c
@@ -2,7 +2,8 @@
  *
  *  Bluetooth low-complexity, subband codec (SBC) library
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
  *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
  *
@@ -236,10 +237,656 @@
 	_sbc_analyze_eight_neon(x + 0, out, analysis_consts_fixed8_simd_even);
 }
 
+static void sbc_calc_scalefactors_neon(
+	int32_t sb_sample_f[16][2][8],
+	uint32_t scale_factor[2][8],
+	int blocks, int channels, int subbands)
+{
+	int ch, sb;
+	for (ch = 0; ch < channels; ch++) {
+		for (sb = 0; sb < subbands; sb += 4) {
+			int blk = blocks;
+			int32_t *in = &sb_sample_f[0][ch][sb];
+			asm volatile (
+				"vmov.s32  q0, #0\n"
+				"vmov.s32  q1, %[c1]\n"
+				"vmov.s32  q14, #1\n"
+				"vmov.s32  q15, %[c2]\n"
+				"vadd.s32  q1, q1, q14\n"
+			"1:\n"
+				"vld1.32   {d16, d17}, [%[in], :128], %[inc]\n"
+				"vabs.s32  q8,  q8\n"
+				"vld1.32   {d18, d19}, [%[in], :128], %[inc]\n"
+				"vabs.s32  q9,  q9\n"
+				"vld1.32   {d20, d21}, [%[in], :128], %[inc]\n"
+				"vabs.s32  q10, q10\n"
+				"vld1.32   {d22, d23}, [%[in], :128], %[inc]\n"
+				"vabs.s32  q11, q11\n"
+				"vmax.s32  q0,  q0,  q8\n"
+				"vmax.s32  q1,  q1,  q9\n"
+				"vmax.s32  q0,  q0,  q10\n"
+				"vmax.s32  q1,  q1,  q11\n"
+				"subs      %[blk], %[blk], #4\n"
+				"bgt       1b\n"
+				"vmax.s32  q0,  q0,  q1\n"
+				"vsub.s32  q0,  q0,  q14\n"
+				"vclz.s32  q0,  q0\n"
+				"vsub.s32  q0,  q15, q0\n"
+				"vst1.32   {d0, d1}, [%[out], :128]\n"
+			:
+			  [blk]    "+r" (blk),
+			  [in]     "+r" (in)
+			:
+			  [inc]     "r" ((char *) &sb_sample_f[1][0][0] -
+					 (char *) &sb_sample_f[0][0][0]),
+			  [out]     "r" (&scale_factor[ch][sb]),
+			  [c1]      "i" (1 << SCALE_OUT_BITS),
+			  [c2]      "i" (31 - SCALE_OUT_BITS)
+			: "d0", "d1", "d2", "d3", "d16", "d17", "d18", "d19",
+			  "d20", "d21", "d22", "d23", "d24", "d25", "d26",
+			  "d27", "d28", "d29", "d30", "d31", "cc", "memory");
+		}
+	}
+}
+
+int sbc_calc_scalefactors_j_neon(
+	int32_t sb_sample_f[16][2][8],
+	uint32_t scale_factor[2][8],
+	int blocks, int subbands)
+{
+	static SBC_ALIGNED int32_t joint_bits_mask[8] = {
+		8,   4,  2,  1, 128, 64, 32, 16
+	};
+	int joint, i;
+	int32_t  *in0, *in1;
+	int32_t  *in = &sb_sample_f[0][0][0];
+	uint32_t *out0, *out1;
+	uint32_t *out = &scale_factor[0][0];
+	int32_t  *consts = joint_bits_mask;
+
+	i = subbands;
+
+	asm volatile (
+		/*
+		 * constants: q13 = (31 - SCALE_OUT_BITS), q14 = 1
+		 * input:     q0  = ((1 << SCALE_OUT_BITS) + 1)
+		 *            %[in0] - samples for channel 0
+		 *            %[in1] - samples for shannel 1
+		 * output:    q0, q1 - scale factors without joint stereo
+		 *            q2, q3 - scale factors with joint stereo
+		 *            q15    - joint stereo selection mask
+		 */
+		".macro calc_scalefactors\n"
+			"vmov.s32  q1, q0\n"
+			"vmov.s32  q2, q0\n"
+			"vmov.s32  q3, q0\n"
+			"mov       %[i], %[blocks]\n"
+		"1:\n"
+			"vld1.32   {d18, d19}, [%[in1], :128], %[inc]\n"
+			"vbic.s32  q11, q9,  q14\n"
+			"vld1.32   {d16, d17}, [%[in0], :128], %[inc]\n"
+			"vhadd.s32 q10, q8,  q11\n"
+			"vhsub.s32 q11, q8,  q11\n"
+			"vabs.s32  q8,  q8\n"
+			"vabs.s32  q9,  q9\n"
+			"vabs.s32  q10, q10\n"
+			"vabs.s32  q11, q11\n"
+			"vmax.s32  q0,  q0,  q8\n"
+			"vmax.s32  q1,  q1,  q9\n"
+			"vmax.s32  q2,  q2,  q10\n"
+			"vmax.s32  q3,  q3,  q11\n"
+			"subs      %[i], %[i], #1\n"
+			"bgt       1b\n"
+			"vsub.s32  q0,  q0,  q14\n"
+			"vsub.s32  q1,  q1,  q14\n"
+			"vsub.s32  q2,  q2,  q14\n"
+			"vsub.s32  q3,  q3,  q14\n"
+			"vclz.s32  q0,  q0\n"
+			"vclz.s32  q1,  q1\n"
+			"vclz.s32  q2,  q2\n"
+			"vclz.s32  q3,  q3\n"
+			"vsub.s32  q0,  q13, q0\n"
+			"vsub.s32  q1,  q13, q1\n"
+			"vsub.s32  q2,  q13, q2\n"
+			"vsub.s32  q3,  q13, q3\n"
+		".endm\n"
+		/*
+		 * constants: q14 = 1
+		 * input: q15    - joint stereo selection mask
+		 *        %[in0] - value set by calc_scalefactors macro
+		 *        %[in1] - value set by calc_scalefactors macro
+		 */
+		".macro update_joint_stereo_samples\n"
+			"sub       %[out1], %[in1], %[inc]\n"
+			"sub       %[out0], %[in0], %[inc]\n"
+			"sub       %[in1], %[in1], %[inc], asl #1\n"
+			"sub       %[in0], %[in0], %[inc], asl #1\n"
+			"vld1.32   {d18, d19}, [%[in1], :128]\n"
+			"vbic.s32  q11, q9,  q14\n"
+			"vld1.32   {d16, d17}, [%[in0], :128]\n"
+			"vld1.32   {d2, d3}, [%[out1], :128]\n"
+			"vbic.s32  q3,  q1,  q14\n"
+			"vld1.32   {d0, d1}, [%[out0], :128]\n"
+			"vhsub.s32 q10, q8,  q11\n"
+			"vhadd.s32 q11, q8,  q11\n"
+			"vhsub.s32 q2,  q0,  q3\n"
+			"vhadd.s32 q3,  q0,  q3\n"
+			"vbif.s32  q10, q9,  q15\n"
+			"vbif.s32  d22, d16, d30\n"
+			"sub       %[inc], %[zero], %[inc], asl #1\n"
+			"sub       %[i], %[blocks], #2\n"
+		"2:\n"
+			"vbif.s32  d23, d17, d31\n"
+			"vst1.32   {d20, d21}, [%[in1], :128], %[inc]\n"
+			"vbif.s32  d4,  d2,  d30\n"
+			"vld1.32   {d18, d19}, [%[in1], :128]\n"
+			"vbif.s32  d5,  d3,  d31\n"
+			"vst1.32   {d22, d23}, [%[in0], :128], %[inc]\n"
+			"vbif.s32  d6,  d0,  d30\n"
+			"vld1.32   {d16, d17}, [%[in0], :128]\n"
+			"vbif.s32  d7,  d1,  d31\n"
+			"vst1.32   {d4, d5}, [%[out1], :128], %[inc]\n"
+			"vbic.s32  q11, q9,  q14\n"
+			"vld1.32   {d2, d3}, [%[out1], :128]\n"
+			"vst1.32   {d6, d7}, [%[out0], :128], %[inc]\n"
+			"vbic.s32  q3,  q1,  q14\n"
+			"vld1.32   {d0, d1}, [%[out0], :128]\n"
+			"vhsub.s32 q10, q8,  q11\n"
+			"vhadd.s32 q11, q8,  q11\n"
+			"vhsub.s32 q2,  q0,  q3\n"
+			"vhadd.s32 q3,  q0,  q3\n"
+			"vbif.s32  q10, q9,  q15\n"
+			"vbif.s32  d22, d16, d30\n"
+			"subs      %[i], %[i], #2\n"
+			"bgt       2b\n"
+			"sub       %[inc], %[zero], %[inc], asr #1\n"
+			"vbif.s32  d23, d17, d31\n"
+			"vst1.32   {d20, d21}, [%[in1], :128]\n"
+			"vbif.s32  q2,  q1,  q15\n"
+			"vst1.32   {d22, d23}, [%[in0], :128]\n"
+			"vbif.s32  q3,  q0,  q15\n"
+			"vst1.32   {d4, d5}, [%[out1], :128]\n"
+			"vst1.32   {d6, d7}, [%[out0], :128]\n"
+		".endm\n"
+
+		"vmov.s32  q14, #1\n"
+		"vmov.s32  q13, %[c2]\n"
+
+		"cmp   %[i], #4\n"
+		"bne   8f\n"
+
+	"4:\n" /* 4 subbands */
+		"add   %[in0], %[in], #0\n"
+		"add   %[in1], %[in], #32\n"
+		"add   %[out0], %[out], #0\n"
+		"add   %[out1], %[out], #32\n"
+		"vmov.s32  q0, %[c1]\n"
+		"vadd.s32  q0, q0, q14\n"
+
+		"calc_scalefactors\n"
+
+		/* check whether to use joint stereo for subbands 0, 1, 2 */
+		"vadd.s32  q15, q0,  q1\n"
+		"vadd.s32  q9,  q2,  q3\n"
+		"vmov.s32  d31[1], %[zero]\n" /* last subband -> no joint */
+		"vld1.32   {d16, d17}, [%[consts], :128]!\n"
+		"vcgt.s32  q15, q15, q9\n"
+
+		/* calculate and save to memory 'joint' variable */
+		/* update and save scale factors to memory */
+		"  vand.s32  q8, q8, q15\n"
+		"vbit.s32  q0,  q2,  q15\n"
+		"  vpadd.s32 d16, d16, d17\n"
+		"vbit.s32  q1,  q3,  q15\n"
+		"  vpadd.s32 d16, d16, d16\n"
+		"vst1.32   {d0, d1}, [%[out0], :128]\n"
+		"vst1.32   {d2, d3}, [%[out1], :128]\n"
+		"  vst1.32   {d16[0]}, [%[joint]]\n"
+
+		"update_joint_stereo_samples\n"
+		"b     9f\n"
+
+	"8:\n" /* 8 subbands */
+		"add   %[in0], %[in], #16\n\n"
+		"add   %[in1], %[in], #48\n"
+		"add   %[out0], %[out], #16\n\n"
+		"add   %[out1], %[out], #48\n"
+		"vmov.s32  q0, %[c1]\n"
+		"vadd.s32  q0, q0, q14\n"
+
+		"calc_scalefactors\n"
+
+		/* check whether to use joint stereo for subbands 4, 5, 6 */
+		"vadd.s32  q15, q0,  q1\n"
+		"vadd.s32  q9,  q2,  q3\n"
+		"vmov.s32  d31[1], %[zero]\n"  /* last subband -> no joint */
+		"vld1.32   {d16, d17}, [%[consts], :128]!\n"
+		"vcgt.s32  q15, q15, q9\n"
+
+		/* calculate part of 'joint' variable and save it to d24 */
+		/* update and save scale factors to memory */
+		"  vand.s32  q8, q8, q15\n"
+		"vbit.s32  q0,  q2,  q15\n"
+		"  vpadd.s32 d16, d16, d17\n"
+		"vbit.s32  q1,  q3,  q15\n"
+		"vst1.32   {d0, d1}, [%[out0], :128]\n"
+		"vst1.32   {d2, d3}, [%[out1], :128]\n"
+		"  vpadd.s32 d24, d16, d16\n"
+
+		"update_joint_stereo_samples\n"
+
+		"add   %[in0], %[in], #0\n"
+		"add   %[in1], %[in], #32\n"
+		"add   %[out0], %[out], #0\n\n"
+		"add   %[out1], %[out], #32\n"
+		"vmov.s32  q0, %[c1]\n"
+		"vadd.s32  q0, q0, q14\n"
+
+		"calc_scalefactors\n"
+
+		/* check whether to use joint stereo for subbands 0, 1, 2, 3 */
+		"vadd.s32  q15, q0,  q1\n"
+		"vadd.s32  q9,  q2,  q3\n"
+		"vld1.32   {d16, d17}, [%[consts], :128]!\n"
+		"vcgt.s32  q15, q15, q9\n"
+
+		/* combine last part of 'joint' with d24 and save to memory */
+		/* update and save scale factors to memory */
+		"  vand.s32  q8, q8, q15\n"
+		"vbit.s32  q0,  q2,  q15\n"
+		"  vpadd.s32 d16, d16, d17\n"
+		"vbit.s32  q1,  q3,  q15\n"
+		"  vpadd.s32 d16, d16, d16\n"
+		"vst1.32   {d0, d1}, [%[out0], :128]\n"
+		"  vadd.s32  d16, d16, d24\n"
+		"vst1.32   {d2, d3}, [%[out1], :128]\n"
+		"  vst1.32   {d16[0]}, [%[joint]]\n"
+
+		"update_joint_stereo_samples\n"
+	"9:\n"
+		".purgem calc_scalefactors\n"
+		".purgem update_joint_stereo_samples\n"
+		:
+		  [i]      "+&r" (i),
+		  [in]     "+&r" (in),
+		  [in0]    "=&r" (in0),
+		  [in1]    "=&r" (in1),
+		  [out]    "+&r" (out),
+		  [out0]   "=&r" (out0),
+		  [out1]   "=&r" (out1),
+		  [consts] "+&r" (consts)
+		:
+		  [inc]      "r" ((char *) &sb_sample_f[1][0][0] -
+				 (char *) &sb_sample_f[0][0][0]),
+		  [blocks]   "r" (blocks),
+		  [joint]    "r" (&joint),
+		  [c1]       "i" (1 << SCALE_OUT_BITS),
+		  [c2]       "i" (31 - SCALE_OUT_BITS),
+		  [zero]     "r" (0)
+		: "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+		  "d16", "d17", "d18", "d19", "d20", "d21", "d22",
+		  "d23", "d24", "d25", "d26", "d27", "d28", "d29",
+		  "d30", "d31", "cc", "memory");
+
+	return joint;
+}
+
+#define PERM_BE(a, b, c, d) {             \
+		(a * 2) + 1, (a * 2) + 0, \
+		(b * 2) + 1, (b * 2) + 0, \
+		(c * 2) + 1, (c * 2) + 0, \
+		(d * 2) + 1, (d * 2) + 0  \
+	}
+#define PERM_LE(a, b, c, d) {             \
+		(a * 2) + 0, (a * 2) + 1, \
+		(b * 2) + 0, (b * 2) + 1, \
+		(c * 2) + 0, (c * 2) + 1, \
+		(d * 2) + 0, (d * 2) + 1  \
+	}
+
+static SBC_ALWAYS_INLINE int sbc_enc_process_input_4s_neon_internal(
+	int position,
+	const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+	int nsamples, int nchannels, int big_endian)
+{
+	static SBC_ALIGNED uint8_t perm_be[2][8] = {
+		PERM_BE(7, 3, 6, 4),
+		PERM_BE(0, 2, 1, 5)
+	};
+	static SBC_ALIGNED uint8_t perm_le[2][8] = {
+		PERM_LE(7, 3, 6, 4),
+		PERM_LE(0, 2, 1, 5)
+	};
+	/* handle X buffer wraparound */
+	if (position < nsamples) {
+		int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 40];
+		int16_t *src = &X[0][position];
+		asm volatile (
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0}, [%[src], :64]!\n"
+			"vst1.16 {d0}, [%[dst], :64]!\n"
+			:
+			  [dst] "+r" (dst),
+			  [src] "+r" (src)
+			: : "memory", "d0", "d1", "d2", "d3");
+		if (nchannels > 1) {
+			dst = &X[1][SBC_X_BUFFER_SIZE - 40];
+			src = &X[1][position];
+			asm volatile (
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0}, [%[src], :64]!\n"
+				"vst1.16 {d0}, [%[dst], :64]!\n"
+				:
+				  [dst] "+r" (dst),
+				  [src] "+r" (src)
+				: : "memory", "d0", "d1", "d2", "d3");
+		}
+		position = SBC_X_BUFFER_SIZE - 40;
+	}
+
+	if ((nchannels > 1) && ((uintptr_t)pcm & 1)) {
+		/* poor 'pcm' alignment */
+		int16_t *x = &X[0][position];
+		int16_t *y = &X[1][position];
+		asm volatile (
+			"vld1.8  {d0, d1}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #16\n"
+			"sub     %[y], %[y], #16\n"
+			"sub     %[position], %[position], #8\n"
+			"vld1.8  {d4, d5}, [%[pcm]]!\n"
+			"vuzp.16 d4,  d5\n"
+			"vld1.8  {d20, d21}, [%[pcm]]!\n"
+			"vuzp.16 d20, d21\n"
+			"vswp    d5,  d20\n"
+			"vtbl.8  d16, {d4, d5}, d0\n"
+			"vtbl.8  d17, {d4, d5}, d1\n"
+			"vtbl.8  d18, {d20, d21}, d0\n"
+			"vtbl.8  d19, {d20, d21}, d1\n"
+			"vst1.16 {d16, d17}, [%[x], :128]\n"
+			"vst1.16 {d18, d19}, [%[y], :128]\n"
+			"subs    %[nsamples], %[nsamples], #8\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [y]        "+r" (y),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+			  "d20", "d21", "d22", "d23");
+	} else if (nchannels > 1) {
+		/* proper 'pcm' alignment */
+		int16_t *x = &X[0][position];
+		int16_t *y = &X[1][position];
+		asm volatile (
+			"vld1.8  {d0, d1}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #16\n"
+			"sub     %[y], %[y], #16\n"
+			"sub     %[position], %[position], #8\n"
+			"vld2.16 {d4, d5}, [%[pcm]]!\n"
+			"vld2.16 {d20, d21}, [%[pcm]]!\n"
+			"vswp    d5, d20\n"
+			"vtbl.8  d16, {d4, d5}, d0\n"
+			"vtbl.8  d17, {d4, d5}, d1\n"
+			"vtbl.8  d18, {d20, d21}, d0\n"
+			"vtbl.8  d19, {d20, d21}, d1\n"
+			"vst1.16 {d16, d17}, [%[x], :128]\n"
+			"vst1.16 {d18, d19}, [%[y], :128]\n"
+			"subs    %[nsamples], %[nsamples], #8\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [y]        "+r" (y),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+			  "d20", "d21", "d22", "d23");
+	} else {
+		int16_t *x = &X[0][position];
+		asm volatile (
+			"vld1.8  {d0, d1}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #16\n"
+			"sub     %[position], %[position], #8\n"
+			"vld1.8  {d4, d5}, [%[pcm]]!\n"
+			"vtbl.8  d16, {d4, d5}, d0\n"
+			"vtbl.8  d17, {d4, d5}, d1\n"
+			"vst1.16 {d16, d17}, [%[x], :128]\n"
+			"subs    %[nsamples], %[nsamples], #8\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19");
+	}
+	return position;
+}
+
+static SBC_ALWAYS_INLINE int sbc_enc_process_input_8s_neon_internal(
+	int position,
+	const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
+	int nsamples, int nchannels, int big_endian)
+{
+	static SBC_ALIGNED uint8_t perm_be[4][8] = {
+		PERM_BE(15, 7, 14, 8),
+		PERM_BE(13, 9, 12, 10),
+		PERM_BE(11, 3, 6,  0),
+		PERM_BE(5,  1, 4,  2)
+	};
+	static SBC_ALIGNED uint8_t perm_le[4][8] = {
+		PERM_LE(15, 7, 14, 8),
+		PERM_LE(13, 9, 12, 10),
+		PERM_LE(11, 3, 6,  0),
+		PERM_LE(5,  1, 4,  2)
+	};
+	/* handle X buffer wraparound */
+	if (position < nsamples) {
+		int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 72];
+		int16_t *src = &X[0][position];
+		asm volatile (
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+			"vld1.16 {d0, d1}, [%[src], :128]!\n"
+			"vst1.16 {d0, d1}, [%[dst], :128]!\n"
+			:
+			  [dst] "+r" (dst),
+			  [src] "+r" (src)
+			: : "memory", "d0", "d1", "d2", "d3");
+		if (nchannels > 1) {
+			dst = &X[1][SBC_X_BUFFER_SIZE - 72];
+			src = &X[1][position];
+			asm volatile (
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
+				"vld1.16 {d0, d1}, [%[src], :128]!\n"
+				"vst1.16 {d0, d1}, [%[dst], :128]!\n"
+				:
+				  [dst] "+r" (dst),
+				  [src] "+r" (src)
+				: : "memory", "d0", "d1", "d2", "d3");
+		}
+		position = SBC_X_BUFFER_SIZE - 72;
+	}
+
+	if ((nchannels > 1) && ((uintptr_t)pcm & 1)) {
+		/* poor 'pcm' alignment */
+		int16_t *x = &X[0][position];
+		int16_t *y = &X[1][position];
+		asm volatile (
+			"vld1.8  {d0, d1, d2, d3}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #32\n"
+			"sub     %[y], %[y], #32\n"
+			"sub     %[position], %[position], #16\n"
+			"vld1.8  {d4, d5, d6, d7}, [%[pcm]]!\n"
+			"vuzp.16 q2,  q3\n"
+			"vld1.8  {d20, d21, d22, d23}, [%[pcm]]!\n"
+			"vuzp.16 q10, q11\n"
+			"vswp    q3,  q10\n"
+			"vtbl.8  d16, {d4, d5, d6, d7}, d0\n"
+			"vtbl.8  d17, {d4, d5, d6, d7}, d1\n"
+			"vtbl.8  d18, {d4, d5, d6, d7}, d2\n"
+			"vtbl.8  d19, {d4, d5, d6, d7}, d3\n"
+			"vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+			"vtbl.8  d16, {d20, d21, d22, d23}, d0\n"
+			"vtbl.8  d17, {d20, d21, d22, d23}, d1\n"
+			"vtbl.8  d18, {d20, d21, d22, d23}, d2\n"
+			"vtbl.8  d19, {d20, d21, d22, d23}, d3\n"
+			"vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n"
+			"subs    %[nsamples], %[nsamples], #16\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [y]        "+r" (y),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+			  "d20", "d21", "d22", "d23");
+	} else if (nchannels > 1) {
+		/* proper 'pcm' alignment */
+		int16_t *x = &X[0][position];
+		int16_t *y = &X[1][position];
+		asm volatile (
+			"vld1.8  {d0, d1, d2, d3}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #32\n"
+			"sub     %[y], %[y], #32\n"
+			"sub     %[position], %[position], #16\n"
+			"vld2.16  {d4, d5, d6, d7}, [%[pcm]]!\n"
+			"vld2.16  {d20, d21, d22, d23}, [%[pcm]]!\n"
+			"vswp    q3, q10\n"
+			"vtbl.8  d16, {d4, d5, d6, d7}, d0\n"
+			"vtbl.8  d17, {d4, d5, d6, d7}, d1\n"
+			"vtbl.8  d18, {d4, d5, d6, d7}, d2\n"
+			"vtbl.8  d19, {d4, d5, d6, d7}, d3\n"
+			"vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+			"vtbl.8  d16, {d20, d21, d22, d23}, d0\n"
+			"vtbl.8  d17, {d20, d21, d22, d23}, d1\n"
+			"vtbl.8  d18, {d20, d21, d22, d23}, d2\n"
+			"vtbl.8  d19, {d20, d21, d22, d23}, d3\n"
+			"vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n"
+			"subs    %[nsamples], %[nsamples], #16\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [y]        "+r" (y),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19",
+			  "d20", "d21", "d22", "d23");
+	} else {
+		int16_t *x = &X[0][position];
+		asm volatile (
+			"vld1.8  {d0, d1, d2, d3}, [%[perm], :128]\n"
+		"1:\n"
+			"sub     %[x], %[x], #32\n"
+			"sub     %[position], %[position], #16\n"
+			"vld1.8  {d4, d5, d6, d7}, [%[pcm]]!\n"
+			"vtbl.8  d16, {d4, d5, d6, d7}, d0\n"
+			"vtbl.8  d17, {d4, d5, d6, d7}, d1\n"
+			"vtbl.8  d18, {d4, d5, d6, d7}, d2\n"
+			"vtbl.8  d19, {d4, d5, d6, d7}, d3\n"
+			"vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
+			"subs    %[nsamples], %[nsamples], #16\n"
+			"bgt     1b\n"
+			:
+			  [x]        "+r" (x),
+			  [pcm]      "+r" (pcm),
+			  [nsamples] "+r" (nsamples),
+			  [position] "+r" (position)
+			:
+			  [perm]      "r" (big_endian ? perm_be : perm_le)
+			: "cc", "memory", "d0", "d1", "d2", "d3", "d4",
+			  "d5", "d6", "d7", "d16", "d17", "d18", "d19");
+	}
+	return position;
+}
+
+#undef PERM_BE
+#undef PERM_LE
+
+static int sbc_enc_process_input_4s_be_neon(int position, const uint8_t *pcm,
+					int16_t X[2][SBC_X_BUFFER_SIZE],
+					int nsamples, int nchannels)
+{
+	return sbc_enc_process_input_4s_neon_internal(
+		position, pcm, X, nsamples, nchannels, 1);
+}
+
+static int sbc_enc_process_input_4s_le_neon(int position, const uint8_t *pcm,
+					int16_t X[2][SBC_X_BUFFER_SIZE],
+					int nsamples, int nchannels)
+{
+	return sbc_enc_process_input_4s_neon_internal(
+		position, pcm, X, nsamples, nchannels, 0);
+}
+
+static int sbc_enc_process_input_8s_be_neon(int position, const uint8_t *pcm,
+					int16_t X[2][SBC_X_BUFFER_SIZE],
+					int nsamples, int nchannels)
+{
+	return sbc_enc_process_input_8s_neon_internal(
+		position, pcm, X, nsamples, nchannels, 1);
+}
+
+static int sbc_enc_process_input_8s_le_neon(int position, const uint8_t *pcm,
+					int16_t X[2][SBC_X_BUFFER_SIZE],
+					int nsamples, int nchannels)
+{
+	return sbc_enc_process_input_8s_neon_internal(
+		position, pcm, X, nsamples, nchannels, 0);
+}
+
 void sbc_init_primitives_neon(struct sbc_encoder_state *state)
 {
 	state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_neon;
 	state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_neon;
+	state->sbc_calc_scalefactors = sbc_calc_scalefactors_neon;
+	state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j_neon;
+	state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le_neon;
+	state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be_neon;
+	state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le_neon;
+	state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be_neon;
 	state->implementation_info = "NEON";
 }
 
diff --git a/sbc/sbc_primitives_neon.h b/sbc/sbc_primitives_neon.h
index 30766ed..ea3da06 100644
--- a/sbc/sbc_primitives_neon.h
+++ b/sbc/sbc_primitives_neon.h
@@ -2,7 +2,8 @@
  *
  *  Bluetooth low-complexity, subband codec (SBC) library
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
  *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
  *
diff --git a/sbc/sbc_tables.h b/sbc/sbc_tables.h
index 0057c73..28c0d54 100644
--- a/sbc/sbc_tables.h
+++ b/sbc/sbc_tables.h
@@ -2,7 +2,8 @@
  *
  *  Bluetooth low-complexity, subband codec (SBC) library
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
  *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
  *
diff --git a/sbc/sbcdec.c b/sbc/sbcdec.c
index 9e87d63..7008e88 100644
--- a/sbc/sbcdec.c
+++ b/sbc/sbcdec.c
@@ -2,7 +2,8 @@
  *
  *  Bluetooth low-complexity, subband codec (SBC) decoder
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -219,7 +220,7 @@
 static void usage(void)
 {
 	printf("SBC decoder utility ver %s\n", VERSION);
-	printf("Copyright (c) 2004-2009  Marcel Holtmann\n\n");
+	printf("Copyright (c) 2004-2010  Marcel Holtmann\n\n");
 
 	printf("Usage:\n"
 		"\tsbcdec [options] file(s)\n"
@@ -258,15 +259,13 @@
 			break;
 
 		case 'd':
-			if (output)
-				free(output);
+			free(output);
 			output = strdup(optarg);
 			tofile = 0;
 			break;
 
 		case 'f' :
-			if (output)
-				free(output);
+			free(output);
 			output = strdup(optarg);
 			tofile = 1;
 			break;
@@ -288,8 +287,7 @@
 	for (i = 0; i < argc; i++)
 		decode(argv[i], output ? output : "/dev/dsp", tofile);
 
-	if (output)
-		free(output);
+	free(output);
 
 	return 0;
 }
diff --git a/sbc/sbcenc.c b/sbc/sbcenc.c
index 0e3b6fb..3d3a7dc 100644
--- a/sbc/sbcenc.c
+++ b/sbc/sbcenc.c
@@ -2,7 +2,8 @@
  *
  *  Bluetooth low-complexity, subband codec (SBC) encoder
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -49,7 +50,7 @@
 	struct au_header au_hdr;
 	sbc_t sbc;
 	int fd, size, srate, codesize, nframes;
-	size_t encoded;
+	ssize_t encoded;
 	ssize_t len;
 
 	if (sizeof(au_hdr) != 24) {
@@ -205,7 +206,7 @@
 static void usage(void)
 {
 	printf("SBC encoder utility ver %s\n", VERSION);
-	printf("Copyright (c) 2004-2009  Marcel Holtmann\n\n");
+	printf("Copyright (c) 2004-2010  Marcel Holtmann\n\n");
 
 	printf("Usage:\n"
 		"\tsbcenc [options] file(s)\n"
diff --git a/sbc/sbcinfo.c b/sbc/sbcinfo.c
index 645de9b..6d92679 100644
--- a/sbc/sbcinfo.c
+++ b/sbc/sbcinfo.c
@@ -2,7 +2,8 @@
  *
  *  Bluetooth low-complexity, subband codec (SBC) library
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/sbc/sbctester.c b/sbc/sbctester.c
index a7cf85f..b1e3608 100644
--- a/sbc/sbctester.c
+++ b/sbc/sbctester.c
@@ -2,7 +2,8 @@
  *
  *  Bluetooth low-complexity, subband codec (SBC) library
  *
- *  Copyright (C) 2007-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2007-2008  Frederic Dalleau <fdalleau@free.fr>
  *
  *
@@ -247,7 +248,7 @@
 static void usage()
 {
 	printf("SBC conformance test ver %s\n", VERSION);
-	printf("Copyright (c) 2007-2009  Marcel Holtmann\n");
+	printf("Copyright (c) 2007-2010  Marcel Holtmann\n");
 	printf("Copyright (c) 2007-2008  Frederic Dalleau\n\n");
 
 	printf("Usage:\n"
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
deleted file mode 100644
index cbd30b1..0000000
--- a/scripts/Makefile.am
+++ /dev/null
@@ -1,35 +0,0 @@
-
-if UDEVRULES
-rulesdir = @UDEV_DATADIR@
-
-rules_DATA = 97-bluetooth.rules
-
-if HID2HCI
-rules_DATA += 97-bluetooth-hid2hci.rules
-endif
-
-if PCMCIA
-rules_DATA += 97-bluetooth-serial.rules
-endif
-endif
-
-if PCMCIA
-udevdir = $(libexecdir)/udev
-
-udev_SCRIPTS = bluetooth_serial
-endif
-
-CLEANFILES = $(rules_DATA)
-
-EXTRA_DIST = bluetooth-hid2hci.rules bluetooth-serial.rules bluetooth_serial
-
-MAINTAINERCLEANFILES = Makefile.in
-
-97-bluetooth.rules: bluetooth.rules
-	cp $< $@
-
-97-bluetooth-hid2hci.rules: bluetooth-hid2hci.rules
-	cp $< $@
-
-97-bluetooth-serial.rules: bluetooth-serial.rules
-	cp $< $@
diff --git a/serial/Makefile.am b/serial/Makefile.am
deleted file mode 100644
index f8f26e2..0000000
--- a/serial/Makefile.am
+++ /dev/null
@@ -1,24 +0,0 @@
-
-if SERIALPLUGIN
-plugindir = $(libdir)/bluetooth/plugins
-
-plugin_LTLIBRARIES = serial.la
-
-serial_la_SOURCES = main.c \
-			manager.h manager.c port.h port.c \
-			proxy.h proxy.c
-
-LDADD = $(top_builddir)/common/libhelper.a \
-		@GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
-endif
-
-AM_LDFLAGS = -module -avoid-version -no-undefined
-
-AM_CFLAGS = -fvisibility=hidden \
-		@BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@
-
-INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/src
-
-EXTRA_DIST = serial.conf
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/serial/main.c b/serial/main.c
index 71e5aa3..38ded03 100644
--- a/serial/main.c
+++ b/serial/main.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/serial/manager.c b/serial/manager.c
index 71f1a5e..1b3f1d6 100644
--- a/serial/manager.c
+++ b/serial/manager.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -55,7 +55,7 @@
 #include "adapter.h"
 #include "device.h"
 
-#include "logging.h"
+#include "log.h"
 #include "textfile.h"
 
 #include "error.h"
@@ -66,14 +66,9 @@
 #include "sdpd.h"
 #include "glib-helper.h"
 
-#define SERIAL_PORT_UUID	"00001101-0000-1000-8000-00805F9B34FB"
-#define DIALUP_NET_UUID		"00001103-0000-1000-8000-00805F9B34FB"
-#define OBJECT_PUSH_UUID	"00001105-0000-1000-8000-00805F9B34FB"
-#define FILE_TRANSFER_UUID	"00001106-0000-1000-8000-00805F9B34FB"
 #define RFCOMM_UUID_STR		"00000003-0000-1000-8000-00805F9B34FB"
 
 static DBusConnection *connection = NULL;
-GSList *adapters = NULL;
 
 static int serial_probe(struct btd_device *device, const char *uuid)
 {
diff --git a/serial/manager.h b/serial/manager.h
index 112cf2f..c8b96e8 100644
--- a/serial/manager.h
+++ b/serial/manager.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/serial/port.c b/serial/port.c
index 42a4f3d..48a60b4 100644
--- a/serial/port.c
+++ b/serial/port.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -47,7 +47,7 @@
 
 #include "../src/dbus-common.h"
 
-#include "logging.h"
+#include "log.h"
 #include "glib-helper.h"
 #include "btio.h"
 
@@ -155,7 +155,7 @@
 		return 0;
 	}
 
-	debug("Serial port %s released", port->dev);
+	DBG("Serial port %s released", port->dev);
 
 	rfcomm_ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM);
 	if (rfcomm_ctl < 0)
@@ -223,7 +223,7 @@
 {
 	struct serial_device *device = data;
 
-	debug("Unregistered interface %s on path %s", SERIAL_PORT_INTERFACE,
+	DBG("Unregistered interface %s on path %s", SERIAL_PORT_INTERFACE,
 		device->path);
 
 	devices = g_slist_remove(devices, device);
@@ -358,7 +358,7 @@
 
 	port->dev = g_strdup_printf("/dev/rfcomm%d", port->id);
 
-	debug("Serial port %s created", port->dev);
+	DBG("Serial port %s created", port->dev);
 
 	g_io_channel_shutdown(chan, TRUE, NULL);
 
@@ -592,7 +592,7 @@
 		return NULL;
 	}
 
-	debug("Registered interface %s on path %s",
+	DBG("Registered interface %s on path %s",
 		SERIAL_PORT_INTERFACE, path);
 
 	return device;
diff --git a/serial/port.h b/serial/port.h
index 6b638cb..74ac9f0 100644
--- a/serial/port.h
+++ b/serial/port.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/serial/proxy.c b/serial/proxy.c
index 88a414d..6577fe2 100644
--- a/serial/proxy.c
+++ b/serial/proxy.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -54,7 +54,7 @@
 #include "../src/dbus-common.h"
 #include "../src/adapter.h"
 
-#include "logging.h"
+#include "log.h"
 #include "textfile.h"
 
 #include "error.h"
@@ -63,12 +63,6 @@
 #include "btio.h"
 #include "proxy.h"
 
-#define SERIAL_PORT_NAME	"spp"
-#define SERIAL_PORT_UUID	"00001101-0000-1000-8000-00805F9B34FB"
-
-#define DIALUP_NET_NAME		"dun"
-#define DIALUP_NET_UUID		"00001103-0000-1000-8000-00805F9B34FB"
-
 #define SERIAL_PROXY_INTERFACE	"org.bluez.SerialProxy"
 #define SERIAL_MANAGER_INTERFACE "org.bluez.SerialProxyManager"
 #define BUF_SIZE		1024
@@ -493,7 +487,7 @@
 		goto drop;
 	}
 
-	debug("Serial Proxy: incoming connect from %s", address);
+	DBG("Serial Proxy: incoming connect from %s", address);
 
 	prx->rfcomm = g_io_channel_ref(chan);
 
@@ -539,7 +533,7 @@
 		goto failed;
 	}
 
-	debug("Allocated channel %d", prx->channel);
+	DBG("Allocated channel %d", prx->channel);
 
 	g_io_channel_set_close_on_unref(prx->io, TRUE);
 
@@ -794,7 +788,7 @@
 	struct serial_proxy *prx = data;
 	int sk;
 
-	debug("Unregistered proxy: %s", prx->address);
+	DBG("Unregistered proxy: %s", prx->address);
 
 	if (prx->type != TTY_PROXY)
 		goto done;
@@ -829,7 +823,7 @@
 	prx->path = g_strdup(path);
 	adapter->proxies = g_slist_append(adapter->proxies, prx);
 
-	debug("Registered proxy: %s", path);
+	DBG("Registered proxy: %s", path);
 
 	return 0;
 }
@@ -1225,19 +1219,21 @@
 		uuid_str = g_key_file_get_string(config, group_str, "UUID",
 									&gerr);
 		if (gerr) {
-			debug("%s: %s", file, gerr->message);
+			DBG("%s: %s", file, gerr->message);
 			g_error_free(gerr);
 			g_key_file_free(config);
+			g_strfreev(group_list);
 			return;
 		}
 
 		address = g_key_file_get_string(config, group_str, "Address",
 									&gerr);
 		if (gerr) {
-			debug("%s: %s", file, gerr->message);
+			DBG("%s: %s", file, gerr->message);
 			g_error_free(gerr);
 			g_key_file_free(config);
 			g_free(uuid_str);
+			g_strfreev(group_list);
 			return;
 		}
 
@@ -1245,7 +1241,7 @@
 		if (err == -EINVAL)
 			error("Invalid address.");
 		else if (err == -EALREADY)
-			debug("Proxy already exists.");
+			DBG("Proxy already exists.");
 		else if (err < 0)
 			error("Proxy creation failed (%s)", strerror(-err));
 		else {
@@ -1289,7 +1285,7 @@
 
 	adapters = g_slist_append(adapters, adapter);
 
-	debug("Registered interface %s on path %s",
+	DBG("Registered interface %s on path %s",
 		SERIAL_MANAGER_INTERFACE, path);
 
 	serial_proxy_init(adapter);
diff --git a/serial/proxy.h b/serial/proxy.h
index 721e97d..7871665 100644
--- a/serial/proxy.h
+++ b/serial/proxy.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/src/Android.mk b/src/Android.mk
index 504a272..7030d79 100755
--- a/src/Android.mk
+++ b/src/Android.mk
@@ -7,25 +7,32 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
+	android_bluez.c \
 	adapter.c \
 	agent.c \
+	btio.c \
 	dbus-common.c \
 	dbus-hci.c \
 	device.c \
 	error.c \
+	glib-helper.c \
+	log.c \
 	main.c \
 	manager.c \
+	oui.c \
 	plugin.c \
 	rfkill.c \
 	sdpd-request.c \
 	sdpd-service.c \
 	sdpd-server.c \
 	sdpd-database.c \
+	sdp-xml.c \
 	security.c \
-	storage.c
+	storage.c \
+	textfile.c
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\" \
+	-DVERSION=\"4.69\" \
 	-DSTORAGEDIR=\"/data/misc/bluetoothd\" \
 	-DCONFIGDIR=\"/etc/bluetooth\" \
 	-DSERVICEDIR=\"/system/bin\" \
@@ -34,8 +41,7 @@
 	-DANDROID_EXPAND_NAME
 
 LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common \
+	$(LOCAL_PATH)/../lib \
 	$(LOCAL_PATH)/../gdbus \
 	$(LOCAL_PATH)/../plugins \
 	$(call include-path-for, glib) \
@@ -50,7 +56,6 @@
 
 LOCAL_STATIC_LIBRARIES := \
 	libglib_static \
-	libbluez-common-static \
 	libbuiltinplugin \
 	libgdbus_static
 
diff --git a/src/Makefile.am b/src/Makefile.am
deleted file mode 100644
index 569c060..0000000
--- a/src/Makefile.am
+++ /dev/null
@@ -1,47 +0,0 @@
-
-if CONFIGFILES
-dbusdir = $(sysconfdir)/dbus-1/system.d
-
-dbus_DATA = bluetooth.conf
-
-confdir = $(sysconfdir)/bluetooth
-
-conf_DATA = main.conf
-
-statedir = $(localstatedir)/lib/bluetooth
-
-state_DATA =
-endif
-
-sbin_PROGRAMS = bluetoothd
-
-bluetoothd_SOURCES = main.c security.c hcid.h sdpd.h \
-	sdpd-server.c sdpd-request.c sdpd-service.c sdpd-database.c \
-	plugin.h plugin.c storage.h storage.c agent.h agent.c rfkill.c \
-	error.h error.c manager.h manager.c adapter.h adapter.c \
-	device.h device.c dbus-common.c dbus-common.h dbus-hci.h dbus-hci.c
-
-bluetoothd_LDADD = $(top_builddir)/common/libhelper.a \
-			$(top_builddir)/plugins/libbuiltin.la \
-			@GDBUS_LIBS@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@ -ldl
-
-bluetoothd_LDFLAGS = -Wl,--export-dynamic
-
-if MAINTAINER_MODE
-plugindir = $(abs_top_srcdir)/plugins
-else
-plugindir = $(libdir)/bluetooth/plugins
-endif
-
-AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @GDBUS_CFLAGS@ \
-						-DPLUGINDIR=\""$(plugindir)"\"
-
-INCLUDES = -I$(top_srcdir)/common -I$(top_builddir)/plugins
-
-if MANPAGES
-man_MANS = bluetoothd.8
-endif
-
-EXTRA_DIST = bluetooth.conf bluetoothd.8 main.conf
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/src/adapter.c b/src/adapter.c
index bb2f320..c6dbd05 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -29,7 +29,6 @@
 #define _GNU_SOURCE
 #include <stdio.h>
 #include <errno.h>
-#include <fcntl.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <sys/ioctl.h>
@@ -37,7 +36,6 @@
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
 #include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
@@ -45,12 +43,11 @@
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 #include "textfile.h"
 
 #include "hcid.h"
 #include "sdpd.h"
-#include "sdp-xml.h"
 #include "manager.h"
 #include "adapter.h"
 #include "device.h"
@@ -61,14 +58,15 @@
 #include "agent.h"
 #include "storage.h"
 
-#define NUM_ELEMENTS(table) (sizeof(table)/sizeof(const char *))
-
 #define IO_CAPABILITY_DISPLAYONLY	0x00
 #define IO_CAPABILITY_DISPLAYYESNO	0x01
 #define IO_CAPABILITY_KEYBOARDONLY	0x02
 #define IO_CAPABILITY_NOINPUTNOOUTPUT	0x03
 #define IO_CAPABILITY_INVALID		0xFF
 
+/* Limited Discoverable bit mask in CoD */
+#define LIMITED_BIT			0x002000
+
 #define check_address(address) bachk(address)
 
 static DBusConnection *connection = NULL;
@@ -90,6 +88,7 @@
 	service_auth_cb cb;
 	void *user_data;
 	struct btd_device *device;
+	struct btd_adapter *adapter;
 };
 
 struct btd_adapter {
@@ -106,20 +105,22 @@
 	uint8_t mode;			/* off, connectable, discoverable,
 					 * limited */
 	uint8_t global_mode;		/* last valid global mode */
+	struct session_req *pending_mode;
 	int state;			/* standard inq, periodic inq, name
 					 * resloving */
 	GSList *found_devices;
 	GSList *oor_devices;		/* out of range device list */
-	DBusMessage *discovery_cancel;	/* discovery cancel message request */
-	GSList *passkey_agents;
 	struct agent *agent;		/* For the new API */
+	guint auth_idle_id;		/* Ongoing authorization */
 	GSList *connections;		/* Connected devices */
 	GSList *devices;		/* Devices structure pointers */
 	GSList *mode_sessions;		/* Request Mode sessions */
 	GSList *disc_sessions;		/* Discovery sessions */
 	guint scheduler_id;		/* Scheduler handle */
+	sdp_list_t *services;		/* Services associated to adapter */
 
 	struct hci_dev dev;		/* hci info */
+	int8_t tx_power;		/* inq response tx power level */
 	gboolean pairable;		/* pairable state */
 
 	gboolean initialized;
@@ -127,7 +128,10 @@
 
 	gboolean off_requested;		/* DEVDOWN ioctl was called */
 
-	uint8_t svc_cache;		/* Service Class cache */
+	uint32_t current_cod;		/* Adapter's current class */
+	uint32_t pending_cod;
+	uint32_t wanted_cod;		/* CoD cache */
+
 	gboolean cache_enable;
 
 	gint ref;
@@ -142,35 +146,18 @@
 			"Invalid arguments in method call");
 }
 
-static inline DBusMessage *not_available(DBusMessage *msg)
-{
-	return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",
-			"Not Available");
-}
-
 static inline DBusMessage *adapter_not_ready(DBusMessage *msg)
 {
 	return g_dbus_create_error(msg, ERROR_INTERFACE ".NotReady",
 			"Adapter is not ready");
 }
 
-static inline DBusMessage *no_such_adapter(DBusMessage *msg)
-{
-	return g_dbus_create_error(msg, ERROR_INTERFACE ".NoSuchAdapter",
-							"No such adapter");
-}
-
 static inline DBusMessage *failed_strerror(DBusMessage *msg, int err)
 {
 	return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 							strerror(err));
 }
 
-static inline DBusMessage *in_progress(DBusMessage *msg, const char *str)
-{
-	return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", str);
-}
-
 static inline DBusMessage *not_in_progress(DBusMessage *msg, const char *str)
 {
 	return g_dbus_create_error(msg, ERROR_INTERFACE ".NotInProgress", str);
@@ -182,13 +169,6 @@
 			"Not authorized");
 }
 
-static inline DBusMessage *unsupported_major_class(DBusMessage *msg)
-{
-	return g_dbus_create_error(msg,
-			ERROR_INTERFACE ".UnsupportedMajorClass",
-			"Unsupported Major Class");
-}
-
 static int found_device_cmp(const struct remote_dev_info *d1,
 			const struct remote_dev_info *d2)
 {
@@ -226,72 +206,58 @@
 	adapter->found_devices = NULL;
 }
 
-static int set_service_classes(struct btd_adapter *adapter, uint8_t value)
+static int adapter_set_service_classes(struct btd_adapter *adapter,
+							uint8_t value)
 {
-	struct hci_dev *dev = &adapter->dev;
-	const uint8_t *cls = dev->class;
-	uint32_t dev_class;
-	int dd, err;
+	int err;
 
-	if (cls[2] == value)
-		return 0; /* Already set */
+	/* Update only the service class, keep the limited bit,
+	 * major/minor class bits intact */
+	adapter->wanted_cod &= 0x00ffff;
+	adapter->wanted_cod |= (value << 16);
 
-	dd = hci_open_dev(adapter->dev_id);
-	if (dd < 0) {
-		err = -errno;
-		error("Can't open device hci%d: %s (%d)",
-				adapter->dev_id, strerror(errno), errno);
-		return err;
-	}
+	/* If we already have the CoD we want or the cache is enabled or an
+	 * existing CoD write is in progress just bail out */
+	if (adapter->current_cod == adapter->wanted_cod ||
+			adapter->cache_enable || adapter->pending_cod)
+		return 0;
 
-	dev_class = (value << 16) | (cls[1] << 8) | cls[0];
+	DBG("Changing service classes to 0x%06x", adapter->wanted_cod);
 
-	debug("Changing service classes to 0x%06x", dev_class);
+	err = adapter_ops->set_class(adapter->dev_id, adapter->wanted_cod);
+	if (err < 0)
+		error("Adapter class update failed: %s(%d)",
+						strerror(err), err);
+	else
+		adapter->pending_cod = adapter->wanted_cod;
 
-	if (hci_write_class_of_dev(dd, dev_class, HCI_REQ_TIMEOUT) < 0) {
-		err = -errno;
-		error("Can't write class of device: %s (%d)",
-						strerror(errno), errno);
-		hci_close_dev(dd);
-		return err;
-	}
-
-	hci_close_dev(dd);
-
-	return 0;
+	return err;
 }
 
-int set_major_and_minor_class(struct btd_adapter *adapter, uint8_t major,
+int btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
 								uint8_t minor)
 {
-	struct hci_dev *dev = &adapter->dev;
-	const uint8_t *cls = dev->class;
-	uint32_t dev_class;
-	int dd, err;
+	int err;
 
-	dd = hci_open_dev(adapter->dev_id);
-	if (dd < 0) {
-		err = -errno;
-		error("Can't open device hci%d: %s (%d)",
-				adapter->dev_id, strerror(errno), errno);
-		return err;
-	}
+	/* Update only the major and minor class bits keeping remaining bits
+	 * intact*/
+	adapter->wanted_cod &= 0xffe000;
+	adapter->wanted_cod |= ((major & 0x1f) << 8) | minor;
 
-	dev_class = (cls[2] << 16) | ((cls[1] & 0x20) << 8) |
-						((major & 0xdf) << 8) | minor;
+	if (adapter->wanted_cod == adapter->current_cod ||
+			adapter->cache_enable || adapter->pending_cod)
+		return 0;
 
-	debug("Changing major/minor class to 0x%06x", dev_class);
+	DBG("Changing Major/Minor class to 0x%06x", adapter->wanted_cod);
 
-	if (hci_write_class_of_dev(dd, dev_class, HCI_REQ_TIMEOUT) < 0) {
-		int err = -errno;
-		error("Can't write class of device: %s (%d)",
-						strerror(errno), errno);
-		hci_close_dev(dd);
-		return err;
-	}
+	err = adapter_ops->set_class(adapter->dev_id, adapter->wanted_cod);
+	if (err < 0)
+		error("Adapter class update failed: %s(%d)",
+						strerror(err), err);
+	else
+		adapter->pending_cod = adapter->wanted_cod;
 
-	hci_close_dev(dd);
-	return 0;
+	return err;
 }
 
 int pending_remote_name_cancel(struct btd_adapter *adapter)
@@ -428,10 +394,66 @@
 							adapter);
 }
 
-static int set_mode(struct btd_adapter *adapter, uint8_t new_mode)
+static void adapter_set_limited_discoverable(struct btd_adapter *adapter,
+							gboolean limited)
+{
+	/* Check if limited bit needs to be set/reset */
+	if (limited)
+		adapter->wanted_cod |= LIMITED_BIT;
+	else
+		adapter->wanted_cod &= ~LIMITED_BIT;
+
+	/* If we dont need the toggling, save an unnecessary CoD write */
+	if (adapter->pending_cod ||
+			adapter->wanted_cod == adapter->current_cod)
+		return;
+
+	if (adapter_ops->set_limited_discoverable(adapter->dev_id,
+					adapter->wanted_cod, limited) == 0)
+		adapter->pending_cod = adapter->wanted_cod;
+}
+
+static struct session_req *session_ref(struct session_req *req)
+{
+	req->refcount++;
+
+	DBG("%p: ref=%d", req, req->refcount);
+
+	return req;
+}
+
+static struct session_req *create_session(struct btd_adapter *adapter,
+					DBusConnection *conn, DBusMessage *msg,
+					uint8_t mode, GDBusWatchFunction cb)
+{
+	const char *sender = dbus_message_get_sender(msg);
+	struct session_req *req;
+
+	req = g_new0(struct session_req, 1);
+	req->adapter = adapter;
+	req->conn = dbus_connection_ref(conn);
+	req->msg = dbus_message_ref(msg);
+	req->mode = mode;
+
+	if (cb == NULL)
+		return session_ref(req);
+
+	req->owner = g_strdup(sender);
+	req->id = g_dbus_add_disconnect_watch(conn, sender, cb, req, NULL);
+
+	info("%s session %p with %s activated",
+		req->mode ? "Mode" : "Discovery", req, sender);
+
+	return session_ref(req);
+}
+
+static int set_mode(struct btd_adapter *adapter, uint8_t new_mode,
+			DBusMessage *msg)
 {
 	int err;
-	const char *modestr;
+
+	if (adapter->pending_mode != NULL)
+		return -EALREADY;
 
 	if (!adapter->up && new_mode != MODE_OFF) {
 		err = adapter_ops->set_powered(adapter->dev_id, TRUE);
@@ -468,16 +490,22 @@
 						adapter->discov_timeout);
 
 		if (new_mode != MODE_LIMITED && adapter->mode == MODE_LIMITED)
-			adapter_ops->set_limited_discoverable(adapter->dev_id,
-						adapter->dev.class, FALSE);
+			adapter_set_limited_discoverable(adapter, FALSE);
 	}
 
 done:
-	modestr = mode2str(new_mode);
+	DBG("%s", mode2str(new_mode));
 
-	write_device_mode(&adapter->bdaddr, modestr);
-
-	adapter->mode = new_mode;
+	if (msg != NULL)
+		/* Wait for mode change to reply */
+		adapter->pending_mode = create_session(adapter, connection,
+							msg, new_mode, NULL);
+	else {
+		/* Nothing to reply just write the new mode */
+		const char *modestr = mode2str(new_mode);
+		adapter->mode = new_mode;
+		write_device_mode(&adapter->bdaddr, modestr);
+	}
 
 	return 0;
 }
@@ -494,7 +522,7 @@
 	if (mode == adapter->mode)
 		return dbus_message_new_method_return(msg);
 
-	err = set_mode(adapter, mode);
+	err = set_mode(adapter, mode, NULL);
 	if (err < 0)
 		return failed_strerror(msg, -err);
 
@@ -518,11 +546,11 @@
 	if (mode == adapter->mode)
 		return dbus_message_new_method_return(msg);
 
-	err = set_mode(adapter, mode);
+	err = set_mode(adapter, mode, msg);
 	if (err < 0)
 		return failed_strerror(msg, -err);
 
-	return dbus_message_new_method_return(msg);
+	return 0;
 }
 
 static DBusMessage *set_pairable(DBusConnection *conn, DBusMessage *msg,
@@ -538,6 +566,19 @@
 	if (pairable == adapter->pairable)
 		goto done;
 
+	if (!(adapter->scan_mode & SCAN_INQUIRY))
+		goto store;
+
+	mode = (pairable && adapter->discov_timeout > 0 &&
+				adapter->discov_timeout <= 60) ?
+					MODE_LIMITED : MODE_DISCOVERABLE;
+
+	err = set_mode(adapter, mode, NULL);
+	if (err < 0 && msg)
+		return failed_strerror(msg, -err);
+
+store:
+
 	adapter->pairable = pairable;
 
 	write_device_pairable(&adapter->bdaddr, pairable);
@@ -550,17 +591,6 @@
 		adapter_set_pairable_timeout(adapter,
 						adapter->pairable_timeout);
 
-	if (!(adapter->scan_mode & SCAN_INQUIRY))
-		goto done;
-
-	mode = (pairable && adapter->discov_timeout > 0 &&
-				adapter->discov_timeout <= 60) ?
-					MODE_LIMITED : MODE_DISCOVERABLE;
-
-	err = set_mode(adapter, mode);
-	if (err < 0 && msg)
-		return failed_strerror(msg, -err);
-
 done:
 	return msg ? dbus_message_new_method_return(msg) : NULL;
 }
@@ -623,6 +653,13 @@
 {
 	struct btd_adapter *adapter = req->adapter;
 
+	/* Ignore set_mode session */
+	if (req->owner == NULL)
+		return;
+
+	DBG("%s session %p with %s deactivated",
+		req->mode ? "Mode" : "Discovery", req, req->owner);
+
 	if (req->mode) {
 		uint8_t mode;
 
@@ -634,9 +671,9 @@
 		if (mode == adapter->mode)
 			return;
 
-		debug("Switching to '%s' mode", mode2str(mode));
+		DBG("Switching to '%s' mode", mode2str(mode));
 
-		set_mode(adapter, mode);
+		set_mode(adapter, mode, NULL);
 	} else {
 		adapter->disc_sessions = g_slist_remove(adapter->disc_sessions,
 							req);
@@ -644,7 +681,7 @@
 		if (adapter->disc_sessions)
 			return;
 
-		debug("Stopping discovery");
+		DBG("Stopping discovery");
 
 		pending_remote_name_cancel(adapter);
 
@@ -653,8 +690,10 @@
 		g_slist_free(adapter->oor_devices);
 		adapter->oor_devices = NULL;
 
-		if (adapter->scheduler_id)
+		if (adapter->scheduler_id) {
 			g_source_remove(adapter->scheduler_id);
+			adapter->scheduler_id = 0;
+		}
 
 		adapter_ops->stop_discovery(adapter->dev_id);
 	}
@@ -662,9 +701,6 @@
 
 static void session_free(struct session_req *req)
 {
-	debug("%s session %p with %s deactivated",
-		req->mode ? "Mode" : "Discovery", req, req->owner);
-
 	if (req->id)
 		g_dbus_remove_watch(req->conn, req->id);
 
@@ -687,20 +723,11 @@
 	session_free(req);
 }
 
-static struct session_req *session_ref(struct session_req *req)
-{
-	req->refcount++;
-
-	debug("session_ref(%p): ref=%d", req, req->refcount);
-
-	return req;
-}
-
 static void session_unref(struct session_req *req)
 {
 	req->refcount--;
 
-	debug("session_unref(%p): ref=%d", req, req->refcount);
+	DBG("%p: ref=%d", req, req->refcount);
 
 	if (req->refcount)
 		return;
@@ -708,30 +735,6 @@
 	session_free(req);
 }
 
-static struct session_req *create_session(struct btd_adapter *adapter,
-					DBusConnection *conn, DBusMessage *msg,
-					uint8_t mode, GDBusWatchFunction cb)
-{
-	struct session_req *req;
-	const char *sender = dbus_message_get_sender(msg);
-
-	req = g_new0(struct session_req, 1);
-	req->adapter = adapter;
-	req->conn = dbus_connection_ref(conn);
-	req->msg = dbus_message_ref(msg);
-	req->owner = g_strdup(dbus_message_get_sender(msg));
-	req->mode = mode;
-
-	if (cb)
-		req->id = g_dbus_add_disconnect_watch(conn, sender, cb, req,
-							NULL);
-
-	info("%s session %p with %s activated",
-		req->mode ? "Mode" : "Discovery", req, sender);
-
-	return session_ref(req);
-}
-
 static void confirm_mode_cb(struct agent *agent, DBusError *derr, void *data)
 {
 	struct session_req *req = data;
@@ -746,7 +749,7 @@
 		return;
 	}
 
-	err = set_mode(req->adapter, req->mode);
+	err = set_mode(req->adapter, req->mode, NULL);
 	if (err < 0)
 		reply = failed_strerror(req->msg, -err);
 	else
@@ -831,7 +834,9 @@
 		return;
 
 	if (dev->ssp_mode > 0)
-		create_ext_inquiry_response((char *) dev->name, data);
+		create_ext_inquiry_response((char *) dev->name,
+						adapter->tx_power,
+						adapter->services, data);
 
 	if (hci_write_ext_inquiry_response(dd, fec, data,
 						HCI_REQ_TIMEOUT) < 0)
@@ -841,6 +846,78 @@
 	hci_close_dev(dd);
 }
 
+void adapter_set_class_complete(bdaddr_t *bdaddr, uint8_t status)
+{
+	uint8_t class[3];
+	struct btd_adapter *adapter;
+	int err;
+
+	if (status)
+		return;
+
+	adapter = manager_find_adapter(bdaddr);
+	if (!adapter) {
+		error("Unable to find matching adapter");
+		return;
+	}
+
+	if (adapter->pending_cod == 0)
+		return;
+
+	adapter->current_cod = adapter->pending_cod;
+	adapter->pending_cod = 0;
+
+	class[2] = (adapter->current_cod >> 16) & 0xff;
+	class[1] = (adapter->current_cod >> 8) & 0xff;
+	class[0] = adapter->current_cod & 0xff;
+
+	write_local_class(&adapter->bdaddr, class);
+
+	emit_property_changed(connection, adapter->path,
+				ADAPTER_INTERFACE, "Class",
+				DBUS_TYPE_UINT32, &adapter->current_cod);
+
+	update_ext_inquiry_response(adapter);
+
+	if (adapter->wanted_cod == adapter->current_cod)
+		return;
+
+	if (adapter->wanted_cod & LIMITED_BIT &&
+			!(adapter->current_cod & LIMITED_BIT))
+		err = adapter_ops->set_limited_discoverable(adapter->dev_id,
+						adapter->wanted_cod, TRUE);
+	else if (!(adapter->wanted_cod & LIMITED_BIT) &&
+					adapter->current_cod & LIMITED_BIT)
+		err = adapter_ops->set_limited_discoverable(adapter->dev_id,
+						adapter->wanted_cod, FALSE);
+	else
+		err = adapter_ops->set_class(adapter->dev_id,
+							adapter->wanted_cod);
+
+	if (err == 0)
+		adapter->pending_cod = adapter->wanted_cod;
+}
+
+void adapter_update_tx_power(bdaddr_t *bdaddr, uint8_t status, void *ptr)
+{
+	struct btd_adapter *adapter;
+
+	if (status)
+		return;
+
+	adapter = manager_find_adapter(bdaddr);
+	if (!adapter) {
+		error("Unable to find matching adapter");
+		return;
+	}
+
+	adapter->tx_power = *((int8_t *) ptr);
+
+	DBG("inquiry respone tx power level is %d", adapter->tx_power);
+
+	update_ext_inquiry_response(adapter);
+}
+
 void adapter_update_local_name(bdaddr_t *bdaddr, uint8_t status, void *ptr)
 {
 	read_local_name_rp rp;
@@ -872,8 +949,9 @@
 	name = g_strdup((char *) dev->name);
 
 	if (connection)
-		emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE,
-				"Name", DBUS_TYPE_STRING, &name);
+		emit_property_changed(connection, adapter->path,
+					ADAPTER_INTERFACE, "Name",
+					DBUS_TYPE_STRING, &name);
 	g_free(name);
 }
 
@@ -903,7 +981,6 @@
 {
 	struct btd_adapter *adapter = data;
 	struct hci_dev *dev = &adapter->dev;
-	int err;
 
 	if (!g_utf8_validate(name, -1, NULL)) {
 		error("Name change failed: supplied name isn't valid UTF-8");
@@ -913,12 +990,14 @@
 	if (strncmp(name, (char *) dev->name, MAX_NAME_LENGTH) == 0)
 		goto done;
 
-	if (!adapter->up)
-		return failed_strerror(msg, -EHOSTDOWN);
-
-	err = adapter_ops->set_name(adapter->dev_id, name);
-	if (err < 0)
-		return failed_strerror(msg, err);
+	if (!adapter->up) {
+		strncpy((char *) adapter->dev.name, name, MAX_NAME_LENGTH);
+		write_local_name(&adapter->bdaddr, name);
+	} else {
+		int err = adapter_ops->set_name(adapter->dev_id, name);
+		if (err < 0)
+			return failed_strerror(msg, err);
+	}
 
 done:
 	return dbus_message_new_method_return(msg);
@@ -977,6 +1056,79 @@
 	g_free(devices);
 }
 
+static void adapter_emit_uuids_updated(struct btd_adapter *adapter)
+{
+	char **uuids;
+	int i;
+	sdp_list_t *list;
+
+	uuids = g_new0(char *, sdp_list_len(adapter->services) + 1);
+
+	for (i = 0, list = adapter->services; list; list = list->next, i++) {
+		sdp_record_t *rec = list->data;
+		uuids[i] = bt_uuid2string(&rec->svclass);
+	}
+
+	emit_array_property_changed(connection, adapter->path,
+			ADAPTER_INTERFACE, "UUIDs", DBUS_TYPE_STRING, &uuids);
+
+	g_strfreev(uuids);
+}
+
+/*
+ * adapter_services_inc_rem - Insert or remove UUID from adapter
+ */
+static void adapter_service_ins_rem(const bdaddr_t *bdaddr, void *rec,
+							gboolean insert)
+{
+	struct btd_adapter *adapter;
+	GSList *adapters;
+
+	adapters = NULL;
+
+	if (bacmp(bdaddr, BDADDR_ANY) != 0) {
+		/* Only one adapter */
+		adapter = manager_find_adapter(bdaddr);
+		if (!adapter)
+			return;
+
+		adapters = g_slist_append(adapters, adapter);
+	} else
+		/* Emit D-Bus msg to all adapters */
+		adapters = manager_get_adapters();
+
+	for (; adapters; adapters = adapters->next) {
+		adapter = adapters->data;
+
+		if (insert == TRUE)
+			adapter->services = sdp_list_insert_sorted(
+							adapter->services, rec,
+							record_sort);
+		else
+			adapter->services = sdp_list_remove(adapter->services,
+									rec);
+
+		adapter_emit_uuids_updated(adapter);
+	}
+}
+
+void adapter_service_insert(const bdaddr_t *bdaddr, void *rec)
+{
+	/* TRUE to include service*/
+	adapter_service_ins_rem(bdaddr, rec, TRUE);
+}
+
+void adapter_service_remove(const bdaddr_t *bdaddr, void *rec)
+{
+	/* FALSE to remove service*/
+	adapter_service_ins_rem(bdaddr, rec, FALSE);
+}
+
+sdp_list_t *adapter_get_services(struct btd_adapter *adapter)
+{
+	return adapter->services;
+}
+
 struct btd_device *adapter_create_device(DBusConnection *conn,
 						struct btd_adapter *adapter,
 						const char *address)
@@ -984,7 +1136,7 @@
 	struct btd_device *device;
 	const char *path;
 
-	debug("adapter_create_device(%s)", address);
+	DBG("%s", address);
 
 	device = device_create(conn, adapter, address);
 	if (!device)
@@ -1006,7 +1158,8 @@
 }
 
 void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,
-				struct btd_device *device)
+						struct btd_device *device,
+						gboolean remove_storage)
 {
 	const gchar *dev_path = device_get_path(device);
 	struct agent *agent;
@@ -1022,20 +1175,11 @@
 			DBUS_TYPE_INVALID);
 
 	agent = device_get_agent(device);
-	if (!agent)
-		agent = adapter->agent;
 
 	if (agent && device_is_authorizing(device))
 		agent_cancel(agent);
 
-	agent = device_get_agent(device);
-
-	if (agent) {
-		agent_destroy(agent, FALSE);
-		device_set_agent(device, NULL);
-	}
-
-	device_remove(device, conn, TRUE);
+	device_remove(device, remove_storage);
 }
 
 struct btd_device *adapter_get_device(DBusConnection *conn,
@@ -1044,7 +1188,7 @@
 {
 	struct btd_device *device;
 
-	debug("adapter_get_device(%s)", address);
+	DBG("%s", address);
 
 	if (!adapter)
 		return NULL;
@@ -1138,11 +1282,11 @@
 	DBusMessageIter iter;
 	DBusMessageIter dict;
 	char str[MAX_NAME_LENGTH + 1], srcaddr[18];
-	uint32_t class;
 	gboolean value;
-	char **devices;
+	char **devices, **uuids;
 	int i;
 	GSList *l;
+	sdp_list_t *list;
 
 	ba2str(&adapter->bdaddr, srcaddr);
 
@@ -1172,10 +1316,8 @@
 	dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &property);
 
 	/* Class */
-	class = adapter->dev.class[0] |
-			adapter->dev.class[1] << 8 |
-			adapter->dev.class[2] << 16;
-	dict_append_entry(&dict, "Class", DBUS_TYPE_UINT32, &class);
+	dict_append_entry(&dict, "Class",
+				DBUS_TYPE_UINT32, &adapter->current_cod);
 
 	/* Powered */
 	value = (adapter->up && !adapter->off_requested) ? TRUE : FALSE;
@@ -1216,6 +1358,18 @@
 								&devices, i);
 	g_free(devices);
 
+	/* UUIDs */
+	uuids = g_new0(char *, sdp_list_len(adapter->services) + 1);
+
+	for (i = 0, list = adapter->services; list; list = list->next, i++) {
+		sdp_record_t *rec = list->data;
+		uuids[i] = bt_uuid2string(&rec->svclass);
+	}
+
+	dict_append_array(&dict, "UUIDs", DBUS_TYPE_STRING, &uuids, i);
+
+	g_strfreev(uuids);
+
 	dbus_message_iter_close_container(&iter, &dict);
 
 	return reply;
@@ -1310,7 +1464,7 @@
 	struct session_req *req;
 	const char *sender = dbus_message_get_sender(msg);
 	uint8_t new_mode;
-	int ret;
+	int err;
 
 	if (!adapter->agent)
 		return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
@@ -1336,11 +1490,11 @@
 	if (adapter->mode >= new_mode)
 		return dbus_message_new_method_return(msg);
 
-	ret = agent_confirm_mode_change(adapter->agent, mode2str(new_mode),
+	err = agent_confirm_mode_change(adapter->agent, mode2str(new_mode),
 					confirm_mode_cb, req, NULL);
-	if (ret < 0) {
+	if (err < 0) {
 		session_unref(req);
-		return failed_strerror(msg, -ret);
+		return failed_strerror(msg, -err);
 	}
 
 	return NULL;
@@ -1414,9 +1568,7 @@
 
 	device = adapter_find_device(adapter, address);
 	if (!device || !device_is_creating(device, NULL))
-		return g_dbus_create_error(msg,
-				ERROR_INTERFACE ".NotInProgress",
-				"Device creation not in progress");
+		return not_in_progress(msg, "Device creation not in progress");
 
 	if (!device_is_creating(device, sender))
 		return not_authorized(msg);
@@ -1428,7 +1580,7 @@
 		return NULL;
 	}
 
-	adapter_remove_device(conn, adapter, device);
+	adapter_remove_device(conn, adapter, device, TRUE);
 
 	return dbus_message_new_method_return(msg);
 }
@@ -1452,7 +1604,7 @@
 				ERROR_INTERFACE ".AlreadyExists",
 				"Device already exists");
 
-	debug("create_device(%s)", address);
+	DBG("%s", address);
 
 	device = adapter_create_device(conn, adapter, address);
 	if (!device)
@@ -1489,7 +1641,7 @@
 	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
 					DBUS_TYPE_OBJECT_PATH, &agent_path,
 					DBUS_TYPE_STRING, &capability,
-						DBUS_TYPE_INVALID) == FALSE)
+					DBUS_TYPE_INVALID) == FALSE)
 		return invalid_args(msg);
 
 	if (check_address(address) < 0)
@@ -1522,8 +1674,8 @@
 	return strcasecmp(dev_path, path);
 }
 
-static DBusMessage *remove_device(DBusConnection *conn,
-						DBusMessage *msg, void *data)
+static DBusMessage *remove_device(DBusConnection *conn, DBusMessage *msg,
+								void *data)
 {
 	struct btd_adapter *adapter = data;
 	struct btd_device *device;
@@ -1550,7 +1702,7 @@
 	device_set_temporary(device, TRUE);
 
 	if (!device_is_connected(device)) {
-		adapter_remove_device(conn, adapter, device);
+		adapter_remove_device(conn, adapter, device, TRUE);
 		return dbus_message_new_method_return(msg);
 	}
 
@@ -1558,8 +1710,8 @@
 	return NULL;
 }
 
-static DBusMessage *find_device(DBusConnection *conn,
-					DBusMessage *msg, void *data)
+static DBusMessage *find_device(DBusConnection *conn, DBusMessage *msg,
+								void *data)
 {
 	struct btd_adapter *adapter = data;
 	struct btd_device *device;
@@ -1599,8 +1751,8 @@
 	adapter->agent = NULL;
 }
 
-static DBusMessage *register_agent(DBusConnection *conn,
-					DBusMessage *msg, void *data)
+static DBusMessage *register_agent(DBusConnection *conn, DBusMessage *msg,
+								void *data)
 {
 	const char *path, *name, *capability;
 	struct agent *agent;
@@ -1631,14 +1783,14 @@
 
 	adapter->agent = agent;
 
-	debug("Agent registered for hci%d at %s:%s", adapter->dev_id, name,
+	DBG("Agent registered for hci%d at %s:%s", adapter->dev_id, name,
 			path);
 
 	return dbus_message_new_method_return(msg);
 }
 
-static DBusMessage *unregister_agent(DBusConnection *conn,
-					DBusMessage *msg, void *data)
+static DBusMessage *unregister_agent(DBusConnection *conn, DBusMessage *msg,
+								void *data)
 {
 	const char *path, *name;
 	struct btd_adapter *adapter = data;
@@ -1651,10 +1803,10 @@
 
 	if (!adapter->agent || !agent_matches(adapter->agent, name, path))
 		return g_dbus_create_error(msg,
-				ERROR_INTERFACE ".DoesNotExist",
-				"No such agent");
+					ERROR_INTERFACE ".DoesNotExist",
+					"No such agent");
 
-	agent_destroy(adapter->agent, FALSE);
+	agent_free(adapter->agent);
 	adapter->agent = NULL;
 
 	return dbus_message_new_method_return(msg);
@@ -1896,13 +2048,14 @@
 	return 0;
 }
 
-static int adapter_setup(struct btd_adapter *adapter)
+static int adapter_setup(struct btd_adapter *adapter, const char *mode)
 {
 	struct hci_dev *dev = &adapter->dev;
 	uint8_t events[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00 };
 	uint8_t inqmode;
 	int err , dd;
 	char name[MAX_NAME_LENGTH + 1];
+	uint8_t cls[3];
 
 	dd = hci_open_dev(adapter->dev_id);
 	if (dd < 0) {
@@ -1945,9 +2098,6 @@
 						sizeof(events), events);
 	}
 
-	if (read_local_name(&adapter->bdaddr, name) == 0)
-		adapter_ops->set_name(adapter->dev_id, name);
-
 	inqmode = get_inquiry_mode(dev);
 	if (inqmode < 1)
 		goto done;
@@ -1960,6 +2110,31 @@
 		return err;
 	}
 
+	if (dev->features[7] & LMP_INQ_TX_PWR)
+		hci_send_cmd(dd, OGF_HOST_CTL,
+				OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL, 0, NULL);
+
+	if (read_local_name(&adapter->bdaddr, name) < 0)
+		expand_name(name, MAX_NAME_LENGTH, main_opts.name,
+							adapter->dev_id);
+
+	adapter_ops->set_name(adapter->dev_id, name);
+	if (g_str_equal(mode, "off"))
+		strncpy((char *) adapter->dev.name, name, MAX_NAME_LENGTH);
+
+	/* Set device class */
+	if (adapter->initialized && adapter->wanted_cod) {
+		cls[1] = (adapter->wanted_cod >> 8) & 0xff;
+		cls[0] = adapter->wanted_cod & 0xff;
+	} else if (read_local_class(&adapter->bdaddr, cls) < 0) {
+		uint32_t class = htobl(main_opts.class);
+		if (class)
+			memcpy(cls, &class, 3);
+		else
+			goto done;
+	}
+
+	btd_adapter_set_class(adapter, cls[1], cls[0]);
 done:
 	hci_close_dev(dd);
 	return 0;
@@ -1971,10 +2146,6 @@
 	struct btd_adapter *adapter = user_data;
 	GSList *uuids = bt_string2list(value);
 	struct btd_device *device;
-	bdaddr_t dst;
-	char srcaddr[18], dstaddr[18];
-
-	ba2str(&adapter->bdaddr, srcaddr);
 
 	if (g_slist_find_custom(adapter->devices,
 				key, (GCompareFunc) device_address_cmp))
@@ -1987,9 +2158,6 @@
 	device_set_temporary(device, FALSE);
 	adapter->devices = g_slist_append(adapter->devices, device);
 
-	device_get_address(device, &dst);
-	ba2str(&dst, dstaddr);
-
 	device_probe_drivers(device, uuids);
 
 	g_slist_foreach(uuids, (GFunc) g_free, NULL);
@@ -1997,7 +2165,24 @@
 }
 
 static void create_stored_device_from_linkkeys(char *key, char *value,
-						void *user_data)
+							void *user_data)
+{
+	struct btd_adapter *adapter = user_data;
+	struct btd_device *device;
+
+	if (g_slist_find_custom(adapter->devices, key,
+					(GCompareFunc) device_address_cmp))
+		return;
+
+	device = device_create(connection, adapter, key);
+	if (device) {
+		device_set_temporary(device, FALSE);
+		adapter->devices = g_slist_append(adapter->devices, device);
+	}
+}
+
+static void create_stored_device_from_blocked(char *key, char *value,
+							void *user_data)
 {
 	struct btd_adapter *adapter = user_data;
 	struct btd_device *device;
@@ -2027,6 +2212,26 @@
 	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "linkkeys");
 	textfile_foreach(filename, create_stored_device_from_linkkeys,
 								adapter);
+
+	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "blocked");
+	textfile_foreach(filename, create_stored_device_from_blocked, adapter);
+}
+
+static void clear_blocked(struct btd_adapter *adapter)
+{
+	int dd;
+
+	dd = hci_open_dev(adapter->dev_id);
+	if (dd < 0) {
+		error("hci_open_dev(hci%d): %s (%d)", adapter->dev_id,
+						strerror(errno), errno);
+		return;
+	}
+
+	if (ioctl(dd, HCIUNBLOCKADDR, BDADDR_ANY) < 0)
+		error("ioctl(HCIUNBLOCKADDR): %s (%d)", strerror(errno), errno);
+
+	hci_close_dev(dd);
 }
 
 static void probe_driver(gpointer data, gpointer user_data)
@@ -2113,9 +2318,34 @@
 	return main_opts.pairto;
 }
 
-static int adapter_up(struct btd_adapter *adapter)
+static void adapter_disable_cod_cache(struct btd_adapter *adapter)
 {
-	char mode[14], srcaddr[18];
+	int err;
+
+	if (!adapter)
+		return;
+
+	if (!adapter->cache_enable)
+		return;
+
+	/* Disable and flush svc cache. All successive service class updates
+	   will be written to the device */
+	adapter->cache_enable = FALSE;
+
+	if (adapter->current_cod == adapter->wanted_cod)
+		return;
+
+	err = adapter_ops->set_class(adapter->dev_id, adapter->wanted_cod);
+	if (err < 0)
+		error("Adapter class update failed: %s(%d)",
+						strerror(err), err);
+	else
+		adapter->pending_cod = adapter->wanted_cod;
+}
+
+static int adapter_up(struct btd_adapter *adapter, const char *mode)
+{
+	char srcaddr[18];
 	uint8_t scan_mode;
 	gboolean powered, dev_down = FALSE;
 	int err;
@@ -2136,19 +2366,9 @@
 	if (read_device_pairable(&adapter->bdaddr, &adapter->pairable) < 0)
 		adapter->pairable = TRUE;
 
-	if (!adapter->initialized && !main_opts.remember_powered) {
-		if (main_opts.mode == MODE_OFF)
-			strcpy(mode, "off");
-		else
-			strcpy(mode, "connectable");
-	} else if (read_device_mode(srcaddr, mode, sizeof(mode)) < 0) {
-		if (!adapter->initialized && main_opts.mode == MODE_OFF)
-			strcpy(mode, "off");
-		else
-			goto proceed;
-	}
-
 	if (g_str_equal(mode, "off")) {
+		char onmode[14];
+
 		powered = FALSE;
 
 		if (!adapter->initialized) {
@@ -2156,13 +2376,13 @@
 			goto proceed;
 		}
 
-		if (read_on_mode(srcaddr, mode, sizeof(mode)) < 0 ||
-						g_str_equal(mode, "off"))
-			write_device_mode(&adapter->bdaddr, "connectable");
-		else
-			write_device_mode(&adapter->bdaddr, mode);
+		if (read_on_mode(srcaddr, onmode, sizeof(onmode)) < 0 ||
+						g_str_equal(onmode, "off"))
+			strcpy(onmode, "connectable");
 
-		return adapter_up(adapter);
+		write_device_mode(&adapter->bdaddr, onmode);
+
+		return adapter_up(adapter, onmode);
 	} else if (!g_str_equal(mode, "connectable") &&
 			adapter->discov_timeout == 0) {
 		/* Set discoverable only if timeout is 0 */
@@ -2181,6 +2401,7 @@
 
 	if (adapter->initialized == FALSE) {
 		load_drivers(adapter);
+		clear_blocked(adapter);
 		load_devices(adapter);
 
 		/* retrieve the active connections: address the scenario where
@@ -2202,7 +2423,8 @@
 					ADAPTER_INTERFACE, "Powered",
 					DBUS_TYPE_BOOLEAN, &powered);
 
-	adapter_disable_svc_cache(adapter);
+	adapter_disable_cod_cache(adapter);
+
 	return 0;
 }
 
@@ -2213,6 +2435,7 @@
 	struct hci_version ver;
 	uint8_t features[8];
 	int dd, err;
+	char mode[14], address[18];
 
 	if (hci_devinfo(adapter->dev_id, &di) < 0)
 		return -errno;
@@ -2225,7 +2448,7 @@
 	if (!bacmp(&di.bdaddr, BDADDR_ANY)) {
 		int err;
 
-		debug("Adapter %s without an address", adapter->path);
+		DBG("Adapter %s without an address", adapter->path);
 
 		err = adapter_read_bdaddr(adapter->dev_id, &di.bdaddr);
 		if (err < 0)
@@ -2234,6 +2457,16 @@
 
 	bacpy(&adapter->bdaddr, &di.bdaddr);
 	memcpy(dev->features, di.features, 8);
+	ba2str(&adapter->bdaddr, address);
+
+	err = read_device_mode(address, mode, sizeof(mode));
+
+	if ((!adapter->initialized && !main_opts.remember_powered) || err < 0) {
+		if (!adapter->initialized && main_opts.mode == MODE_OFF)
+			strcpy(mode, "off");
+		else
+			strcpy(mode, "connectable");
+	}
 
 	dd = hci_open_dev(adapter->dev_id);
 	if (dd < 0) {
@@ -2266,14 +2499,6 @@
 
 	memcpy(dev->features, features, 8);
 
-	if (hci_read_class_of_dev(dd, dev->class, HCI_REQ_TIMEOUT) < 0) {
-		err = -errno;
-		error("Can't read class of adapter on %s: %s (%d)",
-					adapter->path, strerror(errno), errno);
-		hci_close_dev(dd);
-		return err;
-	}
-
 	adapter_ops->read_name(adapter->dev_id);
 
 	if (!(features[6] & LMP_SIMPLE_PAIR))
@@ -2296,14 +2521,16 @@
 								0, NULL);
 	hci_close_dev(dd);
 
-	adapter_setup(adapter);
+	adapter->current_cod = 0;
+
+	adapter_setup(adapter, mode);
 
 	if (!adapter->initialized && adapter->already_up) {
-		debug("Stopping Inquiry at adapter startup");
+		DBG("Stopping Inquiry at adapter startup");
 		adapter_ops->stop_discovery(adapter->dev_id);
 	}
 
-	err = adapter_up(adapter);
+	err = adapter_up(adapter, mode);
 
 	info("Adapter %s has been enabled", adapter->path);
 
@@ -2400,6 +2627,7 @@
 	adapter->mode = MODE_OFF;
 	adapter->state = DISCOVER_TYPE_NONE;
 	adapter->cache_enable = TRUE;
+	adapter->pending_cod = 0;
 
 	info("Adapter %s has been disabled", adapter->path);
 
@@ -2413,60 +2641,7 @@
 	if (dev->ignore)
 		return 0;
 
-	if (adapter->cache_enable) {
-		adapter->svc_cache = new_svc;
-		return 0;
-	}
-
-	set_service_classes(adapter, new_svc);
-
-	update_ext_inquiry_response(adapter);
-
-	return 0;
-}
-
-void adapter_disable_svc_cache(struct btd_adapter *adapter)
-{
-	if (!adapter)
-		return;
-
-	if (!adapter->cache_enable)
-		return;
-
-	/* Disable and flush svc cache. All successive service class updates
-	   will be written to the device */
-	adapter->cache_enable = FALSE;
-
-	set_service_classes(adapter, adapter->svc_cache);
-
-	update_ext_inquiry_response(adapter);
-}
-
-int adapter_get_class(struct btd_adapter *adapter, uint8_t *cls)
-{
-	struct hci_dev *dev = &adapter->dev;
-
-	memcpy(cls, dev->class, 3);
-
-	return 0;
-}
-
-int adapter_set_class(struct btd_adapter *adapter, uint8_t *cls)
-{
-	struct hci_dev *dev = &adapter->dev;
-	uint32_t class;
-
-	if (memcmp(dev->class, cls, 3) == 0)
-		return 0;
-
-	memcpy(dev->class, cls, 3);
-
-	write_local_class(&adapter->bdaddr, cls);
-
-	class = cls[0] | (cls[1] << 8) | (cls[2] << 16);
-
-	emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE,
-				"Class", DBUS_TYPE_UINT32, &class);
+	adapter_set_service_classes(adapter, new_svc);
 
 	return 0;
 }
@@ -2486,10 +2661,13 @@
 {
 	struct btd_adapter *adapter = user_data;
 
-	agent_destroy(adapter->agent, FALSE);
+	agent_free(adapter->agent);
 	adapter->agent = NULL;
 
-	debug("adapter_free(%p)", adapter);
+	DBG("%p", adapter);
+
+	if (adapter->auth_idle_id)
+		g_source_remove(adapter->auth_idle_id);
 
 	g_free(adapter->path);
 	g_free(adapter);
@@ -2499,7 +2677,7 @@
 {
 	adapter->ref++;
 
-	debug("btd_adapter_ref(%p): ref=%d", adapter, adapter->ref);
+	DBG("%p: ref=%d", adapter, adapter->ref);
 
 	return adapter;
 }
@@ -2510,7 +2688,7 @@
 
 	adapter->ref--;
 
-	debug("btd_adapter_unref(%p): ref=%d", adapter, adapter->ref);
+	DBG("%p: ref=%d", adapter, adapter->ref);
 
 	if (adapter->ref > 0)
 		return;
@@ -2546,6 +2724,8 @@
 	adapter->path = g_strdup(path);
 	adapter->already_up = devup;
 
+	adapter->tx_power = 0;
+
 	if (!g_dbus_register_interface(conn, path, ADAPTER_INTERFACE,
 			adapter_methods, adapter_signals, NULL,
 			adapter, adapter_free)) {
@@ -2561,13 +2741,14 @@
 {
 	GSList *l;
 
-	debug("Removing adapter %s", adapter->path);
+	DBG("Removing adapter %s", adapter->path);
 
 	for (l = adapter->devices; l; l = l->next)
-		device_remove(l->data, connection, FALSE);
+		device_remove(l->data, FALSE);
 	g_slist_free(adapter->devices);
 
-	unload_drivers(adapter);
+	if (adapter->initialized)
+		unload_drivers(adapter);
 
 	/* Return adapter to down state if it was not up on init */
 	if (adapter->up && !adapter->already_up)
@@ -2758,13 +2939,13 @@
 
 	dev = adapter_search_found_devices(adapter, &match);
 	if (dev) {
-		if (rssi == dev->rssi)
-			return;
-
 		/* Out of range list update */
 		adapter->oor_devices = g_slist_remove(adapter->oor_devices,
 							dev);
 
+		if (rssi == dev->rssi)
+			return;
+
 		goto done;
 	}
 
@@ -2822,7 +3003,8 @@
 				DBUS_TYPE_STRING, &paddr,
 				DBUS_TYPE_INVALID);
 
-		adapter->found_devices = g_slist_remove(adapter->found_devices, dev);
+		adapter->found_devices = g_slist_remove(adapter->found_devices,
+							dev);
 		dev_info_free(dev);
 	}
 
@@ -2832,11 +3014,49 @@
 	adapter->oor_devices = g_slist_copy(adapter->found_devices);
 }
 
+static void set_mode_complete(struct btd_adapter *adapter)
+{
+	struct session_req *pending;
+	const char *modestr;
+	int err;
+
+	if (adapter->pending_mode == NULL)
+		return;
+
+	pending = adapter->pending_mode;
+	adapter->pending_mode = NULL;
+
+	err = (pending->mode != adapter->mode) ? -EINVAL : 0;
+
+	if (pending->msg != NULL) {
+		DBusMessage *msg = pending->msg;
+		DBusMessage *reply;
+
+		if (err < 0)
+			reply = failed_strerror(msg, -err);
+		else
+			reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+		g_dbus_send_message(connection, reply);
+	}
+
+	modestr = mode2str(adapter->mode);
+
+	DBG("%s", modestr);
+
+	/* Only store if the mode matches the pending */
+	if (err == 0)
+		write_device_mode(&adapter->bdaddr, modestr);
+	else
+		error("unable to set mode: %s", mode2str(pending->mode));
+
+	session_unref(pending);
+}
+
 void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode)
 {
 	const gchar *path = adapter_get_path(adapter);
 	gboolean discoverable, pairable;
-	uint8_t real_class[3];
 
 	if (adapter->scan_mode == scan_mode)
 		return;
@@ -2881,23 +3101,19 @@
 					ADAPTER_INTERFACE, "Pairable",
 					DBUS_TYPE_BOOLEAN, &pairable);
 
-	memcpy(real_class, adapter->dev.class, 3);
-	if (adapter->svc_cache)
-		real_class[2] = adapter->svc_cache;
-
 	if (discoverable && adapter->pairable && adapter->discov_timeout > 0 &&
 						adapter->discov_timeout <= 60)
-		adapter_ops->set_limited_discoverable(adapter->dev_id,
-							real_class, TRUE);
+		adapter_set_limited_discoverable(adapter, TRUE);
 	else if (!discoverable)
-		adapter_ops->set_limited_discoverable(adapter->dev_id,
-							real_class, FALSE);
+		adapter_set_limited_discoverable(adapter, FALSE);
 
 	emit_property_changed(connection, path,
 				ADAPTER_INTERFACE, "Discoverable",
 				DBUS_TYPE_BOOLEAN, &discoverable);
 
 	adapter->scan_mode = scan_mode;
+
+	set_mode_complete(adapter);
 }
 
 struct agent *adapter_get_agent(struct btd_adapter *adapter)
@@ -2945,8 +3161,8 @@
 	if (device_is_temporary(device)) {
 		const char *path = device_get_path(device);
 
-		debug("Removing temporary device %s", path);
-		adapter_remove_device(connection, adapter, device);
+		DBG("Removing temporary device %s", path);
+		adapter_remove_device(connection, adapter, device, TRUE);
 	}
 }
 
@@ -2988,6 +3204,18 @@
 	auth->cb(derr, auth->user_data);
 }
 
+static gboolean auth_idle_cb(gpointer user_data)
+{
+	struct service_auth *auth = user_data;
+	struct btd_adapter *adapter = auth->adapter;
+
+	adapter->auth_idle_id = 0;
+
+	auth->cb(NULL, auth->user_data);
+
+	return FALSE;
+}
+
 static int btd_adapter_authorize(struct btd_adapter *adapter,
 					const bdaddr_t *dst,
 					const char *uuid,
@@ -2997,7 +3225,6 @@
 	struct btd_device *device;
 	struct agent *agent;
 	char address[18];
-	gboolean trusted;
 	const gchar *dev_path;
 	int err;
 
@@ -3010,24 +3237,8 @@
 	if (!g_slist_find(adapter->connections, device))
 		return -ENOTCONN;
 
-	trusted = read_trust(&adapter->bdaddr, address, GLOBAL_TRUST);
-
-	if (trusted) {
-		cb(NULL, user_data);
-		return 0;
-	}
-
-	device = adapter_find_device(adapter, address);
-	if (!device)
-		return -EPERM;
-
-	agent = device_get_agent(device);
-
-	if (!agent)
-		agent = adapter->agent;
-
-	if (!agent)
-		return -EPERM;
+	if (adapter->auth_idle_id)
+		return -EBUSY;
 
 	auth = g_try_new0(struct service_auth, 1);
 	if (!auth)
@@ -3036,12 +3247,27 @@
 	auth->cb = cb;
 	auth->user_data = user_data;
 	auth->device = device;
+	auth->adapter = adapter;
+
+	if (device_is_trusted(device) == TRUE) {
+		adapter->auth_idle_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
+							auth_idle_cb, auth,
+							g_free);
+		return 0;
+	}
+
+	agent = device_get_agent(device);
+	if (!agent) {
+		g_free(auth);
+		return -EPERM;
+	}
 
 	dev_path = device_get_path(device);
 
 	err = agent_authorize(agent, dev_path, uuid, agent_auth_cb, auth, g_free);
-
-	if (err == 0)
+	if (err < 0)
+		g_free(auth);
+	else
 		device_set_authorizing(device, TRUE);
 
 	return err;
@@ -3097,16 +3323,18 @@
 	if (!device)
 		return -EPERM;
 
+	if (adapter->auth_idle_id) {
+		g_source_remove(adapter->auth_idle_id);
+		adapter->auth_idle_id = 0;
+		return 0;
+	}
+
 	/*
 	 * FIXME: Cancel fails if authorization is requested to adapter's
 	 * agent and in the meanwhile CreatePairedDevice is called.
 	 */
 
 	agent = device_get_agent(device);
-
-	if (!agent)
-		agent = adapter->agent;
-
 	if (!agent)
 		return -EPERM;
 
@@ -3179,6 +3407,17 @@
 	return adapter_ops->set_powered(adapter->dev_id, TRUE);
 }
 
+int btd_adapter_switch_online(struct btd_adapter *adapter)
+{
+	if (!adapter_ops)
+		return -EINVAL;
+
+	if (adapter->up)
+		return 0;
+
+	return adapter_ops->set_powered(adapter->dev_id, TRUE);
+}
+
 int btd_adapter_switch_offline(struct btd_adapter *adapter)
 {
 	if (!adapter_ops)
diff --git a/src/adapter.h b/src/adapter.h
index 83f987e..8226514 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,7 @@
  */
 
 #include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
 #include <dbus/dbus.h>
 #include <glib.h>
 
@@ -69,7 +70,6 @@
 
 	uint8_t  ssp_mode;
 	uint8_t  name[MAX_NAME_LENGTH];
-	uint8_t  class[3];
 };
 
 int adapter_start(struct btd_adapter *adapter);
@@ -78,10 +78,6 @@
 
 int adapter_update(struct btd_adapter *adapter, uint8_t cls);
 
-int adapter_get_class(struct btd_adapter *adapter, uint8_t *cls);
-
-int adapter_set_class(struct btd_adapter *adapter, uint8_t *cls);
-
 int adapter_update_ssp_mode(struct btd_adapter *adapter, uint8_t mode);
 
 struct btd_device *adapter_get_device(DBusConnection *conn,
@@ -91,10 +87,9 @@
 
 struct btd_device *adapter_find_connection(struct btd_adapter *adapter, uint16_t handle);
 
-void adapter_disable_svc_cache(struct btd_adapter *adapter);
-
 void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,
-				struct btd_device *device);
+						struct btd_device *device,
+						gboolean remove_storage);
 struct btd_device *adapter_create_device(DBusConnection *conn,
 				struct btd_adapter *adapter, const char *address);
 
@@ -125,7 +120,12 @@
 void adapter_update_oor_devices(struct btd_adapter *adapter);
 void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode);
 void adapter_setname_complete(bdaddr_t *local, uint8_t status);
+void adapter_update_tx_power(bdaddr_t *bdaddr, uint8_t status, void *ptr);
 void adapter_update_local_name(bdaddr_t *bdaddr, uint8_t status, void *ptr);
+void adapter_service_insert(const bdaddr_t *bdaddr, void *rec);
+void adapter_service_remove(const bdaddr_t *bdaddr, void *rec);
+sdp_list_t *adapter_get_services(struct btd_adapter *adapter);
+void adapter_set_class_complete(bdaddr_t *bdaddr, uint8_t status);
 
 struct agent *adapter_get_agent(struct btd_adapter *adapter);
 void adapter_add_connection(struct btd_adapter *adapter,
@@ -136,8 +136,9 @@
 
 struct btd_adapter *btd_adapter_ref(struct btd_adapter *adapter);
 void btd_adapter_unref(struct btd_adapter *adapter);
-int set_major_and_minor_class(struct btd_adapter *adapter, uint8_t major,
-								uint8_t minor);
+
+int btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
+							uint8_t minor);
 
 
 struct btd_adapter_driver {
@@ -162,6 +163,7 @@
 gboolean adapter_powering_down(struct btd_adapter *adapter);
 
 int btd_adapter_restore_powered(struct btd_adapter *adapter);
+int btd_adapter_switch_online(struct btd_adapter *adapter);
 int btd_adapter_switch_offline(struct btd_adapter *adapter);
 
 struct btd_adapter_ops {
@@ -172,7 +174,7 @@
 	int (*set_powered) (int index, gboolean powered);
 	int (*set_connectable) (int index);
 	int (*set_discoverable) (int index);
-	int (*set_limited_discoverable) (int index, const uint8_t *cls,
+	int (*set_limited_discoverable) (int index, uint32_t class,
 						gboolean limited);
 	int (*start_discovery) (int index, gboolean periodic);
 	int (*stop_discovery) (int index);
@@ -180,6 +182,7 @@
 	int (*cancel_resolve_name) (int index, bdaddr_t *bdaddr);
 	int (*set_name) (int index, const char *name);
 	int (*read_name) (int index);
+	int (*set_class) (int index, uint32_t class);
 };
 
 int btd_register_adapter_ops(struct btd_adapter_ops *btd_adapter_ops);
diff --git a/src/agent.c b/src/agent.c
index 4f9ba82..efa0320 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2008  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -41,7 +41,7 @@
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 
 #include "hcid.h"
 #include "adapter.h"
@@ -90,7 +90,7 @@
 {
 	DBusMessage *message;
 
-	debug("Releasing agent %s, %s", agent->name, agent->path);
+	DBG("Releasing agent %s, %s", agent->name, agent->path);
 
 	if (agent->request)
 		agent_cancel(agent);
@@ -138,12 +138,14 @@
 {
 	struct agent *agent = user_data;
 
-	debug("Agent exited without calling Unregister");
+	DBG("Agent exited without calling Unregister");
 
-	agent_destroy(agent, TRUE);
+	agent->exited = TRUE;
+
+	agent_free(agent);
 }
 
-static void agent_free(struct agent *agent)
+void agent_free(struct agent *agent)
 {
 	if (!agent)
 		return;
@@ -207,16 +209,6 @@
 	return agent;
 }
 
-int agent_destroy(struct agent *agent, gboolean exited)
-{
-	if (!agent)
-		return 0;
-
-	agent->exited = exited;
-	agent_free(agent);
-	return 0;
-}
-
 static struct agent_request *agent_request_new(struct agent *agent,
 						agent_request_type_t type,
 						void *cb,
@@ -358,7 +350,7 @@
 
 	agent->request = req;
 
-	debug("authorize request was sent for %s", path);
+	DBG("authorize request was sent for %s", path);
 
 	return 0;
 }
@@ -521,7 +513,7 @@
 	if (agent->request)
 		return -EBUSY;
 
-	debug("Calling Agent.ConfirmModeChange: name=%s, path=%s, mode=%s",
+	DBG("Calling Agent.ConfirmModeChange: name=%s, path=%s, mode=%s",
 			agent->name, agent->path, new_mode);
 
 	req = agent_request_new(agent, AGENT_REQUEST_CONFIRM_MODE,
@@ -626,7 +618,7 @@
 	if (agent->request)
 		return -EBUSY;
 
-	debug("Calling Agent.RequestPasskey: name=%s, path=%s",
+	DBG("Calling Agent.RequestPasskey: name=%s, path=%s",
 			agent->name, agent->path);
 
 	req = agent_request_new(agent, AGENT_REQUEST_PASSKEY, cb,
@@ -685,7 +677,7 @@
 	if (agent->request)
 		return -EBUSY;
 
-	debug("Calling Agent.RequestConfirmation: name=%s, path=%s, passkey=%06u",
+	DBG("Calling Agent.RequestConfirmation: name=%s, path=%s, passkey=%06u",
 			agent->name, agent->path, passkey);
 
 	req = agent_request_new(agent, AGENT_REQUEST_CONFIRMATION, cb,
@@ -742,7 +734,7 @@
 	if (agent->request)
 		return -EBUSY;
 
-	debug("Calling Agent.RequestPairingConsent: name=%s, path=%s",
+	DBG("Calling Agent.RequestPairingConsent: name=%s, path=%s",
 			agent->name, agent->path);
 
 	req = agent_request_new(agent, AGENT_REQUEST_PAIRING_CONSENT, cb,
diff --git a/src/agent.h b/src/agent.h
index 314baf9..e184250 100644
--- a/src/agent.h
+++ b/src/agent.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2008  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -39,7 +39,7 @@
 				const char *path, uint8_t capability,
 				agent_remove_cb cb, void *remove_cb_data);
 
-int agent_destroy(struct agent *agent, gboolean exited);
+void agent_free(struct agent *agent);
 
 int agent_authorize(struct agent *agent, const char *path,
 			const char *uuid, agent_cb cb, void *user_data,
diff --git a/common/android_bluez.c b/src/android_bluez.c
similarity index 100%
rename from common/android_bluez.c
rename to src/android_bluez.c
diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index c047623..56e7a83 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -11,12 +11,19 @@
     <allow own="org.bluez"/>
     <allow send_destination="org.bluez"/>
     <allow send_interface="org.bluez.Agent"/>
+    <allow send_interface="org.bluez.HandsfreeAgent"/>
   </policy>
 
   <policy at_console="true">
     <allow send_destination="org.bluez"/>
   </policy>
 
+  <!-- allow users of lp group (printing subsystem) to 
+       communicate with bluetoothd -->
+  <policy group="lp">
+    <allow send_destination="org.bluez"/>
+  </policy>
+
   <policy context="default">
     <deny send_destination="org.bluez"/>
   </policy>
diff --git a/common/btio.c b/src/btio.c
similarity index 93%
rename from common/btio.c
rename to src/btio.c
index d7e575d..93079ae 100644
--- a/common/btio.c
+++ b/src/btio.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2009  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2009  Nokia Corporation
+ *  Copyright (C) 2009-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2009-2010  Nokia Corporation
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -38,7 +38,6 @@
 
 #include <glib.h>
 
-#include "logging.h"
 #include "btio.h"
 
 #define ERROR_FAILED(gerr, str, err) \
@@ -58,6 +57,7 @@
 	uint16_t imtu;
 	uint16_t omtu;
 	int master;
+	uint8_t mode;
 };
 
 struct connect {
@@ -182,10 +182,8 @@
 	srv_sock = g_io_channel_unix_get_fd(io);
 
 	cli_sock = accept(srv_sock, NULL, NULL);
-	if (cli_sock < 0) {
-		error("accept: %s (%d)", strerror(errno), errno);
+	if (cli_sock < 0)
 		return TRUE;
-	}
 
 	cli_io = g_io_channel_unix_new(cli_sock);
 
@@ -252,7 +250,7 @@
 					(GDestroyNotify) accept_remove);
 }
 
-static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm)
+static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm, GError **err)
 {
 	struct sockaddr_l2 addr;
 
@@ -261,7 +259,12 @@
 	bacpy(&addr.l2_bdaddr, src);
 	addr.l2_psm = htobs(psm);
 
-	return bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+	if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		ERROR_FAILED(err, "l2cap_bind", errno);
+		return -1;
+	}
+
+	return 0;
 }
 
 static int l2cap_connect(int sock, const bdaddr_t *dst, uint16_t psm)
@@ -472,10 +475,10 @@
 	return TRUE;
 }
 
-static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu,
-				uint16_t omtu, int master, GError **err)
+static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu, uint16_t omtu,
+					uint8_t mode, int master, GError **err)
 {
-	if (imtu || omtu) {
+	if (imtu || omtu || mode) {
 		struct l2cap_options l2o;
 		socklen_t len;
 
@@ -491,6 +494,8 @@
 			l2o.imtu = imtu;
 		if (omtu)
 			l2o.omtu = omtu;
+		if (mode)
+			l2o.mode = mode;
 
 		if (setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o,
 							sizeof(l2o)) < 0) {
@@ -510,7 +515,8 @@
 	return TRUE;
 }
 
-static int rfcomm_bind(int sock, const bdaddr_t *src, uint8_t channel)
+static int rfcomm_bind(int sock,
+		const bdaddr_t *src, uint8_t channel, GError **err)
 {
 	struct sockaddr_rc addr;
 
@@ -519,7 +525,12 @@
 	bacpy(&addr.rc_bdaddr, src);
 	addr.rc_channel = channel;
 
-	return bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+	if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		ERROR_FAILED(err, "rfcomm_bind", errno);
+		return -1;
+	}
+
+	return 0;
 }
 
 static int rfcomm_connect(int sock, const bdaddr_t *dst, uint8_t channel)
@@ -552,7 +563,7 @@
 	return TRUE;
 }
 
-static int sco_bind(int sock, const bdaddr_t *src)
+static int sco_bind(int sock, const bdaddr_t *src, GError **err)
 {
 	struct sockaddr_sco addr;
 
@@ -560,7 +571,12 @@
 	addr.sco_family = AF_BLUETOOTH;
 	bacpy(&addr.sco_bdaddr, src);
 
-	return bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+	if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		ERROR_FAILED(err, "sco_bind", errno);
+		return -1;
+	}
+
+	return 0;
 }
 
 static int sco_connect(int sock, const bdaddr_t *dst)
@@ -615,6 +631,8 @@
 	/* Set defaults */
 	opts->defer = DEFAULT_DEFER_TIMEOUT;
 	opts->master = -1;
+	opts->sec_level = BT_IO_SEC_MEDIUM;
+	opts->mode = L2CAP_MODE_BASIC;
 
 	while (opt != BT_IO_OPT_INVALID) {
 		switch (opt) {
@@ -664,6 +682,9 @@
 		case BT_IO_OPT_MASTER:
 			opts->master = va_arg(args, gboolean);
 			break;
+		case BT_IO_OPT_MODE:
+			opts->mode = va_arg(args, int);
+			break;
 		default:
 			g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
 					"Unknown option %d", opt);
@@ -877,6 +898,12 @@
 			*(va_arg(args, uint8_t *)) = src.rc_channel ?
 					src.rc_channel : dst.rc_channel;
 			break;
+		case BT_IO_OPT_SOURCE_CHANNEL:
+			*(va_arg(args, uint8_t *)) = src.rc_channel;
+			break;
+		case BT_IO_OPT_DEST_CHANNEL:
+			*(va_arg(args, uint8_t *)) = dst.rc_channel;
+			break;
 		case BT_IO_OPT_MASTER:
 			len = sizeof(flags);
 			if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags,
@@ -1068,7 +1095,7 @@
 	case BT_IO_L2RAW:
 	case BT_IO_L2CAP:
 		return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu,
-							opts.master, err);
+						opts.mode, opts.master, err);
 	case BT_IO_RFCOMM:
 		return rfcomm_set(sock, opts.sec_level, opts.master, err);
 	case BT_IO_SCO:
@@ -1106,12 +1133,11 @@
 			ERROR_FAILED(err, "socket(RAW, L2CAP)", errno);
 			return NULL;
 		}
-		if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0) < 0) {
-			ERROR_FAILED(err, "l2cap_bind", errno);
-			return NULL;
-		}
-		if (!l2cap_set(sock, opts->sec_level, 0, 0, -1, err))
-			return NULL;
+		if (l2cap_bind(sock, &opts->src,
+					server ? opts->psm : 0, err) < 0)
+			goto failed;
+		if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, err))
+			goto failed;
 		break;
 	case BT_IO_L2CAP:
 		sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
@@ -1119,13 +1145,12 @@
 			ERROR_FAILED(err, "socket(SEQPACKET, L2CAP)", errno);
 			return NULL;
 		}
-		if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0) < 0) {
-			ERROR_FAILED(err, "l2cap_bind", errno);
-			return NULL;
-		}
+		if (l2cap_bind(sock, &opts->src,
+					server ? opts->psm : 0, err) < 0)
+			goto failed;
 		if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu,
-							opts->master, err))
-			return NULL;
+						opts->mode, opts->master, err))
+			goto failed;
 		break;
 	case BT_IO_RFCOMM:
 		sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
@@ -1134,12 +1159,10 @@
 			return NULL;
 		}
 		if (rfcomm_bind(sock, &opts->src,
-					server ? opts->channel : 0) < 0) {
-			ERROR_FAILED(err, "rfcomm_bind", errno);
-			return NULL;
-		}
+					server ? opts->channel : 0, err) < 0)
+			goto failed;
 		if (!rfcomm_set(sock, opts->sec_level, opts->master, err))
-			return NULL;
+			goto failed;
 		break;
 	case BT_IO_SCO:
 		sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
@@ -1147,12 +1170,10 @@
 			ERROR_FAILED(err, "socket(SEQPACKET, SCO)", errno);
 			return NULL;
 		}
-		if (sco_bind(sock, &opts->src) < 0) {
-			ERROR_FAILED(err, "sco_bind", errno);
-			return NULL;
-		}
+		if (sco_bind(sock, &opts->src, err) < 0)
+			goto failed;
 		if (!sco_set(sock, opts->mtu, err))
-			return NULL;
+			goto failed;
 		break;
 	default:
 		g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
@@ -1166,6 +1187,11 @@
 	g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
 
 	return io;
+
+failed:
+	close(sock);
+
+	return NULL;
 }
 
 GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
diff --git a/common/btio.h b/src/btio.h
similarity index 92%
rename from common/btio.h
rename to src/btio.h
index 2e50d98..81fda8e 100644
--- a/common/btio.h
+++ b/src/btio.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2009  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2009  Nokia Corporation
+ *  Copyright (C) 2009-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2009-2010  Nokia Corporation
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -21,8 +21,6 @@
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
-#ifndef BT_IO_H
-#define BT_IO_H
 
 #include <glib.h>
 
@@ -53,6 +51,8 @@
 	BT_IO_OPT_DEFER_TIMEOUT,
 	BT_IO_OPT_SEC_LEVEL,
 	BT_IO_OPT_CHANNEL,
+	BT_IO_OPT_SOURCE_CHANNEL,
+	BT_IO_OPT_DEST_CHANNEL,
 	BT_IO_OPT_PSM,
 	BT_IO_OPT_MTU,
 	BT_IO_OPT_OMTU,
@@ -60,6 +60,7 @@
 	BT_IO_OPT_MASTER,
 	BT_IO_OPT_HANDLE,
 	BT_IO_OPT_CLASS,
+	BT_IO_OPT_MODE,
 } BtIOOption;
 
 typedef enum {
@@ -91,4 +92,3 @@
 				GDestroyNotify destroy, GError **err,
 				BtIOOption opt1, ...);
 
-#endif
diff --git a/src/dbus-common.c b/src/dbus-common.c
index 059c91c..1245b4f 100644
--- a/src/dbus-common.c
+++ b/src/dbus-common.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2005-2007  Johan Hedberg <johan.hedberg@nokia.com>
  *
  *
@@ -42,7 +42,7 @@
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 
 #include "manager.h"
 #include "adapter.h"
diff --git a/src/dbus-common.h b/src/dbus-common.h
index 67c7178..c1d9264 100644
--- a/src/dbus-common.h
+++ b/src/dbus-common.h
@@ -1,8 +1,8 @@
 /* *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/src/dbus-hci.c b/src/dbus-hci.c
index e9a7f96..79bee44 100644
--- a/src/dbus-hci.c
+++ b/src/dbus-hci.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -45,7 +45,7 @@
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 #include "textfile.h"
 
 #include "hcid.h"
@@ -61,7 +61,7 @@
 
 static DBusConnection *connection = NULL;
 
-static gboolean get_adapter_and_device(bdaddr_t *src, bdaddr_t *dst,
+gboolean get_adapter_and_device(bdaddr_t *src, bdaddr_t *dst,
 					struct btd_adapter **adapter,
 					struct btd_device **device,
 					gboolean create)
@@ -114,6 +114,10 @@
 			return "audio-card";	/* Headset */
 		case 0x06:
 			return "audio-card";	/* Headphone */
+		case 0x0b: /* VCR */
+		case 0x0c: /* Video Camera */
+		case 0x0d: /* Camcorder */
+			return "camera-video";
 		default:
 			return "audio-card";	/* Other audio device */
 		}
@@ -156,8 +160,8 @@
  *
  *****************************************************************/
 
-static void pincode_cb(struct agent *agent, DBusError *err, const char *pincode,
-			struct btd_device *device)
+static void pincode_cb(struct agent *agent, DBusError *err,
+				const char *pincode, struct btd_device *device)
 {
 	struct btd_adapter *adapter = device_get_adapter(device);
 	pin_code_reply_cp pr;
@@ -214,31 +218,41 @@
 								pincode_cb);
 }
 
-static void confirm_cb(struct agent *agent, DBusError *err, void *user_data)
+static int confirm_reply(struct btd_adapter *adapter,
+				struct btd_device *device, gboolean success)
 {
-	struct btd_device *device = user_data;
-	struct btd_adapter *adapter = device_get_adapter(device);
-	user_confirm_reply_cp cp;
 	int dd;
+	user_confirm_reply_cp cp;
 	uint16_t dev_id = adapter_get_dev_id(adapter);
 
 	dd = hci_open_dev(dev_id);
 	if (dd < 0) {
 		error("Unable to open hci%d", dev_id);
-		return;
+		return dd;
 	}
 
 	memset(&cp, 0, sizeof(cp));
 	device_get_address(device, &cp.bdaddr);
 
-	if (err)
-		hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY,
+	if (success)
+		hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_REPLY,
 					USER_CONFIRM_REPLY_CP_SIZE, &cp);
 	else
-		hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_REPLY,
+		hci_send_cmd(dd, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY,
 					USER_CONFIRM_REPLY_CP_SIZE, &cp);
 
 	hci_close_dev(dd);
+
+	return 0;
+}
+
+static void confirm_cb(struct agent *agent, DBusError *err, void *user_data)
+{
+	struct btd_device *device = user_data;
+	struct btd_adapter *adapter = device_get_adapter(device);
+	gboolean success = (err == NULL) ? TRUE : FALSE;
+
+	confirm_reply(adapter, device, success);
 }
 
 static void passkey_cb(struct agent *agent, DBusError *err, uint32_t passkey,
@@ -323,7 +337,7 @@
 
 	err = ioctl(dd, HCIGETAUTHINFO, (unsigned long) &req);
 	if (err < 0) {
-		debug("HCIGETAUTHINFO failed: %s (%d)",
+		DBG("HCIGETAUTHINFO failed: %s (%d)",
 					strerror(errno), errno);
 		hci_close_dev(dd);
 		return err;
@@ -341,80 +355,78 @@
 {
 	struct btd_adapter *adapter;
 	struct btd_device *device;
-	uint8_t remcap, remauth, type;
-	uint16_t dev_id;
+	struct agent *agent;
+	uint8_t rem_cap, rem_auth, loc_cap, loc_auth;
+	gboolean bonding_initiator;
 
 	if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE))
 		return -ENODEV;
 
-	dev_id = adapter_get_dev_id(adapter);
-
-	if (get_auth_requirements(sba, dba, &type) < 0) {
-		int dd;
-
-		dd = hci_open_dev(dev_id);
-		if (dd < 0) {
-			error("Unable to open hci%d", dev_id);
-			return -1;
-		}
-
-		hci_send_cmd(dd, OGF_LINK_CTL,
-					OCF_USER_CONFIRM_NEG_REPLY, 6, dba);
-
-		hci_close_dev(dd);
-
-		return 0;
+	if (get_auth_requirements(sba, dba, &loc_auth) < 0) {
+		error("Unable to get local authentication requirements");
+		goto fail;
 	}
 
-	debug("confirm authentication requirement is 0x%02x", type);
+	agent = device_get_agent(device);
+	if (agent == NULL) {
+		error("No agent available for user confirmation");
+		goto fail;
+	}
 
-	remcap = device_get_cap(device);
-	remauth = device_get_auth(device);
+	loc_cap = agent_get_io_capability(agent);
 
-	debug("remote IO capabilities are 0x%02x", remcap);
-	debug("remote authentication requirement is 0x%02x", remauth);
+	DBG("confirm IO capabilities are 0x%02x", loc_cap);
+	DBG("confirm authentication requirement is 0x%02x", loc_auth);
+
+	rem_cap = device_get_cap(device);
+	rem_auth = device_get_auth(device);
+
+	DBG("remote IO capabilities are 0x%02x", rem_cap);
+	DBG("remote authentication requirement is 0x%02x", rem_auth);
+
+	/* If we require MITM but the remote device can't provide that
+	 * (it has NoInputNoOutput) then reject the confirmation
+	 * request. The only exception is when we're dedicated bonding
+	 * initiators since then we always have the MITM bit set. */
+	bonding_initiator = device_is_bonding(device, NULL);
+	if (!bonding_initiator && (loc_auth & 0x01) && rem_cap == 0x03) {
+		error("Rejecting request: remote device can't provide MITM");
+		goto fail;
+	}
 
 	/* If local IO capabilities are DisplayYesNo and remote IO
 	 * capabiltiies are DisplayOnly or NoInputNoOutput;
 	 * call PairingConsent callback for incoming requests. */
-	struct agent *agent = NULL;
 	agent = device_get_agent(device);
 	if (!agent) {
 		agent = adapter_get_agent(adapter);
 		if ((agent_get_io_capability(agent) & 0x01) &&
-		            (remcap == 0x00 || remcap == 0x03))
+		            (rem_cap == 0x00 || rem_cap == 0x03))
 			return device_request_authentication(device,
 					AUTH_TYPE_PAIRING_CONSENT, 0,
 					pairing_consent_cb);
 	}
 
 	/* If no side requires MITM protection; auto-accept */
-	if (!(remauth & 0x01) &&
-			(type == 0xff || !(type & 0x01) || remcap == 0x03)) {
-		int dd;
+	if ((loc_auth == 0xff || !(loc_auth & 0x01) || rem_cap == 0x03) &&
+				(!(rem_auth & 0x01) || loc_cap == 0x03)) {
+		DBG("auto accept of confirmation");
 
 		/* Wait 5 milliseconds before doing auto-accept */
 		usleep(5000);
 
-		dd = hci_open_dev(dev_id);
-		if (dd < 0) {
-			error("Unable to open hci%d", dev_id);
-			return -1;
-		}
+		if (confirm_reply(adapter, device, TRUE) < 0)
+			return -EIO;
 
-		hci_send_cmd(dd, OGF_LINK_CTL,
-					OCF_USER_CONFIRM_REPLY, 6, dba);
-
-		hci_close_dev(dd);
-
-		debug("auto accept of confirmation");
-
-		return device_request_authentication(device,
-						AUTH_TYPE_AUTO, 0, NULL);
+		return device_request_authentication(device, AUTH_TYPE_AUTO,
+								0, NULL);
 	}
 
 	return device_request_authentication(device, AUTH_TYPE_CONFIRM,
 							passkey, confirm_cb);
+
+fail:
+	return confirm_reply(adapter, device, FALSE);
 }
 
 int hcid_dbus_user_passkey(bdaddr_t *sba, bdaddr_t *dba)
@@ -447,7 +459,7 @@
 	struct btd_adapter *adapter;
 	struct btd_device *device;
 
-	debug("hcid_dbus_bonding_process_complete: status=%02x", status);
+	DBG("status=%02x", status);
 
 	if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE))
 		return;
@@ -456,7 +468,7 @@
 		/* This means that there was no pending PIN or SSP token
 		 * request from the controller, i.e. this is not a new
 		 * pairing */
-		debug("hcid_dbus_bonding_process_complete: no pending auth request");
+		DBG("no pending auth request");
 		return;
 	}
 
@@ -466,12 +478,12 @@
 }
 
 void hcid_dbus_simple_pairing_complete(bdaddr_t *local, bdaddr_t *peer,
-					uint8_t status)
+								uint8_t status)
 {
 	struct btd_adapter *adapter;
 	struct btd_device *device;
 
-	debug("hcid_dbus_simple_pairing_complete: status=%02x", status);
+	DBG("status=%02x", status);
 
 	if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE))
 		return;
@@ -510,6 +522,7 @@
 	name_status_t name_status;
 	int state;
 	dbus_bool_t legacy;
+	unsigned char features[8];
 
 	ba2str(local, local_addr);
 	ba2str(peer, peer_addr);
@@ -535,8 +548,6 @@
 		adapter_set_state(adapter, state);
 	}
 
-	legacy = (data == NULL);
-
 	memset(&match, 0, sizeof(struct remote_dev_info));
 	bacpy(&match.bdaddr, peer);
 	match.name_status = NAME_SENT;
@@ -544,7 +555,7 @@
 	dev = adapter_search_found_devices(adapter, &match);
 	if (dev) {
 		adapter_update_found_devices(adapter, peer, rssi, class,
-						NULL, NULL, legacy,
+						NULL, NULL, dev->legacy,
 						NAME_NOT_REQUIRED);
 		return;
 	}
@@ -561,6 +572,18 @@
 	create_name(filename, PATH_MAX, STORAGEDIR, local_addr, "names");
 	name = textfile_get(filename, peer_addr);
 
+	if (data)
+		legacy = FALSE;
+	else if (name == NULL)
+		legacy = TRUE;
+	else if (read_remote_features(local, peer, NULL, features) == 0) {
+		if (features[0] & 0x01)
+			legacy = FALSE;
+		else
+			legacy = TRUE;
+	} else
+		legacy = TRUE;
+
 	tmp_name = extract_eir_name(data, &name_type);
 	if (tmp_name) {
 		if (name_type == 0x09) {
@@ -579,7 +602,6 @@
 		}
 	}
 
-
 	if (name && name_type != 0x08)
 		name_status = NAME_SENT;
 
@@ -591,6 +613,27 @@
 	g_free(alias);
 }
 
+void hcid_dbus_set_legacy_pairing(bdaddr_t *local, bdaddr_t *peer,
+							gboolean legacy)
+{
+	struct btd_adapter *adapter;
+	struct btd_device *device;
+	struct remote_dev_info *dev, match;
+
+	if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE)) {
+		error("No matching adapter found");
+		return;
+	}
+
+	memset(&match, 0, sizeof(struct remote_dev_info));
+	bacpy(&match.bdaddr, peer);
+	match.name_status = NAME_ANY;
+
+	dev = adapter_search_found_devices(adapter, &match);
+	if (dev)
+		dev->legacy = legacy;
+}
+
 void hcid_dbus_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class)
 {
 	uint32_t old_class = 0;
@@ -667,24 +710,47 @@
 	struct btd_device *device;
 	struct btd_adapter *adapter;
 	uint8_t local_auth = 0xff, remote_auth, new_key_type;
-	gboolean bonding;
+	gboolean bonding, temporary = FALSE;
 
 	if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE))
 		return -ENODEV;
 
-	if (key_type == 0x06 && old_key_type != 0xff)
-		new_key_type = old_key_type;
-	else
-		new_key_type = key_type;
+	new_key_type = key_type;
+
+	if (key_type == 0x06) {
+		if (device_get_debug_key(device, NULL))
+			old_key_type = 0x03;
+		if (old_key_type != 0xff)
+			new_key_type = old_key_type;
+		else
+			/* This is Changed Combination Link Key for
+			 * a temporary link key.*/
+			return 0;
+	}
 
 	get_auth_requirements(local, peer, &local_auth);
 	remote_auth = device_get_auth(device);
 	bonding = device_is_bonding(device, NULL);
 
-	debug("local auth 0x%02x and remote auth 0x%02x",
+	DBG("key type 0x%02x old key type 0x%02x new key type 0x%02x",
+					key_type, old_key_type, new_key_type);
+
+	DBG("local auth 0x%02x and remote auth 0x%02x",
 					local_auth, remote_auth);
 
-	/* Only store the link key if one of the following is true:
+	/* Clear any previous debug key */
+	device_set_debug_key(device, NULL);
+
+	/* If this is not the first link key set a flag so a subsequent auth
+	 * complete event doesn't trigger SDP and remove any stored key */
+	if (old_key_type != 0xff) {
+		device_set_renewed_key(device, TRUE);
+		device_remove_bonding(device);
+	}
+
+	/* Store the link key only in runtime memory if it's a debug
+	 * key, else store the link key persistently if one of the
+	 * following is true:
 	 * 1. this is a legacy link key
 	 * 2. this is a changed combination key and there was a previously
 	 *    stored one
@@ -692,14 +758,20 @@
 	 * 4. the local side had dedicated bonding as a requirement
 	 * 5. the remote side is using dedicated bonding since in that case
 	 *    also the local requirements are set to dedicated bonding
+	 * If none of the above match only keep the link key around for
+	 * this connection and set the temporary flag for the device.
 	 */
-	if (key_type < 0x03 || (key_type == 0x06 && old_key_type != 0xff) ||
+	if (new_key_type == 0x03) {
+		DBG("Storing debug key in runtime memory");
+		device_set_debug_key(device, key);
+	} else if (key_type < 0x03 ||
+				(key_type == 0x06 && old_key_type != 0xff) ||
 				(local_auth > 0x01 && remote_auth > 0x01) ||
 				(local_auth == 0x02 || local_auth == 0x03) ||
 				(remote_auth == 0x02 || remote_auth == 0x03)) {
 		int err;
 
-		debug("storing link key of type 0x%02x", key_type);
+		DBG("storing link key of type 0x%02x", key_type);
 
 		err = write_link_key(local, peer, key, new_key_type,
 								pin_length);
@@ -707,18 +779,16 @@
 			error("write_link_key: %s (%d)", strerror(-err), -err);
 			return err;
 		}
-	}
-
-	/* If this is not the first link key set a flag so a subsequent auth
-	 * complete event doesn't trigger SDP */
-	if (old_key_type != 0xff)
-		device_set_renewed_key(device, TRUE);
+	} else
+		temporary = TRUE;
 
 	if (!device_is_connected(device))
 		device_set_secmode3_conn(device, TRUE);
 	else if (!bonding && old_key_type == 0xff)
 		hcid_dbus_bonding_process_complete(local, peer, 0);
 
+	device_set_temporary(device, temporary);
+
 	return 0;
 }
 
@@ -732,11 +802,15 @@
 		return;
 
 	if (status) {
+		gboolean secmode3 = device_get_secmode3_conn(device);
+
 		device_set_secmode3_conn(device, FALSE);
+
 		if (device_is_bonding(device, NULL))
 			device_bonding_complete(device, status);
 		if (device_is_temporary(device))
-			adapter_remove_device(connection, adapter, device);
+			adapter_remove_device(connection, adapter, device,
+								secmode3);
 		return;
 	}
 
@@ -763,7 +837,7 @@
 
 	device = adapter_find_connection(adapter, handle);
 	if (!device) {
-		error("No matching connection found for handle %u", handle);
+		DBG("No matching connection found for handle %u", handle);
 		return;
 	}
 
@@ -823,39 +897,6 @@
 		hci_close_dev(dd);
 }
 
-void hcid_dbus_write_class_complete(bdaddr_t *local)
-{
-	struct btd_adapter *adapter;
-	int dd;
-	uint8_t cls[3];
-	uint16_t dev_id;
-
-	adapter = manager_find_adapter(local);
-	if (!adapter) {
-		error("No matching adapter found");
-		return;
-	}
-
-	dev_id = adapter_get_dev_id(adapter);
-
-	dd = hci_open_dev(dev_id);
-	if (dd < 0) {
-		error("HCI device open failed: hci%d", dev_id);
-		return;
-	}
-
-	if (hci_read_class_of_dev(dd, cls, HCI_REQ_TIMEOUT) < 0) {
-		error("Can't read class of device on hci%d: %s (%d)",
-			dev_id, strerror(errno), errno);
-		hci_close_dev(dd);
-		return;
-	}
-
-	hci_close_dev(dd);
-
-	adapter_set_class(adapter, cls);
-}
-
 void hcid_dbus_write_simple_pairing_mode_complete(bdaddr_t *local)
 {
 	struct btd_adapter *adapter;
@@ -892,12 +933,24 @@
 	adapter_update_ssp_mode(adapter, mode);
 }
 
+void hcid_dbus_returned_link_key(bdaddr_t *local, bdaddr_t *peer)
+{
+	struct btd_adapter *adapter;
+	struct btd_device *device;
+
+	if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE))
+		return;
+
+	device_set_paired(device, TRUE);
+}
+
 int hcid_dbus_get_io_cap(bdaddr_t *local, bdaddr_t *remote,
 						uint8_t *cap, uint8_t *auth)
 {
 	struct btd_adapter *adapter;
 	struct btd_device *device;
 	struct agent *agent = NULL;
+	uint8_t agent_cap;
 
 	if (!get_adapter_and_device(local, remote, &adapter, &device, TRUE))
 		return -ENODEV;
@@ -905,7 +958,7 @@
 	if (get_auth_requirements(local, remote, auth) < 0)
 		return -1;
 
-	debug("initial authentication requirement is 0x%02x", *auth);
+	DBG("initial authentication requirement is 0x%02x", *auth);
 
 	if (*auth == 0xff)
 		*auth = device_get_auth(device);
@@ -914,10 +967,14 @@
 	 * in progress */
 	if (!adapter_is_pairable(adapter) &&
 				!device_is_bonding(device, NULL)) {
-		if (*auth < 0x02 && device_get_auth(device) < 0x02) {
-			debug("Allowing no bonding in non-bondable mode");
+		if (device_get_auth(device) < 0x02) {
+			DBG("Allowing no bonding in non-bondable mode");
 			/* No input, no output */
 			*cap = 0x03;
+			/* Kernel defaults to general bonding and so
+			 * overwrite for this special case. Otherwise
+			 * non-pairable test cases will fail. */
+			*auth = 0x00;
 			goto done;
 		}
 		return -EPERM;
@@ -925,21 +982,21 @@
 
 	/* For CreatePairedDevice use dedicated bonding */
 	agent = device_get_agent(device);
-	if (!agent)
-		agent = adapter_get_agent(adapter);
-
 	if (!agent) {
 		/* This is the non bondable mode case */
 		if (device_get_auth(device) > 0x01) {
-			debug("Bonding request, but no agent present");
+			DBG("Bonding request, but no agent present");
 			return -1;
 		}
 
 		/* No agent available, and no bonding case */
-		if (*auth == 0x00) {
-			debug("Allowing no bonding without agent");
+		if (*auth == 0x00 || *auth == 0x04) {
+			DBG("Allowing no bonding without agent");
 			/* No input, no output */
 			*cap = 0x03;
+			/* If kernel defaults to general bonding, set it
+			 * back to no bonding */
+			*auth = 0x00;
 			goto done;
 		}
 
@@ -947,11 +1004,12 @@
 		return -1;
 	}
 
-	if (*auth == 0x00) {
+	agent_cap = agent_get_io_capability(agent);
+
+	if (*auth == 0x00 || *auth == 0x04) {
 		/* If remote requests dedicated bonding follow that lead */
 		if (device_get_auth(device) == 0x02 ||
 				device_get_auth(device) == 0x03) {
-			uint8_t agent_cap = agent_get_io_capability(agent);
 
 			/* If both remote and local IO capabilities allow MITM
 			 * then require it, otherwise don't */
@@ -962,16 +1020,26 @@
 				*auth = 0x03;
 		}
 
-		/* If remote requires MITM then also require it */
+		/* If remote indicates no bonding then follow that. This
+		 * is important since the kernel might give general bonding
+		 * as default. */
+		if (device_get_auth(device) == 0x00 ||
+					device_get_auth(device) == 0x01)
+			*auth = 0x00;
+
+		/* If remote requires MITM then also require it, unless
+		 * our IO capability is NoInputNoOutput (so some
+		 * just-works security cases can be tested) */
 		if (device_get_auth(device) != 0xff &&
-					(device_get_auth(device) & 0x01))
+					(device_get_auth(device) & 0x01) &&
+					agent_cap != 0x03)
 			*auth |= 0x01;
 	}
 
 	*cap = agent_get_io_capability(agent);
 
 done:
-	debug("final authentication requirement is 0x%02x", *auth);
+	DBG("final authentication requirement is 0x%02x", *auth);
 
 	return 0;
 }
diff --git a/src/dbus-hci.h b/src/dbus-hci.h
index 382e59e..44cd5e5 100644
--- a/src/dbus-hci.h
+++ b/src/dbus-hci.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,7 @@
 
 int hcid_dbus_request_pin(int dev, bdaddr_t *sba, struct hci_conn_info *ci);
 void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, int8_t rssi, uint8_t *data);
+void hcid_dbus_set_legacy_pairing(bdaddr_t *local, bdaddr_t *peer, gboolean legacy);
 void hcid_dbus_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class);
 void hcid_dbus_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status, char *name);
 void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle, bdaddr_t *peer);
@@ -31,8 +32,8 @@
 void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t status);
 void hcid_dbus_simple_pairing_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t status);
 void hcid_dbus_setscan_enable_complete(bdaddr_t *local);
-void hcid_dbus_write_class_complete(bdaddr_t *local);
 void hcid_dbus_write_simple_pairing_mode_complete(bdaddr_t *local);
+void hcid_dbus_returned_link_key(bdaddr_t *local, bdaddr_t *peer);
 int hcid_dbus_get_io_cap(bdaddr_t *local, bdaddr_t *remote,
 						uint8_t *cap, uint8_t *auth);
 int hcid_dbus_set_io_cap(bdaddr_t *local, bdaddr_t *remote,
@@ -44,7 +45,10 @@
 				uint8_t *key, uint8_t key_type,
 				int pin_length, uint8_t old_key_type);
 
-DBusMessage *new_authentication_return(DBusMessage *msg, uint8_t status);
+gboolean get_adapter_and_device(bdaddr_t *src, bdaddr_t *dst,
+					struct btd_adapter **adapter,
+					struct btd_device **device,
+					gboolean create);
 
 const char *class_to_icon(uint32_t class);
 
diff --git a/src/device.c b/src/device.c
index 5328db9..9d50ad9 100644
--- a/src/device.c
+++ b/src/device.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -31,6 +31,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <sys/ioctl.h>
 #include <errno.h>
 
 #include <bluetooth/bluetooth.h>
@@ -44,7 +45,7 @@
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 #include "textfile.h"
 
 #include "hcid.h"
@@ -80,7 +81,6 @@
 	DBusConnection *conn;
 	DBusMessage *msg;
 	GIOChannel *io;
-	guint io_id;
 	guint listener_id;
 	struct btd_device *device;
 };
@@ -110,6 +110,7 @@
 	bdaddr_t	bdaddr;
 	gchar		*path;
 	char		name[MAX_NAME_LENGTH + 1];
+	char		*alias;
 	struct btd_adapter	*adapter;
 	GSList		*uuids;
 	GSList		*drivers;		/* List of driver_data */
@@ -134,10 +135,16 @@
 
 	sdp_list_t	*tmp_records;
 
+	gboolean	trusted;
+	gboolean	paired;
+	gboolean	blocked;
 	gboolean	renewed_key;
 
 	gboolean	authorizing;
 	gint		ref;
+
+	gboolean	has_debug_key;
+	uint8_t		debug_key[16];
 };
 
 static uint16_t uuid_list[] = {
@@ -149,14 +156,6 @@
 
 static GSList *device_drivers = NULL;
 
-static DBusHandlerResult error_connection_attempt_failed(DBusConnection *conn,
-						DBusMessage *msg, int err)
-{
-	return error_common_reply(conn, msg,
-			ERROR_INTERFACE ".ConnectionAttemptFailed",
-			err > 0 ? strerror(err) : "Connection attempt failed");
-}
-
 static DBusHandlerResult error_failed(DBusConnection *conn,
 					DBusMessage *msg, const char * desc)
 {
@@ -190,6 +189,8 @@
 		dbus_message_unref(req->msg);
 	if (req->conn)
 		dbus_connection_unref(req->conn);
+	if (req->device)
+		btd_device_unref(req->device);
 	g_slist_foreach(req->profiles_added, (GFunc) g_free, NULL);
 	g_slist_free(req->profiles_added);
 	g_slist_free(req->profiles_removed);
@@ -211,8 +212,8 @@
 
 	bt_cancel_discovery(&src, &device->bdaddr);
 
-	browse_request_free(req);
 	device->browse = NULL;
+	browse_request_free(req);
 }
 
 static void device_free(gpointer user_data)
@@ -222,7 +223,7 @@
 	struct agent *agent = adapter_get_agent(adapter);
 
 	if (device->agent)
-		agent_destroy(device->agent, FALSE);
+		agent_free(device->agent);
 
 	if (agent && (agent_is_busy(agent, device) ||
 				agent_is_busy(agent, device->authr)))
@@ -231,35 +232,32 @@
 	g_slist_foreach(device->uuids, (GFunc) g_free, NULL);
 	g_slist_free(device->uuids);
 
+	if (device->tmp_records)
+		sdp_list_free(device->tmp_records,
+					(sdp_free_func_t) sdp_record_free);
+
 	if (device->disconn_timer)
 		g_source_remove(device->disconn_timer);
 
-	debug("device_free(%p)", device);
+	if (device->discov_timer)
+		g_source_remove(device->discov_timer);
+
+	DBG("%p", device);
 
 	g_free(device->authr);
 	g_free(device->path);
+	g_free(device->alias);
 	g_free(device);
 }
 
 gboolean device_is_paired(struct btd_device *device)
 {
-	struct btd_adapter *adapter = device->adapter;
-	char filename[PATH_MAX + 1], *str;
-	char srcaddr[18], dstaddr[18];
-	gboolean ret;
-	bdaddr_t src;
+	return device->paired;
+}
 
-	adapter_get_address(adapter, &src);
-	ba2str(&src, srcaddr);
-	ba2str(&device->bdaddr, dstaddr);
-
-	create_name(filename, PATH_MAX, STORAGEDIR,
-			srcaddr, "linkkeys");
-	str = textfile_caseget(filename, dstaddr);
-	ret = str ? TRUE : FALSE;
-	g_free(str);
-
-	return ret;
+gboolean device_is_trusted(struct btd_device *device)
+{
+	return device->trusted;
 }
 
 static DBusMessage *get_properties(DBusConnection *conn,
@@ -306,13 +304,12 @@
 	dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &ptr);
 
 	/* Alias (fallback to name or address) */
-	if (read_device_alias(srcaddr, dstaddr, name, sizeof(name)) < 1) {
-		if (strlen(ptr) == 0) {
-			g_strdelimit(dstaddr, ":", '-');
-			ptr = dstaddr;
-		}
-	} else
-		ptr = name;
+	if (device->alias != NULL)
+		ptr = device->alias;
+	else if (strlen(ptr) == 0) {
+		g_strdelimit(dstaddr, ":", '-');
+		ptr = dstaddr;
+	}
 
 	dict_append_entry(&dict, "Alias", DBUS_TYPE_STRING, &ptr);
 
@@ -332,9 +329,13 @@
 	dict_append_entry(&dict, "Paired", DBUS_TYPE_BOOLEAN, &boolean);
 
 	/* Trusted */
-	boolean = read_trust(&src, dstaddr, GLOBAL_TRUST);
+	boolean = device_is_trusted(device);
 	dict_append_entry(&dict, "Trusted", DBUS_TYPE_BOOLEAN, &boolean);
 
+	/* Blocked */
+	boolean = device->blocked;
+	dict_append_entry(&dict, "Blocked", DBUS_TYPE_BOOLEAN, &boolean);
+
 	/* Connected */
 	boolean = (device->handle != 0);
 	dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN,
@@ -365,6 +366,11 @@
 	bdaddr_t src;
 	int err;
 
+	/* No change */
+	if ((device->alias == NULL && g_str_equal(alias, "")) ||
+			g_strcmp0(device->alias, alias) == 0)
+		return dbus_message_new_method_return(msg);
+
 	adapter_get_address(adapter, &src);
 	ba2str(&src, srcaddr);
 	ba2str(&device->bdaddr, dstaddr);
@@ -377,6 +383,9 @@
 				ERROR_INTERFACE ".Failed",
 				strerror(-err));
 
+	g_free(device->alias);
+	device->alias = g_str_equal(alias, "") ? NULL : g_strdup(alias);
+
 	emit_property_changed(conn, dbus_message_get_path(msg),
 				DEVICE_INTERFACE, "Alias",
 				DBUS_TYPE_STRING, &alias);
@@ -385,18 +394,28 @@
 }
 
 static DBusMessage *set_trust(DBusConnection *conn, DBusMessage *msg,
-					dbus_bool_t value, void *data)
+					gboolean value, void *data)
 {
 	struct btd_device *device = data;
 	struct btd_adapter *adapter = device->adapter;
 	char srcaddr[18], dstaddr[18];
 	bdaddr_t src;
+	int err;
+
+	if (device->trusted == value)
+		return dbus_message_new_method_return(msg);
 
 	adapter_get_address(adapter, &src);
 	ba2str(&src, srcaddr);
 	ba2str(&device->bdaddr, dstaddr);
 
-	write_trust(srcaddr, dstaddr, GLOBAL_TRUST, value);
+	err = write_trust(srcaddr, dstaddr, GLOBAL_TRUST, value);
+	if (err < 0)
+		return g_dbus_create_error(msg,
+				ERROR_INTERFACE ".Failed",
+				strerror(-err));
+
+	device->trusted = value;
 
 	emit_property_changed(conn, dbus_message_get_path(msg),
 				DEVICE_INTERFACE, "Trusted",
@@ -405,11 +424,155 @@
 	return dbus_message_new_method_return(msg);
 }
 
+static void driver_remove(struct btd_driver_data *driver_data,
+						struct btd_device *device)
+{
+	struct btd_device_driver *driver = driver_data->driver;
+
+	driver->remove(device);
+
+	device->drivers = g_slist_remove(device->drivers, driver_data);
+	g_free(driver_data);
+}
+
+static gboolean do_disconnect(gpointer user_data)
+{
+	struct btd_device *device = user_data;
+	disconnect_cp cp;
+	int dd;
+	uint16_t dev_id = adapter_get_dev_id(device->adapter);
+
+	device->disconn_timer = 0;
+
+	dd = hci_open_dev(dev_id);
+	if (dd < 0)
+		goto fail;
+
+	memset(&cp, 0, sizeof(cp));
+	cp.handle = htobs(device->handle);
+	cp.reason = HCI_OE_USER_ENDED_CONNECTION;
+
+	hci_send_cmd(dd, OGF_LINK_CTL, OCF_DISCONNECT,
+			DISCONNECT_CP_SIZE, &cp);
+
+	close(dd);
+
+fail:
+	return FALSE;
+}
+
+static int device_block(DBusConnection *conn, struct btd_device *device)
+{
+	int dev_id, dd, err;
+	bdaddr_t src;
+
+	if (device->blocked)
+		return 0;
+
+	dev_id = adapter_get_dev_id(device->adapter);
+
+	dd = hci_open_dev(dev_id);
+	if (dd < 0)
+		return -errno;
+
+	if (device->handle)
+		do_disconnect(device);
+
+	g_slist_foreach(device->drivers, (GFunc) driver_remove, device);
+
+	if (ioctl(dd, HCIBLOCKADDR, &device->bdaddr) < 0) {
+		err = -errno;
+		hci_close_dev(dd);
+		return err;
+	}
+
+	hci_close_dev(dd);
+
+	device->blocked = TRUE;
+
+	adapter_get_address(device->adapter, &src);
+
+	err = write_blocked(&src, &device->bdaddr, TRUE);
+	if (err < 0)
+		error("write_blocked(): %s (%d)", strerror(-err), -err);
+
+	device_set_temporary(device, FALSE);
+
+	emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Blocked",
+					DBUS_TYPE_BOOLEAN, &device->blocked);
+
+	return 0;
+}
+
+static int device_unblock(DBusConnection *conn, struct btd_device *device,
+							gboolean silent)
+{
+	int dev_id, dd, err;
+	bdaddr_t src;
+
+	if (!device->blocked)
+		return 0;
+
+	dev_id = adapter_get_dev_id(device->adapter);
+
+	dd = hci_open_dev(dev_id);
+	if (dd < 0)
+		return -errno;
+
+	if (ioctl(dd, HCIUNBLOCKADDR, &device->bdaddr) < 0) {
+		err = -errno;
+		hci_close_dev(dd);
+		return err;
+	}
+
+	hci_close_dev(dd);
+
+	device->blocked = FALSE;
+
+	adapter_get_address(device->adapter, &src);
+
+	err = write_blocked(&src, &device->bdaddr, FALSE);
+	if (err < 0)
+		error("write_blocked(): %s (%d)", strerror(-err), -err);
+
+	if (!silent) {
+		emit_property_changed(conn, device->path,
+					DEVICE_INTERFACE, "Blocked",
+					DBUS_TYPE_BOOLEAN, &device->blocked);
+		device_probe_drivers(device, device->uuids);
+	}
+
+	return 0;
+}
+
+static DBusMessage *set_blocked(DBusConnection *conn, DBusMessage *msg,
+						gboolean value, void *data)
+{
+	struct btd_device *device = data;
+	int err;
+
+	if (value)
+		err = device_block(conn, device);
+	else
+		err = device_unblock(conn, device, FALSE);
+
+	switch (-err) {
+	case 0:
+		return dbus_message_new_method_return(msg);
+	case EINVAL:
+		return g_dbus_create_error(msg,
+					ERROR_INTERFACE ".NotSupported",
+					"Kernel lacks blacklist support");
+	default:
+		return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+						"%s", strerror(-err));
+	}
+}
+
 static inline DBusMessage *invalid_args(DBusMessage *msg)
 {
-	return g_dbus_create_error(msg,
-			ERROR_INTERFACE ".InvalidArguments",
-			"Invalid arguments in method call");
+	return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",
+					"Invalid arguments in method call");
 }
 
 static DBusMessage *set_property(DBusConnection *conn,
@@ -434,7 +597,6 @@
 
 	if (g_str_equal("Trusted", property)) {
 		dbus_bool_t value;
-
 		if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
 			return invalid_args(msg);
 		dbus_message_iter_get_basic(&sub, &value);
@@ -448,6 +610,15 @@
 		dbus_message_iter_get_basic(&sub, &alias);
 
 		return set_alias(conn, msg, alias, data);
+	} else if (g_str_equal("Blocked", property)) {
+		dbus_bool_t value;
+
+		if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
+			return invalid_args(msg);
+
+		dbus_message_iter_get_basic(&sub, &value);
+
+		return set_blocked(conn, msg, value, data);
 	}
 
 	return invalid_args(msg);
@@ -457,7 +628,7 @@
 {
 	struct browse_req *req = user_data;
 
-	debug("DiscoverServices requestor exited");
+	DBG("DiscoverServices requestor exited");
 
 	browse_request_cancel(req);
 }
@@ -612,42 +783,11 @@
 	return dbus_message_new_method_return(msg);
 }
 
-static gboolean do_disconnect(gpointer user_data)
-{
-	struct btd_device *device = user_data;
-	disconnect_cp cp;
-	int dd;
-	uint16_t dev_id = adapter_get_dev_id(device->adapter);
-
-	device->disconn_timer = 0;
-
-	dd = hci_open_dev(dev_id);
-	if (dd < 0)
-		goto fail;
-
-	memset(&cp, 0, sizeof(cp));
-	cp.handle = htobs(device->handle);
-	cp.reason = HCI_OE_USER_ENDED_CONNECTION;
-
-	hci_send_cmd(dd, OGF_LINK_CTL, OCF_DISCONNECT,
-			DISCONNECT_CP_SIZE, &cp);
-
-	close(dd);
-
-fail:
-	return FALSE;
-}
-
 static void bonding_request_cancel(struct bonding_req *bonding)
 {
 	if (!bonding->io)
 		return;
 
-	if (bonding->io_id) {
-		g_source_remove(bonding->io_id);
-		bonding->io_id = 0;
-	}
-
 	g_io_channel_shutdown(bonding->io, TRUE, NULL);
 	g_io_channel_unref(bonding->io);
 	bonding->io = NULL;
@@ -842,6 +982,11 @@
 
 	device->handle = 0;
 
+	if (device->disconn_timer > 0) {
+		g_source_remove(device->disconn_timer);
+		device->disconn_timer = 0;
+	}
+
 	while (device->disconnects) {
 		DBusMessage *msg = device->disconnects->data;
 
@@ -898,6 +1043,11 @@
 	}
 }
 
+gboolean device_get_secmode3_conn(struct btd_device *device)
+{
+	return device->secmode3;
+}
+
 void device_set_secmode3_conn(struct btd_device *device, gboolean enable)
 {
 	device->secmode3 = enable;
@@ -911,7 +1061,7 @@
 	struct btd_device *device;
 	const gchar *adapter_path = adapter_get_path(adapter);
 	bdaddr_t src;
-	char srcaddr[18];
+	char srcaddr[18], alias[MAX_NAME_LENGTH + 1];
 
 	device = g_try_malloc0(sizeof(struct btd_device));
 	if (device == NULL)
@@ -922,7 +1072,7 @@
 	g_strdelimit(device->path, ":", '_');
 	g_free(address_up);
 
-	debug("Creating device %s", device->path);
+	DBG("Creating device %s", device->path);
 
 	if (g_dbus_register_interface(conn, device->path, DEVICE_INTERFACE,
 				device_methods, device_signals, NULL,
@@ -936,18 +1086,24 @@
 	adapter_get_address(adapter, &src);
 	ba2str(&src, srcaddr);
 	read_device_name(srcaddr, address, device->name);
+	if (read_device_alias(srcaddr, address, alias, sizeof(alias)) == 0)
+		device->alias = g_strdup(alias);
+	device->trusted = read_trust(&src, address, GLOBAL_TRUST);
+
+	if (read_blocked(&src, &device->bdaddr))
+		device_block(conn, device);
 
 	device->auth = 0xff;
 
+	if (read_link_key(&src, &device->bdaddr, NULL, NULL) == 0)
+		device->paired = TRUE;
+
 	return btd_device_ref(device);
 }
 
 void device_set_name(struct btd_device *device, const char *name)
 {
 	DBusConnection *conn = get_dbus_connection();
-	char alias[MAX_NAME_LENGTH + 1];
-	char srcaddr[18], dstaddr[18];
-	bdaddr_t src;
 
 	if (strncmp(name, device->name, MAX_NAME_LENGTH) == 0)
 		return;
@@ -958,11 +1114,7 @@
 				DEVICE_INTERFACE, "Name",
 				DBUS_TYPE_STRING, &name);
 
-	adapter_get_address(device->adapter, &src);
-	ba2str(&src, srcaddr);
-	ba2str(&device->bdaddr, dstaddr);
-
-	if (read_device_alias(srcaddr, dstaddr, alias, sizeof(alias)) == 0)
+	if (device->alias != NULL)
 		return;
 
 	emit_property_changed(conn, device->path,
@@ -970,14 +1122,17 @@
 				DBUS_TYPE_STRING, &name);
 }
 
-static void device_remove_bonding(struct btd_device *device,
-							DBusConnection *conn)
+void device_get_name(struct btd_device *device, char *name, size_t len)
+{
+	strncpy(name, device->name, len);
+}
+
+void device_remove_bonding(struct btd_device *device)
 {
 	char filename[PATH_MAX + 1];
-	char *str, srcaddr[18], dstaddr[18];
+	char srcaddr[18], dstaddr[18];
 	int dd, dev_id;
 	bdaddr_t bdaddr;
-	gboolean paired;
 
 	adapter_get_address(device->adapter, &bdaddr);
 	ba2str(&bdaddr, srcaddr);
@@ -986,13 +1141,8 @@
 	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr,
 			"linkkeys");
 
-	/* textfile_del doesn't return an error when the key is not found */
-	str = textfile_caseget(filename, dstaddr);
-	paired = str ? TRUE : FALSE;
-	g_free(str);
-
-	if (!paired)
-		return;
+	/* Delete the link key from storage */
+	textfile_casedel(filename, dstaddr);
 
 	dev_id = adapter_get_dev_id(device->adapter);
 
@@ -1000,41 +1150,38 @@
 	if (dd < 0)
 		return;
 
-	/* Delete the link key from storage */
-	textfile_casedel(filename, dstaddr);
-
 	/* Delete the link key from the Bluetooth chip */
 	hci_delete_stored_link_key(dd, &device->bdaddr, 0, HCI_REQ_TIMEOUT);
 
 	hci_close_dev(dd);
-
-	paired = FALSE;
-	emit_property_changed(conn, device->path, DEVICE_INTERFACE,
-				"Paired", DBUS_TYPE_BOOLEAN, &paired);
 }
 
-static void device_remove_stored(struct btd_device *device,
-					DBusConnection *conn)
+static void device_remove_stored(struct btd_device *device)
 {
 	bdaddr_t src;
 	char addr[18];
+	DBusConnection *conn = get_dbus_connection();
 
 	adapter_get_address(device->adapter, &src);
 	ba2str(&device->bdaddr, addr);
 
-	device_remove_bonding(device, conn);
+	if (device->paired)
+		device_remove_bonding(device);
 	delete_entry(&src, "profiles", addr);
 	delete_entry(&src, "trusts", addr);
 	delete_all_records(&src, &device->bdaddr);
+
+	if (device->blocked)
+		device_unblock(conn, device, TRUE);
 }
 
-void device_remove(struct btd_device *device, DBusConnection *conn,
-						gboolean remove_stored)
+void device_remove(struct btd_device *device, gboolean remove_stored)
 {
-	GSList *list;
-	struct btd_device_driver *driver;
 
-	debug("Removing device %s", device->path);
+	DBG("Removing device %s", device->path);
+
+	if (device->agent)
+		agent_free(device->agent);
 
 	if (device->bonding)
 		device_cancel_bonding(device, HCI_OE_USER_ENDED_CONNECTION);
@@ -1046,15 +1193,11 @@
 		do_disconnect(device);
 
 	if (remove_stored)
-		device_remove_stored(device, conn);
+		device_remove_stored(device);
 
-	for (list = device->drivers; list; list = list->next) {
-		struct btd_driver_data *driver_data = list->data;
-		driver = driver_data->driver;
-
-		driver->remove(device);
-		g_free(driver_data);
-	}
+	g_slist_foreach(device->drivers, (GFunc) driver_remove, device);
+	g_slist_free(device->drivers);
+	device->drivers = NULL;
 
 	btd_device_unref(device);
 }
@@ -1149,7 +1292,12 @@
 	GSList *list;
 	int err;
 
-	debug("Probe drivers for %s", device->path);
+	if (device->blocked) {
+		DBG("Skipping drivers for blocked device %s", device->path);
+		goto add_uuids;
+	}
+
+	DBG("Probe drivers for %s", device->path);
 
 	for (list = device_drivers; list; list = list->next) {
 		struct btd_device_driver *driver = list->data;
@@ -1178,6 +1326,7 @@
 		g_slist_free(probe_uuids);
 	}
 
+add_uuids:
 	for (list = profiles; list; list = list->next) {
 		GSList *l = g_slist_find_custom(device->uuids, list->data,
 						(GCompareFunc) strcasecmp);
@@ -1188,12 +1337,6 @@
 						g_strdup(list->data),
 						(GCompareFunc) strcasecmp);
 	}
-
-	if (device->tmp_records) {
-		sdp_list_free(device->tmp_records,
-				(sdp_free_func_t) sdp_record_free);
-		device->tmp_records = NULL;
-	}
 }
 
 static void device_remove_drivers(struct btd_device *device, GSList *uuids)
@@ -1210,7 +1353,7 @@
 
 	records = read_records(&src, &device->bdaddr);
 
-	debug("Remove drivers for %s", device->path);
+	DBG("Remove drivers for %s", device->path);
 
 	for (list = device->drivers; list; list = next) {
 		struct btd_driver_data *driver_data = list->data;
@@ -1221,10 +1364,10 @@
 
 		for (uuid = driver->uuids; *uuid; uuid++) {
 			if (!g_slist_find_custom(uuids, *uuid,
-					(GCompareFunc) strcasecmp))
+						(GCompareFunc) strcasecmp))
 				continue;
 
-			debug("UUID %s was removed from device %s",
+			DBG("UUID %s was removed from device %s",
 							*uuid, dstaddr);
 
 			driver->remove(device);
@@ -1305,6 +1448,12 @@
 		if (sdp_get_service_classes(rec, &svcclass) < 0)
 			continue;
 
+		/* Check for empty service classes list */
+		if (svcclass == NULL) {
+			DBG("Skipping record with no service classes");
+			continue;
+		}
+
 		/* Extract the first element and skip the remainning */
 		profile_uuid = bt_uuid2string(svcclass->data);
 		if (!profile_uuid) {
@@ -1381,30 +1530,43 @@
 	g_free(str);
 }
 
+static void create_device_reply(struct btd_device *device, struct browse_req *req)
+{
+	DBusMessage *reply;
+
+	reply = dbus_message_new_method_return(req->msg);
+	if (!reply)
+		return;
+
+	dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &device->path,
+					DBUS_TYPE_INVALID);
+
+	g_dbus_send_message(req->conn, reply);
+}
+
 static void search_cb(sdp_list_t *recs, int err, gpointer user_data)
 {
 	struct browse_req *req = user_data;
 	struct btd_device *device = req->device;
-	DBusMessage *reply;
 
 	if (err < 0) {
 		error("%s: error updating services: %s (%d)",
 				device->path, strerror(-err), -err);
-		goto proceed;
+		goto send_reply;
 	}
 
 	update_services(req, recs);
 
-	if (device->tmp_records && req->records) {
+	if (device->tmp_records)
 		sdp_list_free(device->tmp_records,
 					(sdp_free_func_t) sdp_record_free);
-		device->tmp_records = req->records;
-		req->records = NULL;
-	}
+
+	device->tmp_records = req->records;
+	req->records = NULL;
 
 	if (!req->profiles_added && !req->profiles_removed) {
-		debug("%s: No service update", device->path);
-		goto proceed;
+		DBG("%s: No service update", device->path);
+		goto send_reply;
 	}
 
 	/* Probe matching drivers for services added */
@@ -1418,34 +1580,32 @@
 	/* Propagate services changes */
 	services_changed(req->device);
 
-proceed:
-	/* Store the device's profiles in the filesystem */
-	store_profiles(device);
-
+send_reply:
 	if (!req->msg)
 		goto cleanup;
 
 	if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE,
-					"DiscoverServices")) {
-		discover_services_reply(req, err, req->records);
-		goto cleanup;
+					"DiscoverServices"))
+		discover_services_reply(req, err, device->tmp_records);
+	else if (dbus_message_is_method_call(req->msg, ADAPTER_INTERFACE,
+						"CreatePairedDevice"))
+		create_device_reply(device, req);
+	else if (dbus_message_is_method_call(req->msg, ADAPTER_INTERFACE,
+						"CreateDevice")) {
+		if (err < 0) {
+			error_failed_errno(req->conn, req->msg, -err);
+			goto cleanup;
+		}
+
+		create_device_reply(device, req);
+		device_set_temporary(device, FALSE);
 	}
 
-	/* Reply create device request */
-	reply = dbus_message_new_method_return(req->msg);
-	if (!reply)
-		goto cleanup;
-
-	dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &device->path,
-							DBUS_TYPE_INVALID);
-
-	g_dbus_send_message(req->conn, reply);
-
-	device_set_temporary(device, FALSE);
-
 cleanup:
-	browse_request_free(req);
+	if (!device->temporary)
+		store_profiles(device);
 	device->browse = NULL;
+	browse_request_free(req);
 }
 
 static void browse_cb(sdp_list_t *recs, int err, gpointer user_data)
@@ -1519,7 +1679,7 @@
 		conn = get_dbus_connection();
 
 	req->conn = dbus_connection_ref(conn);
-	req->device = device;
+	req->device = btd_device_ref(device);
 
 	if (search) {
 		memcpy(&uuid, search, sizeof(uuid_t));
@@ -1547,8 +1707,8 @@
 	err = bt_search_service(&src, &device->bdaddr,
 				&uuid, cb, req, NULL);
 	if (err < 0) {
-		browse_request_free(req);
 		device->browse = NULL;
+		browse_request_free(req);
 	}
 
 	return err;
@@ -1580,15 +1740,10 @@
 	if (!device)
 		return NULL;
 
-	return  device->agent;
-}
+	if (device->agent)
+		return device->agent;
 
-void device_set_agent(struct btd_device *device, struct agent *agent)
-{
-	if (!device)
-		return;
-
-	device->agent = agent;
+	return adapter_get_agent(device->adapter);
 }
 
 gboolean device_is_busy(struct btd_device *device)
@@ -1646,7 +1801,7 @@
 	return FALSE;
 }
 
-DBusMessage *new_authentication_return(DBusMessage *msg, uint8_t status)
+static DBusMessage *new_authentication_return(DBusMessage *msg, int status)
 {
 	switch (status) {
 	case 0x00: /* success */
@@ -1717,9 +1872,6 @@
 	if (bonding->conn)
 		dbus_connection_unref(bonding->conn);
 
-	if (bonding->io_id)
-		g_source_remove(bonding->io_id);
-
 	if (bonding->io)
 		g_io_channel_unref(bonding->io);
 
@@ -1734,14 +1886,20 @@
 	if (!device->agent)
 		return;
 
-	agent_destroy(device->agent, FALSE);
+	agent_cancel(device->agent);
+	agent_free(device->agent);
 	device->agent = NULL;
 }
 
-static void device_set_paired(struct btd_device *device, gboolean value)
+void device_set_paired(struct btd_device *device, gboolean value)
 {
 	DBusConnection *conn = get_dbus_connection();
 
+	if (device->paired == value)
+		return;
+
+	device->paired = value;
+
 	emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Paired",
 				DBUS_TYPE_BOOLEAN, &value);
 }
@@ -1750,7 +1908,7 @@
 {
 	struct btd_device *device = user_data;
 
-	device_set_agent(device, NULL);
+	device->agent = NULL;
 
 	if (device->authr)
 		device->authr->agent = NULL;
@@ -1766,7 +1924,7 @@
 	const char *name = dbus_message_get_sender(msg);
 	struct agent *agent;
 
-	debug("%s: requesting bonding", device->path);
+	DBG("%s: requesting bonding", device->path);
 
 	if (!agent_path)
 		goto proceed;
@@ -1782,7 +1940,7 @@
 
 	device->agent = agent;
 
-	debug("Temporary agent registered for %s at %s:%s",
+	DBG("Temporary agent registered for %s at %s:%s",
 			device->path, name, agent_path);
 
 proceed:
@@ -1794,63 +1952,19 @@
 	return bonding;
 }
 
-static gboolean bonding_io_cb(GIOChannel *io, GIOCondition cond,
-							gpointer user_data)
+static int device_authentication_requested(struct btd_device *device,
+						int handle)
 {
-	struct btd_device *device = user_data;
-	DBusMessage *reply;
-
-	if (!device->bonding)
-		return FALSE;
-
-	reply = new_authentication_return(device->bonding->msg,
-					HCI_CONNECTION_TERMINATED);
-	g_dbus_send_message(device->bonding->conn, reply);
-
-	bonding_request_free(device->bonding);
-
-	return FALSE;
-}
-
-static void bonding_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
-{
-	struct btd_device *device = user_data;
 	struct hci_request rq;
 	auth_requested_cp cp;
 	evt_cmd_status rp;
 	int dd;
-	uint16_t handle;
-
-	if (!device->bonding) {
-		if (!err)
-			g_io_channel_shutdown(io, TRUE, NULL);
-		return;
-	}
-
-	if (err) {
-		error("%s", err->message);
-		error_connection_attempt_failed(device->bonding->conn,
-						device->bonding->msg,
-						ENETDOWN);
-		goto cleanup;
-	}
-
-	if (!bt_io_get(io, BT_IO_L2RAW, &err,
-			BT_IO_OPT_HANDLE, &handle,
-			BT_IO_OPT_INVALID)) {
-		error("Unable to get connection handle: %s", err->message);
-		error_connection_attempt_failed(device->bonding->conn,
-						device->bonding->msg,
-						ENETDOWN);
-		g_error_free(err);
-		goto failed;
-	}
 
 	dd = hci_open_dev(adapter_get_dev_id(device->adapter));
 	if (dd < 0) {
-		DBusMessage *reply = no_such_adapter(device->bonding->msg);
-		g_dbus_send_message(device->bonding->conn, reply);
-		goto failed;
+		int err = -errno;
+		error("Unable to open adapter: %s(%d)", strerror(-err), -err);
+		return err;
 	}
 
 	memset(&rp, 0, sizeof(rp));
@@ -1868,44 +1982,67 @@
 	rq.event  = EVT_CMD_STATUS;
 
 	if (hci_send_req(dd, &rq, HCI_REQ_TIMEOUT) < 0) {
+		int err = -errno;
 		error("Unable to send HCI request: %s (%d)",
-					strerror(errno), errno);
-		error_failed_errno(device->bonding->conn, device->bonding->msg,
-				errno);
+					strerror(-err), -err);
 		hci_close_dev(dd);
-		goto failed;
+		return err;
 	}
 
 	if (rp.status) {
 		error("HCI_Authentication_Requested failed with status 0x%02x",
 				rp.status);
-		error_failed_errno(device->bonding->conn, device->bonding->msg,
-				bt_error(rp.status));
 		hci_close_dev(dd);
+		return rp.status;
+	}
+
+	info("Authentication requested");
+
+	hci_close_dev(dd);
+	return 0;
+}
+
+static void bonding_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
+{
+	struct btd_device *device = user_data;
+	uint16_t handle;
+	int status;
+
+	if (!device->bonding) {
+		if (!err)
+			g_io_channel_shutdown(io, TRUE, NULL);
+		return;
+	}
+
+	if (err)
+		/* Wait proper error to be propagated by bonding complete */
+		return;
+
+	if (!bt_io_get(io, BT_IO_L2RAW, &err,
+			BT_IO_OPT_HANDLE, &handle,
+			BT_IO_OPT_INVALID)) {
+		error("Unable to get connection handle: %s", err->message);
+		g_error_free(err);
+		status = -errno;
 		goto failed;
 	}
 
-	hci_close_dev(dd);
-
-	device->bonding->io_id = g_io_add_watch(io,
-					G_IO_NVAL | G_IO_HUP | G_IO_ERR,
-					bonding_io_cb, device);
+	status = device_authentication_requested(device, handle);
+	if (status != 0)
+		goto failed;
 
 	return;
 
 failed:
 	g_io_channel_shutdown(io, TRUE, NULL);
-
-cleanup:
-	device->bonding->io_id = 0;
-	bonding_request_free(device->bonding);
+	device_cancel_bonding(device, status);
 }
 
 static void create_bond_req_exit(DBusConnection *conn, void *user_data)
 {
 	struct btd_device *device = user_data;
 
-	debug("%s: requestor exited before bonding was completed", device->path);
+	DBG("%s: requestor exited before bonding was completed", device->path);
 
 	if (device->authr)
 		device_cancel_authentication(device, FALSE);
@@ -1929,6 +2066,7 @@
 	bdaddr_t src;
 	GError *err = NULL;
 	GIOChannel *io;
+	BtIOSecLevel sec_level;
 
 	adapter_get_address(adapter, &src);
 	ba2str(&src, srcaddr);
@@ -1949,12 +2087,19 @@
 				"Bonding already exists");
 	}
 
+	/* If our IO capability is NoInputNoOutput use medium security
+	 * level (i.e. don't require MITM protection) else use high
+	 * security level */
+	if (capability == 0x03)
+		sec_level = BT_IO_SEC_MEDIUM;
+	else
+		sec_level = BT_IO_SEC_HIGH;
 
 	io = bt_io_connect(BT_IO_L2RAW, bonding_connect_cb, device,
 				NULL, &err,
 				BT_IO_OPT_SOURCE_BDADDR, &src,
 				BT_IO_OPT_DEST_BDADDR, &device->bdaddr,
-				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH,
+				BT_IO_OPT_SEC_LEVEL, sec_level,
 				BT_IO_OPT_INVALID);
 	if (io == NULL) {
 		DBusMessage *reply;
@@ -2002,8 +2147,11 @@
 	if (auth && auth->type == AUTH_TYPE_NOTIFY && auth->agent)
 		agent_cancel(auth->agent);
 
-	if (status)
-		goto failed;
+	if (status) {
+		device_cancel_authentication(device, TRUE);
+		device_cancel_bonding(device, status);
+		return;
+	}
 
 	device->auth = 0xff;
 
@@ -2037,7 +2185,7 @@
 			/* If we are not initiators and there is no currently
 			 * active discovery or discovery timer, set discovery
 			 * timer */
-			debug("setting timer for reverse service discovery");
+			DBG("setting timer for reverse service discovery");
 			device->discov_timer = g_timeout_add_seconds(
 							DISCOVERY_TIMER,
 							start_discovery,
@@ -2046,11 +2194,6 @@
 	}
 
 	device_set_paired(device, TRUE);
-
-	return;
-
-failed:
-	device_cancel_bonding(device, status);
 }
 
 gboolean device_is_creating(struct btd_device *device, const char *sender)
@@ -2097,7 +2240,7 @@
 	if (!bonding)
 		return;
 
-	debug("%s: canceling bonding request", device->path);
+	DBG("%s: canceling bonding request", device->path);
 
 	if (device->authr)
 		device_cancel_authentication(device, FALSE);
@@ -2109,19 +2252,20 @@
 	bonding_request_free(bonding);
 }
 
-static void pincode_cb(struct agent *agent, DBusError *err, const char *pincode,
-			void *data)
+static void pincode_cb(struct agent *agent, DBusError *err,
+					const char *pincode, void *data)
 {
 	struct authentication_req *auth = data;
 	struct btd_device *device = auth->device;
 
 	/* No need to reply anything if the authentication already failed */
-	if (!auth->cb)
+	if (auth->cb == NULL)
 		return;
 
 	((agent_pincode_cb) auth->cb)(agent, err, pincode, device);
 
-	auth->cb = NULL;
+	device->authr->cb = NULL;
+	device->authr->agent = NULL;
 }
 
 static void confirm_cb(struct agent *agent, DBusError *err, void *data)
@@ -2130,27 +2274,29 @@
 	struct btd_device *device = auth->device;
 
 	/* No need to reply anything if the authentication already failed */
-	if (!auth->cb)
+	if (auth->cb == NULL)
 		return;
 
 	((agent_cb) auth->cb)(agent, err, device);
 
-	auth->cb = NULL;
+	device->authr->cb = NULL;
+	device->authr->agent = NULL;
 }
 
-static void passkey_cb(struct agent *agent, DBusError *err, uint32_t passkey,
-			void *data)
+static void passkey_cb(struct agent *agent, DBusError *err,
+						uint32_t passkey, void *data)
 {
 	struct authentication_req *auth = data;
 	struct btd_device *device = auth->device;
 
 	/* No need to reply anything if the authentication already failed */
-	if (!auth->cb)
+	if (auth->cb == NULL)
 		return;
 
 	((agent_passkey_cb) auth->cb)(agent, err, passkey, device);
 
-	auth->cb = NULL;
+	device->authr->cb = NULL;
+	device->authr->agent = NULL;
 }
 
 static void pairing_consent_cb(struct agent *agent, DBusError *err, void *data)
@@ -2168,19 +2314,15 @@
 }
 
 int device_request_authentication(struct btd_device *device, auth_type_t type,
-				uint32_t passkey, void *cb)
+						uint32_t passkey, void *cb)
 {
 	struct authentication_req *auth;
 	struct agent *agent;
-	int ret;
+	int err;
 
-	debug("%s: requesting agent authentication", device->path);
+	DBG("%s: requesting agent authentication", device->path);
 
-	agent = device->agent;
-
-	if (!agent)
-		agent = adapter_get_agent(device->adapter);
-
+	agent = device_get_agent(device);
 	if (!agent) {
 		error("No agent available for %u request", type);
 		return -EPERM;
@@ -2195,49 +2337,52 @@
 
 	switch (type) {
 	case AUTH_TYPE_PINCODE:
-		ret = agent_request_pincode(agent, device, pincode_cb,
+		err = agent_request_pincode(agent, device, pincode_cb,
 								auth, NULL);
 		break;
 	case AUTH_TYPE_PASSKEY:
-		ret = agent_request_passkey(agent, device, passkey_cb,
+		err = agent_request_passkey(agent, device, passkey_cb,
 								auth, NULL);
 		break;
 	case AUTH_TYPE_CONFIRM:
-		ret = agent_request_confirmation(agent, device, passkey,
+		err = agent_request_confirmation(agent, device, passkey,
 						confirm_cb, auth, NULL);
 		break;
 	case AUTH_TYPE_NOTIFY:
-		ret = agent_display_passkey(agent, device, passkey);
+		err = agent_display_passkey(agent, device, passkey);
 		break;
 	case AUTH_TYPE_AUTO:
-		ret = 0;
+		err = 0;
 		break;
 	case AUTH_TYPE_PAIRING_CONSENT:
-		ret = agent_request_pairing_consent(agent, device,
+		err = agent_request_pairing_consent(agent, device,
 							pairing_consent_cb, auth, NULL);
 		break;
 	default:
-		ret = -EINVAL;
+		err = -EINVAL;
 	}
 
-	if (ret < 0) {
+	if (err < 0) {
 		error("Failed requesting authentication");
 		g_free(auth);
 		device->authr = NULL;
 	}
 
-	return ret;
+	return err;
 }
 
 static void cancel_authentication(struct authentication_req *auth)
 {
-	struct btd_device *device = auth->device;
-	struct agent *agent = auth->agent;
+	struct btd_device *device;
+	struct agent *agent;
 	DBusError err;
 
-	if (!auth->cb)
+	if (!auth || !auth->cb)
 		return;
 
+	device = auth->device;
+	agent = auth->agent;
+
 	dbus_error_init(&err);
 	dbus_set_error_const(&err, "org.bluez.Error.Canceled", NULL);
 
@@ -2271,7 +2416,7 @@
 	if (!auth)
 		return;
 
-	debug("%s: canceling authentication request", device->path);
+	DBG("%s: canceling authentication request", device->path);
 
 	if (auth->agent)
 		agent_cancel(auth->agent);
@@ -2325,12 +2470,17 @@
 }
 
 const sdp_record_t *btd_device_get_record(struct btd_device *device,
-						const char *uuid)
+							const char *uuid)
 {
 	bdaddr_t src;
 
-	if (device->tmp_records)
-		return find_record_in_list(device->tmp_records, uuid);
+	if (device->tmp_records) {
+		const sdp_record_t *record;
+
+		record = find_record_in_list(device->tmp_records, uuid);
+		if (record != NULL)
+			return record;
+	}
 
 	adapter_get_address(device->adapter, &src);
 
@@ -2341,6 +2491,30 @@
 	return find_record_in_list(device->tmp_records, uuid);
 }
 
+gboolean device_set_debug_key(struct btd_device *device, uint8_t *key)
+{
+	if (key == NULL) {
+		device->has_debug_key = FALSE;
+		return TRUE;
+	}
+
+	memcpy(device->debug_key, key, 16);
+	device->has_debug_key = TRUE;
+
+	return TRUE;
+}
+
+gboolean device_get_debug_key(struct btd_device *device, uint8_t *key)
+{
+	if (!device->has_debug_key)
+		return FALSE;
+
+	if (key != NULL)
+		memcpy(key, device->debug_key, 16);
+
+	return TRUE;
+}
+
 int btd_register_device_driver(struct btd_device_driver *driver)
 {
 	device_drivers = g_slist_append(device_drivers, driver);
@@ -2357,7 +2531,7 @@
 {
 	device->ref++;
 
-	debug("btd_device_ref(%p): ref=%d", device, device->ref);
+	DBG("%p: ref=%d", device, device->ref);
 
 	return device;
 }
@@ -2369,7 +2543,7 @@
 
 	device->ref--;
 
-	debug("btd_device_unref(%p): ref=%d", device, device->ref);
+	DBG("%p: ref=%d", device, device->ref);
 
 	if (device->ref > 0)
 		return;
diff --git a/src/device.h b/src/device.h
index c6677dc..752dad3 100644
--- a/src/device.h
+++ b/src/device.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -38,8 +38,8 @@
 struct btd_device *device_create(DBusConnection *conn, struct btd_adapter *adapter,
 				const gchar *address);
 void device_set_name(struct btd_device *device, const char *name);
-void device_remove(struct btd_device *device, DBusConnection *conn,
-						gboolean remove_stored);
+void device_get_name(struct btd_device *device, char *name, size_t len);
+void device_remove(struct btd_device *device, gboolean remove_stored);
 gint device_address_cmp(struct btd_device *device, const gchar *address);
 int device_browse(struct btd_device *device, DBusConnection *conn,
 			DBusMessage *msg, uuid_t *search, gboolean reverse);
@@ -51,21 +51,23 @@
 void device_get_address(struct btd_device *adapter, bdaddr_t *bdaddr);
 const gchar *device_get_path(struct btd_device *device);
 struct agent *device_get_agent(struct btd_device *device);
-void device_set_agent(struct btd_device *device, struct agent *agent);
 gboolean device_is_busy(struct btd_device *device);
 gboolean device_is_temporary(struct btd_device *device);
 gboolean device_is_paired(struct btd_device *device);
+gboolean device_is_trusted(struct btd_device *device);
+void device_set_paired(struct btd_device *device, gboolean paired);
 void device_set_temporary(struct btd_device *device, gboolean temporary);
 void device_set_cap(struct btd_device *device, uint8_t cap);
 uint8_t device_get_cap(struct btd_device *device);
 void device_set_auth(struct btd_device *device, uint8_t auth);
 uint8_t device_get_auth(struct btd_device *device);
 gboolean device_is_connected(struct btd_device *device);
+gboolean device_get_secmode3_conn(struct btd_device *device);
 void device_set_secmode3_conn(struct btd_device *device, gboolean enable);
 DBusMessage *device_create_bonding(struct btd_device *device,
 				DBusConnection *conn, DBusMessage *msg,
 				const char *agent_path, uint8_t capability);
-void device_remove_bondind(struct btd_device *device, DBusConnection *connection);
+void device_remove_bonding(struct btd_device *device);
 void device_bonding_complete(struct btd_device *device, uint8_t status);
 void device_simple_pairing_complete(struct btd_device *device, uint8_t status);
 gboolean device_is_creating(struct btd_device *device, const char *sender);
@@ -78,6 +80,8 @@
 gboolean device_is_authorizing(struct btd_device *device);
 void device_set_authorizing(struct btd_device *device, gboolean auth);
 void device_set_renewed_key(struct btd_device *device, gboolean renewed);
+gboolean device_set_debug_key(struct btd_device *device, uint8_t *key);
+gboolean device_get_debug_key(struct btd_device *device, uint8_t *key);
 void device_add_connection(struct btd_device *device, DBusConnection *conn,
 				uint16_t handle);
 uint16_t device_get_handle(struct btd_device *device);
diff --git a/src/error.c b/src/error.c
index f54e819..c1a2fbf 100644
--- a/src/error.c
+++ b/src/error.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2007-2008  Fabien Chevalier <fabchevalier@free.fr>
  *
  *
diff --git a/src/error.h b/src/error.h
index 82301d5..49ec05e 100644
--- a/src/error.h
+++ b/src/error.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2007-2008  Fabien Chevalier <fabchevalier@free.fr>
  *
  *
diff --git a/src/genbuiltin b/src/genbuiltin
new file mode 100755
index 0000000..8b6f047
--- /dev/null
+++ b/src/genbuiltin
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+for i in $*
+do
+	echo "extern struct bluetooth_plugin_desc __bluetooth_builtin_$i;"
+done
+
+echo
+echo "static struct bluetooth_plugin_desc *__bluetooth_builtin[] = {"
+
+for i in $*
+do
+	echo "  &__bluetooth_builtin_$i,"
+done
+
+echo "  NULL"
+echo "};"
diff --git a/common/glib-helper.c b/src/glib-helper.c
similarity index 99%
rename from common/glib-helper.c
rename to src/glib-helper.c
index 727c55d..41f5e3c 100644
--- a/common/glib-helper.c
+++ b/src/glib-helper.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -765,6 +765,7 @@
 
 	if (setsockopt(dd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0) {
 		err = errno;
+		g_free(cmd);
 		goto failed;
 	}
 
diff --git a/common/glib-helper.h b/src/glib-helper.h
similarity index 95%
rename from common/glib-helper.h
rename to src/glib-helper.h
index 751f3a7..1c8e19a 100644
--- a/common/glib-helper.h
+++ b/src/glib-helper.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/src/hcid.h b/src/hcid.h
index 2f07259..9c5f1d6 100644
--- a/src/hcid.h
+++ b/src/hcid.h
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2000-2001  Qualcomm Incorporated
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -60,6 +60,7 @@
 	gboolean	remember_powered;
 	gboolean	reverse_sdp;
 	gboolean	name_resolv;
+	gboolean	debug_keys;
 
 	uint8_t		scan;
 	uint8_t		mode;
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..4ec4633
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,136 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h>
+
+#include <glib.h>
+
+#include "log.h"
+
+void info(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+
+	vsyslog(LOG_INFO, format, ap);
+
+	va_end(ap);
+}
+
+void error(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+
+	vsyslog(LOG_ERR, format, ap);
+
+	va_end(ap);
+}
+
+void btd_debug(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+
+	vsyslog(LOG_DEBUG, format, ap);
+
+	va_end(ap);
+}
+
+extern struct btd_debug_desc __start___debug[];
+extern struct btd_debug_desc __stop___debug[];
+
+static gchar **enabled = NULL;
+
+static gboolean is_enabled(struct btd_debug_desc *desc)
+{
+	int i;
+
+	if (enabled == NULL)
+		return 0;
+
+	for (i = 0; enabled[i] != NULL; i++) {
+		if (desc->name != NULL && g_pattern_match_simple(enabled[i],
+							desc->name) == TRUE)
+			return 1;
+		if (desc->file != NULL && g_pattern_match_simple(enabled[i],
+							desc->file) == TRUE)
+			return 1;
+	}
+
+	return 0;
+}
+
+void __btd_toggle_debug()
+{
+	struct btd_debug_desc *desc;
+
+	for (desc = __start___debug; desc < __stop___debug; desc++)
+		desc->flags |= BTD_DEBUG_FLAG_PRINT;
+}
+
+void __btd_log_init(const char *debug, int detach)
+{
+	int option = LOG_NDELAY | LOG_PID;
+	struct btd_debug_desc *desc;
+	const char *name = NULL, *file = NULL;
+
+	if (debug != NULL)
+		enabled = g_strsplit_set(debug, ":, ", 0);
+
+	for (desc = __start___debug; desc < __stop___debug; desc++) {
+		if (file != NULL || name != NULL) {
+			if (g_strcmp0(desc->file, file) == 0) {
+				if (desc->name == NULL)
+					desc->name = name;
+			} else
+				file = NULL;
+		}
+
+		if (is_enabled(desc))
+			desc->flags |= BTD_DEBUG_FLAG_PRINT;
+	}
+
+	if (!detach)
+		option |= LOG_PERROR;
+
+	openlog("bluetoothd", option, LOG_DAEMON);
+
+	syslog(LOG_INFO, "Bluetooth deamon %s", VERSION);
+}
+
+void __btd_log_cleanup(void)
+{
+	closelog();
+
+	g_strfreev(enabled);
+}
diff --git a/src/log.h b/src/log.h
new file mode 100644
index 0000000..cc45cbf
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,57 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+void info(const char *format, ...) __attribute__((format(printf, 1, 2)));
+void error(const char *format, ...) __attribute__((format(printf, 1, 2)));
+
+void btd_debug(const char *format, ...) __attribute__((format(printf, 1, 2)));
+
+void __btd_log_init(const char *debug, int detach);
+void __btd_log_cleanup(void);
+void __btd_toggle_debug();
+
+struct btd_debug_desc {
+	const char *name;
+	const char *file;
+#define BTD_DEBUG_FLAG_DEFAULT (0)
+#define BTD_DEBUG_FLAG_PRINT   (1 << 0)
+	unsigned int flags;
+} __attribute__((aligned(8)));
+
+/**
+ * DBG:
+ * @fmt: format string
+ * @arg...: list of arguments
+ *
+ * Simple macro around btd_debug() which also include the function
+ * name it is called in.
+ */
+#define DBG(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__, __FUNCTION__ , ## arg); \
+} while (0)
+
diff --git a/src/main.c b/src/main.c
index 8b66127..2402539 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2000-2001  Qualcomm Incorporated
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -50,7 +50,7 @@
 
 #include <dbus/dbus.h>
 
-#include "logging.h"
+#include "log.h"
 
 #include "hcid.h"
 #include "sdpd.h"
@@ -60,6 +60,10 @@
 #include "agent.h"
 #include "manager.h"
 
+#ifdef HAVE_CAPNG
+#include <cap-ng.h>
+#endif
+
 #define LAST_ADAPTER_EXIT_TIMEOUT 30
 
 struct main_opts main_opts;
@@ -93,15 +97,15 @@
 	if (!config)
 		return;
 
-	debug("parsing main.conf");
+	DBG("parsing main.conf");
 
 	val = g_key_file_get_integer(config, "General",
 						"DiscoverableTimeout", &err);
 	if (err) {
-		debug("%s", err->message);
+		DBG("%s", err->message);
 		g_clear_error(&err);
 	} else {
-		debug("discovto=%d", val);
+		DBG("discovto=%d", val);
 		main_opts.discovto = val;
 		main_opts.flags |= 1 << HCID_SET_DISCOVTO;
 	}
@@ -109,29 +113,29 @@
 	val = g_key_file_get_integer(config, "General",
 						"PairableTimeout", &err);
 	if (err) {
-		debug("%s", err->message);
+		DBG("%s", err->message);
 		g_clear_error(&err);
 	} else {
-		debug("pairto=%d", val);
+		DBG("pairto=%d", val);
 		main_opts.pairto = val;
 	}
 
 	val = g_key_file_get_integer(config, "General", "PageTimeout", &err);
 	if (err) {
-		debug("%s", err->message);
+		DBG("%s", err->message);
 		g_clear_error(&err);
 	} else {
-		debug("pageto=%d", val);
+		DBG("pageto=%d", val);
 		main_opts.pageto = val;
 		main_opts.flags |= 1 << HCID_SET_PAGETO;
 	}
 
 	str = g_key_file_get_string(config, "General", "Name", &err);
 	if (err) {
-		debug("%s", err->message);
+		DBG("%s", err->message);
 		g_clear_error(&err);
 	} else {
-		debug("name=%s", str);
+		DBG("name=%s", str);
 		g_free(main_opts.name);
 		main_opts.name = g_strdup(str);
 		main_opts.flags |= 1 << HCID_SET_NAME;
@@ -140,10 +144,10 @@
 
 	str = g_key_file_get_string(config, "General", "Class", &err);
 	if (err) {
-		debug("%s", err->message);
+		DBG("%s", err->message);
 		g_clear_error(&err);
 	} else {
-		debug("class=%s", str);
+		DBG("class=%s", str);
 		main_opts.class = strtol(str, NULL, 16);
 		main_opts.flags |= 1 << HCID_SET_CLASS;
 		g_free(str);
@@ -152,17 +156,17 @@
 	val = g_key_file_get_integer(config, "General",
 					"DiscoverSchedulerInterval", &err);
 	if (err) {
-		debug("%s", err->message);
+		DBG("%s", err->message);
 		g_clear_error(&err);
 	} else {
-		debug("discov_interval=%d", val);
+		DBG("discov_interval=%d", val);
 		main_opts.discov_interval = val;
 	}
 
 	boolean = g_key_file_get_boolean(config, "General",
 						"InitiallyPowered", &err);
 	if (err) {
-		debug("%s", err->message);
+		DBG("%s", err->message);
 		g_clear_error(&err);
 	} else if (boolean == FALSE)
 		main_opts.mode = MODE_OFF;
@@ -170,17 +174,17 @@
 	boolean = g_key_file_get_boolean(config, "General",
 						"RememberPowered", &err);
 	if (err) {
-		debug("%s", err->message);
+		DBG("%s", err->message);
 		g_clear_error(&err);
 	} else
 		main_opts.remember_powered = boolean;
 
 	str = g_key_file_get_string(config, "General", "DeviceID", &err);
 	if (err) {
-		debug("%s", err->message);
+		DBG("%s", err->message);
 		g_clear_error(&err);
 	} else {
-		debug("deviceid=%s", str);
+		DBG("deviceid=%s", str);
 		strncpy(main_opts.deviceid, str,
 					sizeof(main_opts.deviceid) - 1);
 		g_free(str);
@@ -189,7 +193,7 @@
 	boolean = g_key_file_get_boolean(config, "General",
 						"ReverseServiceDiscovery", &err);
 	if (err) {
-		debug("%s", err->message);
+		DBG("%s", err->message);
 		g_clear_error(&err);
 	} else
 		main_opts.reverse_sdp = boolean;
@@ -201,12 +205,23 @@
 	else
 		main_opts.name_resolv = boolean;
 
+	boolean = g_key_file_get_boolean(config, "General",
+						"DebugKeys", &err);
+	if (err)
+		g_clear_error(&err);
+	else
+		main_opts.debug_keys = boolean;
+
+	main_opts.link_mode = HCI_LM_ACCEPT;
+
+	main_opts.link_policy = HCI_LP_RSWITCH | HCI_LP_SNIFF |
+						HCI_LP_HOLD | HCI_LP_PARK;
 	str = g_key_file_get_string(config, "General",
 						"DefaultLinkPolicy", &err);
 	if (err)
 		g_clear_error(&err);
 	else {
-		debug("default_link_policy=%s", str);
+		DBG("default_link_policy=%s", str);
 		main_opts.link_policy &= strtol(str, NULL, 16);
 	}
 }
@@ -318,11 +333,12 @@
 
 static void sig_debug(int sig)
 {
-	toggle_debug();
+	__btd_toggle_debug();
 }
 
+static gchar *option_debug = NULL;
 static gboolean option_detach = TRUE;
-static gboolean option_debug = FALSE;
+static gboolean option_version = FALSE;
 static gboolean option_udev = FALSE;
 
 static guint last_adapter_timeout = 0;
@@ -355,12 +371,26 @@
 	last_adapter_timeout = 0;
 }
 
+static gboolean parse_debug(const char *key, const char *value,
+				gpointer user_data, GError **error)
+{
+	if (value)
+		option_debug = g_strdup(value);
+	else
+		option_debug = g_strdup("*");
+
+	return TRUE;
+}
+
 static GOptionEntry options[] = {
-	{ "nodaemon", 'n', G_OPTION_FLAG_REVERSE,
+	{ "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
+				G_OPTION_ARG_CALLBACK, parse_debug,
+				"Specify debug options to enable", "DEBUG" },
+	{ "nodetach", 'n', G_OPTION_FLAG_REVERSE,
 				G_OPTION_ARG_NONE, &option_detach,
 				"Don't run as daemon in background" },
-	{ "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug,
-				"Enable debug information output" },
+	{ "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
+				"Show version information and exit" },
 	{ "udev", 'u', 0, G_OPTION_ARG_NONE, &option_udev,
 				"Run from udev mode of operation" },
 	{ NULL },
@@ -383,6 +413,15 @@
 
 	init_defaults();
 
+#ifdef HAVE_CAPNG
+	/* Drop capabilities */
+	capng_clear(CAPNG_SELECT_BOTH);
+	capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
+					CAP_NET_BIND_SERVICE, CAP_NET_ADMIN,
+						CAP_NET_RAW, CAP_IPC_LOCK, -1);
+	capng_apply(CAPNG_SELECT_BOTH);
+#endif
+
 	context = g_option_context_new(NULL);
 	g_option_context_add_main_entries(context, options, NULL);
 
@@ -395,6 +434,13 @@
 		exit(1);
 	}
 
+	g_option_context_free(context);
+
+	if (option_version == TRUE) {
+		printf("%s\n", VERSION);
+		exit(0);
+	}
+
 	if (option_udev == TRUE) {
 		int err;
 
@@ -407,8 +453,6 @@
 		}
 	}
 
-	g_option_context_free(context);
-
 	if (option_detach == TRUE && option_udev == FALSE) {
 		if (daemon(0, 0)) {
 			perror("Can't start daemon");
@@ -418,7 +462,7 @@
 
 	umask(0077);
 
-	start_logging("bluetoothd", "Bluetooth daemon %s", VERSION);
+	__btd_log_init(option_debug, option_detach);
 
 	memset(&sa, 0, sizeof(sa));
 	sa.sa_flags = SA_NOCLDSTOP;
@@ -432,11 +476,6 @@
 	sa.sa_handler = SIG_IGN;
 	sigaction(SIGPIPE, &sa, NULL);
 
-	if (option_debug == TRUE) {
-		info("Enabling debug information");
-		enable_debug();
-	}
-
 	config = load_config(CONFIGDIR "/main.conf");
 
 	parse_config(config);
@@ -472,7 +511,7 @@
 
 	rfkill_init();
 
-	debug("Entering main loop");
+	DBG("Entering main loop");
 
 	g_main_loop_run(event_loop);
 
@@ -495,7 +534,7 @@
 
 	info("Exit");
 
-	stop_logging();
+	__btd_log_cleanup();
 
 	return 0;
 }
diff --git a/src/main.conf b/src/main.conf
index 9174deb..bb401fe 100644
--- a/src/main.conf
+++ b/src/main.conf
@@ -51,6 +51,11 @@
 # remote devices name and want shorter discovery cycle. Defaults to 'true'.
 NameResolving = true
 
+# Enable runtime persistency of debug link keys. Default is false which
+# makes debug link keys valid only for the duration of the connection
+# that they were created for.
+DebugKeys = false
+
 # The link policy for connections. By default it's set to 0x000f which is 
 # a bitwise OR of role switch(0x0001), hold mode(0x0002), sniff mode(0x0004)
 # and park state(0x0008) are all enabled. However, some devices have
diff --git a/src/manager.c b/src/manager.c
index 3cf914d..9b90cab 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -45,7 +45,7 @@
 
 #include "hcid.h"
 #include "dbus-common.h"
-#include "logging.h"
+#include "log.h"
 #include "adapter.h"
 #include "error.h"
 #include "manager.h"
@@ -61,32 +61,9 @@
 	return base_path;
 }
 
-void manager_update_svc(const bdaddr_t *bdaddr, uint8_t svc)
+void manager_update_svc(struct btd_adapter* adapter, uint8_t svc)
 {
-	GSList *l;
-	bdaddr_t src;
-
-	for (l = adapters; l != NULL; l = l->next) {
-		struct btd_adapter *adapter = l->data;
-
-		adapter_get_address(adapter, &src);
-
-		if (bacmp(bdaddr, BDADDR_ANY) != 0 && bacmp(bdaddr, &src) != 0)
-			continue;
-
-		adapter_update(adapter, svc);
-	}
-}
-
-int manager_get_adapter_class(uint16_t dev_id, uint8_t *cls)
-{
-	struct btd_adapter *adapter;
-
-	adapter = manager_find_adapter_by_id(dev_id);
-	if (!adapter)
-		return -EINVAL;
-
-	return adapter_get_class(adapter, cls);
+	adapter_update(adapter, svc);
 }
 
 static inline DBusMessage *invalid_args(DBusMessage *msg)
@@ -139,8 +116,8 @@
 							DBUS_TYPE_INVALID))
 		return NULL;
 
-	/* hci_devid() would make sense to use here, except it
-	   is restricted to devices which are up */
+	/* hci_devid() would make sense to use here, except it is
+	 * restricted to devices which are up */
 	if (!strcmp(pattern, "any") || !strcmp(pattern, "00:00:00:00:00:00")) {
 		path = adapter_any_get_path();
 		if (path != NULL)
@@ -240,7 +217,8 @@
 	{ "GetProperties",	"",	"a{sv}",get_properties	},
 	{ "DefaultAdapter",	"",	"o",	default_adapter	},
 	{ "FindAdapter",	"s",	"o",	find_adapter	},
-	{ "ListAdapters",	"",	"ao",	list_adapters	},
+	{ "ListAdapters",	"",	"ao",	list_adapters,
+						G_DBUS_METHOD_FLAG_DEPRECATED},
 	{ }
 };
 
@@ -259,8 +237,8 @@
 	snprintf(base_path, sizeof(base_path), "/org/bluez/%d", getpid());
 
 	return g_dbus_register_interface(conn, "/", MANAGER_INTERFACE,
-			manager_methods, manager_signals,
-			NULL, NULL, NULL);
+					manager_methods, manager_signals,
+					NULL, NULL, NULL);
 }
 
 static void manager_update_adapters(void)
@@ -359,7 +337,7 @@
 	adapter_get_address(adapter, &bdaddr);
 	ba2str(&bdaddr, addr);
 
-	return strcmp(addr, address);
+	return strcasecmp(addr, address);
 }
 
 struct btd_adapter *manager_find_adapter(const bdaddr_t *sba)
@@ -399,7 +377,8 @@
 {
 	GSList *match;
 
-	match = g_slist_find_custom(adapters, GINT_TO_POINTER(id), adapter_id_cmp);
+	match = g_slist_find_custom(adapters, GINT_TO_POINTER(id),
+							adapter_id_cmp);
 	if (!match)
 		return NULL;
 
@@ -414,9 +393,9 @@
 void manager_add_adapter(const char *path)
 {
 	g_dbus_emit_signal(connection, "/",
-			MANAGER_INTERFACE, "AdapterAdded",
-			DBUS_TYPE_OBJECT_PATH, &path,
-			DBUS_TYPE_INVALID);
+				MANAGER_INTERFACE, "AdapterAdded",
+				DBUS_TYPE_OBJECT_PATH, &path,
+				DBUS_TYPE_INVALID);
 
 	manager_update_adapters();
 
@@ -462,7 +441,7 @@
 
 int manager_start_adapter(int id)
 {
-	struct btd_adapter* adapter;
+	struct btd_adapter *adapter;
 	int ret;
 
 	adapter = manager_find_adapter_by_id(id);
diff --git a/src/manager.h b/src/manager.h
index 9463574..6bf3e76 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -43,6 +43,5 @@
 void manager_add_adapter(const char *path);
 int manager_get_default_adapter();
 void manager_set_default_adapter(int id);
-void manager_update_svc(const bdaddr_t *bdaddr, uint8_t svc);
-int manager_get_adapter_class(uint16_t dev_id, uint8_t *cls);
+void manager_update_svc(struct btd_adapter *adapter, uint8_t svc);
 void btd_manager_set_offline(gboolean offline);
diff --git a/common/oui.c b/src/oui.c
similarity index 96%
rename from common/oui.c
rename to src/oui.c
index 9863973..1096d20 100644
--- a/common/oui.c
+++ b/src/oui.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/common/oui.h b/src/oui.h
similarity index 92%
rename from common/oui.h
rename to src/oui.h
index 79aa30b..ad66e56 100644
--- a/common/oui.h
+++ b/src/oui.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/src/plugin.c b/src/plugin.c
index 706a14f..a63ce8e 100644
--- a/src/plugin.c
+++ b/src/plugin.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -35,7 +35,7 @@
 #include <glib.h>
 
 #include "plugin.h"
-#include "logging.h"
+#include "log.h"
 #include "hcid.h"
 #include "btio.h"
 
@@ -67,7 +67,7 @@
 		return FALSE;
 	}
 
-	debug("Loading %s plugin", desc->name);
+	DBG("Loading %s plugin", desc->name);
 
 	plugin = g_try_new0(struct bluetooth_plugin, 1);
 	if (plugin == NULL)
@@ -86,6 +86,9 @@
 {
 	int i;
 
+	if (list == NULL)
+		return FALSE;
+
 	for (i = 0; list[i] != NULL; i++) {
 		char *str;
 		gboolean equal;
@@ -116,9 +119,6 @@
 	gchar **disabled;
 	unsigned int i;
 
-	if (strlen(PLUGINDIR) == 0)
-		return FALSE;
-
 	/* Make a call to BtIO API so its symbols got resolved before the
 	 * plugins are loaded. */
 	bt_io_error_quark();
@@ -130,22 +130,26 @@
 	else
 		disabled = NULL;
 
-	debug("Loading builtin plugins");
+	DBG("Loading builtin plugins");
 
 	for (i = 0; __bluetooth_builtin[i]; i++) {
-		if (disabled && is_disabled(__bluetooth_builtin[i]->name,
-								disabled))
+		if (is_disabled(__bluetooth_builtin[i]->name, disabled))
 			continue;
 
 		add_plugin(NULL,  __bluetooth_builtin[i]);
 	}
 
-	debug("Loading plugins %s", PLUGINDIR);
+	if (strlen(PLUGINDIR) == 0) {
+		g_strfreev(disabled);
+		goto start;
+	}
+
+	DBG("Loading plugins %s", PLUGINDIR);
 
 	dir = g_dir_open(PLUGINDIR, 0, NULL);
 	if (!dir) {
 		g_strfreev(disabled);
-		return FALSE;
+		goto start;
 	}
 
 	while ((file = g_dir_read_name(dir)) != NULL) {
@@ -157,7 +161,7 @@
 				g_str_has_suffix(file, ".so") == FALSE)
 			continue;
 
-		if (disabled && is_disabled(file, disabled))
+		if (is_disabled(file, disabled))
 			continue;
 
 		filename = g_build_filename(PLUGINDIR, file, NULL);
@@ -187,11 +191,14 @@
 
 	g_strfreev(disabled);
 
+start:
 	for (list = plugins; list; list = list->next) {
 		struct bluetooth_plugin *plugin = list->data;
 
-		if (plugin->desc->init() < 0)
+		if (plugin->desc->init() < 0) {
+			error("Failed to init %s plugin", plugin->desc->name);
 			continue;
+		}
 
 		plugin->active = TRUE;
 	}
@@ -203,7 +210,7 @@
 {
 	GSList *list;
 
-	debug("Cleanup plugins");
+	DBG("Cleanup plugins");
 
 	for (list = plugins; list; list = list->next) {
 		struct bluetooth_plugin *plugin = list->data;
diff --git a/src/plugin.h b/src/plugin.h
index 00e0b3b..30bd415 100644
--- a/src/plugin.h
+++ b/src/plugin.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/common/ppoll.h b/src/ppoll.h
similarity index 100%
rename from common/ppoll.h
rename to src/ppoll.h
diff --git a/src/rfkill.c b/src/rfkill.c
index 286fc5c..7810846 100644
--- a/src/rfkill.c
+++ b/src/rfkill.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -35,7 +35,7 @@
 
 #include <glib.h>
 
-#include "logging.h"
+#include "log.h"
 #include "manager.h"
 #include "adapter.h"
 #include "hcid.h"
@@ -90,7 +90,7 @@
 	if (len != sizeof(struct rfkill_event))
 		return TRUE;
 
-	debug("RFKILL event idx %u type %u op %u soft %u hard %u",
+	DBG("RFKILL event idx %u type %u op %u soft %u hard %u",
 					event->idx, event->type, event->op,
 						event->soft, event->hard);
 
@@ -131,7 +131,7 @@
 	if (!adapter)
 		return TRUE;
 
-	debug("RFKILL unblock for hci%d", id);
+	DBG("RFKILL unblock for hci%d", id);
 
 	btd_adapter_restore_powered(adapter);
 
diff --git a/common/sdp-xml.c b/src/sdp-xml.c
similarity index 97%
rename from common/sdp-xml.c
rename to src/sdp-xml.c
index 18473d0..4b0520d 100644
--- a/common/sdp-xml.c
+++ b/src/sdp-xml.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2005-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2005-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -36,7 +36,6 @@
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
-#include "logging.h"
 #include "sdp-xml.h"
 
 #define STRBUFSIZE 1024
@@ -675,8 +674,6 @@
 
 	ret = sdp_data_alloc_with_length(dtd, url, length);
 
-	debug("URL size %d length %d: -->%s<--", ret->unitSize, length, url);
-
 	free(url);
 
 	return ret;
@@ -696,8 +693,6 @@
 
 	ret = sdp_data_alloc_with_length(dtd, text, length);
 
-	debug("Text size %d length %d: -->%s<--", ret->unitSize, length, text);
-
 	free(text);
 
 	return ret;
@@ -733,12 +728,8 @@
 	if (elem->data)
 		sdp_data_free(elem->data);
 
-	if (elem->name)
-		free(elem->name);
-
-	if (elem->text)
-
-		free(elem->text);
+	free(elem->name);
+	free(elem->text);
 	free(elem);
 }
 
diff --git a/common/sdp-xml.h b/src/sdp-xml.h
similarity index 96%
rename from common/sdp-xml.h
rename to src/sdp-xml.h
index 191f9df..7031276 100644
--- a/common/sdp-xml.h
+++ b/src/sdp-xml.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2005-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2005-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/src/sdpd-database.c b/src/sdpd-database.c
index 3ce056a..4c8acb7 100644
--- a/src/sdpd-database.c
+++ b/src/sdpd-database.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2001-2002  Nokia Corporation
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com>
  *
  *
@@ -39,7 +39,8 @@
 #include <bluetooth/sdp_lib.h>
 
 #include "sdpd.h"
-#include "logging.h"
+#include "log.h"
+#include "adapter.h"
 
 static sdp_list_t *service_db;
 static sdp_list_t *access_db;
@@ -54,7 +55,7 @@
  * The service repository is a linked list in sorted order
  * and the service record handle is the sort key
  */
-static int record_sort(const void *r1, const void *r2)
+int record_sort(const void *r1, const void *r2)
 {
 	const sdp_record_t *rec1 = (const sdp_record_t *) r1;
 	const sdp_record_t *rec2 = (const sdp_record_t *) r2;
@@ -183,6 +184,8 @@
 	dev->handle = rec->handle;
 
 	access_db = sdp_list_insert_sorted(access_db, dev, access_sort);
+
+	adapter_service_insert(device, rec);
 }
 
 static sdp_list_t *record_locate(uint32_t handle)
@@ -252,6 +255,7 @@
 	if (p) {
 		a = (sdp_access_t *) p->data;
 		if (a) {
+			adapter_service_remove(&a->device, r);
 			access_db = sdp_list_remove(access_db, a);
 			access_free(a);
 		}
diff --git a/src/sdpd-request.c b/src/sdpd-request.c
index 1aa0930..d56ffc2 100644
--- a/src/sdpd-request.c
+++ b/src/sdpd-request.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2001-2002  Nokia Corporation
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com>
  *
  *
@@ -43,7 +43,7 @@
 #include <netinet/in.h>
 
 #include "sdpd.h"
-#include "logging.h"
+#include "log.h"
 
 #define MIN(x, y) ((x) < (y)) ? (x): (y)
 
@@ -98,7 +98,7 @@
 
 /*
  * Generic data element sequence extractor. Builds
- * a list whose elements are those found in the 
+ * a list whose elements are those found in the
  * sequence. The data type of elements found in the
  * sequence is returned in the reference pDataType
  */
@@ -301,8 +301,8 @@
  * specified in the "search pattern" must be present in the
  * "target pattern". Here "search pattern" is the set of UUIDs
  * specified by the service discovery client and "target pattern"
- * is the set of UUIDs present in a service record. 
- * 
+ * is the set of UUIDs present in a service record.
+ *
  * Return 1 if each and every UUID in the search
  * pattern exists in the target pattern, 0 if the
  * match succeeds and -1 on error.
@@ -420,7 +420,7 @@
 			sdp_record_t *rec = (sdp_record_t *) list->data;
 
 			SDPDBG("Checking svcRec : 0x%x", rec->handle);
-				
+
 			if (sdp_match_uuid(pattern, rec->pattern) > 0 &&
 					sdp_check_access(rec->handle, &req->device)) {
 				rsp_count++;
@@ -429,7 +429,7 @@
 				handleSize += sizeof(uint32_t);
 			}
 		}
-		
+
 		SDPDBG("Match count: %d", rsp_count);
 
 		buf->data_size += handleSize;
@@ -525,9 +525,8 @@
 		}
 	}
 
-done:	
-	if (cstate)
-		free(cstate);
+done:
+	free(cstate);
 	if (pattern)
 		sdp_list_free(pattern, free);
 
@@ -684,11 +683,11 @@
 	SDPDBG("SvcRecHandle : 0x%x", handle);
 	SDPDBG("max_rsp_size : %d", max_rsp_size);
 
-	/* 
+	/*
 	 * Calculate Attribute size acording to MTU
 	 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
 	 */
-	max_rsp_size = MIN(max_rsp_size, req->mtu - sizeof(sdp_pdu_hdr_t) - 
+	max_rsp_size = MIN(max_rsp_size, req->mtu - sizeof(sdp_pdu_hdr_t) -
 			sizeof(uint32_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));
 
 	/* pull header for AttributeList byte count */
@@ -745,8 +744,7 @@
 	buf->buf_size += sizeof(uint16_t);
 
 done:
-	if (cstate)
-		free(cstate);
+	free(cstate);
 	if (seq)
 		sdp_list_free(seq, free);
 	if (status)
@@ -840,7 +838,7 @@
 	tmpbuf.buf_size = USHRT_MAX;
 	memset(tmpbuf.data, 0, USHRT_MAX);
 
-	/* 
+	/*
 	 * Calculate Attribute size acording to MTU
 	 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
 	 */
@@ -929,10 +927,8 @@
 	}
 
 done:
-	if (cstate)
-		free(cstate);
-	if (tmpbuf.data)
-		free(tmpbuf.data);
+	free(cstate);
+	free(tmpbuf.data);
 	if (pattern)
 		sdp_list_free(pattern, free);
 	if (seq)
@@ -1040,20 +1036,33 @@
 	sdp_req_t req;
 
 	size = sizeof(sa);
-	if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0)
+	if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0) {
+		error("getpeername: %s", strerror(errno));
 		return;
+	}
 
-	if (sa.l2_family == AF_BLUETOOTH) { 
+	if (sa.l2_family == AF_BLUETOOTH) {
 		struct l2cap_options lo;
+
 		memset(&lo, 0, sizeof(lo));
 		size = sizeof(lo);
-		getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &lo, &size);
+
+		if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &lo, &size) < 0) {
+			error("getsockopt: %s", strerror(errno));
+			return;
+		}
+
 		bacpy(&req.bdaddr, &sa.l2_bdaddr);
 		req.mtu = lo.omtu;
 		req.local = 0;
 		memset(&sa, 0, sizeof(sa));
 		size = sizeof(sa);
-		getsockname(sk, (struct sockaddr *) &sa, &size);
+
+		if (getsockname(sk, (struct sockaddr *) &sa, &size) < 0) {
+			error("getsockname: %s", strerror(errno));
+			return;
+		}
+
 		bacpy(&req.device, &sa.l2_bdaddr);
 	} else {
 		bacpy(&req.device, BDADDR_ANY);
diff --git a/src/sdpd-server.c b/src/sdpd-server.c
index a377ada..1c5f638 100644
--- a/src/sdpd-server.c
+++ b/src/sdpd-server.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2001-2002  Nokia Corporation
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com>
  *
  *
@@ -46,7 +46,7 @@
 
 #include <glib.h>
 
-#include "logging.h"
+#include "log.h"
 #include "sdpd.h"
 
 static GIOChannel *l2cap_io = NULL, *unix_io = NULL;
@@ -114,7 +114,10 @@
 		}
 	}
 
-	listen(l2cap_sock, 5);
+	if (listen(l2cap_sock, 5) < 0) {
+		error("listen: %s", strerror(errno));
+		return -1;
+	}
 
 	if (!compat) {
 		unix_sock = -1;
@@ -156,7 +159,6 @@
 
         info("Got Unix socket fd '%d' from environment", unix_sock);
 #endif
-
         return 0;
 }
 
diff --git a/src/sdpd-service.c b/src/sdpd-service.c
index 525c12a..cdbb4f4 100644
--- a/src/sdpd-service.c
+++ b/src/sdpd-service.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2001-2002  Nokia Corporation
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com>
  *
  *
@@ -45,13 +45,12 @@
 #include <dbus/dbus.h>
 
 #include "sdpd.h"
-#include "logging.h"
+#include "log.h"
 #include "manager.h"
+#include "adapter.h"
 
 static sdp_record_t *server = NULL;
 
-static uint8_t service_classes = 0x00;
-
 static uint16_t did_vendor = 0x0000;
 static uint16_t did_product = 0x0000;
 static uint16_t did_version = 0x0000;
@@ -98,9 +97,9 @@
 	sdp_attr_replace(server, SDP_ATTR_SVCDB_STATE, d);
 }
 
-static void update_svclass_list(const bdaddr_t *src)
+static void update_adapter_svclass_list(struct btd_adapter *adapter)
 {
-	sdp_list_t *list = sdp_get_record_list();
+	sdp_list_t *list = adapter_get_services(adapter);
 	uint8_t val = 0;
 
 	for (; list; list = list->next) {
@@ -156,19 +155,30 @@
 
 	SDPDBG("Service classes 0x%02x", val);
 
-	service_classes = val;
-
-	manager_update_svc(src, val);
+	manager_update_svc(adapter, val);
 }
 
-uint8_t get_service_classes(const bdaddr_t *bdaddr)
+static void update_svclass_list(const bdaddr_t *src)
 {
-	return service_classes;
+	GSList *adapters = manager_get_adapters();
+
+	for (; adapters; adapters = adapters->next) {
+		struct btd_adapter *adapter = adapters->data;
+		bdaddr_t bdaddr;
+
+		adapter_get_address(adapter, &bdaddr);
+
+		if (bacmp(src, BDADDR_ANY) == 0 || bacmp(src, &bdaddr) == 0)
+			update_adapter_svclass_list(adapter);
+	}
+
 }
 
-void create_ext_inquiry_response(const char *name, uint8_t *data)
+void create_ext_inquiry_response(const char *name,
+					int8_t tx_power, sdp_list_t *services,
+					uint8_t *data)
 {
-	sdp_list_t *list = sdp_get_record_list();
+	sdp_list_t *list = services;
 	uint8_t *ptr = data;
 	uint16_t uuid[24];
 	int i, index = 0;
@@ -189,10 +199,16 @@
 		ptr += len + 2;
 	}
 
+	if (tx_power != 0) {
+		*ptr++ = 2;
+		*ptr++ = 0x0a;
+		*ptr++ = (uint8_t) tx_power;
+	}
+
 	if (did_vendor != 0x0000) {
 		uint16_t source = 0x0002;
 		*ptr++ = 9;
-		*ptr++ = 11;
+		*ptr++ = 0x10;
 		*ptr++ = (source & 0x00ff);
 		*ptr++ = (source & 0xff00) >> 8;
 		*ptr++ = (did_vendor & 0x00ff);
@@ -214,6 +230,9 @@
 		if (rec->svclass.value.uuid16 < 0x1100)
 			continue;
 
+		if (rec->svclass.value.uuid16 == PNP_INFO_SVCLASS_ID)
+			continue;
+
 		if (index > 23) {
 			ptr[1] = 0x02;
 			break;
@@ -396,7 +415,7 @@
 			return -1;
 	}
 
-	debug("Adding record with handle 0x%05x", rec->handle);
+	DBG("Adding record with handle 0x%05x", rec->handle);
 
 	sdp_record_add(src, rec);
 
@@ -416,7 +435,7 @@
 			continue;
 
 		sdp_uuid2strn((uuid_t *) pattern->data, uuid, sizeof(uuid));
-		debug("Record pattern UUID %s", uuid);
+		DBG("Record pattern UUID %s", uuid);
 	}
 
 	update_db_timestamp();
@@ -429,7 +448,7 @@
 {
 	sdp_record_t *rec;
 
-	debug("Removing record with handle 0x%05x", handle);
+	DBG("Removing record with handle 0x%05x", handle);
 
 	rec = sdp_record_find(handle);
 	if (!rec)
@@ -602,7 +621,7 @@
 	}
 
 	update_db_timestamp();
-	update_svclass_list(BDADDR_ANY);
+	update_svclass_list(&req->device);
 
 	/* Build a rsp buffer */
 	bt_put_unaligned(htonl(rec->handle), (uint32_t *) rsp->data);
diff --git a/src/sdpd.h b/src/sdpd.h
index 6dadc6b..4abaa55 100644
--- a/src/sdpd.h
+++ b/src/sdpd.h
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2001-2002  Nokia Corporation
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com>
  *
  *
@@ -70,6 +70,7 @@
 void sdp_cstate_cache_init(void);
 void sdp_cstate_clean_buf(void);
 
+int record_sort(const void *r1, const void *r2);
 void sdp_svcdb_reset(void);
 void sdp_svcdb_collect_all(int sock);
 void sdp_svcdb_set_collectable(sdp_record_t *rec, int sock);
@@ -93,6 +94,7 @@
 int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec);
 int remove_record_from_server(uint32_t handle);
 
-uint8_t get_service_classes(const bdaddr_t *bdaddr);
-void create_ext_inquiry_response(const char *name, uint8_t *data);
+void create_ext_inquiry_response(const char *name,
+					int8_t tx_power, sdp_list_t *services,
+					uint8_t *data);
 static inline int android_get_control_socket(const char *name);
diff --git a/src/security.c b/src/security.c
index 646921b..ca394e1 100644
--- a/src/security.c
+++ b/src/security.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2000-2001  Qualcomm Incorporated
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -47,10 +47,11 @@
 #include <dbus/dbus.h>
 
 #include "hcid.h"
-#include "logging.h"
+#include "log.h"
 #include "textfile.h"
 
 #include "adapter.h"
+#include "device.h"
 #include "dbus-hci.h"
 #include "storage.h"
 #include "manager.h"
@@ -126,7 +127,8 @@
 
 	do {
 		struct hci_req_data *data;
-		GSList *l = g_slist_find_custom(hci_req_queue, &dev_id, hci_req_find_by_devid);
+		GSList *l = g_slist_find_custom(hci_req_queue, &dev_id,
+							hci_req_find_by_devid);
 
 		if (!l)
 			break;
@@ -134,7 +136,8 @@
 		data = l->data;
 		data->status = REQ_SENT;
 
-		ret_val = hci_send_cmd(dd, data->ogf, data->ocf, data->clen, data->cparam);
+		ret_val = hci_send_cmd(dd, data->ogf, data->ocf,
+						data->clen, data->cparam);
 		if (ret_val < 0) {
 			hci_req_queue = g_slist_remove(hci_req_queue, data);
 			g_free(data->cparam);
@@ -151,10 +154,10 @@
 	GSList *l;
 	struct hci_req_data *match;
 
-
 	hci_req_queue = g_slist_append(hci_req_queue, data);
 
-	l = g_slist_find_custom(hci_req_queue, &data->dev_id, hci_req_find_by_devid);
+	l = g_slist_find_custom(hci_req_queue, &data->dev_id,
+							hci_req_find_by_devid);
 	match = l->data;
 
 	if (match->status == REQ_SENT)
@@ -299,12 +302,17 @@
 
 static void link_key_request(int dev, bdaddr_t *sba, bdaddr_t *dba)
 {
+	struct btd_adapter *adapter;
+	struct btd_device *device;
 	struct hci_auth_info_req req;
 	unsigned char key[16];
 	char sa[18], da[18];
 	uint8_t type;
 	int err;
 
+	if (!get_adapter_and_device(sba, dba, &adapter, &device, FALSE))
+		device = NULL;
+
 	ba2str(sba, sa); ba2str(dba, da);
 	info("link_key_request (sba=%s, dba=%s)", sa, da);
 
@@ -314,33 +322,37 @@
 	err = ioctl(dev, HCIGETAUTHINFO, (unsigned long) &req);
 	if (err < 0) {
 		if (errno != EINVAL)
-			debug("HCIGETAUTHINFO failed %s (%d)",
+			DBG("HCIGETAUTHINFO failed %s (%d)",
 						strerror(errno), errno);
 		req.type = 0x00;
 	}
 
-	debug("kernel auth requirements = 0x%02x", req.type);
+	DBG("kernel auth requirements = 0x%02x", req.type);
 
-	err = read_link_key(sba, dba, key, &type);
-	if (err < 0) {
+	if (main_opts.debug_keys && device && device_get_debug_key(device, key))
+		type = 0x03;
+	else if (read_link_key(sba, dba, key, &type) < 0 || type == 0x03) {
 		/* Link key not found */
 		hci_send_cmd(dev, OGF_LINK_CTL, OCF_LINK_KEY_NEG_REPLY, 6, dba);
-	} else {
-		/* Link key found */
+		return;
+	}
+
+	/* Link key found */
+
+	DBG("link key type = 0x%02x", type);
+
+	/* Don't use unauthenticated combination keys if MITM is
+	 * required */
+	if (type == 0x04 && req.type != 0xff && (req.type & 0x01))
+		hci_send_cmd(dev, OGF_LINK_CTL, OCF_LINK_KEY_NEG_REPLY,
+								6, dba);
+	else {
 		link_key_reply_cp lr;
+
 		memcpy(lr.link_key, key, 16);
 		bacpy(&lr.bdaddr, dba);
 
-		debug("stored link key type = 0x%02x", type);
-
-		/* Don't use debug link keys (0x03) and also don't use
-		 * unauthenticated combination keys if MITM is required */
-		if (type == 0x03 || (type == 0x04 && req.type != 0xff &&
-							(req.type & 0x01)))
-			hci_send_cmd(dev, OGF_LINK_CTL,
-					OCF_LINK_KEY_NEG_REPLY, 6, dba);
-		else
-			hci_send_cmd(dev, OGF_LINK_CTL, OCF_LINK_KEY_REPLY,
+		hci_send_cmd(dev, OGF_LINK_CTL, OCF_LINK_KEY_REPLY,
 						LINK_KEY_REPLY_CP_SIZE, &lr);
 	}
 }
@@ -365,11 +377,14 @@
 	dev_id = hci_devid(sa);
 	if (dev_id < 0)
 		err = -errno;
-	else
+	else {
 		err = hcid_dbus_link_key_notify(sba, dba, evt->link_key,
 						evt->key_type,
 						io_data[dev_id].pin_length,
 						old_key_type);
+		io_data[dev_id].pin_length = -1;
+	}
+
 	if (err < 0) {
 		uint16_t handle;
 
@@ -391,8 +406,6 @@
 						DISCONNECT_CP_SIZE, &cp);
 		}
 	}
-
-	io_data[dev_id].pin_length = -1;
 }
 
 static void return_link_keys(int dev, bdaddr_t *sba, void *ptr)
@@ -413,6 +426,8 @@
 
 		info("return_link_keys (sba=%s, dba=%s)", sa, da);
 
+		hcid_dbus_returned_link_key(sba, &dba);
+
 		ptr += 22;
 	}
 }
@@ -651,6 +666,18 @@
 	adapter_set_state(adapter, state);
 }
 
+static inline void remote_features_notify(int dev, bdaddr_t *sba, void *ptr)
+{
+	evt_remote_host_features_notify *evt = ptr;
+
+	if (evt->features[0] & 0x01)
+		hcid_dbus_set_legacy_pairing(sba, &evt->bdaddr, FALSE);
+	else
+		hcid_dbus_set_legacy_pairing(sba, &evt->bdaddr, TRUE);
+
+	write_features_info(sba, &evt->bdaddr, NULL, evt->features);
+}
+
 static inline void cmd_status(int dev, bdaddr_t *sba, void *ptr)
 {
 	evt_cmd_status *evt = ptr;
@@ -683,7 +710,7 @@
 		hcid_dbus_setscan_enable_complete(sba);
 		break;
 	case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV):
-		hcid_dbus_write_class_complete(sba);
+		adapter_set_class_complete(sba, status);
 		break;
 	case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SIMPLE_PAIRING_MODE):
 		hcid_dbus_write_simple_pairing_mode_complete(sba);
@@ -692,6 +719,10 @@
 		ptr += sizeof(evt_cmd_complete);
 		adapter_update_local_name(sba, status, ptr);
 		break;
+	case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL):
+		ptr += sizeof(evt_cmd_complete);
+		adapter_update_tx_power(sba, status, ptr);
+		break;
 	};
 }
 
@@ -751,7 +782,8 @@
 	}
 }
 
-static inline void inquiry_result_with_rssi(int dev, bdaddr_t *sba, int plen, void *ptr)
+static inline void inquiry_result_with_rssi(int dev, bdaddr_t *sba,
+							int plen, void *ptr)
 {
 	uint8_t num = *(uint8_t *) ptr++;
 	int i;
@@ -790,7 +822,8 @@
 	}
 }
 
-static inline void extended_inquiry_result(int dev, bdaddr_t *sba, int plen, void *ptr)
+static inline void extended_inquiry_result(int dev, bdaddr_t *sba,
+							int plen, void *ptr)
 {
 	uint8_t num = *(uint8_t *) ptr++;
 	int i;
@@ -810,7 +843,8 @@
 	}
 }
 
-static inline void remote_features_information(int dev, bdaddr_t *sba, void *ptr)
+static inline void remote_features_information(int dev, bdaddr_t *sba,
+								void *ptr)
 {
 	evt_read_remote_features_complete *evt = ptr;
 	bdaddr_t dba;
@@ -821,7 +855,7 @@
 	if (get_bdaddr(dev, sba, btohs(evt->handle), &dba) < 0)
 		return;
 
-	write_features_info(sba, &dba, evt->features);
+	write_features_info(sba, &dba, evt->features, NULL);
 }
 
 static inline void conn_complete(int dev, int dev_id, bdaddr_t *sba, void *ptr)
@@ -849,7 +883,8 @@
 	cp_name.pscan_rep_mode = 0x02;
 
 	data = hci_req_data_new(dev_id, &evt->bdaddr, OGF_LINK_CTL,
-				OCF_REMOTE_NAME_REQ, EVT_REMOTE_NAME_REQ_COMPLETE,
+				OCF_REMOTE_NAME_REQ,
+				EVT_REMOTE_NAME_REQ_COMPLETE,
 				&cp_name, REMOTE_NAME_REQ_CP_SIZE);
 
 	hci_req_queue_append(data);
@@ -858,7 +893,8 @@
 	ba2str(sba, local_addr);
 	ba2str(&evt->bdaddr, peer_addr);
 
-	create_name(filename, sizeof(filename), STORAGEDIR, local_addr, "manufacturers");
+	create_name(filename, sizeof(filename), STORAGEDIR, local_addr,
+							"manufacturers");
 
 	str = textfile_get(filename, peer_addr);
 	if (!str) {
@@ -868,7 +904,8 @@
 		cp.handle = evt->handle;
 
 		data = hci_req_data_new(dev_id, &evt->bdaddr, OGF_LINK_CTL,
-					OCF_READ_REMOTE_VERSION, EVT_READ_REMOTE_VERSION_COMPLETE,
+					OCF_READ_REMOTE_VERSION,
+					EVT_READ_REMOTE_VERSION_COMPLETE,
 					&cp, READ_REMOTE_VERSION_CP_SIZE);
 
 		hci_req_queue_append(data);
@@ -927,7 +964,8 @@
 	error("IO channel not found in the io_data table");
 }
 
-static gboolean io_security_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+static gboolean io_security_event(GIOChannel *chan, GIOCondition cond,
+								gpointer data)
 {
 	unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr = buf;
 	struct hci_dev_info *di = data;
@@ -985,6 +1023,10 @@
 		remote_features_information(dev, &di->bdaddr, ptr);
 		break;
 
+	case EVT_REMOTE_HOST_FEATURES_NOTIFY:
+		remote_features_notify(dev, &di->bdaddr, ptr);
+		break;
+
 	case EVT_INQUIRY_COMPLETE:
 		evt = (evt_cmd_status *) ptr;
 		inquiry_complete(&di->bdaddr, evt->status, FALSE);
@@ -1137,7 +1179,7 @@
 
 	chan = g_io_channel_unix_new(dev);
 	g_io_channel_set_close_on_unref(chan, TRUE);
-	io_data[hdev].watch_id = g_io_add_watch_full(chan, G_PRIORITY_HIGH,
+	io_data[hdev].watch_id = g_io_add_watch_full(chan, G_PRIORITY_LOW,
 						G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
 						io_security_event, di, (GDestroyNotify) g_free);
 	io_data[hdev].channel = chan;
diff --git a/src/storage.c b/src/storage.c
index e2d7632..e09e257 100644
--- a/src/storage.c
+++ b/src/storage.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -73,7 +73,7 @@
 
 	free(tmp);
 
-	return err;
+	return err < 0 ? -EIO : 0;
 }
 
 int write_device_alias(const char *src, const char *dst, const char *alias)
@@ -203,7 +203,7 @@
 	return 0;
 }
 
-int write_local_name(bdaddr_t *bdaddr, char *name)
+int write_local_name(bdaddr_t *bdaddr, const char *name)
 {
 	char filename[PATH_MAX + 1], str[249];
 	int i;
@@ -483,21 +483,81 @@
 	return textfile_put(filename, addr, str);
 }
 
-int write_features_info(bdaddr_t *local, bdaddr_t *peer, unsigned char *features)
+int write_features_info(bdaddr_t *local, bdaddr_t *peer,
+				unsigned char *page1, unsigned char *page2)
 {
-	char filename[PATH_MAX + 1], addr[18], str[17];
+	char filename[PATH_MAX + 1], addr[18];
+	char str[] = "0000000000000000 0000000000000000";
+	char *old_value;
 	int i;
 
-	memset(str, 0, sizeof(str));
-	for (i = 0; i < 8; i++)
-		sprintf(str + (i * 2), "%2.2X", features[i]);
+	ba2str(peer, addr);
+
+	create_filename(filename, PATH_MAX, local, "features");
+	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+	old_value = textfile_get(filename, addr);
+
+	if (page1)
+		for (i = 0; i < 8; i++)
+			sprintf(str + (i * 2), "%2.2X", page1[i]);
+	else if (old_value && strlen(old_value) >= 16)
+		strncpy(str, old_value, 16);
+
+	if (page2)
+		for (i = 0; i < 8; i++)
+			sprintf(str + 17 + (i * 2), "%2.2X", page2[i]);
+	else if (old_value && strlen(old_value) >= 33)
+		strncpy(str + 17, old_value + 17, 16);
+
+	free(old_value);
+
+	return textfile_put(filename, addr, str);
+}
+
+static int decode_bytes(const char *str, unsigned char *bytes, size_t len)
+{
+	unsigned int i;
+
+	for (i = 0; i < len; i++) {
+		if (sscanf(str + (i * 2), "%02hhX", &bytes[i]) != 1)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+int read_remote_features(bdaddr_t *local, bdaddr_t *peer,
+				unsigned char *page1, unsigned char *page2)
+{
+	char filename[PATH_MAX + 1], addr[18], *str;
+	size_t len;
+	int err;
+
+	if (page1 == NULL && page2 == NULL)
+		return -EINVAL;
 
 	create_filename(filename, PATH_MAX, local, "features");
 
-	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
 	ba2str(peer, addr);
-	return textfile_put(filename, addr, str);
+
+	str = textfile_get(filename, addr);
+	if (!str)
+		return -ENOENT;
+
+	len = strlen(str);
+
+	err = -ENOENT;
+
+	if (page1 && len >= 16)
+		err = decode_bytes(str, page1, 8);
+
+	if (page2 && len >= 33)
+		err = decode_bytes(str + 17, page2, 8);
+
+	free(str);
+
+	return err;
 }
 
 int write_lastseen_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm)
@@ -570,6 +630,11 @@
 	if (!str)
 		return -ENOENT;
 
+	if (!key) {
+		free(str);
+		return 0;
+	}
+
 	memset(tmp, 0, sizeof(tmp));
 	for (i = 0; i < 16; i++) {
 		memcpy(tmp, str + (i * 2), 2);
@@ -698,8 +763,7 @@
 	/* If the old setting is the same as the requested one, we're done */
 	if (trusted == trust) {
 		g_slist_free(services);
-		if (str)
-			free(str);
+		free(str);
 		return 0;
 	}
 
@@ -719,8 +783,7 @@
 
 	g_slist_free(services);
 
-	if (str)
-		free(str);
+	free(str);
 
 	return ret;
 }
@@ -908,10 +971,9 @@
 	rec_list->recs = sdp_list_append(rec_list->recs, rec);
 }
 
-void delete_all_records(bdaddr_t *src, bdaddr_t *dst)
+void delete_all_records(const bdaddr_t *src, const bdaddr_t *dst)
 {
 	sdp_list_t *records, *seq;
-	sdp_record_t *rec;
 	char srcaddr[18], dstaddr[18];
 
 	ba2str(src, srcaddr);
@@ -920,7 +982,7 @@
 	records = read_records(src, dst);
 
 	for (seq = records; seq; seq = seq->next) {
-		rec = seq->data;
+		sdp_record_t *rec = seq->data;
 		delete_record(srcaddr, dstaddr, rec->handle);
 	}
 
@@ -928,7 +990,7 @@
 		sdp_list_free(records, (sdp_free_func_t) sdp_record_free);
 }
 
-sdp_list_t *read_records(bdaddr_t *src, bdaddr_t *dst)
+sdp_list_t *read_records(const bdaddr_t *src, const bdaddr_t *dst)
 {
 	char filename[PATH_MAX + 1];
 	struct record_list rec_list;
@@ -1141,3 +1203,37 @@
 
 	return 0;
 }
+
+gboolean read_blocked(const bdaddr_t *local, const bdaddr_t *remote)
+{
+	char filename[PATH_MAX + 1], *str, addr[18];
+
+	create_filename(filename, PATH_MAX, local, "blocked");
+
+	ba2str(remote, addr);
+
+	str = textfile_caseget(filename, addr);
+	if (!str)
+		return FALSE;
+
+	free(str);
+
+	return TRUE;
+}
+
+int write_blocked(const bdaddr_t *local, const bdaddr_t *remote,
+							gboolean blocked)
+{
+	char filename[PATH_MAX + 1], addr[18];
+
+	create_filename(filename, PATH_MAX, local, "blocked");
+
+	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+	ba2str(remote, addr);
+
+	if (blocked == FALSE)
+		return textfile_casedel(filename, addr);
+
+	return textfile_caseput(filename, addr, "");
+}
diff --git a/src/storage.h b/src/storage.h
index de0e837..eee71d3 100644
--- a/src/storage.h
+++ b/src/storage.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -30,7 +30,7 @@
 int write_device_mode(bdaddr_t *bdaddr, const char *mode);
 int read_device_mode(const char *src, char *mode, int length);
 int read_on_mode(const char *src, char *mode, int length);
-int write_local_name(bdaddr_t *bdaddr, char *name);
+int write_local_name(bdaddr_t *bdaddr, const char *name);
 int read_local_name(bdaddr_t *bdaddr, char *name);
 int write_local_class(bdaddr_t *bdaddr, uint8_t *class);
 int read_local_class(bdaddr_t *bdaddr, uint8_t *class);
@@ -47,7 +47,8 @@
 			uint16_t *mtu_result, uint16_t *mtu,
 			uint16_t *mask_result, uint32_t *mask);
 int write_version_info(bdaddr_t *local, bdaddr_t *peer, uint16_t manufacturer, uint8_t lmp_ver, uint16_t lmp_subver);
-int write_features_info(bdaddr_t *local, bdaddr_t *peer, unsigned char *features);
+int write_features_info(bdaddr_t *local, bdaddr_t *peer, unsigned char *page1, unsigned char *page2);
+int read_remote_features(bdaddr_t *local, bdaddr_t *peer, unsigned char *page1, unsigned char *page2);
 int write_lastseen_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm);
 int write_lastused_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm);
 int write_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t type, int length);
@@ -63,8 +64,8 @@
 sdp_record_t *record_from_string(const gchar *str);
 sdp_record_t *fetch_record(const gchar *src, const gchar *dst, const uint32_t handle);
 int delete_record(const gchar *src, const gchar *dst, const uint32_t handle);
-void delete_all_records(bdaddr_t *src, bdaddr_t *dst);
-sdp_list_t *read_records(bdaddr_t *src, bdaddr_t *dst);
+void delete_all_records(const bdaddr_t *src, const bdaddr_t *dst);
+sdp_list_t *read_records(const bdaddr_t *src, const bdaddr_t *dst);
 sdp_record_t *find_record_in_list(sdp_list_t *recs, const char *uuid);
 int store_device_id(const gchar *src, const gchar *dst,
 				const uint16_t source, const uint16_t vendor,
@@ -74,6 +75,9 @@
 					uint16_t *product, uint16_t *version);
 int write_device_pairable(bdaddr_t *local, gboolean mode);
 int read_device_pairable(bdaddr_t *local, gboolean *mode);
+gboolean read_blocked(const bdaddr_t *local, const bdaddr_t *remote);
+int write_blocked(const bdaddr_t *local, const bdaddr_t *remote,
+							gboolean blocked);
 
 #define PNP_UUID		"00001200-0000-1000-8000-00805f9b34fb"
 
diff --git a/common/textfile.c b/src/textfile.c
similarity index 98%
rename from common/textfile.c
rename to src/textfile.c
index a755ab7..b1722c8 100644
--- a/common/textfile.c
+++ b/src/textfile.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/common/textfile.h b/src/textfile.h
similarity index 95%
rename from common/textfile.h
rename to src/textfile.h
index a49e249..8353bc7 100644
--- a/common/textfile.h
+++ b/src/textfile.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/common/uinput.h b/src/uinput.h
similarity index 99%
rename from common/uinput.h
rename to src/uinput.h
index 230dfb7..e83986b 100644
--- a/common/uinput.h
+++ b/src/uinput.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/test/Android.mk b/test/Android.mk
index 68006aa..946dc12 100755
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -9,17 +9,17 @@
 include $(CLEAR_VARS)
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\"
+	-DVERSION=\"4.69\"
 
 LOCAL_SRC_FILES:= \
 	hstest.c
 
 LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth
+	libbluetoothd libbluetooth
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := eng
@@ -34,17 +34,17 @@
 include $(CLEAR_VARS)
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\"
+	-DVERSION=\"4.69\"
 
 LOCAL_SRC_FILES:= \
 	l2test.c
 
 LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth
+	libbluetoothd libbluetooth
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := eng
@@ -59,17 +59,17 @@
 include $(CLEAR_VARS)
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\"
+	-DVERSION=\"4.69\"
 
 LOCAL_SRC_FILES:= \
 	rctest.c
 
 LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth
+	libbluetoothd libbluetooth
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := eng
@@ -85,17 +85,17 @@
 include $(CLEAR_VARS)
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\"
+	-DVERSION=\"4.69\"
 
 LOCAL_SRC_FILES:= \
 	scotest.c
 
 LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth
+	libbluetoothd libbluetooth
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := eng
@@ -110,14 +110,14 @@
 include $(CLEAR_VARS)
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\"
+	-DVERSION=\"4.69\"
 
 LOCAL_SRC_FILES:= \
 	agent.c
 
 LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common \
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src \
 	$(call include-path-for, dbus)
 
 LOCAL_SHARED_LIBRARIES := \
@@ -136,17 +136,17 @@
 include $(CLEAR_VARS)
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\"
+	-DVERSION=\"4.69\"
 
 LOCAL_SRC_FILES:= \
 	attest.c
 
 LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth
+	libbluetoothd libbluetooth
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := eng
@@ -161,17 +161,17 @@
 include $(CLEAR_VARS)
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\"
+	-DVERSION=\"4.69\"
 
 LOCAL_SRC_FILES:= \
 	avtest.c
 
 LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth
+	libbluetoothd libbluetooth
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := eng
@@ -186,20 +186,17 @@
 include $(CLEAR_VARS)
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\"
+	-DVERSION=\"4.69\"
 
 LOCAL_SRC_FILES:= \
 	bdaddr.c
 
 LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth
-
-LOCAL_STATIC_LIBRARIES := \
-	libbluez-common-static
+	libbluetoothd libbluetooth
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := eng
@@ -215,23 +212,22 @@
 include $(CLEAR_VARS)
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\"
+	-DVERSION=\"4.69\"
 
 LOCAL_SRC_FILES:= \
 	btiotest.c
 
 LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common \
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src \
 	$(call include-path-for, glib) \
 	$(call include-path-for, glib)\glib
 
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth \
+	libbluetoothd libbluetooth
 
 LOCAL_STATIC_LIBRARIES := \
-	libbluez-common-static \
 	libglib_static \
 
 
@@ -251,18 +247,19 @@
 include $(CLEAR_VARS)
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\"
+	-DVERSION=\"4.69\"
 
 LOCAL_SRC_FILES:= \
 	hciemu.c
 
 LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common \
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src \
 	$(call include-path-for, glib) \
 	$(call include-path-for, glib)\glib
 
 LOCAL_SHARED_LIBRARIES := \
+	libbluetoothd \
 	libbluetooth \
 	libc \
 	libcutils
@@ -284,17 +281,17 @@
 include $(CLEAR_VARS)
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\"
+	-DVERSION=\"4.69\"
 
 LOCAL_SRC_FILES:= \
 	lmptest.c
 
 LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth
+	libbluetoothd libbluetooth
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := eng
@@ -309,17 +306,17 @@
 include $(CLEAR_VARS)
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\"
+	-DVERSION=\"4.69\"
 
 LOCAL_SRC_FILES:= \
 	sdptest.c
 
 LOCAL_C_INCLUDES:= \
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth
+	libbluetoothd libbluetooth
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := eng
diff --git a/test/Makefile.am b/test/Makefile.am
deleted file mode 100644
index 2e58d24..0000000
--- a/test/Makefile.am
+++ /dev/null
@@ -1,55 +0,0 @@
-
-if TEST
-sbin_PROGRAMS = hciemu
-
-bin_PROGRAMS = l2test rctest
-
-noinst_PROGRAMS = sdptest scotest attest hstest avtest lmptest \
-						bdaddr agent btiotest
-
-hciemu_LDADD = $(top_builddir)/common/libhelper.a \
-			@GLIB_LIBS@ @BLUEZ_LIBS@
-
-l2test_LDADD = @BLUEZ_LIBS@
-
-rctest_LDADD = @BLUEZ_LIBS@
-
-sdptest_LDADD = @BLUEZ_LIBS@
-
-scotest_LDADD = @BLUEZ_LIBS@
-
-attest_LDADD = @BLUEZ_LIBS@
-
-hstest_LDADD = @BLUEZ_LIBS@
-
-avtest_LDADD = @BLUEZ_LIBS@
-
-bdaddr_SOURCES = bdaddr.c
-
-bdaddr_LDADD = @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a
-
-lmptest_LDADD = @BLUEZ_LIBS@
-
-agent_LDADD = @DBUS_LIBS@
-
-btiotest_LDADD = $(top_builddir)/common/libhelper.a @GLIB_LIBS@ @BLUEZ_LIBS@
-
-noinst_MANS = bdaddr.8
-
-if MANPAGES
-man_MANS = rctest.1 hciemu.1
-endif
-
-AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@
-endif
-
-INCLUDES = -I$(top_srcdir)/common
-
-EXTRA_DIST = apitest hsplay hsmicro bdaddr.8 rctest.1 hciemu.1 dbusdef.py \
-		monitor-bluetooth list-devices test-discovery test-manager \
-		test-adapter test-device test-service test-serial \
-		test-telephony test-network simple-agent simple-service \
-		service-record.dtd service-did.xml service-spp.xml \
-		service-opp.xml service-ftp.xml
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/test/agent.c b/test/agent.c
index 4c12ea3..a40039e 100644
--- a/test/agent.c
+++ b/test/agent.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -35,8 +35,8 @@
 
 #include <dbus/dbus.h>
 
-static char *passkey = NULL;
-
+static char *passkey_value = NULL;
+static int passkey_delay = 0;
 static int do_reject = 0;
 
 static volatile sig_atomic_t __io_canceled = 0;
@@ -61,8 +61,7 @@
 					DBUS_TYPE_STRING, &old,
 					DBUS_TYPE_STRING, &new,
 					DBUS_TYPE_INVALID)) {
-		fprintf(stderr,
-			"Invalid arguments for NameOwnerChanged signal");
+		fprintf(stderr, "Invalid arguments for NameOwnerChanged signal");
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 	}
 
@@ -80,19 +79,17 @@
 	DBusMessage *reply;
 	const char *path;
 
-	if (!passkey)
+	if (!passkey_value)
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
-	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_OBJECT_PATH, &path,
-					DBUS_TYPE_INVALID)) {
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID)) {
 		fprintf(stderr, "Invalid arguments for RequestPinCode method");
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 	}
 
 	if (do_reject) {
-		reply = dbus_message_new_error(msg,
-					"org.bluez.Error.Rejected", "");
+		reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
 		goto send;
 	}
 
@@ -104,8 +101,13 @@
 
 	printf("Pincode request for device %s\n", path);
 
-	dbus_message_append_args(reply, DBUS_TYPE_STRING, &passkey,
-					DBUS_TYPE_INVALID);
+	if (passkey_delay) {
+		printf("Waiting for %d seconds\n", passkey_delay);
+		sleep(passkey_delay);
+	}
+
+	dbus_message_append_args(reply, DBUS_TYPE_STRING, &passkey_value,
+							DBUS_TYPE_INVALID);
 
 send:
 	dbus_connection_send(conn, reply, NULL);
@@ -122,22 +124,19 @@
 {
 	DBusMessage *reply;
 	const char *path;
-	unsigned int int_passkey;
+	unsigned int passkey;
 
-	if (!passkey)
+	if (!passkey_value)
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
-
-	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_OBJECT_PATH, &path,
-					DBUS_TYPE_INVALID)) {
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+							DBUS_TYPE_INVALID)) {
 		fprintf(stderr, "Invalid arguments for RequestPasskey method");
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 	}
 
 	if (do_reject) {
-		reply = dbus_message_new_error(msg,
-					"org.bluez.Error.Rejected", "");
+		reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
 		goto send;
 	}
 
@@ -149,10 +148,93 @@
 
 	printf("Passkey request for device %s\n", path);
 
-	int_passkey = strtoul(passkey, NULL, 10);
+	if (passkey_delay) {
+		printf("Waiting for %d seconds\n", passkey_delay);
+		sleep(passkey_delay);
+	}
 
-	dbus_message_append_args(reply, DBUS_TYPE_UINT32, &int_passkey,
-					DBUS_TYPE_INVALID);
+	passkey = strtoul(passkey_value, NULL, 10);
+
+	dbus_message_append_args(reply, DBUS_TYPE_UINT32, &passkey,
+							DBUS_TYPE_INVALID);
+
+send:
+	dbus_connection_send(conn, reply, NULL);
+
+	dbus_connection_flush(conn);
+
+	dbus_message_unref(reply);
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult request_confirmation_message(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	DBusMessage *reply;
+	const char *path;
+	unsigned int passkey;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+						DBUS_TYPE_UINT32, &passkey,
+							DBUS_TYPE_INVALID)) {
+		fprintf(stderr, "Invalid arguments for RequestPasskey method");
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+	}
+
+	if (do_reject) {
+		reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
+		goto send;
+	}
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply) {
+		fprintf(stderr, "Can't create reply message\n");
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+	}
+
+	printf("Confirmation request of %u for device %s\n", passkey, path);
+
+	if (passkey_delay) {
+		printf("Waiting for %d seconds\n", passkey_delay);
+		sleep(passkey_delay);
+	}
+
+send:
+	dbus_connection_send(conn, reply, NULL);
+
+	dbus_connection_flush(conn);
+
+	dbus_message_unref(reply);
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult authorize_message(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	DBusMessage *reply;
+	const char *path, *uuid;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+						DBUS_TYPE_STRING, &uuid,
+							DBUS_TYPE_INVALID)) {
+		fprintf(stderr, "Invalid arguments for Authorize method");
+		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+	}
+
+	if (do_reject) {
+		reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
+		goto send;
+	}
+
+	reply = dbus_message_new_method_return(msg);
+	if (!reply) {
+		fprintf(stderr, "Can't create reply message\n");
+		return DBUS_HANDLER_RESULT_NEED_MEMORY;
+	}
+
+	printf("Authorizing request for %s\n", path);
 
 send:
 	dbus_connection_send(conn, reply, NULL);
@@ -221,43 +303,6 @@
 	return DBUS_HANDLER_RESULT_HANDLED;
 }
 
-static DBusHandlerResult authorize_message(DBusConnection *conn,
-						DBusMessage *msg, void *data)
-{
-	DBusMessage *reply;
-	const char *path, *uuid;
-
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-					DBUS_TYPE_STRING, &uuid,
-					DBUS_TYPE_INVALID)) {
-		fprintf(stderr, "Invalid arguments for Authorize method");
-		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-	}
-
-	if (do_reject) {
-		reply = dbus_message_new_error(msg,
-					"org.bluez.Error.Rejected", "");
-		goto send;
-	}
-
-	reply = dbus_message_new_method_return(msg);
-	if (!reply) {
-		fprintf(stderr, "Can't create reply message\n");
-		return DBUS_HANDLER_RESULT_NEED_MEMORY;
-	}
-
-	printf("Authorizing request for %s\n", path);
-
-send:
-	dbus_connection_send(conn, reply, NULL);
-
-	dbus_connection_flush(conn);
-
-	dbus_message_unref(reply);
-
-	return DBUS_HANDLER_RESULT_HANDLED;
-}
-
 static DBusHandlerResult agent_message(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
@@ -269,15 +314,19 @@
 							"RequestPasskey"))
 		return request_passkey_message(conn, msg, data);
 
+	if (dbus_message_is_method_call(msg, "org.bluez.Agent",
+							"RequestConfirmation"))
+		return request_confirmation_message(conn, msg, data);
+
+	if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Authorize"))
+		return authorize_message(conn, msg, data);
+
 	if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Cancel"))
 		return cancel_message(conn, msg, data);
 
 	if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Release"))
 		return release_message(conn, msg, data);
 
-	if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Authorize"))
-		return authorize_message(conn, msg, data);
-
 	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
@@ -292,12 +341,6 @@
 	DBusMessage *msg, *reply;
 	DBusError err;
 
-	if (!dbus_connection_register_object_path(conn, agent_path,
-							&agent_table, NULL)) {
-		fprintf(stderr, "Can't register object path for agent\n");
-		return -1;
-	}
-
 	msg = dbus_message_new_method_call("org.bluez", adapter_path,
 					"org.bluez.Adapter", "RegisterAgent");
 	if (!msg) {
@@ -529,6 +572,7 @@
 	{ "adapter",	1, 0, 'a' },
 	{ "path",	1, 0, 'p' },
 	{ "capabilites",1, 0, 'c' },
+	{ "delay",	1, 0, 'd' },
 	{ "reject",	0, 0, 'r' },
 	{ "help",	0, 0, 'h' },
 	{ 0, 0, 0, 0 }
@@ -546,7 +590,7 @@
 	snprintf(default_path, sizeof(default_path),
 					"/org/bluez/agent_%d", getpid());
 
-	while ((opt = getopt_long(argc, argv, "+a:p:c:rh", main_options, NULL)) != EOF) {
+	while ((opt = getopt_long(argc, argv, "+a:p:c:d:rh", main_options, NULL)) != EOF) {
 		switch(opt) {
 		case 'a':
 			adapter_id = optarg;
@@ -561,6 +605,9 @@
 		case 'c':
 			capabilities = optarg;
 			break;
+		case 'd':
+			passkey_delay = atoi(optarg);
+			break;
 		case 'r':
 			do_reject = 1;
 			break;
@@ -581,7 +628,7 @@
 		exit(1);
 	}
 
-	passkey = strdup(argv[0]);
+	passkey_value = strdup(argv[0]);
 
 	if (argc > 1)
 		device = strdup(argv[1]);
@@ -599,6 +646,12 @@
 	if (!adapter_path)
 		exit(1);
 
+	if (!dbus_connection_register_object_path(conn, agent_path,
+							&agent_table, NULL)) {
+		fprintf(stderr, "Can't register object path for agent\n");
+		exit(1);
+	}
+
 	if (device) {
 		if (create_paired_device(conn, adapter_path, agent_path,
 						capabilities, device) < 0) {
@@ -639,7 +692,7 @@
 	free(adapter_path);
 	free(agent_path);
 
-	free(passkey);
+	free(passkey_value);
 
 	dbus_connection_unref(conn);
 
diff --git a/test/attest.c b/test/attest.c
index 8813f41..12ba682 100644
--- a/test/attest.c
+++ b/test/attest.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2001-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2001-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/test/avtest.c b/test/avtest.c
index 6ec6035..168326f 100644
--- a/test/avtest.c
+++ b/test/avtest.c
@@ -2,7 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2007-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2009-2010  Nokia Corporation
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -25,7 +26,844 @@
 #include <config.h>
 #endif
 
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sdp.h>
+
+#define AVDTP_PKT_TYPE_SINGLE		0x00
+#define AVDTP_PKT_TYPE_START		0x01
+#define AVDTP_PKT_TYPE_CONTINUE		0x02
+#define AVDTP_PKT_TYPE_END		0x03
+
+#define AVDTP_MSG_TYPE_COMMAND		0x00
+#define AVDTP_MSG_TYPE_GEN_REJECT	0x01
+#define AVDTP_MSG_TYPE_ACCEPT		0x02
+#define AVDTP_MSG_TYPE_REJECT		0x03
+
+#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_SEP_TYPE_SOURCE		0x00
+#define AVDTP_SEP_TYPE_SINK		0x01
+
+#define AVDTP_MEDIA_TYPE_AUDIO		0x00
+#define AVDTP_MEDIA_TYPE_VIDEO		0x01
+#define AVDTP_MEDIA_TYPE_MULTIMEDIA	0x02
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avdtp_header {
+	uint8_t message_type:2;
+	uint8_t packet_type:2;
+	uint8_t transaction:4;
+	uint8_t signal_id:6;
+	uint8_t rfa0:2;
+} __attribute__ ((packed));
+
+struct seid_info {
+	uint8_t rfa0:1;
+	uint8_t inuse:1;
+	uint8_t seid:6;
+	uint8_t rfa2:3;
+	uint8_t type:1;
+	uint8_t media_type:4;
+} __attribute__ ((packed));
+
+struct avdtp_start_header {
+	uint8_t message_type:2;
+	uint8_t packet_type:2;
+	uint8_t transaction:4;
+	uint8_t no_of_packets;
+	uint8_t signal_id:6;
+	uint8_t rfa0:2;
+} __attribute__ ((packed));
+
+struct avdtp_continue_header {
+	uint8_t message_type:2;
+	uint8_t packet_type:2;
+	uint8_t transaction:4;
+} __attribute__ ((packed));
+
+struct avctp_header {
+	uint8_t ipid:1;
+	uint8_t cr:1;
+	uint8_t packet_type:2;
+	uint8_t transaction:4;
+	uint16_t pid;
+} __attribute__ ((packed));
+#define AVCTP_HEADER_LENGTH 3
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avdtp_header {
+	uint8_t transaction:4;
+	uint8_t packet_type:2;
+	uint8_t message_type:2;
+	uint8_t rfa0:2;
+	uint8_t signal_id:6;
+} __attribute__ ((packed));
+
+struct seid_info {
+	uint8_t seid:6;
+	uint8_t inuse:1;
+	uint8_t rfa0:1;
+	uint8_t media_type:4;
+	uint8_t type:1;
+	uint8_t rfa2:3;
+} __attribute__ ((packed));
+
+struct avdtp_start_header {
+	uint8_t transaction:4;
+	uint8_t packet_type:2;
+	uint8_t message_type:2;
+	uint8_t no_of_packets;
+	uint8_t rfa0:2;
+	uint8_t signal_id:6;
+} __attribute__ ((packed));
+
+struct avdtp_continue_header {
+	uint8_t transaction:4;
+	uint8_t packet_type:2;
+	uint8_t message_type:2;
+} __attribute__ ((packed));
+
+struct avctp_header {
+	uint8_t transaction:4;
+	uint8_t packet_type:2;
+	uint8_t cr:1;
+	uint8_t ipid:1;
+	uint16_t pid;
+} __attribute__ ((packed));
+#define AVCTP_HEADER_LENGTH 3
+
+#else
+#error "Unknown byte order"
+#endif
+
+#define AVCTP_COMMAND		0
+#define AVCTP_RESPONSE		1
+
+#define AVCTP_PACKET_SINGLE	0
+
+static const unsigned char media_transport[] = {
+		0x01,	/* Media transport category */
+		0x00,
+		0x07,	/* Media codec category */
+		0x06,
+		0x00,	/* Media type audio */
+		0x00,	/* Codec SBC */
+		0x22,	/* 44.1 kHz, stereo */
+		0x15,	/* 16 blocks, 8 subbands */
+		0x02,
+		0x33,
+};
+
+static int media_sock = -1;
+
+static void dump_avctp_header(struct avctp_header *hdr)
+{
+	printf("TL %d PT %d CR %d IPID %d PID 0x%04x\n", hdr->transaction,
+			hdr->packet_type, hdr->cr, hdr->ipid, ntohs(hdr->pid));
+}
+
+static void dump_avdtp_header(struct avdtp_header *hdr)
+{
+	printf("TL %d PT %d MT %d SI %d\n", hdr->transaction,
+			hdr->packet_type, hdr->message_type, hdr->signal_id);
+}
+
+static void dump_buffer(const unsigned char *buf, int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		printf("%02x ", buf[i]);
+	printf("\n");
+}
+
+static void process_avdtp(int srv_sk, int sk, unsigned char reject,
+								int fragment)
+{
+	unsigned char buf[672];
+	ssize_t len;
+
+	while (1) {
+		struct avdtp_header *hdr = (void *) buf;
+
+		len = read(sk, buf, sizeof(buf));
+		if (len <= 0) {
+			perror("Read failed");
+			break;
+		}
+
+		dump_buffer(buf, len);
+		dump_avdtp_header(hdr);
+
+		if (hdr->packet_type != AVDTP_PKT_TYPE_SINGLE) {
+			fprintf(stderr, "Only single packets are supported\n");
+			break;
+		}
+
+		if (hdr->message_type != AVDTP_MSG_TYPE_COMMAND) {
+			fprintf(stderr, "Ignoring non-command messages\n");
+			continue;
+		}
+
+		switch (hdr->signal_id) {
+		case AVDTP_DISCOVER:
+			if (reject == AVDTP_DISCOVER) {
+				hdr->message_type = AVDTP_MSG_TYPE_REJECT;
+				buf[2] = 0x29; /* Unsupported configuration */
+				printf("Rejecting discover command\n");
+				len = write(sk, buf, 3);
+			} else {
+				struct seid_info *sei = (void *) (buf + 2);
+				hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+				buf[2] = 0x00;
+				buf[3] = 0x00;
+				sei->seid = 0x01;
+				sei->type = AVDTP_SEP_TYPE_SINK;
+				sei->media_type = AVDTP_MEDIA_TYPE_AUDIO;
+				printf("Accepting discover command\n");
+				len = write(sk, buf, 4);
+			}
+			break;
+
+		case AVDTP_GET_CAPABILITIES:
+			if (reject == AVDTP_GET_CAPABILITIES) {
+				hdr->message_type = AVDTP_MSG_TYPE_REJECT;
+				buf[2] = 0x29; /* Unsupported configuration */
+				printf("Rejecting get capabilties command\n");
+				len = write(sk, buf, 3);
+			} else if (fragment) {
+				struct avdtp_start_header *start = (void *) buf;
+
+				printf("Sending fragmented reply to getcap\n");
+
+				hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+
+				/* Start packet */
+				hdr->packet_type = AVDTP_PKT_TYPE_START;
+				start->signal_id = AVDTP_GET_CAPABILITIES;
+				start->no_of_packets = 3;
+				memcpy(&buf[3], media_transport,
+						sizeof(media_transport));
+				len = write(sk, buf,
+						3 + sizeof(media_transport));
+
+				/* Continue packet */
+				hdr->packet_type = AVDTP_PKT_TYPE_CONTINUE;
+				memcpy(&buf[1], media_transport,
+						sizeof(media_transport));
+				len = write(sk, buf,
+						1 + sizeof(media_transport));
+
+				/* End packet */
+				hdr->packet_type = AVDTP_PKT_TYPE_END;
+				memcpy(&buf[1], media_transport,
+						sizeof(media_transport));
+				len = write(sk, buf,
+						1 + sizeof(media_transport));
+			} else {
+				hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+				memcpy(&buf[2], media_transport,
+						sizeof(media_transport));
+				printf("Accepting get capabilities command\n");
+				len = write(sk, buf,
+						2 + sizeof(media_transport));
+			}
+			break;
+
+		case AVDTP_SET_CONFIGURATION:
+			if (reject == AVDTP_SET_CONFIGURATION) {
+				hdr->message_type = AVDTP_MSG_TYPE_REJECT;
+				buf[2] = buf[4];
+				buf[3] = 0x13; /* SEP In Use */
+				printf("Rejecting set configuration command\n");
+				len = write(sk, buf, 4);
+			} else {
+				hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+				printf("Accepting set configuration command\n");
+				len = write(sk, buf, 2);
+			}
+			break;
+
+		case AVDTP_GET_CONFIGURATION:
+			if (reject == AVDTP_GET_CONFIGURATION) {
+				hdr->message_type = AVDTP_MSG_TYPE_REJECT;
+				buf[2] = 0x12; /* Bad ACP SEID */
+				printf("Rejecting get configuration command\n");
+				len = write(sk, buf, 3);
+			} else {
+				hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+				printf("Accepting get configuration command\n");
+				len = write(sk, buf, 2);
+			}
+			break;
+
+		case AVDTP_OPEN:
+			if (reject == AVDTP_OPEN) {
+				hdr->message_type = AVDTP_MSG_TYPE_REJECT;
+				buf[2] = 0x31; /* Bad State */
+				printf("Rejecting open command\n");
+				len = write(sk, buf, 3);
+			} else {
+				struct sockaddr_l2 addr;
+				socklen_t optlen;
+
+				hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+				printf("Accepting open command\n");
+				len = write(sk, buf, 2);
+
+				memset(&addr, 0, sizeof(addr));
+				optlen = sizeof(addr);
+
+				media_sock = accept(srv_sk,
+						(struct sockaddr *) &addr,
+								&optlen);
+				if (media_sock < 0) {
+					perror("Accept failed");
+					break;
+				}
+			}
+			break;
+
+		case AVDTP_START:
+			if (reject == AVDTP_ABORT)
+				printf("Ignoring start to cause abort");
+			else if (reject == AVDTP_START) {
+				hdr->message_type = AVDTP_MSG_TYPE_REJECT;
+				buf[3] = 0x31; /* Bad State */
+				printf("Rejecting start command\n");
+				len = write(sk, buf, 4);
+			} else {
+				hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+				printf("Accepting start command\n");
+				len = write(sk, buf, 2);
+			}
+			break;
+
+		case AVDTP_CLOSE:
+			if (reject == AVDTP_CLOSE) {
+				hdr->message_type = AVDTP_MSG_TYPE_REJECT;
+				buf[2] = 0x31; /* Bad State */
+				printf("Rejecting close command\n");
+				len = write(sk, buf, 3);
+			} else {
+				hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+				printf("Accepting close command\n");
+				len = write(sk, buf, 2);
+				if (media_sock >= 0) {
+					close(media_sock);
+					media_sock = -1;
+				}
+			}
+			break;
+
+		case AVDTP_SUSPEND:
+			if (reject == AVDTP_SUSPEND) {
+				hdr->message_type = AVDTP_MSG_TYPE_REJECT;
+				buf[3] = 0x31; /* Bad State */
+				printf("Rejecting suspend command\n");
+				len = write(sk, buf, 4);
+			} else {
+				hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+				printf("Accepting suspend command\n");
+				len = write(sk, buf, 2);
+			}
+			break;
+
+		case AVDTP_ABORT:
+			hdr->message_type = AVDTP_MSG_TYPE_ACCEPT;
+			printf("Accepting abort command\n");
+			len = write(sk, buf, 2);
+			if (media_sock >= 0) {
+				close(media_sock);
+				media_sock = -1;
+			}
+			break;
+
+		default:
+			buf[1] = 0x00;
+			printf("Unknown command\n");
+			len = write(sk, buf, 2);
+			break;
+		}
+	}
+}
+
+static void process_avctp(int sk, int reject)
+{
+	unsigned char buf[672];
+	ssize_t len;
+
+	while (1) {
+		struct avctp_header *hdr = (void *) buf;
+
+		len = read(sk, buf, sizeof(buf));
+		if (len <= 0) {
+			perror("Read failed");
+			break;
+		}
+
+		dump_buffer(buf, len);
+
+		if (len >= AVCTP_HEADER_LENGTH)
+			dump_avctp_header(hdr);
+	}
+}
+
+static int set_minimum_mtu(int sk)
+{
+	struct l2cap_options l2o;
+	socklen_t optlen;
+
+	memset(&l2o, 0, sizeof(l2o));
+	optlen = sizeof(l2o);
+
+	if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &optlen) < 0) {
+		perror("getsockopt");
+		return -1;
+	}
+
+	l2o.imtu = 48;
+	l2o.omtu = 48;
+
+	if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, sizeof(l2o)) < 0) {
+		perror("setsockopt");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void do_listen(const bdaddr_t *src, unsigned char reject, int fragment)
+{
+	struct sockaddr_l2 addr;
+	socklen_t optlen;
+	int sk, nsk;
+
+	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+	if (sk < 0) {
+		perror("Can't create socket");
+		return;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.l2_family = AF_BLUETOOTH;
+	bacpy(&addr.l2_bdaddr, src);
+	addr.l2_psm = htobs(25);
+
+	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("Can't bind socket");
+		goto error;
+	}
+
+	if (fragment)
+		set_minimum_mtu(sk);
+
+	if (listen(sk, 10)) {
+		perror("Can't listen on the socket");
+		goto error;
+	}
+
+	while (1) {
+		memset(&addr, 0, sizeof(addr));
+		optlen = sizeof(addr);
+
+		nsk = accept(sk, (struct sockaddr *) &addr, &optlen);
+		if (nsk < 0) {
+			perror("Accept failed");
+			continue;
+		}
+
+		process_avdtp(sk, nsk, reject, fragment);
+
+		if (media_sock >= 0) {
+			close(media_sock);
+			media_sock = -1;
+		}
+
+		close(nsk);
+	}
+
+error:
+	close(sk);
+}
+
+static int do_connect(const bdaddr_t *src, const bdaddr_t *dst, int avctp,
+								int fragment)
+{
+	struct sockaddr_l2 addr;
+	int sk, err;
+
+	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+	if (sk < 0) {
+		perror("Can't create socket");
+		return -1;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.l2_family = AF_BLUETOOTH;
+	bacpy(&addr.l2_bdaddr, src);
+
+	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("Can't bind socket");
+		goto error;
+	}
+
+	if (fragment)
+		set_minimum_mtu(sk);
+
+	memset(&addr, 0, sizeof(addr));
+	addr.l2_family = AF_BLUETOOTH;
+	bacpy(&addr.l2_bdaddr, dst);
+	addr.l2_psm = htobs(avctp ? 23 : 25);
+
+	err = connect(sk, (struct sockaddr *) &addr, sizeof(addr));
+	if (err < 0) {
+		perror("Unable to connect");
+		goto error;
+	}
+
+	return sk;
+
+error:
+	close(sk);
+	return -1;
+}
+
+static void do_avdtp_send(int sk, const bdaddr_t *src, const bdaddr_t *dst,
+				unsigned char cmd, int invalid, int preconf)
+{
+	unsigned char buf[672];
+	struct avdtp_header *hdr = (void *) buf;
+	ssize_t len;
+
+	memset(buf, 0, sizeof(buf));
+
+	switch (cmd) {
+	case AVDTP_DISCOVER:
+		if (invalid)
+			hdr->message_type = 0x01;
+		else
+			hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+		hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+		hdr->signal_id = AVDTP_DISCOVER;
+		len = write(sk, buf, 2);
+		break;
+
+	case AVDTP_GET_CAPABILITIES:
+		hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+		hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+		hdr->signal_id = AVDTP_GET_CAPABILITIES;
+		buf[2] = 1 << 2; /* SEID 1 */
+		len = write(sk, buf, invalid ? 2 : 3);
+		break;
+
+	case AVDTP_SET_CONFIGURATION:
+		if (preconf)
+			do_avdtp_send(sk, src, dst, cmd, 0, 0);
+		hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+		hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+		hdr->signal_id = AVDTP_SET_CONFIGURATION;
+		buf[2] = 1 << 2; /* ACP SEID */
+		buf[3] = 1 << 2; /* INT SEID */
+		memcpy(&buf[4], media_transport, sizeof(media_transport));
+		if (invalid)
+			buf[5] = 0x01; /* LOSC != 0 */
+		len = write(sk, buf, 4 + sizeof(media_transport));
+		break;
+
+	case AVDTP_GET_CONFIGURATION:
+		if (preconf)
+			do_avdtp_send(sk, src, dst, AVDTP_SET_CONFIGURATION, 0, 0);
+		hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+		hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+		hdr->signal_id = AVDTP_GET_CONFIGURATION;
+		if (invalid)
+			buf[2] = 13 << 2; /* Invalid ACP SEID */
+		else
+			buf[2] = 1 << 2; /* Valid ACP SEID */
+		len = write(sk, buf, 3);
+		break;
+
+	case AVDTP_OPEN:
+		if (preconf)
+			do_avdtp_send(sk, src, dst, AVDTP_SET_CONFIGURATION, 0, 0);
+		hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+		hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+		hdr->signal_id = AVDTP_OPEN;
+		buf[2] = 1 << 2; /* ACP SEID */
+		len = write(sk, buf, 3);
+		break;
+
+	case AVDTP_START:
+		if (preconf)
+			do_avdtp_send(sk, src, dst, AVDTP_SET_CONFIGURATION, 0, 0);
+		if (!invalid)
+			do_avdtp_send(sk, src, dst, AVDTP_OPEN, 0, 0);
+		hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+		hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+		hdr->signal_id = AVDTP_START;
+		buf[2] = 1 << 2; /* ACP SEID */
+		len = write(sk, buf, 3);
+		break;
+
+	case AVDTP_CLOSE:
+		if (preconf) {
+			do_avdtp_send(sk, src, dst, AVDTP_SET_CONFIGURATION, 0, 0);
+			do_avdtp_send(sk, src, dst, AVDTP_OPEN, 0, 0);
+		}
+		hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+		hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+		hdr->signal_id = AVDTP_CLOSE;
+		if (invalid)
+			buf[2] = 13 << 2; /* Invalid ACP SEID */
+		else
+			buf[2] = 1 << 2; /* Valid ACP SEID */
+		len = write(sk, buf, 3);
+		break;
+
+	case AVDTP_SUSPEND:
+		if (invalid)
+			do_avdtp_send(sk, src, dst, AVDTP_OPEN, 0, preconf);
+		else
+			do_avdtp_send(sk, src, dst, AVDTP_START, 0, preconf);
+		hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+		hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+		hdr->signal_id = AVDTP_SUSPEND;
+		buf[2] = 1 << 2; /* ACP SEID */
+		len = write(sk, buf, 3);
+		break;
+
+	case AVDTP_ABORT:
+		do_avdtp_send(sk, src, dst, AVDTP_OPEN, 0, 1);
+		hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+		hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+		hdr->signal_id = AVDTP_ABORT;
+		buf[2] = 1 << 2; /* ACP SEID */
+		len = write(sk, buf, 3);
+		break;
+
+	default:
+		hdr->message_type = AVDTP_MSG_TYPE_COMMAND;
+		hdr->packet_type = AVDTP_PKT_TYPE_SINGLE;
+		hdr->signal_id = cmd;
+		len = write(sk, buf, 2);
+		break;
+	}
+
+	do {
+		len = read(sk, buf, sizeof(buf));
+
+		dump_buffer(buf, len);
+		dump_avdtp_header(hdr);
+	} while (len < 2 || (hdr->message_type != AVDTP_MSG_TYPE_ACCEPT &&
+				hdr->message_type != AVDTP_MSG_TYPE_REJECT &&
+				hdr->message_type != AVDTP_MSG_TYPE_GEN_REJECT));
+
+	if (cmd == AVDTP_OPEN && len >= 2 &&
+				hdr->message_type == AVDTP_MSG_TYPE_ACCEPT)
+		media_sock = do_connect(src, dst, 0, 0);
+}
+
+static void do_avctp_send(int sk, int invalid)
+{
+	unsigned char buf[672];
+	struct avctp_header *hdr = (void *) buf;
+	unsigned char play_pressed[] = { 0x00, 0x48, 0x7c, 0x44, 0x00 };
+	ssize_t len;
+
+	memset(buf, 0, sizeof(buf));
+
+	hdr->packet_type = AVCTP_PACKET_SINGLE;
+	hdr->cr = AVCTP_COMMAND;
+	if (invalid)
+		hdr->pid = 0xffff;
+	else
+		hdr->pid = htons(AV_REMOTE_SVCLASS_ID);
+
+	memcpy(&buf[AVCTP_HEADER_LENGTH], play_pressed, sizeof(play_pressed));
+
+	len = write(sk, buf, AVCTP_HEADER_LENGTH + sizeof(play_pressed));
+
+	len = read(sk, buf, sizeof(buf));
+
+	dump_buffer(buf, len);
+	if (len >= AVCTP_HEADER_LENGTH)
+		dump_avctp_header(hdr);
+}
+
+static void usage()
+{
+	printf("avtest - Audio/Video testing ver %s\n", VERSION);
+	printf("Usage:\n"
+		"\tavtest [options] [remote address]\n");
+	printf("Options:\n"
+		"\t--device <hcidev>    HCI device\n"
+		"\t--reject <command>   Reject command\n"
+		"\t--send <command>     Send command\n"
+		"\t--preconf            Configure stream before actual command\n"
+		"\t--wait <N>           Wait N seconds before exiting\n"
+		"\t--fragment           Use minimum MTU and fragmented messages\n"
+		"\t--invalid <command>  Send invalid command\n");
+}
+
+static struct option main_options[] = {
+	{ "help",	0, 0, 'h' },
+	{ "device",	1, 0, 'i' },
+	{ "reject",	1, 0, 'r' },
+	{ "send",	1, 0, 's' },
+	{ "invalid",	1, 0, 'f' },
+	{ "preconf",	0, 0, 'c' },
+	{ "fragment",   0, 0, 'F' },
+	{ "avctp",	0, 0, 'C' },
+	{ "wait",	1, 0, 'w' },
+	{ 0, 0, 0, 0 }
+};
+
+static unsigned char parse_cmd(const char *arg)
+{
+	if (!strncmp(arg, "discov", 6))
+		return AVDTP_DISCOVER;
+	else if (!strncmp(arg, "capa", 4))
+		return AVDTP_GET_CAPABILITIES;
+	else if (!strncmp(arg, "getcapa", 7))
+		return AVDTP_GET_CAPABILITIES;
+	else if (!strncmp(arg, "setconf", 7))
+		return AVDTP_SET_CONFIGURATION;
+	else if (!strncmp(arg, "getconf", 7))
+		return AVDTP_GET_CONFIGURATION;
+	else if (!strncmp(arg, "open", 4))
+		return AVDTP_OPEN;
+	else if (!strncmp(arg, "start", 5))
+		return AVDTP_START;
+	else if (!strncmp(arg, "close", 5))
+		return AVDTP_CLOSE;
+	else if (!strncmp(arg, "suspend", 7))
+		return AVDTP_SUSPEND;
+	else if (!strncmp(arg, "abort", 7))
+		return AVDTP_ABORT;
+	else
+		return atoi(arg);
+}
+
+enum {
+	MODE_NONE, MODE_REJECT, MODE_SEND,
+};
+
 int main(int argc, char *argv[])
 {
+	unsigned char cmd = 0x00;
+	bdaddr_t src, dst;
+	int opt, mode = MODE_NONE, sk, invalid = 0, preconf = 0, fragment = 0;
+	int avctp = 0, wait_before_exit = 0;
+
+	bacpy(&src, BDADDR_ANY);
+	bacpy(&dst, BDADDR_ANY);
+
+	while ((opt = getopt_long(argc, argv, "+i:r:s:f:hcFCw:",
+						main_options, NULL)) != EOF) {
+		switch (opt) {
+		case 'i':
+			if (!strncmp(optarg, "hci", 3))
+				hci_devba(atoi(optarg + 3), &src);
+			else
+				str2ba(optarg, &src);
+			break;
+
+		case 'r':
+			mode = MODE_REJECT;
+			cmd = parse_cmd(optarg);
+			break;
+
+		case 'f':
+			invalid = 1;
+			/* Intentionally missing break */
+
+		case 's':
+			mode = MODE_SEND;
+			cmd = parse_cmd(optarg);
+			break;
+
+		case 'c':
+			preconf = 1;
+			break;
+
+		case 'F':
+			fragment = 1;
+			break;
+
+		case 'C':
+			avctp = 1;
+			break;
+
+		case 'w':
+			wait_before_exit = atoi(optarg);
+			break;
+
+		case 'h':
+		default:
+			usage();
+			exit(0);
+		}
+	}
+
+	if (argv[optind])
+		str2ba(argv[optind], &dst);
+
+	if (avctp) {
+		avctp = mode;
+		mode = MODE_SEND;
+	}
+
+	switch (mode) {
+	case MODE_REJECT:
+		do_listen(&src, cmd, fragment);
+		break;
+	case MODE_SEND:
+		sk = do_connect(&src, &dst, avctp, fragment);
+		if (sk < 0)
+			exit(1);
+		if (avctp) {
+			if (avctp == MODE_SEND)
+				do_avctp_send(sk, invalid);
+			else
+				process_avctp(sk, cmd);
+		} else
+			do_avdtp_send(sk, &src, &dst, cmd, invalid, preconf);
+		if (wait_before_exit) {
+			printf("Waiting %d seconds before exiting\n", wait_before_exit);
+			sleep(wait_before_exit);
+		}
+		if (media_sock >= 0)
+			close(media_sock);
+		close(sk);
+		break;
+	default:
+		fprintf(stderr, "No operating mode specified!\n");
+		exit(1);
+	}
+
 	return 0;
 }
diff --git a/test/bdaddr.c b/test/bdaddr.c
index 77193f4..683b3b9 100644
--- a/test/bdaddr.c
+++ b/test/bdaddr.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/test/btiotest.c b/test/btiotest.c
index 128df63..c02a25a 100644
--- a/test/btiotest.c
+++ b/test/btiotest.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2009  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2009  Nokia Corporation
+ *  Copyright (C) 2009-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2009-2010  Nokia Corporation
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/test/gaptest.c b/test/gaptest.c
new file mode 100644
index 0000000..3e9f534
--- /dev/null
+++ b/test/gaptest.c
@@ -0,0 +1,335 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#include <dbus/dbus.h>
+
+#define BLUEZ_SERVICE	"org.bluez"
+
+#define MANAGER_PATH	"/"
+#define MANAGER_INTF	BLUEZ_SERVICE ".Manager"
+#define ADAPTER_INTF	BLUEZ_SERVICE ".Adapter"
+
+static char *get_adapter(DBusConnection *conn)
+{
+	DBusMessage *message, *reply;
+	DBusError error;
+	const char *path;
+	char *result = NULL;
+
+	message = dbus_message_new_method_call(BLUEZ_SERVICE, MANAGER_PATH,
+					MANAGER_INTF, "DefaultAdapter");
+	if (!message)
+		return NULL;
+
+	dbus_error_init(&error);
+
+	reply = dbus_connection_send_with_reply_and_block(conn,
+							message, -1, &error);
+
+	dbus_message_unref(message);
+
+	if (!reply) {
+		if (dbus_error_is_set(&error) == TRUE) {
+			fprintf(stderr, "%s\n", error.message);
+			dbus_error_free(&error);
+		} else
+			fprintf(stderr, "Failed to set property\n");
+		return NULL;
+	}
+
+	if (dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+						DBUS_TYPE_INVALID) == FALSE)
+		goto done;
+
+	printf("Using default adapter %s\n", path);
+
+	result = strdup(path);
+
+done:
+	dbus_message_unref(reply);
+
+	return result;
+}
+
+static char *find_device(DBusConnection *conn, const char *adapter,
+							const char *address)
+{
+	DBusMessage *message, *reply;
+	DBusError error;
+	const char *path;
+	char *result = NULL;
+
+	message = dbus_message_new_method_call(BLUEZ_SERVICE, adapter,
+					ADAPTER_INTF, "FindDevice");
+	if (!message)
+		return NULL;
+
+	dbus_message_append_args(message, DBUS_TYPE_STRING, &address,
+							DBUS_TYPE_INVALID);
+
+	dbus_error_init(&error);
+
+	reply = dbus_connection_send_with_reply_and_block(conn,
+							message, -1, &error);
+
+	dbus_message_unref(message);
+
+	if (!reply) {
+		if (dbus_error_is_set(&error) == TRUE) {
+			fprintf(stderr, "%s\n", error.message);
+			dbus_error_free(&error);
+		} else
+			fprintf(stderr, "Failed to set property\n");
+		return NULL;
+	}
+
+	if (dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+						DBUS_TYPE_INVALID) == FALSE)
+		goto done;
+
+	printf("Using device %s for address %s\n", path, address);
+
+	result = strdup(path);
+
+done:
+	dbus_message_unref(reply);
+
+	return result;
+}
+
+static int remove_device(DBusConnection *conn, const char *adapter,
+							const char *device)
+{
+	DBusMessage *message, *reply;
+	DBusError error;
+
+	message = dbus_message_new_method_call(BLUEZ_SERVICE, adapter,
+					ADAPTER_INTF, "RemoveDevice");
+	if (!message)
+		return -ENOMEM;
+
+	dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &device,
+							DBUS_TYPE_INVALID);
+
+	dbus_error_init(&error);
+
+	reply = dbus_connection_send_with_reply_and_block(conn,
+							message, -1, &error);
+
+	dbus_message_unref(message);
+
+	if (!reply) {
+		if (dbus_error_is_set(&error) == TRUE) {
+			fprintf(stderr, "%s\n", error.message);
+			dbus_error_free(&error);
+		} else
+			fprintf(stderr, "Failed to set property\n");
+		return -EIO;
+	}
+
+	dbus_message_unref(reply);
+
+	printf("Removed device %s\n", device);
+
+	return 0;
+}
+
+static int set_property(DBusConnection *conn, const char *adapter,
+					const char *key, int type, void *val)
+{
+	DBusMessage *message, *reply;
+	DBusMessageIter array, value;
+	DBusError error;
+	const char *signature;
+
+	message = dbus_message_new_method_call(BLUEZ_SERVICE, adapter,
+						ADAPTER_INTF, "SetProperty");
+	if (!message)
+		return -ENOMEM;
+
+	switch (type) {
+	case DBUS_TYPE_BOOLEAN:
+		signature = DBUS_TYPE_BOOLEAN_AS_STRING;
+		break;
+	case DBUS_TYPE_UINT32:
+		signature = DBUS_TYPE_UINT32_AS_STRING;
+		break;
+	default:
+		return -EILSEQ;
+	}
+
+	dbus_message_iter_init_append(message, &array);
+
+	dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &key);
+
+	dbus_message_iter_open_container(&array, DBUS_TYPE_VARIANT,
+							signature, &value);
+	dbus_message_iter_append_basic(&value, type, val);
+	dbus_message_iter_close_container(&array, &value);
+
+	dbus_error_init(&error);
+
+	reply = dbus_connection_send_with_reply_and_block(conn,
+							message, -1, &error);
+
+	dbus_message_unref(message);
+
+	if (!reply) {
+		if (dbus_error_is_set(&error) == TRUE) {
+			fprintf(stderr, "%s\n", error.message);
+			dbus_error_free(&error);
+		} else
+			fprintf(stderr, "Failed to set property\n");
+		return -EIO;
+	}
+
+	dbus_message_unref(reply);
+
+	printf("Set property %s for %s\n", key, adapter);
+
+	return 0;
+}
+
+static void usage(void)
+{
+	printf("gaptest - GAP testing\n"
+		"Usage:\n");
+	printf("\tgaptest [options]\n");
+	printf("Options:\n"
+		"\t-T <timeout>        Set timeout\n"
+		"\t-P <powered>        Set powered\n"
+		"\t-D <discoverable>   Set discoverable\n"
+		"\t-B <pairable>       Set pairable\n"
+		"\t-C <address>        Create device\n"
+		"\t-R <address>        Remove device\n");
+}
+
+int main(int argc, char *argv[])
+{
+	DBusConnection *conn;
+	char *adapter, *device;
+	const char *create = NULL, *remove = NULL;
+	int opt, timeout = -1, powered = -1, discoverable = -1, pairable = -1;
+
+	while ((opt = getopt(argc, argv, "T:P:D:B:C:R:h")) != EOF) {
+		switch (opt) {
+		case 'T':
+			timeout = atoi(optarg);
+			break;
+		case 'P':
+			powered = atoi(optarg);
+			break;
+		case 'D':
+			discoverable = atoi(optarg);
+			break;
+		case 'B':
+			pairable = atoi(optarg);
+			break;
+		case 'C':
+			create = optarg;
+			break;
+		case 'R':
+			remove = optarg;
+			break;
+		case 'h':
+			usage();
+			exit(0);
+		default:
+			usage();
+			exit(1);
+		}
+	}
+
+	conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+	if (!conn) {
+		fprintf(stderr, "Can't get on system bus\n");
+		exit(1);
+	}
+
+	adapter = get_adapter(conn);
+	if (!adapter) {
+		fprintf(stderr, "Can't get default adapter\n");
+		exit(1);
+	}
+
+	if (powered >= 0) {
+		set_property(conn, adapter, "Powered",
+					DBUS_TYPE_BOOLEAN, &powered);
+	}
+
+	if (discoverable >= 0) {
+		set_property(conn, adapter, "Discoverable",
+					DBUS_TYPE_BOOLEAN, &discoverable);
+
+		if (timeout >= 0)
+			set_property(conn, adapter, "DiscoverableTimeout",
+						DBUS_TYPE_UINT32, &timeout);
+	}
+
+	if (pairable >= 0) {
+		set_property(conn, adapter, "Pairable",
+					DBUS_TYPE_BOOLEAN, &pairable);
+
+		if (timeout >= 0)
+			set_property(conn, adapter, "PairableTimeout",
+						DBUS_TYPE_UINT32, &timeout);
+	}
+
+	if (create) {
+		device = find_device(conn, adapter, create);
+		if (!device) {
+			fprintf(stderr, "Can't find device\n");
+			exit(1);
+		}
+
+		free(device);
+	}
+
+	if (remove) {
+		device = find_device(conn, adapter, remove);
+		if (!device) {
+			fprintf(stderr, "Can't find device\n");
+			exit(1);
+		}
+
+		remove_device(conn, adapter, device);
+
+		free(device);
+	}
+
+	free(adapter);
+
+	dbus_connection_unref(conn);
+
+	return 0;
+}
diff --git a/test/hciemu.c b/test/hciemu.c
index 66bd84f..195e933 100644
--- a/test/hciemu.c
+++ b/test/hciemu.c
@@ -3,7 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2000-2002  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -296,7 +296,7 @@
 	he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
 
 	he->evt  = EVT_CMD_COMPLETE;
-	he->plen = EVT_CMD_COMPLETE_SIZE + plen; 
+	he->plen = EVT_CMD_COMPLETE_SIZE + plen;
 
 	cc = (void *) ptr; ptr += EVT_CMD_COMPLETE_SIZE;
 
@@ -328,7 +328,7 @@
 	he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
 
 	he->evt  = EVT_CONN_REQUEST;
-	he->plen = EVT_CONN_REQUEST_SIZE; 
+	he->plen = EVT_CONN_REQUEST_SIZE;
 
 	cr = (void *) ptr; ptr += EVT_CONN_REQUEST_SIZE;
 
@@ -356,7 +356,7 @@
 	he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
 
 	he->evt  = EVT_CONN_COMPLETE;
-	he->plen = EVT_CONN_COMPLETE_SIZE; 
+	he->plen = EVT_CONN_COMPLETE_SIZE;
 
 	cc = (void *) ptr; ptr += EVT_CONN_COMPLETE_SIZE;
 
diff --git a/test/hstest.c b/test/hstest.c
index b6a58c6..08f2257 100644
--- a/test/hstest.c
+++ b/test/hstest.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -277,7 +277,7 @@
 					case PLAY:
 						rlen = read(fd, buf, rlen);
 
-						wlen = 0; 
+						wlen = 0;
 						p = buf;
 						while (rlen > sco_mtu) {
 						        wlen += write(sd, p, sco_mtu);
diff --git a/audio/ipctest-a2dp-easy.test b/test/ipctest-a2dp-easy.test
similarity index 100%
rename from audio/ipctest-a2dp-easy.test
rename to test/ipctest-a2dp-easy.test
diff --git a/audio/ipctest-a2dp-resume-fast.test b/test/ipctest-a2dp-resume-fast.test
similarity index 100%
rename from audio/ipctest-a2dp-resume-fast.test
rename to test/ipctest-a2dp-resume-fast.test
diff --git a/audio/ipctest-hsp-a2dp-switch.test b/test/ipctest-hsp-a2dp-switch.test
similarity index 100%
rename from audio/ipctest-hsp-a2dp-switch.test
rename to test/ipctest-hsp-a2dp-switch.test
diff --git a/audio/ipctest-hsp-easy.test b/test/ipctest-hsp-easy.test
similarity index 100%
rename from audio/ipctest-hsp-easy.test
rename to test/ipctest-hsp-easy.test
diff --git a/audio/ipctest-init-shutdown.test b/test/ipctest-init-shutdown.test
similarity index 100%
rename from audio/ipctest-init-shutdown.test
rename to test/ipctest-init-shutdown.test
diff --git a/audio/ipctest.c b/test/ipctest.c
similarity index 98%
rename from audio/ipctest.c
rename to test/ipctest.c
index d18f62e..9fdfac4 100644
--- a/audio/ipctest.c
+++ b/test/ipctest.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2009  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2009	Lennart Poettering
  *  Copyright (C) 2008	Joao Paulo Rechi Vita
  *
@@ -1029,8 +1029,7 @@
 		if (sscanf(line, "%*s %as", &address) != 1)
 			DBG("set with bdaddr BDADDR");
 
-		if (u->address)
-			free(u->address);
+		free(u->address);
 
 		u->address = address;
 		DBG("bdaddr %s", u->address);
@@ -1049,8 +1048,7 @@
 			DBG("set with profile [hsp|a2dp]");
 		}
 
-		if (profile)
-			free(profile);
+		free(profile);
 		DBG("profile %s", u->transport == BT_CAPABILITIES_TRANSPORT_SCO ?
 			"hsp" : "a2dp");
 	}
diff --git a/test/l2test.c b/test/l2test.c
index 6ba50c3..0bb46f3 100644
--- a/test/l2test.c
+++ b/test/l2test.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2000-2001  Qualcomm Incorporated
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -60,6 +60,8 @@
 	LSEND,
 	SENDDUMP,
 	LSENDDUMP,
+	LSENDRECV,
+	CSENDRECV,
 	INFOREQ,
 	PAIRING,
 };
@@ -70,6 +72,15 @@
 static int imtu = 672;
 static int omtu = 0;
 
+/* Default FCS option */
+static int fcs = 0x01;
+
+/* Default Transmission Window */
+static int txwin_size = 63;
+
+/* Default Max Transmission */
+static int max_transmit = 3;
+
 /* Default data size */
 static long data_size = -1;
 static long buffer_size = 2048;
@@ -217,8 +228,11 @@
 	/* Set new options */
 	opts.omtu = omtu;
 	opts.imtu = imtu;
-	if (rfcmode > 0)
-		opts.mode = rfcmode;
+	opts.mode = rfcmode;
+
+	opts.fcs = fcs;
+	opts.txwin_size = txwin_size;
+	opts.max_tx = max_transmit;
 
 	if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) {
 		syslog(LOG_ERR, "Can't set L2CAP options: %s (%d)",
@@ -380,6 +394,10 @@
 	if (rfcmode > 0)
 		opts.mode = rfcmode;
 
+	opts.fcs = fcs;
+	opts.txwin_size = txwin_size;
+	opts.max_tx = max_transmit;
+
 	if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) {
 		syslog(LOG_ERR, "Can't set L2CAP options: %s (%d)",
 							strerror(errno), errno);
@@ -768,6 +786,22 @@
 	dump_mode(sk);
 }
 
+static void send_and_recv_mode(int sk)
+{
+	int flags;
+
+	if ((flags = fcntl(sk, F_GETFL, 0)) < 0)
+		flags = 0;
+	fcntl(sk, F_SETFL, flags | O_NONBLOCK);
+
+	/* fork for duplex channel */
+	if (fork())
+		send_mode(sk);
+	else
+		recv_mode(sk);
+	return;
+}
+
 static void reconnect_mode(char *svr)
 {
 	while (1) {
@@ -1017,6 +1051,8 @@
 		"\t-w listen and send\n"
 		"\t-d listen and dump incoming data\n"
 		"\t-x listen, then send, then dump incoming data\n"
+		"\t-t listen, then send and receive at the same time\n"
+		"\t-q connect, then send and receive at the same time\n"
 		"\t-s connect and send\n"
 		"\t-u connect and receive\n"
 		"\t-n connect and be silent\n"
@@ -1030,14 +1066,18 @@
 		"\t[-b bytes] [-i device] [-P psm]\n"
 		"\t[-I imtu] [-O omtu]\n"
 		"\t[-L seconds] enable SO_LINGER\n"
-		"\t[-F seconds] enable deferred setup\n"
+		"\t[-W seconds] enable deferred setup\n"
 		"\t[-B filename] use data packets from file\n"
 		"\t[-N num] send num frames (default = infinite)\n"
 		"\t[-C num] send num frames before delay (default = 1)\n"
 		"\t[-D milliseconds] delay after sending num frames (default = 0)\n"
 		"\t[-X mode] select retransmission/flow-control mode\n"
+		"\t[-F fcs] use CRC16 check (default = 1)\n"
+		"\t[-Q num] Max Transmit value (default = 3)\n"
+		"\t[-Z size] Transmission Window size (default = 63)\n"
 		"\t[-R] reliable mode\n"
 		"\t[-G] use connectionless channel (datagram)\n"
+		"\t[-U] use sock stream\n"
 		"\t[-A] request authentication\n"
 		"\t[-E] request encryption\n"
 		"\t[-S] secure connection\n"
@@ -1052,7 +1092,7 @@
 
 	bacpy(&bdaddr, BDADDR_ANY);
 
-	while ((opt=getopt(argc,argv,"rdscuwmnxyzpb:i:P:I:O:B:N:L:F:C:D:X:RGAESMT")) != EOF) {
+	while ((opt=getopt(argc,argv,"rdscuwmntqxyzpb:i:P:I:O:B:N:L:W:C:D:X:F:Q:Z:RUGAESMT")) != EOF) {
 		switch(opt) {
 		case 'r':
 			mode = RECV;
@@ -1091,6 +1131,15 @@
 			need_addr = 1;
 			break;
 
+		case 't':
+			mode = LSENDRECV;
+			break;
+
+		case 'q':
+			mode = CSENDRECV;
+			need_addr = 1;
+			break;
+
 		case 'x':
 			mode = LSENDDUMP;
 			break;
@@ -1136,7 +1185,7 @@
 			linger = atoi(optarg);
 			break;
 
-		case 'F':
+		case 'W':
 			defer_setup = atoi(optarg);
 			break;
 
@@ -1163,6 +1212,10 @@
 				rfcmode = atoi(optarg);
 			break;
 
+		case 'F':
+			fcs = atoi(optarg);
+			break;
+
 		case 'R':
 			reliable = 1;
 			break;
@@ -1187,10 +1240,22 @@
 			socktype = SOCK_DGRAM;
 			break;
 
+		case 'U':
+			socktype = SOCK_STREAM;
+			break;
+
 		case 'T':
 			timestamp = 1;
 			break;
 
+		case 'Q':
+			max_transmit = atoi(optarg);
+			break;
+
+		case 'Z':
+			txwin_size = atoi(optarg);
+			break;
+
 		default:
 			usage();
 			exit(1);
@@ -1269,6 +1334,18 @@
 			do_listen(senddump_mode);
 			break;
 
+		case LSENDRECV:
+			do_listen(send_and_recv_mode);
+			break;
+
+		case CSENDRECV:
+			sk = do_connect(argv[optind]);
+			if (sk < 0)
+				exit(1);
+
+			send_and_recv_mode(sk);
+			break;
+
 		case INFOREQ:
 			info_request(argv[optind]);
 			exit(0);
diff --git a/test/list-devices b/test/list-devices
index 511d0cf..9120714 100755
--- a/test/list-devices
+++ b/test/list-devices
@@ -40,6 +40,9 @@
 		if (key == "Devices"):
 			list = extract_objects(value)
 			print "    %s = %s" % (key, list)
+		elif (key == "UUIDs"):
+			list = extract_uuids(value)
+			print "    %s = %s" % (key, list)
 		else:
 			print "    %s = %s" % (key, value)
 
diff --git a/test/lmptest.c b/test/lmptest.c
index ce30bb1..549ae12 100644
--- a/test/lmptest.c
+++ b/test/lmptest.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2005-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2005-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/test/rctest.1 b/test/rctest.1
index b83d694..dfedbef 100644
--- a/test/rctest.1
+++ b/test/rctest.1
@@ -54,7 +54,7 @@
 .BI -L\  seconds
 enable SO_LINGER options for \fIseconds\fR
 .TP
-.BI -F\  seconds
+.BI -W\  seconds
 enable deferred setup for \fIseconds\fR
 .TP
 .BI -B\  filename
diff --git a/test/rctest.c b/test/rctest.c
index a246262..b3804f5 100644
--- a/test/rctest.c
+++ b/test/rctest.c
@@ -3,7 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -436,7 +436,7 @@
 				if (r < 0)
 					syslog(LOG_ERR, "Read failed: %s (%d)",
 							strerror(errno), errno);
-				return;	
+				return;
 			}
 
 			if (timestamp) {
@@ -459,15 +459,15 @@
 				seq = sq;
 			}
 			seq++;
-			
+
 			/* Check length */
 			l = btohs(*(uint16_t *) (buf + 4));
 			if (r != l) {
 				syslog(LOG_INFO, "size missmatch: %d -> %d", r, l);
 				continue;
 			}
-			
-			/* Verify data */	
+
+			/* Verify data */
 			for (i = 6; i < r; i++) {
 				if (buf[i] != 0x7f)
 					syslog(LOG_INFO, "data missmatch: byte %d 0x%2.2x", i, buf[i]);
@@ -511,7 +511,7 @@
 		*(uint32_t *) buf = htobl(seq);
 		*(uint16_t *) (buf + 4) = htobs(data_size);
 		seq++;
-		
+
 		if (send(sk, buf, data_size, 0) <= 0) {
 			syslog(LOG_ERR, "Send failed: %s (%d)",
 							strerror(errno), errno);
@@ -581,7 +581,7 @@
 	printf("Options:\n"
 		"\t[-b bytes] [-i device] [-P channel] [-U uuid]\n"
 		"\t[-L seconds] enabled SO_LINGER option\n"
-		"\t[-F seconds] enable deferred setup\n"
+		"\t[-W seconds] enable deferred setup\n"
 		"\t[-B filename] use data packets from file\n"
 		"\t[-N num] number of frames to send\n"
 		"\t[-C num] send num frames before delay (default = 1)\n"
@@ -600,7 +600,7 @@
 
 	bacpy(&bdaddr, BDADDR_ANY);
 
-	while ((opt=getopt(argc,argv,"rdscuwmnb:i:P:U:B:N:MAESL:F:C:D:T")) != EOF) {
+	while ((opt=getopt(argc,argv,"rdscuwmnb:i:P:U:B:N:MAESL:W:C:D:T")) != EOF) {
 		switch (opt) {
 		case 'r':
 			mode = RECV;
@@ -683,7 +683,7 @@
 			linger = atoi(optarg);
 			break;
 
-		case 'F':
+		case 'W':
 			defer_setup = atoi(optarg);
 			break;
 
diff --git a/test/scotest.c b/test/scotest.c
index d72c610..d5aa940 100644
--- a/test/scotest.c
+++ b/test/scotest.c
@@ -3,7 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -235,7 +235,7 @@
 				if (r < 0)
 					syslog(LOG_ERR, "Read failed: %s (%d)",
 							strerror(errno), errno);
-				return;	
+				return;
 			}
 			total += r;
 		}
diff --git a/test/sdptest.c b/test/sdptest.c
index cccb1da..480a468 100644
--- a/test/sdptest.c
+++ b/test/sdptest.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2005-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2005-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/test/test-adapter b/test/test-adapter
index 4c1a28a..00ef6f5 100755
--- a/test/test-adapter
+++ b/test/test-adapter
@@ -3,15 +3,29 @@
 import sys
 import dbus
 import time
+from optparse import OptionParser, make_option
 
 bus = dbus.SystemBus()
 
 manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
 
-adapter = dbus.Interface(bus.get_object("org.bluez", manager.DefaultAdapter()),
+option_list = [
+		make_option("-i", "--device", action="store",
+				type="string", dest="dev_id"),
+		]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+	adapter_path = manager.FindAdapter(options.dev_id)
+else:
+	adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
 							"org.bluez.Adapter")
 
-if (len(sys.argv) < 2):
+if (len(args) < 1):
 	print "Usage: %s <command>" % (sys.argv[0])
 	print ""
 	print "  address"
@@ -24,80 +38,80 @@
 	print "  discovering"
 	sys.exit(1)
 
-if (sys.argv[1] == "address"):
+if (args[0] == "address"):
 	properties = adapter.GetProperties()
 	print properties["Address"]
 	sys.exit(0)
 
-if (sys.argv[1] == "name"):
-	if (len(sys.argv) < 3):
+if (args[0] == "name"):
+	if (len(args) < 2):
 		properties = adapter.GetProperties()
 		print properties["Name"]
 	else:
-		adapter.SetProperty("Name", sys.argv[2])
+		adapter.SetProperty("Name", args[1])
 	sys.exit(0)
 
-if (sys.argv[1] == "powered"):
-	if (len(sys.argv) < 3):
+if (args[0] == "powered"):
+	if (len(args) < 2):
 		properties = adapter.GetProperties()
 		print properties["Powered"]
 	else:
-		if (sys.argv[2] == "on"):
+		if (args[1] == "on"):
 			value = dbus.Boolean(1)
-		elif (sys.argv[2] == "off"):
+		elif (args[1] == "off"):
 			value = dbus.Boolean(0)
 		else:
-			value = dbus.Boolean(sys.argv[2])
+			value = dbus.Boolean(args[1])
 		adapter.SetProperty("Powered", value)
 	sys.exit(0)
 
-if (sys.argv[1] == "pairable"):
-	if (len(sys.argv) < 3):
+if (args[0] == "pairable"):
+	if (len(args) < 2):
 		properties = adapter.GetProperties()
 		print properties["Pairable"]
 	else:
-		if (sys.argv[2] == "on"):
+		if (args[1] == "on"):
 			value = dbus.Boolean(1)
-		elif (sys.argv[2] == "off"):
+		elif (args[1] == "off"):
 			value = dbus.Boolean(0)
 		else:
-			value = dbus.Boolean(sys.argv[2])
+			value = dbus.Boolean(args[1])
 		adapter.SetProperty("Pairable", value)
 	sys.exit(0)
 
-if (sys.argv[1] == "pairabletimeout"):
-	if (len(sys.argv) < 3):
+if (args[0] == "pairabletimeout"):
+	if (len(args) < 2):
 		properties = adapter.GetProperties()
 		print properties["PairableTimeout"]
 	else:
-		timeout = dbus.UInt32(sys.argv[2])
+		timeout = dbus.UInt32(args[1])
 		adapter.SetProperty("PairableTimeout", timeout)
 	sys.exit(0)
 
-if (sys.argv[1] == "discoverable"):
-	if (len(sys.argv) < 3):
+if (args[0] == "discoverable"):
+	if (len(args) < 2):
 		properties = adapter.GetProperties()
 		print properties["Discoverable"]
 	else:
-		if (sys.argv[2] == "on"):
+		if (args[1] == "on"):
 			value = dbus.Boolean(1)
-		elif (sys.argv[2] == "off"):
+		elif (args[1] == "off"):
 			value = dbus.Boolean(0)
 		else:
-			value = dbus.Boolean(sys.argv[2])
+			value = dbus.Boolean(args[1])
 		adapter.SetProperty("Discoverable", value)
 	sys.exit(0)
 
-if (sys.argv[1] == "discoverabletimeout"):
-	if (len(sys.argv) < 3):
+if (args[0] == "discoverabletimeout"):
+	if (len(args) < 2):
 		properties = adapter.GetProperties()
 		print properties["DiscoverableTimeout"]
 	else:
-		timeout = dbus.UInt32(sys.argv[2])
+		timeout = dbus.UInt32(args[1])
 		adapter.SetProperty("DiscoverableTimeout", timeout)
 	sys.exit(0)
 
-if (sys.argv[1] == "discovering"):
+if (args[0] == "discovering"):
 	properties = adapter.GetProperties()
 	print properties["Discovering"]
 	sys.exit(0)
diff --git a/test/test-audio b/test/test-audio
new file mode 100755
index 0000000..8b7a62d
--- /dev/null
+++ b/test/test-audio
@@ -0,0 +1,45 @@
+#!/usr/bin/python
+
+import sys
+import dbus
+from optparse import OptionParser, make_option
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
+
+option_list = [
+		make_option("-i", "--device", action="store",
+				type="string", dest="dev_id"),
+		]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+	adapter_path = manager.FindAdapter(options.dev_id)
+else:
+	adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+							"org.bluez.Adapter")
+
+if len(args) < 2:
+	print """Usage: %s <command>
+
+	connect <bdaddr>
+	disconnect <bdaddr>
+	""" % sys.argv[0]
+	sys.exit(1)
+
+device = adapter.FindDevice(args[1])
+audio = dbus.Interface(bus.get_object("org.bluez", device),
+				"org.bluez.Audio")
+
+if args[0] == "connect":
+	audio.Connect()
+elif args[0] == "disconnect":
+	audio.Disconnect()
+else:
+	print "Unknown command"
+	sys.exit(1)
diff --git a/test/test-device b/test/test-device
index f8f2d14..a04ff35 100755
--- a/test/test-device
+++ b/test/test-device
@@ -3,15 +3,29 @@
 import sys
 import dbus
 import re
+from optparse import OptionParser, make_option
 
 bus = dbus.SystemBus()
 
 manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
 
-adapter = dbus.Interface(bus.get_object("org.bluez", manager.DefaultAdapter()),
+option_list = [
+		make_option("-i", "--device", action="store",
+				type="string", dest="dev_id"),
+		]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+	adapter_path = manager.FindAdapter(options.dev_id)
+else:
+	adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
 							"org.bluez.Adapter")
 
-if (len(sys.argv) < 2):
+if (len(args) < 1):
 	print "Usage: %s <command>" % (sys.argv[0])
 	print ""
 	print "  list"
@@ -22,43 +36,48 @@
 	print "  name <address>"
 	print "  alias <address> [alias]"
 	print "  trusted <address> [yes/no]"
+	print "  blocked <address> [yes/no]"
 	sys.exit(1)
 
-if (sys.argv[1] == "list"):
-	list = adapter.ListDevices()
-	print list
+if (args[0] == "list"):
+	for path in adapter.ListDevices():
+		device = dbus.Interface(bus.get_object("org.bluez", path),
+							"org.bluez.Device")
+		properties = device.GetProperties()
+		print "%s %s" % (properties["Address"], properties["Alias"])
+
 	sys.exit(0)
 
-if (sys.argv[1] == "create"):
-	if (len(sys.argv) < 3):
+if (args[0] == "create"):
+	if (len(args) < 2):
 		print "Need address parameter"
 	else:
-		device = adapter.CreateDevice(sys.argv[2])
+		device = adapter.CreateDevice(args[1])
 		print device
 	sys.exit(0)
 
-if (sys.argv[1] == "remove"):
-	if (len(sys.argv) < 3):
+if (args[0] == "remove"):
+	if (len(args) < 2):
 		print "Need address or object path parameter"
 	else:
 		try:
-			path = adapter.FindDevice(sys.argv[2])
+			path = adapter.FindDevice(args[1])
 		except:
-			path = sys.argv[2]
+			path = args[1]
 		adapter.RemoveDevice(path)
 	sys.exit(0)
 
-if (sys.argv[1] == "discover"):
-	if (len(sys.argv) < 3):
+if (args[0] == "discover"):
+	if (len(args) < 2):
 		print "Need address parameter"
 	else:
-		path = adapter.FindDevice(sys.argv[2])
+		path = adapter.FindDevice(args[1])
 		device = dbus.Interface(bus.get_object("org.bluez", path),
 							"org.bluez.Device")
-		if (len(sys.argv) < 4):
+		if (len(args) < 3):
 			pattern = ""
 		else:
-			pattern = sys.argv[3]
+			pattern = args[2]
 		services = device.DiscoverServices(pattern);
 		for key in services.keys():
 			p = re.compile(">.*?<")
@@ -68,61 +87,81 @@
 			print
 	sys.exit(0)
 
-if (sys.argv[1] == "class"):
-	if (len(sys.argv) < 3):
+if (args[0] == "class"):
+	if (len(args) < 2):
 		print "Need address parameter"
 	else:
-		path = adapter.FindDevice(sys.argv[2])
+		path = adapter.FindDevice(args[1])
 		device = dbus.Interface(bus.get_object("org.bluez", path),
 							"org.bluez.Device")
 		properties = device.GetProperties()
 		print "0x%06x" % (properties["Class"])
 	sys.exit(0)
 
-if (sys.argv[1] == "name"):
-	if (len(sys.argv) < 3):
+if (args[0] == "name"):
+	if (len(args) < 2):
 		print "Need address parameter"
 	else:
-		path = adapter.FindDevice(sys.argv[2])
+		path = adapter.FindDevice(args[1])
 		device = dbus.Interface(bus.get_object("org.bluez", path),
 							"org.bluez.Device")
 		properties = device.GetProperties()
 		print properties["Name"]
 	sys.exit(0)
 
-if (sys.argv[1] == "alias"):
-	if (len(sys.argv) < 3):
+if (args[0] == "alias"):
+	if (len(args) < 2):
 		print "Need address parameter"
 	else:
-		path = adapter.FindDevice(sys.argv[2])
+		path = adapter.FindDevice(args[1])
 		device = dbus.Interface(bus.get_object("org.bluez", path),
 							"org.bluez.Device")
-		if (len(sys.argv) < 4):
+		if (len(args) < 3):
 			properties = device.GetProperties()
 			print properties["Alias"]
 		else:
-			device.SetProperty("Alias", sys.argv[3])
+			device.SetProperty("Alias", args[2])
 	sys.exit(0)
 
-if (sys.argv[1] == "trusted"):
-	if (len(sys.argv) < 3):
+if (args[0] == "trusted"):
+	if (len(args) < 2):
 		print "Need address parameter"
 	else:
-		path = adapter.FindDevice(sys.argv[2])
+		path = adapter.FindDevice(args[1])
 		device = dbus.Interface(bus.get_object("org.bluez", path),
 							"org.bluez.Device")
-		if (len(sys.argv) < 4):
+		if (len(args) < 3):
 			properties = device.GetProperties()
 			print properties["Trusted"]
 		else:
-			if (sys.argv[3] == "yes"):
+			if (args[2] == "yes"):
 				value = dbus.Boolean(1)
-			elif (sys.argv[3] == "no"):
+			elif (args[2] == "no"):
 				value = dbus.Boolean(0)
 			else:
-				value = dbus.Boolean(sys.argv[3])
+				value = dbus.Boolean(args[2])
 			device.SetProperty("Trusted", value)
 	sys.exit(0)
 
+if (args[0] == "blocked"):
+	if (len(args) < 2):
+		print "Need address parameter"
+	else:
+		path = adapter.FindDevice(args[1])
+		device = dbus.Interface(bus.get_object("org.bluez", path),
+							"org.bluez.Device")
+		if (len(args) < 3):
+			properties = device.GetProperties()
+			print properties["Blocked"]
+		else:
+			if (args[2] == "yes"):
+				value = dbus.Boolean(1)
+			elif (args[2] == "no"):
+				value = dbus.Boolean(0)
+			else:
+				value = dbus.Boolean(args[2])
+			device.SetProperty("Blocked", value)
+	sys.exit(0)
+
 print "Unknown command"
 sys.exit(1)
diff --git a/test/test-discovery b/test/test-discovery
index e45bcc0..22c88c3 100755
--- a/test/test-discovery
+++ b/test/test-discovery
@@ -4,6 +4,7 @@
 
 import dbus
 import dbus.mainloop.glib
+from optparse import OptionParser, make_option
 
 def device_found(address, properties):
 	print "[ " + address + " ]"
@@ -26,8 +27,20 @@
 	manager = dbus.Interface(bus.get_object("org.bluez", "/"),
 							"org.bluez.Manager")
 
-	path = manager.DefaultAdapter()
-	adapter = dbus.Interface(bus.get_object("org.bluez", path),
+	option_list = [
+			make_option("-i", "--device", action="store",
+					type="string", dest="dev_id"),
+			]
+	parser = OptionParser(option_list=option_list)
+
+	(options, args) = parser.parse_args()
+
+	if options.dev_id:
+		adapter_path = manager.FindAdapter(options.dev_id)
+	else:
+		adapter_path = manager.DefaultAdapter()
+
+	adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
 							"org.bluez.Adapter")
 
 	bus.add_signal_receiver(device_found,
diff --git a/test/test-input b/test/test-input
new file mode 100755
index 0000000..405bb59
--- /dev/null
+++ b/test/test-input
@@ -0,0 +1,45 @@
+#!/usr/bin/python
+
+import sys
+import dbus
+from optparse import OptionParser, make_option
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
+
+option_list = [
+		make_option("-i", "--device", action="store",
+				type="string", dest="dev_id"),
+		]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+	adapter_path = manager.FindAdapter(options.dev_id)
+else:
+	adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+							"org.bluez.Adapter")
+
+if len(args) < 2:
+	print """Usage: %s <command>
+
+	connect <bdaddr>
+	disconnect <bdaddr>
+	""" % sys.argv[0]
+	sys.exit(1)
+
+device = adapter.FindDevice(args[1])
+input = dbus.Interface(bus.get_object("org.bluez", device),
+				"org.bluez.Input")
+
+if args[0] == "connect":
+	input.Connect()
+elif args[0] == "disconnect":
+	input.Disconnect()
+else:
+	print "Unknown command"
+	sys.exit(1)
diff --git a/test/test-nap b/test/test-nap
new file mode 100755
index 0000000..c83d928
--- /dev/null
+++ b/test/test-nap
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+
+import sys
+import time
+import dbus
+from optparse import OptionParser, make_option
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+						"org.bluez.Manager")
+
+option_list = [
+		make_option("-i", "--device", action="store",
+				type="string", dest="dev_id"),
+		]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+	adapter_path = manager.FindAdapter(options.dev_id)
+else:
+	adapter_path = manager.DefaultAdapter()
+
+server = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+						"org.bluez.NetworkServer")
+
+service = "nap"
+
+if (len(args) < 1):
+	bridge = "tether"
+else:
+	bridge = args[0]
+
+server.Register(service, bridge)
+
+print "Server for %s registered for %s" % (service, bridge)
+
+print "Press CTRL-C to disconnect"
+
+try:
+	time.sleep(1000)
+	print "Terminating connection"
+except:
+	pass
+
+server.Unregister(service)
diff --git a/test/test-network b/test/test-network
index 6f75bed..676fb30 100755
--- a/test/test-network
+++ b/test/test-network
@@ -3,25 +3,39 @@
 import sys
 import time
 import dbus
+from optparse import OptionParser, make_option
 
 bus = dbus.SystemBus()
 
 manager = dbus.Interface(bus.get_object("org.bluez", "/"),
 						"org.bluez.Manager")
 
-adapter = dbus.Interface(bus.get_object("org.bluez", manager.DefaultAdapter()),
+option_list = [
+		make_option("-i", "--device", action="store",
+				type="string", dest="dev_id"),
+		]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+	adapter_path = manager.FindAdapter(options.dev_id)
+else:
+	adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
 							"org.bluez.Adapter")
 
-if (len(sys.argv) < 2):
+if (len(args) < 1):
 	print "Usage: %s <address> [service]" % (sys.argv[0])
 	sys.exit(1)
 
-address = sys.argv[1]
+address = args[0]
 
-if (len(sys.argv) < 3):
+if (len(args) < 2):
 	service = "panu"
 else:
-	service = sys.argv[2]
+	service = args[1]
 
 device = adapter.FindDevice(address)
 
diff --git a/test/test-serial b/test/test-serial
index f6d6022..ed151dc 100755
--- a/test/test-serial
+++ b/test/test-serial
@@ -3,25 +3,38 @@
 import sys
 import time
 import dbus
+from optparse import OptionParser, make_option
 
 bus = dbus.SystemBus()
 
 manager = dbus.Interface(bus.get_object("org.bluez", "/"),
 						"org.bluez.Manager")
+option_list = [
+		make_option("-i", "--device", action="store",
+				type="string", dest="dev_id"),
+		]
+parser = OptionParser(option_list=option_list)
 
-adapter = dbus.Interface(bus.get_object("org.bluez", manager.DefaultAdapter()),
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+	adapter_path = manager.FindAdapter(options.dev_id)
+else:
+	adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
 							"org.bluez.Adapter")
 
-if (len(sys.argv) < 2):
+if (len(args) < 1):
 	print "Usage: %s <address> [service]" % (sys.argv[0])
 	sys.exit(1)
 
-address = sys.argv[1]
+address = sys.argv[0]
 
-if (len(sys.argv) < 3):
+if (len(args) < 2):
 	service = "spp"
 else:
-	service = sys.argv[2]
+	service = args[1]
 
 path = adapter.FindDevice(address)
 
diff --git a/test/test-service b/test/test-service
index e005201..dae40fc 100755
--- a/test/test-service
+++ b/test/test-service
@@ -3,25 +3,39 @@
 import sys
 import dbus
 import time
+from optparse import OptionParser, make_option
 
 bus = dbus.SystemBus()
 
 manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
 
-adapter = dbus.Interface(bus.get_object("org.bluez", manager.FindAdapter("any")),
-							"org.bluez.Service")
+option_list = [
+		make_option("-i", "--device", action="store",
+				type="string", dest="dev_id"),
+		]
+parser = OptionParser(option_list=option_list)
 
-if (len(sys.argv) < 2):
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+	adapter_path = manager.FindAdapter(options.dev_id)
+else:
+	adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+							"org.bluez.Adapter")
+
+if (len(args) < 1):
 	print "Usage: %s <command>" % (sys.argv[0])
 	print ""
 	print "  addrecord <file>"
 	sys.exit(1)
 
-if (sys.argv[1] == "addrecord"):
-	if (len(sys.argv) < 3):
+if (args[0] == "addrecord"):
+	if (len(args) < 2):
 		print "Need file parameter"
 	else:
-		f = open(sys.argv[2])
+		f = open(args[1])
 		record = f.read()
 		f.close()
 		handle = adapter.AddRecord(record)
diff --git a/test/test-telephony b/test/test-telephony
index eb69511..5ef0ac8 100755
--- a/test/test-telephony
+++ b/test/test-telephony
@@ -2,16 +2,32 @@
 
 import sys
 import dbus
+from optparse import OptionParser, make_option
 
 bus = dbus.SystemBus()
 
 manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
-adapter = dbus.Interface(bus.get_object("org.bluez", manager.DefaultAdapter()),
-				"org.bluez.Adapter")
+
+option_list = [
+		make_option("-i", "--device", action="store",
+				type="string", dest="dev_id"),
+		]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+	adapter_path = manager.FindAdapter(options.dev_id)
+else:
+	adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+							"org.bluez.Adapter")
+
 test = dbus.Interface(bus.get_object("org.bluez", "/org/bluez/test"),
 			"org.bluez.TelephonyTest")
 
-if len(sys.argv) < 2:
+if len(args) < 1:
 	print """Usage: %s <command>
 
 	connect <bdaddr>
@@ -31,127 +47,127 @@
 	""" % sys.argv[0]
 	sys.exit(1)
 
-if sys.argv[1] == "connect":
-	if len(sys.argv) < 3:
+if args[0] == "connect":
+	if len(args) < 2:
 		print "Need device address parameter"
 		sys.exit(1)
-	device = adapter.FindDevice(sys.argv[2])
+	device = adapter.FindDevice(args[1])
 	headset = dbus.Interface(bus.get_object("org.bluez", device),
 					"org.bluez.Headset")
 	headset.Connect()
 	sys.exit(0)
 
-if sys.argv[1] == "disconnect":
-	if len(sys.argv) < 3:
+if args[0] == "disconnect":
+	if len(args) < 2:
 		print "Need device address parameter"
 		sys.exit(1)
-	device = adapter.FindDevice(sys.argv[2])
+	device = adapter.FindDevice(args[1])
 	headset = dbus.Interface(bus.get_object("org.bluez", device),
 					"org.bluez.Headset")
 	headset.Disconnect()
 	sys.exit(0)
 
-if sys.argv[1] == "speakergain":
-	if len(sys.argv) < 3:
+if args[0] == "speakergain":
+	if len(args) < 2:
 		print "Need device address parameter"
 		sys.exit(1)
-	device = adapter.FindDevice(sys.argv[2])
+	device = adapter.FindDevice(args[1])
 	headset = dbus.Interface(bus.get_object("org.bluez", device),
 					"org.bluez.Headset")
-	if len(sys.argv) > 3:
-		headset.SetProperty('SpeakerGain', dbus.UInt16(sys.argv[3]))
+	if len(args) > 2:
+		headset.SetProperty('SpeakerGain', dbus.UInt16(args[2]))
 	else:
 		props = headset.GetProperties()
 		print props['SpeakerGain']
 
 	sys.exit(0)
 
-if sys.argv[1] == "microphonegain":
-	if len(sys.argv) < 3:
+if args[0] == "microphonegain":
+	if len(args) < 2:
 		print "Need device address parameter"
 		sys.exit(1)
-	device = adapter.FindDevice(sys.argv[2])
+	device = adapter.FindDevice(args[1])
 	headset = dbus.Interface(bus.get_object("org.bluez", device),
 					"org.bluez.Headset")
-	if len(sys.argv) > 3:
-		headset.SetProperty('MicrophoneGain', dbus.UInt16(sys.argv[3]))
+	if len(args) > 2:
+		headset.SetProperty('MicrophoneGain', dbus.UInt16(args[2]))
 	else:
 		props = headset.GetProperties()
 		print props['MicrophoneGain']
 
 	sys.exit(0)
 
-if sys.argv[1] == "play":
-	if len(sys.argv) < 3:
+if args[0] == "play":
+	if len(args) < 2:
 		print "Need device address parameter"
 		sys.exit(1)
-	device = adapter.FindDevice(sys.argv[2])
+	device = adapter.FindDevice(args[1])
 	headset = dbus.Interface(bus.get_object("org.bluez", device),
 					"org.bluez.Headset")
 	headset.Play()
 
 	sys.exit(0)
 
-if sys.argv[1] == "stop":
-	if len(sys.argv) < 3:
+if args[0] == "stop":
+	if len(args) < 2:
 		print "Need device address parameter"
 		sys.exit(1)
-	device = adapter.FindDevice(sys.argv[2])
+	device = adapter.FindDevice(args[1])
 	headset = dbus.Interface(bus.get_object("org.bluez", device),
 					"org.bluez.Headset")
 	headset.Stop()
 
 	sys.exit(0)
 
-if sys.argv[1] == "outgoing":
-	if len(sys.argv) > 2:
-		test.OutgoingCall(sys.argv[2])
+if args[0] == "outgoing":
+	if len(args) > 1:
+		test.OutgoingCall(args[1])
 	else:
 		print "Need number parameter"
 	sys.exit(0)
 
-if sys.argv[1] == "incoming":
-	if len(sys.argv) > 2:
-		test.IncomingCall(sys.argv[2])
+if args[0] == "incoming":
+	if len(args) > 1:
+		test.IncomingCall(args[1])
 	else:
 		print "Need number parameter"
 	sys.exit(0)
 
-if sys.argv[1] == "cancel":
+if args[0] == "cancel":
 	test.CancelCall()
 	sys.exit(0)
 
-if sys.argv[1] == "signal":
-	if len(sys.argv) > 2:
-		test.SignalStrength(sys.argv[2])
+if args[0] == "signal":
+	if len(args) > 1:
+		test.SignalStrength(args[1])
 	else:
 		print "Need signal strength parameter"
 	sys.exit(0)
 
-if sys.argv[1] == "battery":
-	if len(sys.argv) > 2:
-		test.BatteryLevel(sys.argv[2])
+if args[0] == "battery":
+	if len(args) > 1:
+		test.BatteryLevel(args[1])
 	else:
 		print "Need battery level parameter"
 	sys.exit(0)
 
-if sys.argv[1] == "roaming":
-	if len(sys.argv) > 2:
-		test.RoamingStatus(sys.argv[2] == "yes" or False)
+if args[0] == "roaming":
+	if len(args) > 1:
+		test.RoamingStatus(args[1] == "yes" or False)
 	else:
 		print "Need yes/no parameter"
 	sys.exit(0)
 
-if sys.argv[1] == "registration":
-	if len(sys.argv) > 2:
-		test.RegistrationStatus(sys.argv[2] == "yes" or False)
+if args[0] == "registration":
+	if len(args) > 1:
+		test.RegistrationStatus(args[1] == "yes" or False)
 	else:
 		print "Need yes/no parameter"
 	sys.exit(0)
 
-if sys.argv[1] == "subscriber":
-	if len(sys.argv) > 2:
-		test.SetSubscriberNumber(sys.argv[2])
+if args[0] == "subscriber":
+	if len(args) > 1:
+		test.SetSubscriberNumber(args[1])
 	else:
 		print "Need number parameter"
 	sys.exit(0)
diff --git a/common/test_textfile.c b/test/test-textfile.c
similarity index 96%
rename from common/test_textfile.c
rename to test/test-textfile.c
index 29ca493..970e9e7 100644
--- a/common/test_textfile.c
+++ b/test/test-textfile.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -65,7 +65,7 @@
 
 
 	sprintf(key, "00:00:00:00:00:00");
-	if (textfile_del(filename, key) < 0) 
+	if (textfile_del(filename, key) < 0)
 		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
 
 	memset(value, 0, sizeof(value));
@@ -88,7 +88,7 @@
 	if (textfile_put(filename, key, value) < 0)
 		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
 
-	if (textfile_del(filename, key) < 0) 
+	if (textfile_del(filename, key) < 0)
 		fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
 
 	str = textfile_get(filename, key);
diff --git a/tools/Android.mk b/tools/Android.mk
index c966a3b..3d21163 100755
--- a/tools/Android.mk
+++ b/tools/Android.mk
@@ -10,14 +10,14 @@
 	avinfo.c
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\"
+	-DVERSION=\"4.69\"
 
 LOCAL_C_INCLUDES:=\
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common \
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src \
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth
+	libbluetoothd libbluetooth
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := eng
@@ -35,17 +35,14 @@
 	sdptool.c
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\" -fpermissive
+	-DVERSION=\"4.69\" -fpermissive
 
 LOCAL_C_INCLUDES:=\
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common \
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src \
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth
-
-LOCAL_STATIC_LIBRARIES := \
-	libbluez-common-static
+	libbluetoothd libbluetooth
 
 LOCAL_MODULE:=sdptool
 
@@ -64,17 +61,14 @@
 
 LOCAL_CFLAGS:= \
 	-DSTORAGEDIR=\"/tmp\" \
-	-DVERSION=\"4.47\"
+	-DVERSION=\"4.69\"
 
 LOCAL_C_INCLUDES:=\
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common \
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src \
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth
-
-LOCAL_STATIC_LIBRARIES := \
-	libbluez-common-static
+	libbluetoothd libbluetooth
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := eng
@@ -93,17 +87,14 @@
 
 LOCAL_CFLAGS:= \
 	-DSTORAGEDIR=\"/tmp\" \
-	-DVERSION=\"4.47\"
+	-DVERSION=\"4.69\"
 
 LOCAL_C_INCLUDES:=\
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common \
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src \
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth
-
-LOCAL_STATIC_LIBRARIES := \
-	libbluez-common-static
+	libbluetoothd libbluetooth
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := eng
@@ -121,11 +112,11 @@
 	l2ping.c
 
 LOCAL_C_INCLUDES:=\
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common \
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src \
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth
+	libbluetoothd libbluetooth
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := eng
@@ -146,19 +137,46 @@
 	hciattach_tialt.c
 
 LOCAL_CFLAGS:= \
-	-DVERSION=\"4.47\" \
+	-DVERSION=\"4.69\" \
 	-D__BSD_VISIBLE=1
 
 LOCAL_C_INCLUDES:=\
-	$(LOCAL_PATH)/../include \
-	$(LOCAL_PATH)/../common \
+	$(LOCAL_PATH)/../lib \
+	$(LOCAL_PATH)/../src \
 
 LOCAL_SHARED_LIBRARIES := \
-	libbluetooth
-
-LOCAL_STATIC_LIBRARIES := \
-	libbluez-common-static
+	libbluetoothd libbluetooth
 
 LOCAL_MODULE:=hciattach
 
 include $(BUILD_EXECUTABLE)
+
+#
+# rfcomm
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+        kword.c \
+        main.c \
+        parser.c \
+        lexer.c
+
+LOCAL_CFLAGS:= \
+        -DVERSION=\"4.69\" \
+	-DCONFIGDIR=\"/etc/bluetooth\" \
+        -DNEED_PPOLL
+
+LOCAL_C_INCLUDES:= \
+        $(LOCAL_PATH)/../src \
+        $(LOCAL_PATH)/../lib
+
+LOCAL_SHARED_LIBRARIES := \
+        libbluetooth
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE:=rfcomm
+
+include $(BUILD_EXECUTABLE)
diff --git a/tools/Makefile.am b/tools/Makefile.am
deleted file mode 100644
index 5589a5a..0000000
--- a/tools/Makefile.am
+++ /dev/null
@@ -1,106 +0,0 @@
-
-if TOOLS
-tools_programs = l2ping hcitool sdptool ciptool
-tools_manfiles = l2ping.8 hcitool.1 sdptool.1 ciptool.1
-else
-tools_programs =
-tools_manfiles =
-endif
-
-if BCCMD
-bccmd_programs = bccmd
-bccmd_manfiles = bccmd.8
-else
-bccmd_programs =
-bccmd_manfiles =
-endif
-
-if HID2HCI
-hid2hci_programs = hid2hci
-hid2hci_manfiles = hid2hci.8
-else
-hid2hci_programs =
-hid2hci_manfiles =
-endif
-
-if DFUTOOL
-dfutool_programs = dfutool
-dfutool_manfiles = dfutool.1
-else
-dfutool_programs =
-dfutool_manfiles =
-endif
-
-if USB
-usb_programs = dfubabel avctrl
-else
-usb_programs =
-endif
-
-sbin_PROGRAMS = hciattach hciconfig $(bccmd_programs) $(avctrl_programs) $(hid2hci_programs)
-
-bin_PROGRAMS = $(tools_programs) $(dfutool_programs) $(dfubabel_programs)
-
-noinst_PROGRAMS = hcieventmask hcisecfilter ppporc avinfo $(usb_programs)
-
-hcieventmask_LDADD = @BLUEZ_LIBS@
-
-hciattach_SOURCES = hciattach.c hciattach.h \
-			hciattach_st.c hciattach_ti.c hciattach_tialt.c
-hciattach_LDADD = @BLUEZ_LIBS@
-
-hciconfig_SOURCES = hciconfig.c csr.h csr.c
-hciconfig_LDADD = @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a
-
-if TOOLS
-hcitool_SOURCES = hcitool.c
-hcitool_LDADD = @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a
-
-l2ping_LDADD = @BLUEZ_LIBS@
-
-sdptool_LDADD = @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a
-
-ciptool_LDADD = @BLUEZ_LIBS@
-
-avinfo_LDADD = @BLUEZ_LIBS@
-endif
-
-ppporc_LDADD = @BLUEZ_LIBS@
-
-if BCCMD
-bccmd_SOURCES = bccmd.c csr.h csr.c csr_hci.c \
-			csr_bcsp.c csr_h4.c csr_3wire.c ubcsp.h ubcsp.c
-bccmd_LDADD = @BLUEZ_LIBS@
-if USB
-bccmd_SOURCES += csr_usb.c
-bccmd_LDADD += @USB_LIBS@
-endif
-endif
-
-if HID2HCI
-hid2hci_LDADD = @USB_LIBS@
-endif
-
-if DFUTOOL
-dfutool_SOURCES = dfutool.c dfu.h dfu.c
-dfutool_LDADD = @USB_LIBS@
-endif
-
-if USB
-dfubabel_LDADD = @USB_LIBS@
-avctrl_LDADD = @USB_LIBS@
-endif
-
-AM_CFLAGS = @BLUEZ_CFLAGS@ @USB_CFLAGS@
-
-INCLUDES = -I$(top_srcdir)/common
-
-if MANPAGES
-man_MANS = hciattach.8 hciconfig.8 $(tools_manfiles) \
-		$(bccmd_manfiles) $(hid2hci_manfiles) $(dfutool_manfiles)
-endif
-
-EXTRA_DIST = hciattach.8 hciconfig.8 l2ping.8 hcitool.1 sdptool.1 ciptool.1 \
-		 bccmd.8 avctrl.8 hid2hci.8 dfutool.1 dfubabel.1 example.psr
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/tools/avctrl.c b/tools/avctrl.c
index 7b5e685..3621a68 100644
--- a/tools/avctrl.c
+++ b/tools/avctrl.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/tools/avinfo.c b/tools/avinfo.c
index a3cfd45..7f76c03 100644
--- a/tools/avinfo.c
+++ b/tools/avinfo.c
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/tools/bccmd.c b/tools/bccmd.c
index 0e0c28c..686e858 100644
--- a/tools/bccmd.c
+++ b/tools/bccmd.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -984,7 +984,7 @@
 			str = NULL;
 		}
 
-		printf("// %s%s\n&%04x =", str ? "PSKEY_" : "", 
+		printf("// %s%s\n&%04x =", str ? "PSKEY_" : "",
 						str ? str : val, pskey);
 		for (i = 0; i < length; i++)
 			printf(" %02x%02x", array[(i * 2) + 7], array[(i * 2) + 6]);
diff --git a/tools/ciptool.c b/tools/ciptool.c
index 2afa30e..edce9da 100644
--- a/tools/ciptool.c
+++ b/tools/ciptool.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/tools/csr.c b/tools/csr.c
index 884f0d1..b4ea1fb 100644
--- a/tools/csr.c
+++ b/tools/csr.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/tools/csr.h b/tools/csr.h
index 42bdb9f..1d70491 100644
--- a/tools/csr.h
+++ b/tools/csr.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/tools/csr_3wire.c b/tools/csr_3wire.c
index 34a0db9..33fcf38 100644
--- a/tools/csr_3wire.c
+++ b/tools/csr_3wire.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/tools/csr_bcsp.c b/tools/csr_bcsp.c
index 2c73323..e551311 100644
--- a/tools/csr_bcsp.c
+++ b/tools/csr_bcsp.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/tools/csr_h4.c b/tools/csr_h4.c
index 6fa326f..3371770 100644
--- a/tools/csr_h4.c
+++ b/tools/csr_h4.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/tools/csr_hci.c b/tools/csr_hci.c
index 7f54d55..6bd37c3 100644
--- a/tools/csr_hci.c
+++ b/tools/csr_hci.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/tools/csr_usb.c b/tools/csr_usb.c
index e756150..19903b0 100644
--- a/tools/csr_usb.c
+++ b/tools/csr_usb.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/tools/dfu.c b/tools/dfu.c
index 0207086..39ec088 100644
--- a/tools/dfu.c
+++ b/tools/dfu.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/tools/dfu.h b/tools/dfu.h
index 427cb42..7f999f4 100644
--- a/tools/dfu.h
+++ b/tools/dfu.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/tools/dfubabel.c b/tools/dfubabel.c
index 498a717..612accc 100644
--- a/tools/dfubabel.c
+++ b/tools/dfubabel.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/tools/dfutool.c b/tools/dfutool.c
index 055de25..16dd62e 100644
--- a/tools/dfutool.c
+++ b/tools/dfutool.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -341,7 +341,7 @@
 	size = st.st_size;
 
 	if (!(buf = malloc(size))) {
-		perror("Unable to allocate file buffer"); 
+		perror("Unable to allocate file buffer");
 		exit(1);
 	}
 
@@ -442,7 +442,7 @@
 	filesize = st.st_size;
 
 	if (!(buf = malloc(filesize))) {
-		perror("Unable to allocate file buffer"); 
+		perror("Unable to allocate file buffer");
 		exit(1);
 	}
 
diff --git a/tools/hciattach.8 b/tools/hciattach.8
index f750222..9bd1538 100644
--- a/tools/hciattach.8
+++ b/tools/hciattach.8
@@ -3,10 +3,15 @@
 hciattach \- attach serial devices via UART HCI to BlueZ stack
 .SH SYNOPSIS
 .B hciattach
+.RB [\| \-b \|]
 .RB [\| \-n \|]
 .RB [\| \-p \|]
 .RB [\| \-t
 .IR timeout \|]
+.RB [\| \-s
+.IR speed \|]
+.RB [\| \-l \|]
+.RB [\| \-r \|]
 .I tty
 .IR type \||\| id
 .I speed
@@ -18,6 +23,9 @@
 transport interface.
 .SH OPTIONS
 .TP
+.B \-b
+Send break.
+.TP
 .B \-n
 Don't detach from controlling terminal.
 .TP
@@ -27,6 +35,15 @@
 .BI \-t " timeout"
 Specify an initialization timeout.  (Default is 5 seconds.)
 .TP
+.BI \-s " speed"
+Specify an initial speed instead of the hardware default.
+.TP
+.B \-l
+List all available configurations.
+.TP
+.B \-r
+Set the HCI device into raw mode (the kernel and bluetoothd will ignore it).
+.TP
 .I tty
 This specifies the serial device to attach. A leading
 .B /dev
diff --git a/tools/hciattach.c b/tools/hciattach.c
index 65737f2..1e4fb89 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2000-2001  Qualcomm Incorporated
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -144,10 +144,10 @@
 	return tcsetattr(fd, TCSANOW, ti);
 }
 
-/* 
+/*
  * Read an HCI event from the given file descriptor.
  */
-int read_hci_event(int fd, unsigned char* buf, int size) 
+int read_hci_event(int fd, unsigned char* buf, int size)
 {
 	int remain, r;
 	int count = 0;
@@ -175,9 +175,9 @@
 	}
 
 	/* Now we read the parameters. */
-	if (buf[2] < (size - 3)) 
+	if (buf[2] < (size - 3))
 		remain = buf[2];
-	else 
+	else
 		remain = size - 3;
 
 	while ((count - 3) < remain) {
@@ -190,8 +190,8 @@
 	return count;
 }
 
-/* 
- * Ericsson specific initialization 
+/*
+ * Ericsson specific initialization
  */
 static int ericsson(int fd, struct uart_t *u, struct termios *ti)
 {
@@ -245,8 +245,8 @@
 	return 0;
 }
 
-/* 
- * Digianswer specific initialization 
+/*
+ * Digianswer specific initialization
  */
 static int digi(int fd, struct uart_t *u, struct termios *ti)
 {
@@ -304,7 +304,7 @@
 	do {
 		res = read(fd, buf, count);
 		if (res != -1) {
-			buf += res; 
+			buf += res;
 			count -= res;
 		}
 	} while (count && (errno == 0 || errno == EINTR));
@@ -324,7 +324,8 @@
 static void bcsp_tshy_sig_alarm(int sig)
 {
 	unsigned char bcsp_sync_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xda,0xdc,0xed,0xed,0xc0};
-	int len, retries = 0;
+	int len;
+	static int retries = 0;
 
 	if (retries < bcsp_max_retries) {
 		retries++;
@@ -341,7 +342,8 @@
 static void bcsp_tconf_sig_alarm(int sig)
 {
 	unsigned char bcsp_conf_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xad,0xef,0xac,0xed,0xc0};
-	int len, retries = 0;
+	int len;
+	static int retries = 0;
 
 	if (retries < bcsp_max_retries){
 		retries++;
@@ -478,8 +480,8 @@
 	return 0;
 }
 
-/* 
- * CSR specific initialization 
+/*
+ * CSR specific initialization
  * Inspired strongly by code in OpenBT and experimentations with Brainboxes
  * Pcmcia card.
  * Jean Tourrilhes <jt@hpl.hp.com> - 14.11.01
@@ -542,7 +544,7 @@
 			return -1;
 		}
 
-	/* Event code 0xFF is for vendor-specific events, which is 
+	/* Event code 0xFF is for vendor-specific events, which is
 	 * what we're looking for. */
 	} while (resp[1] != 0xFF);
 
@@ -558,7 +560,7 @@
 	}
 #endif
 	/* Display that to user */
-	fprintf(stderr, "CSR build ID 0x%02X-0x%02X\n", 
+	fprintf(stderr, "CSR build ID 0x%02X-0x%02X\n",
 		resp[15] & 0xFF, resp[14] & 0xFF);
 
 	/* Try to read the current speed of the CSR chip */
@@ -586,7 +588,7 @@
 			return -1;
 		}
 
-	/* Event code 0xFF is for vendor-specific events, which is 
+	/* Event code 0xFF is for vendor-specific events, which is
 	 * what we're looking for. */
 	} while (resp[1] != 0xFF);
 
@@ -600,7 +602,7 @@
 #endif
 
 	if (u->speed > 1500000) {
-		fprintf(stderr, "Speed %d too high. Remaining at %d baud\n", 
+		fprintf(stderr, "Speed %d too high. Remaining at %d baud\n",
 			u->speed, u->init_speed);
 		u->speed = u->init_speed;
 	} else if (u->speed != 57600 && uart_speed(u->speed) == B57600) {
@@ -650,8 +652,8 @@
 	return 0;
 }
 
-/* 
- * Silicon Wave specific initialization 
+/*
+ * Silicon Wave specific initialization
  * Thomas Moser <thomas.moser@tmoser.ch>
  */
 static int swave(int fd, struct uart_t *u, struct termios *ti)
@@ -667,7 +669,7 @@
 	// Subcommand", e.g. "soft reset" to make the changes effective.
 
 	cmd[0] = HCI_COMMAND_PKT;	// it's a command packet
-	cmd[1] = 0x0B;			// OCF 0x0B	= param access set	
+	cmd[1] = 0x0B;			// OCF 0x0B	= param access set
 	cmd[2] = 0xfc;			// OGF bx111111 = vendor specific
 	cmd[3] = 0x06;			// 6 bytes of data following
 	cmd[4] = 0x01;			// param sub command
@@ -701,9 +703,9 @@
 		return -1;
 	}
 
-	// We should wait for a "GET Event" to confirm the success of 
-	// the baud rate setting. Wait some time before reading. Better:  
-	// read with timeout, parse data 
+	// We should wait for a "GET Event" to confirm the success of
+	// the baud rate setting. Wait some time before reading. Better:
+	// read with timeout, parse data
 	// until correct answer, else error handling ... todo ...
 
 	nanosleep(&tm, NULL);
@@ -747,7 +749,7 @@
 	// now the uart baud rate on the silicon wave module is set and effective.
 	// change our own baud rate as well. Then there is a reset event comming in
  	// on the *new* baud rate. This is *undocumented*! The packet looks like this:
-	// 04 FF 01 0B (which would make that a confirmation of 0x0B = "Param 
+	// 04 FF 01 0B (which would make that a confirmation of 0x0B = "Param
 	// subcommand class". So: change to new baud rate, read with timeout, parse
 	// data, error handling. BTW: all param access in Silicon Wave is done this way.
 	// Maybe this code would belong in a seperate file, or at least code reuse...
@@ -1093,10 +1095,14 @@
 }
 
 /* Initialize UART driver */
-static int init_uart(char *dev, struct uart_t *u, int send_break)
+static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
 {
 	struct termios ti;
 	int fd, i;
+	unsigned long flags = 0;
+
+	if (raw)
+		flags |= 1 << HCI_UART_RAW_DEVICE;
 
 	fd = open(dev, O_RDWR | O_NOCTTY);
 	if (fd < 0) {
@@ -1155,6 +1161,11 @@
 		return -1;
 	}
 
+	if (flags && ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
+		perror("Can't set UART flags");
+		return -1;
+	}
+
 	if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) {
 		perror("Can't set device");
 		return -1;
@@ -1170,14 +1181,14 @@
 {
 	printf("hciattach - HCI UART driver initialization utility\n");
 	printf("Usage:\n");
-	printf("\thciattach [-n] [-p] [-b] [-t timeout] [-s initial_speed] <tty> <type | id> [speed] [flow|noflow] [bdaddr]\n");
+	printf("\thciattach [-n] [-p] [-b] [-r] [-t timeout] [-s initial_speed] <tty> <type | id> [speed] [flow|noflow] [bdaddr]\n");
 	printf("\thciattach -l\n");
 }
 
 int main(int argc, char *argv[])
 {
 	struct uart_t *u = NULL;
-	int detach, printpid, opt, i, n, ld, err;
+	int detach, printpid, raw, opt, i, n, ld, err;
 	int to = 10;
 	int init_speed = 0;
 	int send_break = 0;
@@ -1189,8 +1200,9 @@
 
 	detach = 1;
 	printpid = 0;
+	raw = 0;
 
-	while ((opt=getopt(argc, argv, "bnpt:s:l")) != EOF) {
+	while ((opt=getopt(argc, argv, "bnpt:s:lr")) != EOF) {
 		switch(opt) {
 		case 'b':
 			send_break = 1;
@@ -1219,6 +1231,10 @@
 			}
 			exit(0);
 
+		case 'r':
+			raw = 1;
+			break;
+
 		default:
 			usage();
 			exit(1);
@@ -1257,7 +1273,7 @@
 				fprintf(stderr, "Unknown device type or id\n");
 				exit(1);
 			}
-			
+
 			break;
 
 		case 2:
@@ -1296,9 +1312,9 @@
 	alarm(to);
 	bcsp_max_retries = to;
 
-	n = init_uart(dev, u, send_break);
+	n = init_uart(dev, u, send_break, raw);
 	if (n < 0) {
-		perror("Can't initialize device"); 
+		perror("Can't initialize device");
 		exit(1);
 	}
 
diff --git a/tools/hciattach.h b/tools/hciattach.h
index e772211..c0b80a1 100644
--- a/tools/hciattach.h
+++ b/tools/hciattach.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -30,6 +30,8 @@
 #define HCIUARTSETPROTO		_IOW('U', 200, int)
 #define HCIUARTGETPROTO		_IOR('U', 201, int)
 #define HCIUARTGETDEVICE	_IOR('U', 202, int)
+#define HCIUARTSETFLAGS		_IOW('U', 203, int)
+#define HCIUARTGETFLAGS		_IOR('U', 204, int)
 
 #define HCI_UART_H4	0
 #define HCI_UART_BCSP	1
@@ -37,6 +39,8 @@
 #define HCI_UART_H4DS	3
 #define HCI_UART_LL	4
 
+#define HCI_UART_RAW_DEVICE	0
+
 int read_hci_event(int fd, unsigned char* buf, int size);
 int set_speed(int fd, struct termios *ti, int speed);
 
diff --git a/tools/hciattach_st.c b/tools/hciattach_st.c
index e2363bf..dbb7c47 100644
--- a/tools/hciattach_st.c
+++ b/tools/hciattach_st.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2005-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2005-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -140,7 +140,7 @@
 			return -errno;
 	}
 
-	found_fw_file = 0;	
+	found_fw_file = 0;
 	while (1) {
 		d = readdir(dir);
 		if (!d)
@@ -203,14 +203,14 @@
 	int len;
 	int err;
 
-	/* Hci_Cmd_Ericsson_Read_Revision_Information */	
+	/* Hci_Cmd_Ericsson_Read_Revision_Information */
 	len = do_command(dd, 0xff, 0x000f, NULL, 0, buf, sizeof(buf));
 	if (len < 0)
 		return -1;
 
 	printf("%s\n", buf);
 
-	/* HCI_Read_Local_Version_Information */	
+	/* HCI_Read_Local_Version_Information */
 	len = do_command(dd, 0x04, 0x0001, NULL, 0, buf, sizeof(buf));
 	if (len < 0)
 		return -1;
@@ -219,7 +219,7 @@
 
 	err = load_file(dd, version, ".ptc");
 	if (err < 0) {
-		if (err == -ENOENT) 	
+		if (err == -ENOENT)
 			fprintf(stderr, "No ROM patch file loaded.\n");
 		else
 			return -1;
@@ -227,7 +227,7 @@
 
 	err = load_file(dd, buf[2] << 8 | buf[1], ".ssf");
 	if (err < 0) {
-		if (err == -ENOENT) 	
+		if (err == -ENOENT)
 			fprintf(stderr, "No static settings file loaded.\n");
 		else
 			return -1;
@@ -237,7 +237,7 @@
 	cmd[1] = 0x06;
 	bacpy((bdaddr_t *) (cmd + 2), bdaddr);
 
-	/* Hci_Cmd_ST_Store_In_NVDS */	
+	/* Hci_Cmd_ST_Store_In_NVDS */
 	len = do_command(dd, 0xff, 0x0022, cmd, 8, buf, sizeof(buf));
 	if (len < 0)
 		return -1;
diff --git a/tools/hciattach_ti.c b/tools/hciattach_ti.c
index e169f89..7627bc1 100644
--- a/tools/hciattach_ti.c
+++ b/tools/hciattach_ti.c
@@ -3,7 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2007-2008  Texas Instruments, Inc.
- *  Copyright (C) 2005-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2005-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -446,7 +446,7 @@
 
 	memset(resp,'\0', 100);
 
-	/* It is possible to get software version with manufacturer specific 
+	/* It is possible to get software version with manufacturer specific
 	   HCI command HCI_VS_TI_Version_Number. But the only thing you get more
 	   is if this is point-to-point or point-to-multipoint module */
 
diff --git a/tools/hciattach_tialt.c b/tools/hciattach_tialt.c
index 325e006..e4ad995 100644
--- a/tools/hciattach_tialt.c
+++ b/tools/hciattach_tialt.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2005-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2005-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -68,10 +68,10 @@
 	/* Read reply. */
 	FAILIF(read_hci_event(fd, (unsigned char *)&resp, sizeof(resp)) < 0,
 		   "Failed to read response");
-	
+
 	/* Parse speed-change reply */
 	FAILIF(resp.uart_prefix != HCI_EVENT_PKT,
-		   "Error in response: not an event packet, but 0x%02x!\n", 
+		   "Error in response: not an event packet, but 0x%02x!\n",
 		   resp.uart_prefix);
 
 	FAILIF(resp.hci_hdr.evt != EVT_CMD_COMPLETE, /* event must be event-complete */
@@ -135,7 +135,7 @@
 
 	fprintf(stdout, "Opening firmware file: %s\n", firmware);
 
-	FAILIF(fw < 0, 
+	FAILIF(fw < 0,
 		   "Could not open firmware file %s: %s (%d).\n",
 		   firmware, strerror(errno), errno);
 
@@ -151,17 +151,17 @@
 			break;
 		FAILIF(nr != sizeof(cmdp), "Could not read H4 + HCI header!\n");
 		FAILIF(*cmdp != HCI_COMMAND_PKT, "Command is not an H4 command packet!\n");
-		
+
 		FAILIF(read(fw, data, cmd->plen) != cmd->plen,
 			   "Could not read %d bytes of data for command with opcode %04x!\n",
 			   cmd->plen,
 			   cmd->opcode);
-				
+
 		{
 			int nw;
 #if 0
-			fprintf(stdout, "\topcode 0x%04x (%d bytes of data).\n", 
-					cmd->opcode, 
+			fprintf(stdout, "\topcode 0x%04x (%d bytes of data).\n",
+					cmd->opcode,
 					cmd->plen);
 #endif
 			struct iovec iov_cmd[2];
@@ -170,18 +170,18 @@
 			iov_cmd[1].iov_base = data;
 			iov_cmd[1].iov_len	= cmd->plen;
 			nw = writev(fd, iov_cmd, 2);
-			FAILIF(nw != (int) sizeof(cmd) +	cmd->plen, 
+			FAILIF(nw != (int) sizeof(cmd) +	cmd->plen,
 				   "Could not send entire command (sent only %d bytes)!\n",
 				   nw);
 		}
 
 		/* Wait for response */
-		if (read_command_complete(fd, 
+		if (read_command_complete(fd,
 								  cmd->opcode,
 								  cmd->plen) < 0) {
 			return -1;
 		}
-			
+
 	} while(1);
 	fprintf(stdout, "Firmware upload successful.\n");
 
@@ -198,7 +198,7 @@
 
 	memset(resp,'\0', 100);
 
-	/* It is possible to get software version with manufacturer specific 
+	/* It is possible to get software version with manufacturer specific
 	   HCI command HCI_VS_TI_Version_Number. But the only thing you get more
 	   is if this is point-to-point or point-to-multipoint module */
 
diff --git a/tools/hciconfig.8 b/tools/hciconfig.8
index 13f52c6..35956c4 100644
--- a/tools/hciconfig.8
+++ b/tools/hciconfig.8
@@ -10,6 +10,7 @@
 .br
 .B hciconfig
 .RB [\| \-a \|]
+.B hciX
 .RI [\| command
 .RI [\| "command parameters" \|]\|]
 
diff --git a/tools/hciconfig.c b/tools/hciconfig.c
index a89aed1..87dd127 100644
--- a/tools/hciconfig.c
+++ b/tools/hciconfig.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2000-2001  Qualcomm Incorporated
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -453,7 +453,7 @@
 	hci_close_dev(dd);
 }
 
-/* 
+/*
  * see http://www.bluetooth.org/assigned-numbers/baseband.htm --- all
  * strings are reproduced verbatim
  */
@@ -562,7 +562,7 @@
 		break;
 	case 5:	/* peripheral */ {
 		static char cls_str[48];
-		
+
 		cls_str[0] = '\0';
 
 		switch(minor & 48) {
@@ -944,7 +944,8 @@
 	lmpver = lmp_vertostr(ver.hci_ver);
 
 	print_dev_hdr(&di);
-	printf("\tHCI Ver: %s (0x%x) HCI Rev: 0x%x LMP Ver: %s (0x%x) LMP Subver: 0x%x\n"
+	printf("\tHCI Version: %s (0x%x)  Revision: 0x%x\n"
+		"\tLMP Version: %s (0x%x)  Subversion: 0x%x\n"
 		"\tManufacturer: %s (%d)\n",
 		hciver ? hciver : "n/a", ver.hci_ver, ver.hci_rev,
 		lmpver ? lmpver : "n/a", ver.lmp_ver, ver.lmp_subver,
@@ -980,7 +981,7 @@
 	} else {
 		int8_t level;
 
-		if (hci_read_inquiry_transmit_power_level(dd, &level, 1000) < 0) {
+		if (hci_read_inq_response_tx_power_level(dd, &level, 1000) < 0) {
 			fprintf(stderr, "Can't read inquiry transmit power level on hci%d: %s (%d)\n",
 						hdev, strerror(errno), errno);
 			exit(1);
@@ -1127,7 +1128,11 @@
 				}
 				break;
 			case 0x0a:
-				printf("\tTX power level: %d\n", *((uint8_t *) ptr));
+				printf("\tTX power level: %d\n", *((int8_t *) ptr));
+				break;
+			case 0x10:
+				printf("\tDevice ID with %d bytes data\n",
+								len - 1);
 				break;
 			default:
 				printf("\tUnknown type 0x%02x with %d bytes data\n",
@@ -1375,7 +1380,7 @@
 			exit(1);
 		}
 		print_dev_hdr(&di);
-		
+
 		timeout = btohs(rp.timeout);
 		printf("\tPage timeout: %u slots (%.2f ms)\n",
 				timeout, (float)timeout * 0.625);
@@ -1572,6 +1577,59 @@
 	return;
 }
 
+static void cmd_block(int ctl, int hdev, char *opt)
+{
+	bdaddr_t bdaddr;
+	int dd;
+
+	if (!opt)
+		return;
+
+	dd = hci_open_dev(hdev);
+	if (dd < 0) {
+		fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+						hdev, strerror(errno), errno);
+		exit(1);
+	}
+
+	str2ba(opt, &bdaddr);
+
+	if (ioctl(dd, HCIBLOCKADDR, &bdaddr) < 0) {
+		perror("ioctl(HCIBLOCKADDR)");
+		exit(1);
+	}
+
+	hci_close_dev(dd);
+}
+
+static void cmd_unblock(int ctl, int hdev, char *opt)
+{
+	bdaddr_t bdaddr;
+	int dd;
+
+	if (!opt)
+		return;
+
+	dd = hci_open_dev(hdev);
+	if (dd < 0) {
+		fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
+						hdev, strerror(errno), errno);
+		exit(1);
+	}
+
+	if (!strcasecmp(opt, "all"))
+		bacpy(&bdaddr, BDADDR_ANY);
+	else
+		str2ba(opt, &bdaddr);
+
+	if (ioctl(dd, HCIUNBLOCKADDR, &bdaddr) < 0) {
+		perror("ioctl(HCIUNBLOCKADDR)");
+		exit(1);
+	}
+
+	hci_close_dev(dd);
+}
+
 static void print_dev_hdr(struct hci_dev_info *di)
 {
 	static int hdr = -1;
@@ -1583,10 +1641,12 @@
 
 	ba2str(&di->bdaddr, addr);
 
-	printf("%s:\tType: %s\n", di->name, hci_dtypetostr(di->type) );
-	printf("\tBD Address: %s ACL MTU: %d:%d SCO MTU: %d:%d\n",
-		addr, di->acl_mtu, di->acl_pkts,
-		di->sco_mtu, di->sco_pkts);
+	printf("%s:\tType: %s  Bus: %s\n", di->name,
+					hci_typetostr(di->type >> 4),
+					hci_bustostr(di->type & 0x0f));
+	printf("\tBD Address: %s  ACL MTU: %d:%d  SCO MTU: %d:%d\n",
+					addr, di->acl_mtu, di->acl_pkts,
+						di->sco_mtu, di->sco_pkts);
 }
 
 static void print_dev_info(int ctl, struct hci_dev_info *di)
@@ -1666,6 +1726,8 @@
 	{ "features",	cmd_features,	0,		"Display device features" },
 	{ "version",	cmd_version,	0,		"Display version information" },
 	{ "revision",	cmd_revision,	0,		"Display revision information" },
+	{ "block",	cmd_block,	"<bdaddr>",	"Add a device to the blacklist" },
+	{ "unblock",	cmd_unblock,	"<bdaddr>",	"Remove a device from the blacklist" },
 	{ NULL, NULL, 0 }
 };
 
diff --git a/tools/hcieventmask.c b/tools/hcieventmask.c
index 0976e1f..37d1d0c 100644
--- a/tools/hcieventmask.c
+++ b/tools/hcieventmask.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/tools/hcisecfilter.c b/tools/hcisecfilter.c
index b3034da..9ad4ce0 100644
--- a/tools/hcisecfilter.c
+++ b/tools/hcisecfilter.c
@@ -3,7 +3,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -121,7 +121,7 @@
 	hci_set_bit(OCF_READ_AFH_MODE,			ocf_mask);
 	hci_set_bit(OCF_READ_EXT_INQUIRY_RESPONSE,	ocf_mask);
 	hci_set_bit(OCF_READ_SIMPLE_PAIRING_MODE,	ocf_mask);
-	hci_set_bit(OCF_READ_INQUIRY_TRANSMIT_POWER_LEVEL,	ocf_mask);
+	hci_set_bit(OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL,	ocf_mask);
 	hci_set_bit(OCF_READ_DEFAULT_ERROR_DATA_REPORTING,	ocf_mask);
 
 	printf("OGF_HOST_CTL:     { 0x%08x, 0x%08x, 0x%08x, 0x%02x }\n",
diff --git a/tools/hcitool.c b/tools/hcitool.c
index e8b5dd0..a91cbdf 100644
--- a/tools/hcitool.c
+++ b/tools/hcitool.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2000-2001  Qualcomm Incorporated
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -111,6 +111,7 @@
 		bt_free(str);
 	}
 
+	free(cl);
 	return 0;
 }
 
@@ -134,9 +135,12 @@
 	}
 
 	for (i = 0; i < cl->conn_num; i++, ci++)
-		if (!bacmp((bdaddr_t *) arg, &ci->bdaddr))
+		if (!bacmp((bdaddr_t *) arg, &ci->bdaddr)) {
+			free(cl);
 			return 1;
+		}
 
+	free(cl);
 	return 0;
 }
 
@@ -505,7 +509,6 @@
 	uint8_t lap[3] = { 0x33, 0x8b, 0x9e };
 	int num_rsp, length, flags;
 	uint8_t cls[3], features[8];
-	uint16_t handle;
 	char addr[18], name[249], oui[9], *comp, *tmp;
 	struct hci_version version;
 	struct hci_dev_info di;
@@ -605,6 +608,8 @@
 		printf("\n");
 
 	for (i = 0; i < num_rsp; i++) {
+		uint16_t handle = 0;
+
 		if (!refresh) {
 			memset(name, 0, sizeof(name));
 			tmp = get_device_name(&di.bdaddr, &(info+i)->bdaddr);
@@ -2349,6 +2354,240 @@
 	hci_close_dev(dd);
 }
 
+static int print_advertising_devices(int dd)
+{
+	unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr;
+	struct hci_filter nf, of;
+	socklen_t olen;
+	hci_event_hdr *hdr;
+	int num, len;
+
+	olen = sizeof(of);
+	if (getsockopt(dd, SOL_HCI, HCI_FILTER, &of, &olen) < 0) {
+		printf("Could not get socket options\n");
+		return -1;
+	}
+
+	hci_filter_clear(&nf);
+	hci_filter_set_ptype(HCI_EVENT_PKT, &nf);
+	hci_filter_set_event(EVT_LE_META_EVENT, &nf);
+
+	if (setsockopt(dd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0) {
+		printf("Could not set socket options\n");
+		return -1;
+	}
+
+	/* Wait for 10 report events */
+	num = 10;
+	while (num--) {
+		evt_le_meta_event *meta;
+		le_advertising_info *info;
+		char addr[18];
+
+		while ((len = read(dd, buf, sizeof(buf))) < 0) {
+			if (errno == EAGAIN || errno == EINTR)
+				continue;
+			goto done;
+		}
+
+		hdr = (void *) (buf + 1);
+		ptr = buf + (1 + HCI_EVENT_HDR_SIZE);
+		len -= (1 + HCI_EVENT_HDR_SIZE);
+
+		meta = (void *) ptr;
+
+		if (meta->subevent != 0x02)
+			goto done;
+
+		/* Ignoring multiple reports */
+		info = (le_advertising_info *) (meta->data + 1);
+		ba2str(&info->bdaddr, addr);
+		printf("%s\n", addr);
+	}
+
+done:
+	setsockopt(dd, SOL_HCI, HCI_FILTER, &of, sizeof(of));
+
+	if (len < 0)
+		return -1;
+
+	return 0;
+}
+
+static struct option lescan_options[] = {
+	{ "help",	0, 0, 'h' },
+	{ 0, 0, 0, 0 }
+};
+
+static const char *lescan_help =
+	"Usage:\n"
+	"\tlescan\n";
+
+static void cmd_lescan(int dev_id, int argc, char **argv)
+{
+	int err, opt, dd;
+
+	for_each_opt(opt, lescan_options, NULL) {
+		switch (opt) {
+		default:
+			printf("%s", lescan_help);
+			return;
+		}
+	}
+
+	dd = hci_open_dev(dev_id);
+	if (dd < 0) {
+		perror("Could not open device");
+		exit(1);
+	}
+
+	err = hci_le_set_scan_parameters(dd, 0x01, htobs(0x0010), htobs(0x0010),
+								0x00, 0x00);
+	if (err < 0) {
+		perror("Set scan parameters failed");
+		exit(1);
+	}
+
+	err = hci_le_set_scan_enable(dd, 0x01, 0x00);
+	if (err < 0) {
+		perror("Enable scan failed");
+		exit(1);
+	}
+
+	printf("LE Scan ...\n");
+
+	err = print_advertising_devices(dd);
+	if (err < 0) {
+		perror("Could not receive advertising events");
+		exit(1);
+	}
+
+	err = hci_le_set_scan_enable(dd, 0x00, 0x00);
+	if (err < 0) {
+		perror("Disable scan failed");
+		exit(1);
+	}
+
+	hci_close_dev(dd);
+}
+
+static struct option lecc_options[] = {
+	{ "help",	0, 0, 'h' },
+	{ 0, 0, 0, 0 }
+};
+
+static const char *lecc_help =
+	"Usage:\n"
+	"\tlecc <bdaddr>\n";
+
+static void cmd_lecc(int dev_id, int argc, char **argv)
+{
+	int err, opt, dd;
+	bdaddr_t bdaddr;
+	uint16_t interval, latency, max_ce_length, max_interval, min_ce_length;
+	uint16_t min_interval, supervision_timeout, window, handle;
+	uint8_t initiator_filter, own_bdaddr_type, peer_bdaddr_type;
+
+	for_each_opt(opt, lecc_options, NULL) {
+		switch (opt) {
+		default:
+			printf("%s", lecc_help);
+			return;
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 1) {
+		printf("%s", lecc_help);
+		return;
+	}
+
+	dd = hci_open_dev(dev_id);
+	if (dd < 0) {
+		perror("Could not open device");
+		exit(1);
+	}
+
+	str2ba(argv[0], &bdaddr);
+
+	interval = htobs(0x0004);
+	window = htobs(0x0004);
+	initiator_filter = 0x00;
+	peer_bdaddr_type = 0x00;
+	own_bdaddr_type = 0x00;
+	min_interval = htobs(0x000F);
+	max_interval = htobs(0x000F);
+	latency = htobs(0x0000);
+	supervision_timeout = htobs(0x0C80);
+	min_ce_length = htobs(0x0001);
+	max_ce_length = htobs(0x0001);
+
+	err = hci_le_create_conn(dd, interval, window, initiator_filter,
+			peer_bdaddr_type, bdaddr, own_bdaddr_type, min_interval,
+			max_interval, latency, supervision_timeout,
+			min_ce_length, max_ce_length, &handle, 25000);
+	if (err < 0) {
+		perror("Could not create connection");
+		exit(1);
+	}
+
+	printf("Connection handle %d\n", handle);
+
+	hci_close_dev(dd);
+}
+
+static struct option ledc_options[] = {
+	{ "help",	0, 0, 'h' },
+	{ 0, 0, 0, 0 }
+};
+
+static const char *ledc_help =
+	"Usage:\n"
+	"\tledc <handle> [reason]\n";
+
+static void cmd_ledc(int dev_id, int argc, char **argv)
+{
+	int err, opt, dd;
+	uint16_t handle;
+	uint8_t reason;
+
+	for_each_opt(opt, ledc_options, NULL) {
+		switch (opt) {
+		default:
+			printf("%s", ledc_help);
+			return;
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 1) {
+		printf("%s", ledc_help);
+		return;
+	}
+
+	dd = hci_open_dev(dev_id);
+	if (dd < 0) {
+		perror("Could not open device");
+		exit(1);
+	}
+
+	handle = atoi(argv[0]);
+
+	reason = (argc > 1) ? atoi(argv[1]) : HCI_OE_USER_ENDED_CONNECTION;
+
+	err = hci_disconnect(dd, handle, reason, 10000);
+	if (err < 0) {
+		perror("Could not disconnect");
+		exit(1);
+	}
+
+	hci_close_dev(dd);
+}
+
 static struct {
 	char *cmd;
 	void (*func)(int dev_id, int argc, char **argv);
@@ -2378,6 +2617,9 @@
 	{ "key",    cmd_key,    "Change connection link key"           },
 	{ "clkoff", cmd_clkoff, "Read clock offset"                    },
 	{ "clock",  cmd_clock,  "Read local or remote clock"           },
+	{ "lescan", cmd_lescan, "Start LE scan"                        },
+	{ "lecc",   cmd_lecc,   "Create a LE Connection",              },
+	{ "ledc",   cmd_ledc,   "Disconnect a LE Connection",          },
 	{ NULL, NULL, 0 }
 };
 
diff --git a/tools/hid2hci.c b/tools/hid2hci.c
index 11d707f..a640772 100644
--- a/tools/hid2hci.c
+++ b/tools/hid2hci.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2003-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/rfcomm/kword.c b/tools/kword.c
similarity index 95%
rename from rfcomm/kword.c
rename to tools/kword.c
index 659f293..62e24fe 100644
--- a/rfcomm/kword.c
+++ b/tools/kword.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/rfcomm/kword.h b/tools/kword.h
similarity index 91%
rename from rfcomm/kword.h
rename to tools/kword.h
index ccc0cc7..81a2a88 100644
--- a/rfcomm/kword.h
+++ b/tools/kword.h
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,7 @@
 	int type;
 };
 
-extern struct keyword_t rfcomm_keyword[]; 
+extern struct keyword_t rfcomm_keyword[];
 
 int rfcomm_find_keyword(struct keyword_t *keyword, char *string);
 
diff --git a/tools/l2ping.c b/tools/l2ping.c
index 55597cc..29fb3d0 100644
--- a/tools/l2ping.c
+++ b/tools/l2ping.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2000-2001  Qualcomm Incorporated
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -240,6 +240,8 @@
 			id = ident;
 	}
 	stat(0);
+	free(send_buf);
+	free(recv_buf);
 	return;
 
 error:
diff --git a/rfcomm/lexer.c b/tools/lexer.c
similarity index 100%
rename from rfcomm/lexer.c
rename to tools/lexer.c
diff --git a/rfcomm/lexer.l b/tools/lexer.l
similarity index 96%
rename from rfcomm/lexer.l
rename to tools/lexer.l
index e15c8ab..ff9ce81 100644
--- a/rfcomm/lexer.l
+++ b/tools/lexer.l
@@ -3,7 +3,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/rfcomm/main.c b/tools/main.c
similarity index 98%
rename from rfcomm/main.c
rename to tools/main.c
index ed82432..6800445 100644
--- a/rfcomm/main.c
+++ b/tools/main.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -118,7 +118,7 @@
 
 	printf("rfcomm%d: %s channel %d %s %s\n",
 		di->id, addr, di->channel,
-		rfcomm_state[di->state], 
+		rfcomm_state[di->state],
 		di->flags ? rfcomm_flagstostr(di->flags) : "");
 }
 
@@ -139,11 +139,13 @@
 
 	if (ioctl(ctl, RFCOMMGETDEVLIST, (void *) dl) < 0) {
 		perror("Can't get device list");
+		free(dl);
 		exit(1);
 	}
 
 	for (i = 0; i < dl->dev_num; i++)
 		print_dev_info(di + i);
+	free(dl);
 }
 
 static int create_dev(int ctl, int dev, uint32_t flags, bdaddr_t *bdaddr, int argc, char **argv)
@@ -249,12 +251,14 @@
 
 	if (ioctl(ctl, RFCOMMGETDEVLIST, (void *) dl) < 0) {
 		perror("Can't get device list");
+		free(dl);
 		exit(1);
 	}
 
 	for (i = 0; i < dl->dev_num; i++)
 		release_dev(ctl, (di + i)->id, 0);
 
+	free(dl);
 	return 0;
 }
 
@@ -713,7 +717,7 @@
 		"\t-E, --encrypt         Enable encryption\n"
 		"\t-S, --secure          Secure connection\n"
 		"\t-M, --master          Become the master of a piconet\n"
-		"\t-f, --config [file]   Specify alternate config file\n" 
+		"\t-f, --config [file]   Specify alternate config file\n"
 		"\t-a                    Show all devices (default)\n"
 		"\n");
 
@@ -739,7 +743,7 @@
 	{ 0, 0, 0, 0 }
 };
 
-int main(int argc, char *argv[]) 
+int main(int argc, char *argv[])
 {
 	bdaddr_t bdaddr;
 	int i, opt, ctl, dev_id, show_all = 0;
diff --git a/rfcomm/parser.c b/tools/parser.c
similarity index 100%
rename from rfcomm/parser.c
rename to tools/parser.c
diff --git a/rfcomm/parser.h b/tools/parser.h
similarity index 100%
rename from rfcomm/parser.h
rename to tools/parser.h
diff --git a/rfcomm/parser.y b/tools/parser.y
similarity index 97%
rename from rfcomm/parser.y
rename to tools/parser.y
index c550e2f..96e6a56 100644
--- a/rfcomm/parser.y
+++ b/tools/parser.y
@@ -3,7 +3,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2002-2008  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/tools/ppporc.c b/tools/ppporc.c
index ea42c0c..ca44b40 100644
--- a/tools/ppporc.c
+++ b/tools/ppporc.c
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -147,7 +147,7 @@
 
 	p[0].fd = 0;
 	p[0].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
-	
+
 	p[1].fd = fd;
 	p[1].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
 
@@ -156,7 +156,7 @@
 	while (!__io_canceled) {
 		p[0].revents = 0;
 		p[1].revents = 0;
-		
+
 		err = poll(p, 2, -1);
 		if (err < 0)
 			break;
diff --git a/rfcomm/rfcomm.1 b/tools/rfcomm.1
similarity index 100%
rename from rfcomm/rfcomm.1
rename to tools/rfcomm.1
diff --git a/rfcomm/rfcomm.conf b/tools/rfcomm.conf
similarity index 100%
rename from rfcomm/rfcomm.conf
rename to tools/rfcomm.conf
diff --git a/tools/sdptool.c b/tools/sdptool.c
index 46ff101..6cf3fdb 100644
--- a/tools/sdptool.c
+++ b/tools/sdptool.c
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2001-2002  Nokia Corporation
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com>
  *  Copyright (C) 2002-2003  Jean Tourrilhes <jt@hpl.hp.com>
  *
@@ -322,9 +322,9 @@
 	{ 0x1303, "VideoSource", NULL, 0 },
 	{ 0x1304, "VideoSink", NULL, 0 },
 	{ 0x1305, "VideoDistribution", NULL, 0 },
-	{ 0x1400, "MDP", NULL, 0 },
-	{ 0x1401, "MDPSource", NULL, 0 },
-	{ 0x1402, "MDPSink", NULL, 0 },
+	{ 0x1400, "HDP", NULL, 0 },
+	{ 0x1401, "HDPSource", NULL, 0 },
+	{ 0x1402, "HDPSink", NULL, 0 },
 	{ 0x2112, "AppleAgent", NULL, 0 },
 };
 
@@ -513,14 +513,16 @@
  */
 static void print_tree_attr_func(void *value, void *userData)
 {
-	sdp_data_t *sdpdata = NULL;
+	sdp_data_t *sdpdata = value;
 	uint16_t attrId;
 	struct service_context *service = (struct service_context *) userData;
 	struct attrib_context context;
 	struct attrib_def *attrDef = NULL;
 	int i;
 
-	sdpdata = (sdp_data_t *)value;
+	if (!sdpdata)
+		return;
+
 	attrId = sdpdata->attrId;
 	/* Search amongst the generic attributes */
 	for (i = 0; i < attrib_max; i++)
@@ -549,10 +551,7 @@
 	context.attrib = attrDef;
 	context.member_index = 0;
 	/* Parse attribute members */
-	if (sdpdata)
-		sdp_data_printf(sdpdata, &context, 2);
-	else
-		printf("  NULL value\n");
+	sdp_data_printf(sdpdata, &context, 2);
 	/* Update service */
 	service->service = context.service;
 }
@@ -723,6 +722,9 @@
 	struct attrib_def *def = NULL;
 	int i;
 
+	if (!data)
+		return;
+
 	/* Search amongst the generic attributes */
 	for (i = 0; i < attrib_max; i++)
 		if (attrib_names[i].num == data->attrId) {
@@ -735,10 +737,7 @@
 	else
 		printf("\tAttribute 0x%04x\n", data->attrId);
 
-	if (data)
-		print_raw_data(data, 2);
-	else
-		printf("  NULL value\n");
+	print_raw_data(data, 2);
 }
 
 static void print_raw_attr(sdp_record_t *rec)
@@ -753,7 +752,7 @@
  * Set attributes with single values in SDP record
  * Jean II
  */
-static int set_attrib(sdp_session_t *sess, uint32_t handle, uint16_t attrib, char *value) 
+static int set_attrib(sdp_session_t *sess, uint32_t handle, uint16_t attrib, char *value)
 {
 	sdp_list_t *attrid_list;
 	uint32_t range = 0x0000ffff;
@@ -783,7 +782,7 @@
 		sdp_attr_add_new(rec, attrib, SDP_UUID16, &value_uuid.value.uuid16);
 	} else if (!strncasecmp(value, "0x", 2)) {
 		/* Int */
-		uint32_t value_int;  
+		uint32_t value_int;
 		value_int = strtoul(value + 2, NULL, 16);
 		printf("Adding attrib 0x%X int 0x%X to record 0x%X\n",
 			attrib, value_int, handle);
@@ -811,7 +810,7 @@
 	{ 0, 0, 0, 0 }
 };
 
-static const char *set_help = 
+static const char *set_help =
 	"Usage:\n"
 	"\tget record_handle attrib_id attrib_value\n";
 
@@ -949,7 +948,7 @@
 	{ 0, 0, 0, 0 }
 };
 
-static const char *seq_help = 
+static const char *seq_help =
 	"Usage:\n"
 	"\tget record_handle attrib_id attrib_values\n";
 
@@ -1688,7 +1687,7 @@
 	sdp_record_t record;
 	uint8_t u8 = si->channel? si->channel : 8;
 	uint16_t u16 = 0x31;
-	sdp_data_t *channel, *features;	
+	sdp_data_t *channel, *features;
 	int ret = 0;
 
 	memset((void *)&record, 0, sizeof(sdp_record_t));
@@ -1832,8 +1831,6 @@
 	uint8_t chan = si->channel ? si->channel : 19;
 	sdp_data_t *channel;
 	uint8_t formats[] = {0x01};
-	void *dtds[sizeof(formats)], *values[sizeof(formats)];
-	int i;
 	uint8_t dtd = SDP_UINT8;
 	sdp_data_t *sflist;
 	int ret = 0;
@@ -2255,7 +2252,7 @@
 	static const uint16_t intr = 0x13;
 	static const uint16_t hid_attr[] = { 0x100, 0x111, 0x40, 0x0d, 0x01, 0x01 };
 	static const uint16_t hid_attr2[] = { 0x0, 0x01, 0x100, 0x1f40, 0x01, 0x01 };
-	const uint8_t hid_spec[] = { 
+	const uint8_t hid_spec[] = {
 		0x05, 0x01, // usage page
 		0x09, 0x06, // keyboard
 		0xa1, 0x01, // key codes
@@ -2268,14 +2265,14 @@
 		0x75, 0x01, // input data variable absolute
 		0x95, 0x08, // report count
 		0x81, 0x02, // report size
-		0x75, 0x08, 
-		0x95, 0x01, 
-		0x81, 0x01, 
-		0x75, 0x01, 
+		0x75, 0x08,
+		0x95, 0x01,
+		0x81, 0x01,
+		0x75, 0x01,
 		0x95, 0x05,
 		0x05, 0x08,
 		0x19, 0x01,
-		0x29, 0x05, 
+		0x29, 0x05,
 		0x91, 0x02,
 		0x75, 0x03,
 		0x95, 0x01,
@@ -3531,7 +3528,7 @@
 	{ 0, 0, 0, 0 }
 };
 
-static const char *add_help = 
+static const char *add_help =
 	"Usage:\n"
 	"\tadd [--handle=RECORD_HANDLE --channel=CHANNEL] service\n";
 
@@ -3596,7 +3593,7 @@
 	sdp_session_t *sess;
 	sdp_record_t *rec;
 
-	if (!arg) { 
+	if (!arg) {
 		printf("Record handle was not specified.\n");
 		return -1;
 	}
@@ -3635,7 +3632,7 @@
 	{ 0, 0, 0, 0 }
 };
 
-static const char *del_help = 
+static const char *del_help =
 	"Usage:\n"
 	"\tdel record_handle\n";
 
@@ -3776,7 +3773,7 @@
 	{ 0, 0, 0, 0 }
 };
 
-static const char *browse_help = 
+static const char *browse_help =
 	"Usage:\n"
 	"\tbrowse [--tree] [--raw] [--xml] [--uuid uuid] [--l2cap] [bdaddr]\n";
 
@@ -3842,7 +3839,7 @@
 	{ 0, 0, 0, 0}
 };
 
-static const char *search_help = 
+static const char *search_help =
 	"Usage:\n"
 	"\tsearch [--bdaddr bdaddr] [--tree] [--raw] [--xml] SERVICE\n"
 	"SERVICE is a name (string) or UUID (0x1002)\n";
@@ -4001,7 +3998,7 @@
 	{ 0, 0, 0, 0 }
 };
 
-static const char *records_help = 
+static const char *records_help =
 	"Usage:\n"
 	"\trecords [--tree] [--raw] [--xml] bdaddr\n";
 
@@ -4071,7 +4068,7 @@
 	{ 0, 0, 0, 0 }
 };
 
-static const char *get_help = 
+static const char *get_help =
 	"Usage:\n"
 	"\tget [--tree] [--raw] [--xml] [--bdaddr bdaddr] record_handle\n";
 
diff --git a/tracer/main.c b/tracer/main.c
new file mode 100644
index 0000000..0806ffe
--- /dev/null
+++ b/tracer/main.c
@@ -0,0 +1,152 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <syslog.h>
+
+#include <glib.h>
+
+#ifdef HAVE_CAPNG
+#include <cap-ng.h>
+#endif
+
+static GMainLoop *event_loop;
+
+static void sig_term(int sig)
+{
+	g_main_loop_quit(event_loop);
+}
+
+static gboolean option_detach = TRUE;
+static gboolean option_debug = FALSE;
+
+static GOptionEntry options[] = {
+	{ "nodaemon", 'n', G_OPTION_FLAG_REVERSE,
+				G_OPTION_ARG_NONE, &option_detach,
+				"Don't run as daemon in background" },
+	{ "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug,
+				"Enable debug information output" },
+	{ NULL },
+};
+
+static void debug(const char *format, ...)
+{
+	va_list ap;
+
+	if (!option_debug)
+		return;
+
+	va_start(ap, format);
+
+	vsyslog(LOG_DEBUG, format, ap);
+
+	va_end(ap);
+}
+
+static void sig_debug(int sig)
+{
+	option_debug = !option_debug;
+}
+
+int main(int argc, char *argv[])
+{
+	GOptionContext *context;
+	GError *err = NULL;
+	struct sigaction sa;
+
+#ifdef HAVE_CAPNG
+	/* Drop capabilities */
+	capng_clear(CAPNG_SELECT_BOTH);
+	capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
+					CAP_NET_BIND_SERVICE, CAP_NET_ADMIN,
+						CAP_NET_RAW, CAP_IPC_LOCK, -1);
+	capng_apply(CAPNG_SELECT_BOTH);
+#endif
+
+	context = g_option_context_new(NULL);
+	g_option_context_add_main_entries(context, options, NULL);
+
+	if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
+		if (err != NULL) {
+			g_printerr("%s\n", err->message);
+			g_error_free(err);
+		} else
+			g_printerr("An unknown error occurred\n");
+		exit(1);
+	}
+
+	g_option_context_free(context);
+
+	if (option_detach == TRUE) {
+		if (daemon(0, 0)) {
+			perror("Can't start daemon");
+			exit(1);
+		}
+	}
+
+	umask(0077);
+
+	openlog("hcitrace", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
+
+	syslog(LOG_INFO, "HCI trace deamon %s", VERSION);
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_flags = SA_NOCLDSTOP;
+	sa.sa_handler = sig_term;
+	sigaction(SIGTERM, &sa, NULL);
+	sigaction(SIGINT,  &sa, NULL);
+
+	sa.sa_handler = sig_debug;
+	sigaction(SIGUSR2, &sa, NULL);
+
+	sa.sa_handler = SIG_IGN;
+	sigaction(SIGPIPE, &sa, NULL);
+
+	if (option_debug == TRUE) {
+		syslog(LOG_INFO, "Enabling debug information");
+	}
+
+	event_loop = g_main_loop_new(NULL, FALSE);
+
+	debug("Entering main loop");
+
+	g_main_loop_run(event_loop);
+
+	g_main_loop_unref(event_loop);
+
+	syslog(LOG_INFO, "Exit");
+
+	closelog();
+
+	return 0;
+}