[meego-commits] 5880: Changes to Trunk/bluez

Anas Nashif nashif at linux.intel.com
Tue Jul 20 22:43:08 UTC 2010


Hi,
I have made the following changes to bluez in project Trunk. Please review and accept ASAP.

Thank You,
Anas Nashif

[This message was auto-generated]

---

Request #5880:

  submit:   Trunk:Testing/bluez(r13) -> Trunk/bluez


Message:
    Move to Trunk

State:   new          2010-07-20T10:37:10 nashif
Comment: None



changes files:
--------------
--- bluez.changes
+++ bluez.changes
@@ -0,0 +1,3 @@
+* Mon Jul 19 2010 Zhu Yanhai <yanhai.zhu at linux.intel.com> 4.69
+- Upgrade to 4.69
+

old:
----
  bluez-4.66.tar.gz

new:
----
  bluez-4.69.tar.gz

spec files:
-----------
--- bluez.spec
+++ bluez.spec
@@ -1,13 +1,13 @@
 # 
-# Do NOT Edit the Auto-generated Part!
-# Generated by: spectacle version 0.19~pre
+# Do not Edit! Generated by:
+# spectacle version 0.17
 # 
 # >> macros
 # << macros
 
 Name:       bluez
 Summary:    Bluetooth utilities
-Version:    4.66
+Version:    4.69
 Release:    1
 Group:      Applications/System
 License:    GPLv2+

other changes:
--------------

++++++ bluez-4.66.tar.gz -> bluez-4.69.tar.gz
--- ChangeLog
+++ ChangeLog
@@ -1,3 +1,25 @@
+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.
--- Makefile.am
+++ Makefile.am
@@ -53,7 +53,7 @@
 
 lib_libbluetooth_la_SOURCES = $(lib_headers) \
 					lib/bluetooth.c lib/hci.c lib/sdp.c
-lib_libbluetooth_la_LDFLAGS = -version-info 11:0:8
+lib_libbluetooth_la_LDFLAGS = -version-info 12:0:9
 lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
 
 CLEANFILES += $(local_headers)
@@ -65,7 +65,8 @@
 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_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
@@ -159,7 +160,6 @@
 			network/manager.h network/manager.c \
 			network/common.h network/common.c \
 			network/server.h network/server.c \
-			network/bridge.h network/bridge.c \
 			network/connection.h network/connection.c
 endif
 
@@ -177,6 +177,11 @@
 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) \
@@ -306,7 +311,7 @@
 
 EXTRA_DIST += doc/manager-api.txt \
 		doc/adapter-api.txt doc/device-api.txt \
-		doc/service-api.txt doc/agent-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
 
--- Makefile.in
+++ Makefile.in
@@ -88,11 +88,12 @@
 @NETWORKPLUGIN_TRUE@			network/manager.h network/manager.c \
 @NETWORKPLUGIN_TRUE@			network/common.h network/common.c \
 @NETWORKPLUGIN_TRUE@			network/server.h network/server.c \
- at NETWORKPLUGIN_TRUE@			network/bridge.h network/bridge.c \
 @NETWORKPLUGIN_TRUE@			network/connection.h network/connection.c
 
 @SERVICEPLUGIN_TRUE at am__append_18 = service
 @SERVICEPLUGIN_TRUE at am__append_19 = plugins/service.c
+ at MAEMO6PLUGIN_TRUE@am__append_20 = maemo6
+ at MAEMO6PLUGIN_TRUE@am__append_21 = plugins/maemo6.c
 DIST_COMMON = README $(am__configure_deps) \
 	$(am__dist_udev_SCRIPTS_DIST) $(dist_man_MANS) \
 	$(include_HEADERS) $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
@@ -104,57 +105,57 @@
 	ChangeLog INSTALL NEWS compile config.guess config.sub depcomp \
 	install-sh ltmain.sh missing tools/lexer.c tools/parser.c \
 	tools/parser.h ylwrap
- at CONFIGFILES_TRUE@@TOOLS_TRUE at am__append_20 = tools/rfcomm.conf
- at TOOLS_TRUE@am__append_21 = tools/rfcomm tools/l2ping \
+ at CONFIGFILES_TRUE@@TOOLS_TRUE at am__append_22 = tools/rfcomm.conf
+ at TOOLS_TRUE@am__append_23 = tools/rfcomm tools/l2ping \
 @TOOLS_TRUE@				tools/hcitool tools/sdptool tools/ciptool
 
- at TOOLS_TRUE@am__append_22 = tools/hciattach tools/hciconfig
- at TOOLS_TRUE@am__append_23 = tools/avinfo tools/ppporc \
+ at TOOLS_TRUE@am__append_24 = tools/hciattach tools/hciconfig
+ at TOOLS_TRUE@am__append_25 = tools/avinfo tools/ppporc \
 @TOOLS_TRUE@				tools/hcieventmask tools/hcisecfilter
 
- at TOOLS_TRUE@am__append_24 = tools/rfcomm.1 tools/l2ping.8 \
+ at TOOLS_TRUE@am__append_26 = tools/rfcomm.1 tools/l2ping.8 \
 @TOOLS_TRUE@			tools/hciattach.8 tools/hciconfig.8 \
 @TOOLS_TRUE@			tools/hcitool.1 tools/sdptool.1 tools/ciptool.1
 
- at TOOLS_FALSE@am__append_25 = tools/rfcomm.1 tools/l2ping.8 \
+ at TOOLS_FALSE@am__append_27 = tools/rfcomm.1 tools/l2ping.8 \
 @TOOLS_FALSE@			tools/hciattach.8 tools/hciconfig.8 \
 @TOOLS_FALSE@			tools/hcitool.1 tools/sdptool.1 tools/ciptool.1
 
- at TRACER_TRUE@am__append_26 = tracer/hcitrace
- at BCCMD_TRUE@am__append_27 = tools/bccmd
- at BCCMD_TRUE@@USB_TRUE at am__append_28 = tools/csr_usb.c
- at BCCMD_TRUE@@USB_TRUE at am__append_29 = @USB_LIBS@
- at BCCMD_TRUE@am__append_30 = tools/bccmd.8
- at BCCMD_FALSE@am__append_31 = tools/bccmd.8
- at HID2HCI_TRUE@am__append_32 = tools/hid2hci
- at HID2HCI_TRUE@am__append_33 = tools/hid2hci.8
- at HID2HCI_FALSE@am__append_34 = tools/hid2hci.8
- at DFUTOOL_TRUE@am__append_35 = tools/dfutool
- at DFUTOOL_TRUE@am__append_36 = tools/dfutool.1
- at DFUTOOL_FALSE@am__append_37 = tools/dfutool.1
- at USB_TRUE@am__append_38 = tools/dfubabel tools/avctrl
+ at TRACER_TRUE@am__append_28 = tracer/hcitrace
+ at BCCMD_TRUE@am__append_29 = tools/bccmd
+ at BCCMD_TRUE@@USB_TRUE at am__append_30 = tools/csr_usb.c
+ at BCCMD_TRUE@@USB_TRUE at am__append_31 = @USB_LIBS@
+ at BCCMD_TRUE@am__append_32 = tools/bccmd.8
+ at BCCMD_FALSE@am__append_33 = tools/bccmd.8
+ at HID2HCI_TRUE@am__append_34 = tools/hid2hci
+ at HID2HCI_TRUE@am__append_35 = tools/hid2hci.8
+ at HID2HCI_FALSE@am__append_36 = tools/hid2hci.8
+ at DFUTOOL_TRUE@am__append_37 = tools/dfutool
+ at DFUTOOL_TRUE@am__append_38 = tools/dfutool.1
+ at DFUTOOL_FALSE@am__append_39 = tools/dfutool.1
+ at USB_TRUE@am__append_40 = tools/dfubabel tools/avctrl
 @CUPS_TRUE at cups_PROGRAMS = cups/bluetooth$(EXEEXT)
- at TEST_TRUE@am__append_39 = test/hciemu
- at TEST_TRUE@am__append_40 = test/l2test test/rctest
- at TEST_TRUE@am__append_41 = test/gaptest test/sdptest test/scotest \
+ at TEST_TRUE@am__append_41 = test/hciemu
+ at TEST_TRUE@am__append_42 = test/l2test test/rctest
+ at TEST_TRUE@am__append_43 = test/gaptest test/sdptest test/scotest \
 @TEST_TRUE@			test/attest test/hstest test/avtest test/ipctest \
 @TEST_TRUE@					test/lmptest test/bdaddr test/agent \
 @TEST_TRUE@					test/btiotest test/test-textfile
 
- at TEST_TRUE@am__append_42 = test/rctest.1 test/hciemu.1
- at TEST_TRUE@am__append_43 = test/bdaddr.8
- at TEST_FALSE@am__append_44 = test/rctest.1 test/hciemu.1 test/bdaddr.8
- at HIDD_TRUE@am__append_45 = compat/hidd
- at HIDD_TRUE@am__append_46 = compat/hidd.1
- at HIDD_FALSE@am__append_47 = compat/hidd.1
- at PAND_TRUE@am__append_48 = compat/pand
- at PAND_TRUE@am__append_49 = compat/pand.1
- at PAND_FALSE@am__append_50 = compat/pand.1
- at DUND_TRUE@am__append_51 = compat/dund
- at DUND_TRUE@am__append_52 = compat/dund.1
- at DUND_FALSE@am__append_53 = compat/dund.1
- at HID2HCI_TRUE@@UDEVRULES_TRUE at am__append_54 = scripts/bluetooth-hid2hci.rules
- at PCMCIA_TRUE@@UDEVRULES_TRUE at am__append_55 = scripts/bluetooth-serial.rules
+ at TEST_TRUE@am__append_44 = test/rctest.1 test/hciemu.1
+ at TEST_TRUE@am__append_45 = test/bdaddr.8
+ at TEST_FALSE@am__append_46 = test/rctest.1 test/hciemu.1 test/bdaddr.8
+ at HIDD_TRUE@am__append_47 = compat/hidd
+ at HIDD_TRUE@am__append_48 = compat/hidd.1
+ at HIDD_FALSE@am__append_49 = compat/hidd.1
+ at PAND_TRUE@am__append_50 = compat/pand
+ at PAND_TRUE@am__append_51 = compat/pand.1
+ at PAND_FALSE@am__append_52 = compat/pand.1
+ at DUND_TRUE@am__append_53 = compat/dund
+ at DUND_TRUE@am__append_54 = compat/dund.1
+ at DUND_FALSE@am__append_55 = compat/dund.1
+ at HID2HCI_TRUE@@UDEVRULES_TRUE at am__append_56 = scripts/bluetooth-hid2hci.rules
+ at PCMCIA_TRUE@@UDEVRULES_TRUE at am__append_57 = scripts/bluetooth-serial.rules
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
@@ -301,11 +302,13 @@
 am__sbc_libsbc_la_SOURCES_DIST = 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_neon.h sbc/sbc_primitives_neon.c \
+	sbc/sbc_primitives_armv6.h sbc/sbc_primitives_armv6.c
 @SBC_TRUE at am_sbc_libsbc_la_OBJECTS = sbc/sbc_libsbc_la-sbc.lo \
 @SBC_TRUE@	sbc/sbc_libsbc_la-sbc_primitives.lo \
 @SBC_TRUE@	sbc/sbc_libsbc_la-sbc_primitives_mmx.lo \
- at SBC_TRUE@	sbc/sbc_libsbc_la-sbc_primitives_neon.lo
+ at SBC_TRUE@	sbc/sbc_libsbc_la-sbc_primitives_neon.lo \
+ at SBC_TRUE@	sbc/sbc_libsbc_la-sbc_primitives_armv6.lo
 sbc_libsbc_la_OBJECTS = $(am_sbc_libsbc_la_OBJECTS)
 sbc_libsbc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(sbc_libsbc_la_CFLAGS) \
@@ -403,20 +406,20 @@
 	serial/manager.c serial/proxy.h serial/proxy.c serial/port.h \
 	serial/port.c network/main.c network/manager.h \
 	network/manager.c network/common.h network/common.c \
-	network/server.h network/server.c network/bridge.h \
-	network/bridge.c network/connection.h network/connection.c \
-	plugins/service.c plugins/hciops.c plugins/hal.c \
-	plugins/storage.c 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
+	network/server.h network/server.c network/connection.h \
+	network/connection.c plugins/service.c plugins/hciops.c \
+	plugins/hal.c plugins/storage.c plugins/maemo6.c 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
 @PNATPLUGIN_TRUE at am__objects_3 = plugins/pnat.$(OBJEXT)
 @ECHOPLUGIN_TRUE at am__objects_4 = plugins/echo.$(OBJEXT)
 @AUDIOPLUGIN_TRUE at am__objects_5 = audio/main.$(OBJEXT) \
@@ -441,14 +444,15 @@
 @NETWORKPLUGIN_TRUE@	network/manager.$(OBJEXT) \
 @NETWORKPLUGIN_TRUE@	network/common.$(OBJEXT) \
 @NETWORKPLUGIN_TRUE@	network/server.$(OBJEXT) \
- at NETWORKPLUGIN_TRUE@	network/bridge.$(OBJEXT) \
 @NETWORKPLUGIN_TRUE@	network/connection.$(OBJEXT)
 @SERVICEPLUGIN_TRUE at am__objects_9 = plugins/service.$(OBJEXT)
-am__objects_10 = $(am__objects_3) $(am__objects_4) $(am__objects_5) \
+ at MAEMO6PLUGIN_TRUE@am__objects_10 = plugins/maemo6.$(OBJEXT)
+am__objects_11 = $(am__objects_3) $(am__objects_4) $(am__objects_5) \
 	$(am__objects_6) $(am__objects_7) $(am__objects_8) \
 	$(am__objects_9) plugins/hciops.$(OBJEXT) \
-	plugins/hal.$(OBJEXT) plugins/storage.$(OBJEXT)
-am_src_bluetoothd_OBJECTS = $(am__objects_2) $(am__objects_10) \
+	plugins/hal.$(OBJEXT) plugins/storage.$(OBJEXT) \
+	$(am__objects_10)
+am_src_bluetoothd_OBJECTS = $(am__objects_2) $(am__objects_11) \
 	src/main.$(OBJEXT) src/log.$(OBJEXT) src/security.$(OBJEXT) \
 	src/rfkill.$(OBJEXT) src/sdpd-server.$(OBJEXT) \
 	src/sdpd-request.$(OBJEXT) src/sdpd-service.$(OBJEXT) \
@@ -459,10 +463,10 @@
 	src/error.$(OBJEXT) src/manager.$(OBJEXT) \
 	src/adapter.$(OBJEXT) src/device.$(OBJEXT) \
 	src/dbus-common.$(OBJEXT) src/dbus-hci.$(OBJEXT)
- at AUDIOPLUGIN_TRUE@am__objects_11 = audio/telephony.$(OBJEXT)
-am__objects_12 = $(am__objects_11)
+ at AUDIOPLUGIN_TRUE@am__objects_12 = audio/telephony.$(OBJEXT)
 am__objects_13 = $(am__objects_12)
-nodist_src_bluetoothd_OBJECTS = $(am__objects_13)
+am__objects_14 = $(am__objects_13)
+nodist_src_bluetoothd_OBJECTS = $(am__objects_14)
 src_bluetoothd_OBJECTS = $(am_src_bluetoothd_OBJECTS) \
 	$(nodist_src_bluetoothd_OBJECTS)
 src_bluetoothd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
@@ -532,12 +536,12 @@
 am__tools_bccmd_SOURCES_DIST = 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/csr_usb.c
- at BCCMD_TRUE@@USB_TRUE at am__objects_14 = tools/csr_usb.$(OBJEXT)
+ at BCCMD_TRUE@@USB_TRUE at am__objects_15 = tools/csr_usb.$(OBJEXT)
 @BCCMD_TRUE at am_tools_bccmd_OBJECTS = tools/bccmd.$(OBJEXT) \
 @BCCMD_TRUE@	tools/csr.$(OBJEXT) tools/csr_hci.$(OBJEXT) \
 @BCCMD_TRUE@	tools/csr_h4.$(OBJEXT) tools/csr_3wire.$(OBJEXT) \
 @BCCMD_TRUE@	tools/csr_bcsp.$(OBJEXT) tools/ubcsp.$(OBJEXT) \
- at BCCMD_TRUE@	$(am__objects_14)
+ at BCCMD_TRUE@	$(am__objects_15)
 tools_bccmd_OBJECTS = $(am_tools_bccmd_OBJECTS)
 am__DEPENDENCIES_1 =
 @BCCMD_TRUE at tools_bccmd_DEPENDENCIES = lib/libbluetooth.la \
@@ -861,9 +865,9 @@
 AM_MAKEFLAGS = --no-print-directory
 lib_LTLIBRARIES = lib/libbluetooth.la
 noinst_LTLIBRARIES = $(am__append_1)
-dist_man_MANS = $(am__append_24) $(am__append_30) $(am__append_33) \
-	$(am__append_36) $(am__append_42) $(am__append_46) \
-	$(am__append_49) $(am__append_52)
+dist_man_MANS = $(am__append_26) $(am__append_32) $(am__append_35) \
+	$(am__append_38) $(am__append_44) $(am__append_48) \
+	$(am__append_51) $(am__append_54)
 dist_noinst_MANS = 
 CLEANFILES = $(local_headers) src/bluetooth.ver src/bluetooth.exp \
 	$(builtin_files) tools/lexer.c tools/parser.c tools/parser.h \
@@ -872,10 +876,10 @@
 	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 audio/bluetooth.conf $(am__append_25) \
-	tools/rfcomm.conf $(am__append_31) $(am__append_34) \
-	$(am__append_37) tools/dfubabel.1 tools/avctrl.8 \
-	$(am__append_43) $(am__append_44) test/apitest test/hsplay \
+	audio/telephony-maemo6.c audio/bluetooth.conf $(am__append_27) \
+	tools/rfcomm.conf $(am__append_33) $(am__append_36) \
+	$(am__append_39) tools/dfubabel.1 tools/avctrl.8 \
+	$(am__append_45) $(am__append_46) 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 \
@@ -883,17 +887,18 @@
 	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 \
-	$(am__append_47) $(am__append_50) $(am__append_53) \
+	$(am__append_49) $(am__append_52) $(am__append_55) \
 	scripts/bluetooth.rules scripts/bluetooth-hid2hci.rules \
 	scripts/bluetooth-serial.rules doc/manager-api.txt \
 	doc/adapter-api.txt doc/device-api.txt doc/service-api.txt \
-	doc/agent-api.txt doc/serial-api.txt doc/network-api.txt \
-	doc/input-api.txt doc/audio-api.txt doc/control-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
 include_HEADERS = $(lib_headers)
 @CONFIGFILES_TRUE at dbusdir = $(sysconfdir)/dbus-1/system.d
 @CONFIGFILES_TRUE at dbus_DATA = src/bluetooth.conf
 @CONFIGFILES_TRUE at confdir = $(sysconfdir)/bluetooth
- at CONFIGFILES_TRUE@conf_DATA = src/main.conf $(am__append_20)
+ at CONFIGFILES_TRUE@conf_DATA = src/main.conf $(am__append_22)
 @CONFIGFILES_TRUE at statedir = $(localstatedir)/lib/bluetooth
 @CONFIGFILES_TRUE at state_DATA = 
 plugindir = $(libdir)/bluetooth/plugins
@@ -906,12 +911,13 @@
 lib_libbluetooth_la_SOURCES = $(lib_headers) \
 					lib/bluetooth.c lib/hci.c lib/sdp.c
 
-lib_libbluetooth_la_LDFLAGS = -version-info 11:0:8
+lib_libbluetooth_la_LDFLAGS = -version-info 12:0:9
 lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
 @SBC_TRUE at sbc_libsbc_la_SOURCES = sbc/sbc.h sbc/sbc.c sbc/sbc_math.h sbc/sbc_tables.h \
 @SBC_TRUE@			sbc/sbc_primitives.h sbc/sbc_primitives.c \
 @SBC_TRUE@			sbc/sbc_primitives_mmx.h sbc/sbc_primitives_mmx.c \
- at SBC_TRUE@			sbc/sbc_primitives_neon.h sbc/sbc_primitives_neon.c
+ at SBC_TRUE@			sbc/sbc_primitives_neon.h sbc/sbc_primitives_neon.c \
+ at SBC_TRUE@			sbc/sbc_primitives_armv6.h sbc/sbc_primitives_armv6.c
 
 @SBC_TRUE at sbc_libsbc_la_CFLAGS = -finline-functions -fgcse-after-reload \
 @SBC_TRUE@					-funswitch-loops -funroll-loops
@@ -930,11 +936,11 @@
 gdbus_sources = gdbus/gdbus.h gdbus/mainloop.c gdbus/object.c gdbus/watch.c
 builtin_modules = $(am__append_5) $(am__append_7) $(am__append_9) \
 	$(am__append_12) $(am__append_14) $(am__append_16) \
-	$(am__append_18) hciops hal storage
+	$(am__append_18) hciops hal storage $(am__append_20)
 builtin_sources = $(am__append_6) $(am__append_8) $(am__append_10) \
 	$(am__append_13) $(am__append_15) $(am__append_17) \
 	$(am__append_19) plugins/hciops.c plugins/hal.c \
-	plugins/storage.c
+	plugins/storage.c $(am__append_21)
 builtin_nodist = $(am__append_11)
 @AUDIOPLUGIN_TRUE at noinst_LIBRARIES = audio/libtelephony.a
 @AUDIOPLUGIN_TRUE at audio_libtelephony_a_SOURCES = audio/telephony.h audio/telephony-dummy.c \
@@ -1045,8 +1051,8 @@
 @BCCMD_TRUE at tools_bccmd_SOURCES = tools/bccmd.c tools/csr.h \
 @BCCMD_TRUE@	tools/csr.c tools/csr_hci.c tools/csr_h4.c \
 @BCCMD_TRUE@	tools/csr_3wire.c tools/csr_bcsp.c tools/ubcsp.h \
- at BCCMD_TRUE@	tools/ubcsp.c $(am__append_28)
- at BCCMD_TRUE@tools_bccmd_LDADD = lib/libbluetooth.la $(am__append_29)
+ at BCCMD_TRUE@	tools/ubcsp.c $(am__append_30)
+ at BCCMD_TRUE@tools_bccmd_LDADD = lib/libbluetooth.la $(am__append_31)
 @HID2HCI_TRUE at tools_hid2hci_LDADD = @USB_LIBS@
 @DFUTOOL_TRUE at tools_dfutool_SOURCES = tools/dfutool.c tools/dfu.h tools/dfu.c
 @DFUTOOL_TRUE at tools_dfutool_LDADD = @USB_LIBS@
@@ -1091,8 +1097,8 @@
 
 @DUND_TRUE at compat_dund_LDADD = lib/libbluetooth.la
 @UDEVRULES_TRUE at rulesdir = @UDEV_DATADIR@
- at UDEVRULES_TRUE@udev_files = scripts/bluetooth.rules $(am__append_54) \
- at UDEVRULES_TRUE@	$(am__append_55)
+ at UDEVRULES_TRUE@udev_files = scripts/bluetooth.rules $(am__append_56) \
+ at UDEVRULES_TRUE@	$(am__append_57)
 @UDEVRULES_TRUE at rules_DATA = $(foreach file,$(udev_files), scripts/97-$(notdir $(file)))
 @PCMCIA_TRUE at udevdir = $(libexecdir)/udev
 @PCMCIA_TRUE at dist_udev_SCRIPTS = scripts/bluetooth_serial
@@ -1396,6 +1402,8 @@
 	sbc/$(DEPDIR)/$(am__dirstamp)
 sbc/sbc_libsbc_la-sbc_primitives_neon.lo: sbc/$(am__dirstamp) \
 	sbc/$(DEPDIR)/$(am__dirstamp)
+sbc/sbc_libsbc_la-sbc_primitives_armv6.lo: sbc/$(am__dirstamp) \
+	sbc/$(DEPDIR)/$(am__dirstamp)
 sbc/libsbc.la: $(sbc_libsbc_la_OBJECTS) $(sbc_libsbc_la_DEPENDENCIES) sbc/$(am__dirstamp)
 	$(AM_V_CCLD)$(sbc_libsbc_la_LINK) $(am_sbc_libsbc_la_rpath) $(sbc_libsbc_la_OBJECTS) $(sbc_libsbc_la_LIBADD) $(LIBS)
 install-binPROGRAMS: $(bin_PROGRAMS)
@@ -1696,8 +1704,6 @@
 	network/$(DEPDIR)/$(am__dirstamp)
 network/server.$(OBJEXT): network/$(am__dirstamp) \
 	network/$(DEPDIR)/$(am__dirstamp)
-network/bridge.$(OBJEXT): network/$(am__dirstamp) \
-	network/$(DEPDIR)/$(am__dirstamp)
 network/connection.$(OBJEXT): network/$(am__dirstamp) \
 	network/$(DEPDIR)/$(am__dirstamp)
 plugins/service.$(OBJEXT): plugins/$(am__dirstamp) \
@@ -1708,6 +1714,8 @@
 	plugins/$(DEPDIR)/$(am__dirstamp)
 plugins/storage.$(OBJEXT): plugins/$(am__dirstamp) \
 	plugins/$(DEPDIR)/$(am__dirstamp)
+plugins/maemo6.$(OBJEXT): plugins/$(am__dirstamp) \
+	plugins/$(DEPDIR)/$(am__dirstamp)
 src/main.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
 src/log.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
 src/security.$(OBJEXT): src/$(am__dirstamp) \
@@ -2066,7 +2074,6 @@
 	-rm -f lib/hci.lo
 	-rm -f lib/sdp.$(OBJEXT)
 	-rm -f lib/sdp.lo
-	-rm -f network/bridge.$(OBJEXT)
 	-rm -f network/common.$(OBJEXT)
 	-rm -f network/connection.$(OBJEXT)
 	-rm -f network/main.$(OBJEXT)
@@ -2075,6 +2082,7 @@
 	-rm -f plugins/echo.$(OBJEXT)
 	-rm -f plugins/hal.$(OBJEXT)
 	-rm -f plugins/hciops.$(OBJEXT)
+	-rm -f plugins/maemo6.$(OBJEXT)
 	-rm -f plugins/plugins_netlink_la-netlink.$(OBJEXT)
 	-rm -f plugins/plugins_netlink_la-netlink.lo
 	-rm -f plugins/pnat.$(OBJEXT)
@@ -2084,6 +2092,8 @@
 	-rm -f sbc/sbc_libsbc_la-sbc.lo
 	-rm -f sbc/sbc_libsbc_la-sbc_primitives.$(OBJEXT)
 	-rm -f sbc/sbc_libsbc_la-sbc_primitives.lo
+	-rm -f sbc/sbc_libsbc_la-sbc_primitives_armv6.$(OBJEXT)
+	-rm -f sbc/sbc_libsbc_la-sbc_primitives_armv6.lo
 	-rm -f sbc/sbc_libsbc_la-sbc_primitives_mmx.$(OBJEXT)
 	-rm -f sbc/sbc_libsbc_la-sbc_primitives_mmx.lo
 	-rm -f sbc/sbc_libsbc_la-sbc_primitives_neon.$(OBJEXT)
@@ -2221,7 +2231,6 @@
 @AMDEP_TRUE@@am__include@ @am__quote at lib/$(DEPDIR)/bluetooth.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at lib/$(DEPDIR)/hci.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at lib/$(DEPDIR)/sdp.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at network/$(DEPDIR)/bridge.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at network/$(DEPDIR)/common.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at network/$(DEPDIR)/connection.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at network/$(DEPDIR)/main.Po at am__quote@
@@ -2230,12 +2239,14 @@
 @AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/echo.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/hal.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/hciops.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/maemo6.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/plugins_netlink_la-netlink.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/pnat.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/service.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/storage.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at sbc/$(DEPDIR)/sbc_libsbc_la-sbc.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_armv6.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_mmx.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_neon.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at sbc/$(DEPDIR)/sbcdec.Po at am__quote@
@@ -2486,6 +2497,14 @@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -c -o sbc/sbc_libsbc_la-sbc_primitives_neon.lo `test -f 'sbc/sbc_primitives_neon.c' || echo '$(srcdir)/'`sbc/sbc_primitives_neon.c
 
+sbc/sbc_libsbc_la-sbc_primitives_armv6.lo: sbc/sbc_primitives_armv6.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -MT sbc/sbc_libsbc_la-sbc_primitives_armv6.lo -MD -MP -MF sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_armv6.Tpo -c -o sbc/sbc_libsbc_la-sbc_primitives_armv6.lo `test -f 'sbc/sbc_primitives_armv6.c' || echo '$(srcdir)/'`sbc/sbc_primitives_armv6.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_armv6.Tpo sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_armv6.Plo
+ at am__fastdepCC_FALSE@	$(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	source='sbc/sbc_primitives_armv6.c' object='sbc/sbc_libsbc_la-sbc_primitives_armv6.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -c -o sbc/sbc_libsbc_la-sbc_primitives_armv6.lo `test -f 'sbc/sbc_primitives_armv6.c' || echo '$(srcdir)/'`sbc/sbc_primitives_armv6.c
+
 .l.c:
 	$(AM_V_LEX)$(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE)
 
--- acinclude.m4
+++ acinclude.m4
@@ -182,6 +182,7 @@
 	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}
@@ -293,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
@@ -340,4 +345,5 @@
 	AM_CONDITIONAL(DFUTOOL, test "${dfutool_enable}" = "yes" && test "${usb_found}" = "yes")
 	AM_CONDITIONAL(UDEVRULES, test "${udevrules_enable}" = "yes")
 	AM_CONDITIONAL(CONFIGFILES, test "${configfiles_enable}" = "yes")
+	AM_CONDITIONAL(MAEMO6PLUGIN, test "${maemo6_enable}" = "yes")
 ])
--- audio/a2dp.c
+++ audio/a2dp.c
@@ -112,14 +112,14 @@
 {
 	setup->ref++;
 
-	DBG("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)
 {
-	DBG("setup_free(%p)", s);
+	DBG("%p", s);
 	setups = g_slist_remove(setups, s);
 	if (s->session)
 		avdtp_unref(s->session);
@@ -132,7 +132,7 @@
 {
 	setup->ref--;
 
-	DBG("setup_unref(%p): ref=%d", setup, setup->ref);
+	DBG("%p: ref=%d", setup, setup->ref);
 
 	if (setup->ref <= 0)
 		setup_free(setup);
--- audio/avdtp.c
+++ audio/avdtp.c
@@ -541,8 +541,7 @@
 	cont_fragments = (len - (session->omtu - sizeof(start))) /
 					(session->omtu - sizeof(cont)) + 1;
 
-	DBG("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));
@@ -559,8 +558,7 @@
 	if (!try_send(sock, session->buf, session->omtu))
 		return FALSE;
 
-	DBG("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);
 
@@ -572,13 +570,11 @@
 		if (left + sizeof(cont) > session->omtu) {
 			cont.packet_type = AVDTP_PKT_TYPE_CONTINUE;
 			to_copy = session->omtu - sizeof(cont);
-			DBG("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;
-			DBG("avdtp_send: sending end with %d bytes",
-								to_copy);
+			DBG("sending end with %d bytes", to_copy);
 		}
 
 		cont.transaction = transaction;
@@ -804,7 +800,8 @@
 	struct avdtp_stream *stream = user_data;
 	struct avdtp *session = stream->session;
 
-	avdtp_close(session, stream, FALSE);
+	if (avdtp_close(session, stream, FALSE) < 0)
+		error("stream_timeout: closing AVDTP stream failed");
 
 	stream->idle_timer = 0;
 
@@ -1119,7 +1116,7 @@
 
 	session->ref--;
 
-	DBG("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 &&
@@ -1146,8 +1143,7 @@
 
 	server = session->server;
 
-	DBG("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);
@@ -1168,7 +1164,7 @@
 struct avdtp *avdtp_ref(struct avdtp *session)
 {
 	session->ref++;
-	DBG("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;
@@ -1980,7 +1976,7 @@
 	struct avdtp_common_header *header;
 	gsize size;
 
-	DBG("session_cb");
+	DBG("");
 
 	if (cond & G_IO_NVAL)
 		return FALSE;
@@ -2329,8 +2325,7 @@
 	 * Abort the device's channel in favor of our own.
 	 */
 	if (session->state == AVDTP_SESSION_STATE_CONNECTING) {
-		DBG("avdtp_confirm_cb: connect already in progress"
-						" (XCASE connect:connect)");
+		DBG("connect already in progress (XCASE connect:connect)");
 		goto drop;
 	}
 
@@ -3345,8 +3340,8 @@
 	if (!(lsep && rsep))
 		return -EINVAL;
 
-	DBG("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;
--- audio/gstbluetooth.c
+++ audio/gstbluetooth.c
@@ -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 };
--- audio/manager.c
+++ audio/manager.c
@@ -171,8 +171,7 @@
 	uuid16 = uuid.value.uuid16;
 
 	if (!server_is_enabled(&device->src, uuid16)) {
-		DBG("audio handle_uuid: server not enabled for %s (0x%04x)",
-				uuidstr, uuid16);
+		DBG("server not enabled for %s (0x%04x)", uuidstr, uuid16);
 		return;
 	}
 
@@ -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);
@@ -770,7 +775,7 @@
 
 	audio_dev = manager_get_device(&src, &dst, TRUE);
 	if (!audio_dev) {
-		DBG("audio_probe: unable to get a device object");
+		DBG("unable to get a device object");
 		return -1;
 	}
 
@@ -800,7 +805,7 @@
 {
 	adp->ref++;
 
-	DBG("audio_adapter_ref(%p): ref=%d", adp, adp->ref);
+	DBG("%p: ref=%d", adp, adp->ref);
 
 	return adp;
 }
@@ -809,7 +814,7 @@
 {
 	adp->ref--;
 
-	DBG("audio_adapter_unref(%p): ref=%d", adp, adp->ref);
+	DBG("%p: ref=%d", adp, adp->ref);
 
 	if (adp->ref > 0)
 		return;
--- audio/pcm_bluetooth.c
+++ audio/pcm_bluetooth.c
@@ -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",
--- audio/telephony-maemo6.c
+++ audio/telephony-maemo6.c
@@ -134,11 +134,14 @@
 static struct {
 	char *operator_name;
 	uint8_t status;
-	int32_t signals_bar;
+	int32_t signal_bars;
 } net = {
 	.operator_name = NULL,
 	.status = NETWORK_REG_STATUS_UNKOWN,
-	.signals_bar = 0,
+	/* 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 int get_property(const char *iface, const char *prop);
@@ -181,6 +184,7 @@
 static struct indicator maemo_indicators[] =
 {
 	{ "battchg",	"0-5",	5,	TRUE },
+	/* signal strength in terms of bars */
 	{ "signal",	"0-5",	0,	TRUE },
 	{ "service",	"0,1",	0,	TRUE },
 	{ "call",	"0,1",	0,	TRUE },
@@ -1227,43 +1231,39 @@
 	update_registration_status(status);
 }
 
-static void update_signal_strength(int32_t signals_bar)
+static void update_signal_strength(int32_t signal_bars)
 {
-	int signal;
-
-	if (signals_bar < 0)
-		signals_bar = 0;
-	else if (signals_bar > 100) {
-		DBG("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);
+	telephony_update_indicator(maemo_indicators, "signal", signal_bars);
 
-	net.signals_bar = signals_bar;
-
-	DBG("telephony-maemo6: 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_changed(DBusMessage *msg)
+static void handle_signal_bars_changed(DBusMessage *msg)
 {
-	int32_t signals_bar, rssi_in_dbm;
+	int32_t signal_bars;
 
 	if (!dbus_message_get_args(msg, NULL,
-					DBUS_TYPE_INT32, &signals_bar,
-					DBUS_TYPE_INT32, &rssi_in_dbm,
+					DBUS_TYPE_INT32, &signal_bars,
 					DBUS_TYPE_INVALID)) {
-		error("Unexpected parameters in SignalStrengthChanged");
+		error("Unexpected parameters in SignalBarsChanged");
 		return;
 	}
 
-	update_signal_strength(signals_bar);
+	update_signal_strength(signal_bars);
 }
 
 static gboolean iter_get_basic_args(DBusMessageIter *iter,
@@ -1311,9 +1311,12 @@
 		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;
 
@@ -1527,7 +1530,7 @@
 		dbus_message_iter_get_basic(&sub, &name);
 		update_operator_name(name);
 	} else if (g_strcmp0(prop, "SignalBars") == 0) {
-		uint32_t signal_bars;
+		int32_t signal_bars;
 
 		dbus_message_iter_get_basic(&sub, &signal_bars);
 		update_signal_strength(signal_bars);
@@ -1828,9 +1831,19 @@
 		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 },
 	{ }
 };
 
@@ -1896,8 +1909,8 @@
 				"OperatorNameChanged"))
 		handle_operator_name_changed(msg);
 	else if (dbus_message_is_signal(msg, CSD_CSNET_SIGNAL,
-				"SignalStrengthChanged"))
-		handle_signal_strength_changed(msg);
+				"SignalBarsChanged"))
+		handle_signal_bars_changed(msg);
 	else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
 					"PropertyModified"))
 		handle_hal_property_modified(msg);
@@ -1978,6 +1991,12 @@
 
 void telephony_exit(void)
 {
+	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);
 	calls = NULL;
--- audio/telephony-ofono.c
+++ audio/telephony-ofono.c
@@ -598,8 +598,11 @@
 
 		dbus_message_iter_get_basic(&sub, &modem_obj_path_local);
 		modem_obj_path = g_strdup(modem_obj_path_local);
-		DBG("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);
 	}
 
--- configure
+++ configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.63 for bluez 4.66.
+# Generated by GNU Autoconf 2.63 for bluez 4.69.
 #
 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
 # 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
@@ -743,8 +743,8 @@
 # Identity of this package.
 PACKAGE_NAME='bluez'
 PACKAGE_TARNAME='bluez'
-PACKAGE_VERSION='4.66'
-PACKAGE_STRING='bluez 4.66'
+PACKAGE_VERSION='4.69'
+PACKAGE_STRING='bluez 4.69'
 PACKAGE_BUGREPORT=''
 
 ac_default_prefix=/usr/local
@@ -794,6 +794,8 @@
 NETLINK_CFLAGS
 CAPNG_LIBS
 CAPNG_CFLAGS
+MAEMO6PLUGIN_FALSE
+MAEMO6PLUGIN_TRUE
 CONFIGFILES_FALSE
 CONFIGFILES_TRUE
 UDEVRULES_FALSE
@@ -1015,6 +1017,7 @@
 enable_configfiles
 enable_debug
 with_telephony
+enable_maemo6
 enable_capng
 enable_netlink
 '
@@ -1598,7 +1601,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures bluez 4.66 to adapt to many kinds of systems.
+\`configure' configures bluez 4.69 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1668,7 +1671,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of bluez 4.66:";;
+     short | recursive ) echo "Configuration of bluez 4.69:";;
    esac
   cat <<\_ACEOF
 
@@ -1713,6 +1716,7 @@
   --enable-udevrules      install Bluetooth udev rules
   --enable-configfiles    install Bluetooth configuration files
   --enable-debug          enable compiling with debugging information
+  --enable-maemo6         compile with maemo6 plugin
   --enable-capng          enable capabilities support
   --enable-netlink        enable netlink support
 
@@ -1828,7 +1832,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-bluez configure 4.66
+bluez configure 4.69
 generated by GNU Autoconf 2.63
 
 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1842,7 +1846,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by bluez $as_me 4.66, which was
+It was created by bluez $as_me 4.69, which was
 generated by GNU Autoconf 2.63.  Invocation command line was
 
   $ $0 $@
@@ -2692,7 +2696,7 @@
 
 # Define the identity of the package.
  PACKAGE='bluez'
- VERSION='4.66'
+ VERSION='4.69'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -5350,13 +5354,13 @@
 else
   lt_cv_nm_interface="BSD nm"
   echo "int some_variable = 0;" > conftest.$ac_ext
-  (eval echo "\"\$as_me:5353: $ac_compile\"" >&5)
+  (eval echo "\"\$as_me:5357: $ac_compile\"" >&5)
   (eval "$ac_compile" 2>conftest.err)
   cat conftest.err >&5
-  (eval echo "\"\$as_me:5356: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval echo "\"\$as_me:5360: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
   (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
   cat conftest.err >&5
-  (eval echo "\"\$as_me:5359: output\"" >&5)
+  (eval echo "\"\$as_me:5363: output\"" >&5)
   cat conftest.out >&5
   if $GREP 'External.*some_variable' conftest.out > /dev/null; then
     lt_cv_nm_interface="MS dumpbin"
@@ -6561,7 +6565,7 @@
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 6564 "configure"' > conftest.$ac_ext
+  echo '#line 6568 "configure"' > conftest.$ac_ext
   if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -8384,11 +8388,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8387: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8391: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:8391: \$? = $ac_status" >&5
+   echo "$as_me:8395: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -8723,11 +8727,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8726: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8730: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:8730: \$? = $ac_status" >&5
+   echo "$as_me:8734: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -8828,11 +8832,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8831: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8835: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:8835: \$? = $ac_status" >&5
+   echo "$as_me:8839: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -8883,11 +8887,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8886: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8890: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:8890: \$? = $ac_status" >&5
+   echo "$as_me:8894: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -11686,7 +11690,7 @@
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11689 "configure"
+#line 11693 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11782,7 +11786,7 @@
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11785 "configure"
+#line 11789 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13020,6 +13024,7 @@
 	udevrules_enable=yes
 	configfiles_enable=yes
 	telephony_driver=dummy
+	maemo6_enable=no
 
 	# Check whether --enable-optimization was given.
 if test "${enable_optimization+set}" = set; then
@@ -13241,6 +13246,14 @@
 	TELEPHONY_DRIVER=telephony-${telephony_driver}.c
 
 
+	# Check whether --enable-maemo6 was given.
+if test "${enable_maemo6+set}" = set; then
+  enableval=$enable_maemo6;
+		maemo6_enable=${enableval}
+
+fi
+
+
 	if (test "${fortify_enable}" = "yes"); then
 		CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2"
 	fi
@@ -13467,6 +13480,14 @@
   CONFIGFILES_FALSE=
 fi
 
+	 if test "${maemo6_enable}" = "yes"; then
+  MAEMO6PLUGIN_TRUE=
+  MAEMO6PLUGIN_FALSE='#'
+else
+  MAEMO6PLUGIN_TRUE='#'
+  MAEMO6PLUGIN_FALSE=
+fi
+
 
 
 # Check whether --enable-capng was given.
@@ -13947,6 +13968,13 @@
 Usually this means the macro was only invoked conditionally." >&2;}
    { (exit 1); exit 1; }; }
 fi
+if test -z "${MAEMO6PLUGIN_TRUE}" && test -z "${MAEMO6PLUGIN_FALSE}"; then
+  { { $as_echo "$as_me:$LINENO: error: conditional \"MAEMO6PLUGIN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+$as_echo "$as_me: error: conditional \"MAEMO6PLUGIN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
 if test -z "${NETLINK_TRUE}" && test -z "${NETLINK_FALSE}"; then
   { { $as_echo "$as_me:$LINENO: error: conditional \"NETLINK\" was never defined.
 Usually this means the macro was only invoked conditionally." >&5
@@ -14276,7 +14304,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by bluez $as_me 4.66, which was
+This file was extended by bluez $as_me 4.69, which was
 generated by GNU Autoconf 2.63.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -14339,7 +14367,7 @@
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_version="\\
-bluez config.status 4.66
+bluez config.status 4.69
 configured by $0, generated by GNU Autoconf 2.63,
   with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 
--- configure.ac
+++ configure.ac
@@ -1,5 +1,5 @@
 AC_PREREQ(2.60)
-AC_INIT(bluez, 4.66)
+AC_INIT(bluez, 4.69)
 
 AM_INIT_AUTOMAKE([foreign subdir-objects])
 AM_CONFIG_HEADER(config.h)
--- doc/attribute-api.txt
+++ doc/attribute-api.txt
+BlueZ D-Bus Attribute API description
+*************************************
+
+Copyright (C) 2004-2010  Marcel Holtmann <marcel at 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.
--- doc/network-api.txt
+++ doc/network-api.txt
@@ -60,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.
--- lib/bluetooth.c
+++ lib/bluetooth.c
@@ -474,6 +474,12 @@
 		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:
--- lib/hci.c
+++ lib/hci.c
@@ -1093,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)
@@ -1106,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;
 
@@ -1186,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;
@@ -2591,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;
+}
--- lib/hci.h
+++ lib/hci.h
@@ -1259,6 +1259,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
 
@@ -1661,6 +1905,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
--- lib/hci_lib.h
+++ lib/hci_lib.h
@@ -115,6 +115,19 @@
 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);
 
--- lib/sdp.c
+++ lib/sdp.c
@@ -4769,13 +4769,32 @@
 
 		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;
-			if (dd->dtd != SDP_UINT8 && dd->dtd != SDP_UINT16 &&
-						dd->dtd != SDP_TEXT_STR8)
+			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(dd->dtd, &dd->val);
+			}
+
+			data = sdp_data_alloc_with_length(dd->dtd, val, length);
 			if (data)
 				subseq = sdp_list_append(subseq, data);
 		}
--- network/bridge.c
+++ network/bridge.c
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel at 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 "log.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;
-}
--- network/bridge.h
+++ network/bridge.h
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel at 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);
--- network/common.c
+++ network/common.c
@@ -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>
@@ -45,7 +46,6 @@
 #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))
-		DBG("%d exited with status %d", pid, WEXITSTATUS(status));
-	else
-		DBG("%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)
-{
-}
-
-static int bnep_exec(const char **argv)
+int bnep_if_up(const char *devname)
 {
-	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;
-
-	/* Check if a script is running */
-	l = g_slist_find_custom(pids, devname, find_devname);
-	if (l) {
-		bnep = l->data;
-
-		if (bnep->script && !strcmp(bnep->script, "avahi-autoipd")) {
-			argv[0] = bnep->script;
-			argv[1] = devname;
-			argv[2] = "--refresh";
-			argv[3] = NULL;
+	int sk, err;
 
-			bnep->pid = bnep_exec(argv);
-		}
-	}
+	sk = socket(AF_INET, SOCK_DGRAM, 0);
 
-	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;
-	}
-
-	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;
+	err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr);
 
-	bnep->pid = bnep_exec(argv);
-	g_child_watch_add(bnep->pid, script_exited, bnep);
+	close(sk);
 
-done:
-	pids = g_slist_append(pids, bnep);
+	if (err < 0) {
+		error("Could not bring up %s", devname);
+		return err;
+	}
 
-	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;
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
 
-	if (!bnep->pid)
-		goto done;
+	ifr.ifr_flags &= ~IFF_UP;
 
-	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);
+	/* Bring down the interface */
+	err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr);
 
-		goto done;
-	}
+	close(sk);
 
-	/* Kill script */
-	err = kill(bnep->pid, SIGTERM);
-	if (err < 0)
-		error("kill(%d, SIGTERM): %s (%d)", bnep->pid,
-			strerror(errno), errno);
+	return 0;
+}
 
-done:
-	sd = socket(AF_INET, SOCK_DGRAM, 0);
-	memset(&ifr, 0, sizeof(ifr));
-	strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1);
+int bnep_add_to_bridge(const char *devname, const char *bridge)
+{
+	int ifindex = if_nametoindex(devname);
+	struct ifreq ifr;
+	int sk, err;
 
-	ifr.ifr_flags &= ~IFF_UP;
+	if (!devname || !bridge)
+		return -EINVAL;
 
-	/* Bring down the interface */
-	ioctl(sd, SIOCSIFFLAGS, (caddr_t) &ifr);
+	sk = socket(AF_INET, SOCK_STREAM, 0);
+	if (sk < 0)
+		return -1;
 
-	pids = g_slist_remove(pids, bnep);
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
+	ifr.ifr_ifindex = ifindex;
+
+	err = ioctl(sk, SIOCBRADDIF, &ifr);
 
-	if (bnep->devname)
-		g_free(bnep->devname);
+	close(sk);
 
-	if (bnep->script)
-		g_free(bnep->script);
+	if (err < 0)
+		return err;
 
-	g_free(bnep);
+	info("bridge %s: interface %s added", bridge, devname);
 
 	return 0;
 }
--- network/common.h
+++ network/common.h
@@ -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);
--- network/connection.c
+++ network/connection.c
@@ -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)
@@ -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);
 
@@ -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;
 }
--- network/connection.h
+++ network/connection.h
@@ -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);
--- network/manager.c
+++ network/manager.c
@@ -37,152 +37,39 @@
 
 #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) {
-		DBG("%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) {
 		DBG("%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) {
-		DBG("%s: %s", file, err->message);
-		g_clear_error(&err);
-	}
-
-	conf.gn_script = g_key_file_get_string(keyfile, "GN Role",
-						"Script", &err);
-	if (err) {
-		DBG("%s: %s", file, err->message);
-		g_clear_error(&err);
-	}
-
-	conf.nap_script = g_key_file_get_string(keyfile, "NAP Role",
-						"Script", &err);
-	if (err) {
-		DBG("%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) {
-		DBG("%s: %s", file, err->message);
-		g_clear_error(&err);
-	}
-
-	conf.gn_iface = g_key_file_get_string(keyfile, "GN Role",
-						"Interface", &err);
-	if (err) {
-		DBG("%s: %s", file, err->message);
-		g_clear_error(&err);
-	}
-
-	conf.nap_iface = g_key_file_get_string(keyfile, "NAP Role",
-						"Interface", &err);
-	if (err) {
-		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);
-
-	DBG("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);
+
+	connection_exit();
 
-	btd_unregister_adapter_driver(&network_panu_server_driver);
-	btd_unregister_adapter_driver(&network_gn_server_driver);
-	btd_unregister_adapter_driver(&network_nap_server_driver);
+	btd_unregister_adapter_driver(&network_server_driver);
 
 	dbus_connection_unref(connection);
 	connection = NULL;
 
 	bnep_cleanup();
-	bridge_cleanup();
-	conf_cleanup();
 }
--- network/network.conf
+++ 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
--- network/server.c
+++ network/server.c
@@ -50,13 +50,10 @@
 #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];
@@ -507,6 +504,16 @@
 		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;
 	}
 
-	DBG("register_server_record: got record id 0x%x", record->handle);
+	DBG("got record id 0x%x", record->handle);
 
 	return record->handle;
 }
@@ -583,166 +582,81 @@
 				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");
+	if (ns->record_id) {
+		remove_record_from_server(ns->record_id);
+		ns->record_id = 0;
 	}
 
-	ns->enable = TRUE;
-
-	return reply;
+	g_free(ns->bridge);
+	ns->bridge = NULL;
 }
 
-static DBusMessage *disable(DBusConnection *conn,
+static DBusMessage *register_server(DBusConnection *conn,
 				DBusMessage *msg, void *data)
 {
 	struct network_server *ns = data;
 	DBusMessage *reply;
+	const char *uuid, *bridge;
 
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &uuid,
+				DBUS_TYPE_STRING, &bridge, DBUS_TYPE_INVALID))
 		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;
-}
+	if (g_strcmp0(uuid, "nap"))
+		return failed(msg, "Invalid UUID");
 
-static DBusMessage *set_name(DBusConnection *conn, DBusMessage *msg,
-				const char *name, void *data)
-{
-	struct network_server *ns = data;
-	DBusMessage *reply;
+	if (ns->record_id)
+		return failed(msg, "Already registered");
 
 	reply = dbus_message_new_method_return(msg);
 	if (!reply)
 		return NULL;
 
-	if (!name || (strlen(name) == 0))
-		return invalid_arguments(msg, "Invalid name");
+	ns->record_id = register_server_record(ns);
+	if (!ns->record_id)
+		return failed(msg, "SDP record registration failed");
 
-	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");
-		}
+	g_free(ns->bridge);
+	ns->bridge = g_strdup(bridge);
 
-		remove_record_from_server(ns->record_id);
-		ns->record_id = handle;
-	}
+	ns->watch_id = g_dbus_add_disconnect_watch(conn,
+					dbus_message_get_sender(msg),
+					server_disconnect, ns, NULL);
 
 	return reply;
 }
 
-static DBusMessage *get_properties(DBusConnection *conn,
-				DBusMessage *msg, void *data)
+static DBusMessage *unregister_server(DBusConnection *conn,
+					DBusMessage *msg, void *data)
 {
 	struct network_server *ns = data;
 	DBusMessage *reply;
-	DBusMessageIter iter;
-	DBusMessageIter dict;
 	const char *uuid;
 
-	reply = dbus_message_new_method_return(msg);
-	if (!reply)
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &uuid,
+							DBUS_TYPE_INVALID))
 		return NULL;
 
-	dbus_message_iter_init_append(reply, &iter);
+	if (g_strcmp0(uuid, "nap"))
+		return failed(msg, "Invalid UUID");
 
-	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-	dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &ns->name);
-
-	uuid = bnep_uuid(ns->id);
-	dict_append_entry(&dict, "Uuid", DBUS_TYPE_STRING, &uuid);
+	reply = dbus_message_new_method_return(msg);
+	if (!reply)
+		return NULL;
 
-	dict_append_entry(&dict, "Enabled", DBUS_TYPE_BOOLEAN, &ns->enable);
+	g_dbus_remove_watch(conn, ns->watch_id);
 
-	dbus_message_iter_close_container(&iter, &dict);
+	server_disconnect(conn, ns);
 
 	return reply;
 }
 
-static DBusMessage *set_property(DBusConnection *conn,
-					DBusMessage *msg, void *data)
-{
-	DBusMessageIter iter;
-	DBusMessageIter sub;
-	const char *property;
-
-	if (!dbus_message_iter_init(msg, &iter))
-		return invalid_arguments(msg, "Not a dict");
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-		return invalid_arguments(msg, "Key not a string");
-
-	dbus_message_iter_get_basic(&iter, &property);
-	dbus_message_iter_next(&iter);
-
-	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);
-
-	if (g_str_equal("Name", property)) {
-		const char *name;
-
-		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");
-}
-
 static void adapter_free(struct network_adapter *na)
 {
 	if (na->io != NULL) {
@@ -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);
@@ -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,10 +779,9 @@
 	}
 
 	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);
 
 	DBG("Registered interface %s on path %s", ns->iface, path);
@@ -898,10 +789,11 @@
 	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)
--- network/server.h
+++ network/server.h
@@ -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);
--- plugins/hciops.c
+++ plugins/hciops.c
@@ -76,7 +76,7 @@
 		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;
@@ -111,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)
@@ -202,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) {
@@ -456,7 +451,7 @@
 
 static int hciops_powered(int index, gboolean powered)
 {
-	int dd;
+	int dd, err;
 	uint8_t mode = SCAN_DISABLED;
 
 	if (powered)
@@ -466,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);
 
@@ -476,36 +476,40 @@
 
 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_class(int index, uint32_t class)
@@ -533,7 +537,7 @@
 static int hciops_set_limited_discoverable(int index, uint32_t class,
 							gboolean limited)
 {
-	int dd;
+	int dd, err;
 	int num = (limited ? 2 : 1);
 	uint8_t lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
 	write_current_iac_lap_cp cp;
@@ -550,8 +554,13 @@
 	cp.num_current_iac = num;
 	memcpy(&cp.lap, lap, num * 3);
 
-	hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_CURRENT_IAC_LAP,
+	err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_CURRENT_IAC_LAP,
 			(num * 3 + 1), &cp);
+	if (err < 0) {
+		err = -errno;
+		hci_close_dev(dd);
+		return err;
+	}
 
 	hci_close_dev(dd);
 
--- plugins/maemo6.c
+++ plugins/maemo6.c
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel at 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)
--- sbc/sbc.c
+++ sbc/sbc.c
@@ -78,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];
@@ -160,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;
 
@@ -171,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];
@@ -202,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)
@@ -215,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 {
@@ -225,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++;
@@ -235,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++;
@@ -251,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];
@@ -259,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];
@@ -286,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)
@@ -301,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 {
@@ -325,7 +328,8 @@
 			if (ch == 1) {
 				ch = 0;
 				sb++;
-				if (sb >= frame->subbands) break;
+				if (sb >= subbands)
+					break;
 			} else
 				ch = 1;
 		}
@@ -340,7 +344,8 @@
 			if (ch == 1) {
 				ch = 0;
 				sb++;
-				if (sb >= frame->subbands) break;
+				if (sb >= subbands)
+					break;
 			} else
 				ch = 1;
 		}
@@ -349,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.
@@ -743,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;
@@ -802,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;
@@ -916,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);
 	}
 }
 
@@ -1056,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);
@@ -1121,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;
--- sbc/sbc.h
+++ sbc/sbc.h
@@ -92,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);
--- sbc/sbc_primitives.c
+++ sbc/sbc_primitives.c
@@ -34,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
@@ -440,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
  */
@@ -457,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 */
@@ -465,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
--- sbc/sbc_primitives.h
+++ sbc/sbc_primitives.h
@@ -63,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;
 };
 
--- sbc/sbc_primitives_armv6.c
+++ sbc/sbc_primitives_armv6.c
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel at holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk at ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley at 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
--- sbc/sbc_primitives_armv6.h
+++ sbc/sbc_primitives_armv6.h
+/*
+ *
+ *  Bluetooth low-complexity, subband codec (SBC) library
+ *
+ *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel at holtmann.org>
+ *  Copyright (C) 2004-2005  Henryk Ploetz <henryk at ploetzli.ch>
+ *  Copyright (C) 2005-2006  Brad Midgley <bmidgley at 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
--- sbc/sbc_primitives_mmx.c
+++ sbc/sbc_primitives_mmx.c
@@ -276,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__
@@ -314,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";
 	}
 }
--- sbc/sbc_primitives_neon.c
+++ sbc/sbc_primitives_neon.c
@@ -237,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";
 }
 
--- sbc/sbcenc.c
+++ sbc/sbcenc.c
@@ -50,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) {
--- src/adapter.c
+++ src/adapter.c
@@ -105,6 +105,7 @@
 	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;
@@ -412,10 +413,47 @@
 		adapter->pending_cod = adapter->wanted_cod;
 }
 
-static int set_mode(struct btd_adapter *adapter, uint8_t new_mode)
+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);
@@ -456,11 +494,18 @@
 	}
 
 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;
 }
@@ -477,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);
 
@@ -501,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,
@@ -521,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);
@@ -533,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;
 }
@@ -606,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;
 
@@ -619,7 +673,7 @@
 
 		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);
@@ -647,9 +701,6 @@
 
 static void session_free(struct session_req *req)
 {
-	DBG("%s session %p with %s deactivated",
-		req->mode ? "Mode" : "Discovery", req, req->owner);
-
 	if (req->id)
 		g_dbus_remove_watch(req->conn, req->id);
 
@@ -672,20 +723,11 @@
 	session_free(req);
 }
 
-static struct session_req *session_ref(struct session_req *req)
-{
-	req->refcount++;
-
-	DBG("session_ref(%p): ref=%d", req, req->refcount);
-
-	return req;
-}
-
 static void session_unref(struct session_req *req)
 {
 	req->refcount--;
 
-	DBG("session_unref(%p): ref=%d", req, req->refcount);
+	DBG("%p: ref=%d", req, req->refcount);
 
 	if (req->refcount)
 		return;
@@ -693,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;
@@ -731,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
@@ -1118,7 +1136,7 @@
 	struct btd_device *device;
 	const char *path;
 
-	DBG("adapter_create_device(%s)", address);
+	DBG("%s", address);
 
 	device = device_create(conn, adapter, address);
 	if (!device)
@@ -1170,7 +1188,7 @@
 {
 	struct btd_device *device;
 
-	DBG("adapter_get_device(%s)", address);
+	DBG("%s", address);
 
 	if (!adapter)
 		return NULL;
@@ -1586,7 +1604,7 @@
 				ERROR_INTERFACE ".AlreadyExists",
 				"Device already exists");
 
-	DBG("create_device(%s)", address);
+	DBG("%s", address);
 
 	device = adapter_create_device(conn, adapter, address);
 	if (!device)
@@ -2498,7 +2516,7 @@
 	agent_free(adapter->agent);
 	adapter->agent = NULL;
 
-	DBG("adapter_free(%p)", adapter);
+	DBG("%p", adapter);
 
 	if (adapter->auth_idle_id)
 		g_source_remove(adapter->auth_idle_id);
@@ -2511,7 +2529,7 @@
 {
 	adapter->ref++;
 
-	DBG("btd_adapter_ref(%p): ref=%d", adapter, adapter->ref);
+	DBG("%p: ref=%d", adapter, adapter->ref);
 
 	return adapter;
 }
@@ -2522,7 +2540,7 @@
 
 	adapter->ref--;
 
-	DBG("btd_adapter_unref(%p): ref=%d", adapter, adapter->ref);
+	DBG("%p: ref=%d", adapter, adapter->ref);
 
 	if (adapter->ref > 0)
 		return;
@@ -2848,6 +2866,45 @@
 	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);
@@ -2907,6 +2964,8 @@
 				DBUS_TYPE_BOOLEAN, &discoverable);
 
 	adapter->scan_mode = scan_mode;
+
+	set_mode_complete(adapter);
 }
 
 struct agent *adapter_get_agent(struct btd_adapter *adapter)
@@ -3198,6 +3257,17 @@
 		return 0;
 
 	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)
--- src/adapter.h
+++ src/adapter.h
@@ -163,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 {
--- src/btio.c
+++ src/btio.c
@@ -57,6 +57,7 @@
 	uint16_t imtu;
 	uint16_t omtu;
 	int master;
+	uint8_t mode;
 };
 
 struct connect {
@@ -474,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;
 
@@ -493,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) {
@@ -629,6 +632,7 @@
 	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) {
@@ -678,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);
@@ -1088,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:
@@ -1129,7 +1136,7 @@
 		if (l2cap_bind(sock, &opts->src,
 					server ? opts->psm : 0, err) < 0)
 			goto failed;
-		if (!l2cap_set(sock, opts->sec_level, 0, 0, -1, err))
+		if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, err))
 			goto failed;
 		break;
 	case BT_IO_L2CAP:
@@ -1142,7 +1149,7 @@
 					server ? opts->psm : 0, err) < 0)
 			goto failed;
 		if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu,
-							opts->master, err))
+						opts->mode, opts->master, err))
 			goto failed;
 		break;
 	case BT_IO_RFCOMM:
--- src/btio.h
+++ src/btio.h
@@ -60,6 +60,7 @@
 	BT_IO_OPT_MASTER,
 	BT_IO_OPT_HANDLE,
 	BT_IO_OPT_CLASS,
+	BT_IO_OPT_MODE,
 } BtIOOption;
 
 typedef enum {
--- src/dbus-hci.c
+++ src/dbus-hci.c
@@ -418,7 +418,7 @@
 	struct btd_adapter *adapter;
 	struct btd_device *device;
 
-	DBG("hcid_dbus_bonding_process_complete: status=%02x", status);
+	DBG("status=%02x", status);
 
 	if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE))
 		return;
@@ -427,7 +427,7 @@
 		/* This means that there was no pending PIN or SSP token
 		 * request from the controller, i.e. this is not a new
 		 * pairing */
-		DBG("hcid_dbus_bonding_process_complete: no pending auth request");
+		DBG("no pending auth request");
 		return;
 	}
 
@@ -442,7 +442,7 @@
 	struct btd_adapter *adapter;
 	struct btd_device *device;
 
-	DBG("hcid_dbus_simple_pairing_complete: status=%02x", status);
+	DBG("status=%02x", status);
 
 	if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE))
 		return;
@@ -681,12 +681,19 @@
 			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);
 
+	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);
 
--- src/dbus-hci.h
+++ src/dbus-hci.h
@@ -50,8 +50,6 @@
 					struct btd_device **device,
 					gboolean create);
 
-DBusMessage *new_authentication_return(DBusMessage *msg, uint8_t status);
-
 const char *class_to_icon(uint32_t class);
 
 void set_dbus_connection(DBusConnection *conn);
--- src/device.c
+++ src/device.c
@@ -81,7 +81,6 @@
 	DBusConnection *conn;
 	DBusMessage *msg;
 	GIOChannel *io;
-	guint io_id;
 	guint listener_id;
 	struct btd_device *device;
 };
@@ -157,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)
 {
@@ -251,7 +242,7 @@
 	if (device->discov_timer)
 		g_source_remove(device->discov_timer);
 
-	DBG("device_free(%p)", device);
+	DBG("%p", device);
 
 	g_free(device->authr);
 	g_free(device->path);
@@ -513,7 +504,8 @@
 	return 0;
 }
 
-static int device_unblock(DBusConnection *conn, struct btd_device *device)
+static int device_unblock(DBusConnection *conn, struct btd_device *device,
+							gboolean silent)
 {
 	int dev_id, dd, err;
 	bdaddr_t src;
@@ -543,10 +535,12 @@
 	if (err < 0)
 		error("write_blocked(): %s (%d)", strerror(-err), -err);
 
-	emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Blocked",
+	if (!silent) {
+		emit_property_changed(conn, device->path,
+					DEVICE_INTERFACE, "Blocked",
 					DBUS_TYPE_BOOLEAN, &device->blocked);
-
-	device_probe_drivers(device, device->uuids);
+		device_probe_drivers(device, device->uuids);
+	}
 
 	return 0;
 }
@@ -560,7 +554,7 @@
 	if (value)
 		err = device_block(conn, device);
 	else
-		err = device_unblock(conn, device);
+		err = device_unblock(conn, device, FALSE);
 
 	switch (-err) {
 	case 0:
@@ -794,11 +788,6 @@
 	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;
@@ -1100,6 +1089,7 @@
 {
 	bdaddr_t src;
 	char addr[18];
+	DBusConnection *conn = get_dbus_connection();
 
 	adapter_get_address(device->adapter, &src);
 	ba2str(&device->bdaddr, addr);
@@ -1109,6 +1099,9 @@
 	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, gboolean remove_stored)
@@ -1737,7 +1730,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 */
@@ -1808,9 +1801,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);
 
@@ -1891,63 +1881,19 @@
 	return bonding;
 }
 
-static gboolean bonding_io_cb(GIOChannel *io, GIOCondition cond,
-							gpointer user_data)
-{
-	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)
+static int device_authentication_requested(struct btd_device *device,
+						int handle)
 {
-	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));
@@ -1965,37 +1911,60 @@
 	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);
-		goto failed;
+		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;
+	}
 
-	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)
@@ -2108,6 +2077,7 @@
 		agent_cancel(auth->agent);
 
 	if (status) {
+		device_cancel_authentication(device, TRUE);
 		device_cancel_bonding(device, status);
 		return;
 	}
@@ -2267,11 +2237,7 @@
 
 	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;
@@ -2473,7 +2439,7 @@
 {
 	device->ref++;
 
-	DBG("btd_device_ref(%p): ref=%d", device, device->ref);
+	DBG("%p: ref=%d", device, device->ref);
 
 	return device;
 }
@@ -2485,7 +2451,7 @@
 
 	device->ref--;
 
-	DBG("btd_device_unref(%p): ref=%d", device, device->ref);
+	DBG("%p: ref=%d", device, device->ref);
 
 	if (device->ref > 0)
 		return;
--- src/log.c
+++ src/log.c
@@ -73,21 +73,21 @@
 
 static gboolean is_enabled(struct btd_debug_desc *desc)
 {
-        int i;
+	int i;
 
-        if (enabled == NULL)
-                return 0;
+	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;
-        }
+	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;
+	return 0;
 }
 
 void __btd_toggle_debug()
--- src/log.h
+++ src/log.h
@@ -31,11 +31,11 @@
 void __btd_toggle_debug();
 
 struct btd_debug_desc {
-        const char *name;
-        const char *file;
+	const char *name;
+	const char *file;
 #define BTD_DEBUG_FLAG_DEFAULT (0)
 #define BTD_DEBUG_FLAG_PRINT   (1 << 0)
-        unsigned int flags;
+	unsigned int flags;
 } __attribute__((aligned(8)));
 
 /**
@@ -47,12 +47,11 @@
  * 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); \
+	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)
 
--- src/main.c
+++ src/main.c
@@ -302,6 +302,7 @@
 
 static gchar *option_debug = NULL;
 static gboolean option_detach = TRUE;
+static gboolean option_version = FALSE;
 static gboolean option_udev = FALSE;
 
 static guint last_adapter_timeout = 0;
@@ -334,7 +335,8 @@
 	last_adapter_timeout = 0;
 }
 
-static gboolean parse_debug(const char *key, const char *value, gpointer user_data, GError **error)
+static gboolean parse_debug(const char *key, const char *value,
+				gpointer user_data, GError **error)
 {
 	if (value)
 		option_debug = g_strdup(value);
@@ -345,12 +347,14 @@
 }
 
 static GOptionEntry options[] = {
-	{ "nodaemon", 'n', G_OPTION_FLAG_REVERSE,
-				G_OPTION_ARG_NONE, &option_detach,
-				"Don't run as daemon in background" },
 	{ "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
 				G_OPTION_ARG_CALLBACK, parse_debug,
-				"Enable debug information output", "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" },
+	{ "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 },
@@ -387,6 +391,13 @@
 		exit(1);
 	}
 
+	g_option_context_free(context);
+
+	if (option_version == TRUE) {
+		printf("%s\n", VERSION);
+		exit(0);
+	}
+
 	if (option_udev == TRUE) {
 		int err;
 
@@ -399,8 +410,6 @@
 		}
 	}
 
-	g_option_context_free(context);
-
 	if (option_detach == TRUE && option_udev == FALSE) {
 		if (daemon(0, 0)) {
 			perror("Can't start daemon");
--- src/manager.c
+++ src/manager.c
@@ -337,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)
--- src/security.c
+++ src/security.c
@@ -377,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;
 
@@ -403,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)
--- src/storage.c
+++ src/storage.c
@@ -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)
--- test/test-adapter
+++ 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)
--- test/test-audio
+++ test/test-audio
@@ -2,14 +2,29 @@
 
 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")
 
-if len(sys.argv) < 3:
+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>
@@ -17,13 +32,13 @@
 	""" % sys.argv[0]
 	sys.exit(1)
 
-device = adapter.FindDevice(sys.argv[2])
+device = adapter.FindDevice(args[1])
 audio = dbus.Interface(bus.get_object("org.bluez", device),
 				"org.bluez.Audio")
 
-if sys.argv[1] == "connect":
+if args[0] == "connect":
 	audio.Connect()
-elif sys.argv[1] == "disconnect":
+elif args[0] == "disconnect":
 	audio.Disconnect()
 else:
 	print "Unknown command"
--- test/test-device
+++ 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"
@@ -25,41 +39,45 @@
 	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(">.*?<")
@@ -69,79 +87,79 @@
 			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 (sys.argv[1] == "blocked"):
-	if (len(sys.argv) < 3):
+if (args[0] == "blocked"):
+	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["Blocked"]
 		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("Blocked", value)
 	sys.exit(0)
 
--- test/test-discovery
+++ 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,
--- test/test-input
+++ test/test-input
@@ -2,14 +2,29 @@
 
 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")
 
-if len(sys.argv) < 3:
+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>
@@ -17,13 +32,13 @@
 	""" % sys.argv[0]
 	sys.exit(1)
 
-device = adapter.FindDevice(sys.argv[2])
+device = adapter.FindDevice(args[1])
 input = dbus.Interface(bus.get_object("org.bluez", device),
 				"org.bluez.Input")
 
-if sys.argv[1] == "connect":
+if args[0] == "connect":
 	input.Connect()
-elif sys.argv[1] == "disconnect":
+elif args[0] == "disconnect":
 	input.Disconnect()
 else:
 	print "Unknown command"
--- test/test-network
+++ 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)
 
--- test/test-serial
+++ 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)
 
--- test/test-service
+++ 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)
--- test/test-telephony
+++ 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)
--- tools/hciattach.8
+++ 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
--- tools/hciattach.c
+++ tools/hciattach.c
@@ -326,7 +326,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++;
@@ -343,7 +344,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++;
@@ -1095,10 +1097,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) {
@@ -1157,6 +1163,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;
@@ -1172,14 +1183,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;
@@ -1191,8 +1202,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;
@@ -1221,6 +1233,10 @@
 			}
 			exit(0);
 
+		case 'r':
+			raw = 1;
+			break;
+
 		default:
 			usage();
 			exit(1);
@@ -1298,7 +1314,7 @@
 	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");
 		exit(1);
--- tools/hciattach.h
+++ tools/hciattach.h
@@ -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);
 
--- tools/hciconfig.8
+++ tools/hciconfig.8
@@ -10,6 +10,7 @@
 .br
 .B hciconfig
 .RB [\| \-a \|]
+.B hciX
 .RI [\| command
 .RI [\| "command parameters" \|]\|]
 
--- tools/hcitool.c
+++ tools/hcitool.c
@@ -2354,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);
@@ -2383,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 }
 };
 

++++++ bluez.yaml
--- bluez.yaml
+++ bluez.yaml
@@ -1,6 +1,6 @@
 Name: bluez
 Summary: Bluetooth utilities
-Version: 4.66
+Version: 4.69
 Release: 1
 Group: Applications/System
 License: GPLv2+



More information about the MeeGo-commits mailing list