Upgrade Bluez 5.28 and synchronize Tizen 2.4's bluez 07/40707/2
authorDoHyun Pyun <dh79.pyun@samsung.com>
Mon, 8 Jun 2015 08:17:10 +0000 (17:17 +0900)
committerDoHyun Pyun <dh79.pyun@samsung.com>
Mon, 8 Jun 2015 11:46:56 +0000 (20:46 +0900)
Change-Id: Ifaf2154ba0ab19b180946e0d92f1817a1d9ed839
Signed-off-by: DoHyun Pyun <dh79.pyun@samsung.com>
422 files changed:
ChangeLog
Makefile.am [changed mode: 0755->0644]
Makefile.obexd
Makefile.plugins
Makefile.tools [changed mode: 0755->0644]
TODO
acinclude.m4
android/Android.mk
android/Makefile.am
android/README
android/a2dp.c
android/avctp.c
android/avdtp.c
android/avdtp.h
android/avdtptest.c
android/avrcp-lib.c
android/bas.c
android/bluetooth.c
android/bluetooth.h
android/bluetoothd-snoop.c
android/client/if-rc-ctrl.c
android/compat/readline/history.h [moved from attrib/client.h with 69% similarity]
android/compat/readline/readline.h [new file with mode: 0644]
android/compat/wordexp.h [new file with mode: 0644]
android/dis.c
android/gatt.c
android/hal-ipc-api.txt
android/hal-msg.h
android/handsfree-client.c
android/handsfree.c
android/hidhost.c
android/hog.c
android/log.c
android/main.c
android/pan.c
android/pics-a2dp.txt
android/pics-avctp.txt
android/pics-avdtp.txt
android/pics-avrcp.txt
android/pics-did.txt
android/pics-dis.txt
android/pics-gap.txt
android/pics-gatt.txt
android/pics-gavdp.txt [new file with mode: 0644]
android/pics-hdp.txt
android/pics-hfp.txt
android/pics-hid.txt
android/pics-hogp.txt
android/pics-hsp.txt
android/pics-iopt.txt
android/pics-mcap.txt
android/pics-opp.txt
android/pics-pan.txt
android/pics-pbap.txt
android/pics-rfcomm.txt
android/pics-scpp.txt
android/pics-sdp.txt
android/pics-sm.txt
android/pics-spp.txt
android/pixit-a2dp.txt
android/pixit-avctp.txt
android/pixit-avdtp.txt
android/pixit-avrcp.txt
android/pixit-did.txt
android/pixit-dis.txt
android/pixit-gap.txt
android/pixit-gatt.txt
android/pixit-gavdp.txt [new file with mode: 0644]
android/pixit-hdp.txt
android/pixit-hfp.txt
android/pixit-hid.txt
android/pixit-hogp.txt
android/pixit-hsp.txt
android/pixit-iopt.txt
android/pixit-mcap.txt
android/pixit-opp.txt
android/pixit-pan.txt
android/pixit-pbap.txt
android/pixit-rfcomm.txt
android/pixit-scpp.txt
android/pixit-sdp.txt [new file with mode: 0644]
android/pixit-sm.txt
android/pixit-spp.txt
android/pts-a2dp.txt
android/pts-avctp.txt
android/pts-avdtp.txt
android/pts-avrcp.txt
android/pts-did.txt
android/pts-dis.txt
android/pts-gap.txt
android/pts-gatt.txt
android/pts-gavdp.txt [new file with mode: 0644]
android/pts-hdp.txt
android/pts-hfp.txt
android/pts-hid.txt
android/pts-hogp.txt
android/pts-hsp.txt
android/pts-iopt.txt
android/pts-l2cap.txt
android/pts-mcap.txt
android/pts-mps.txt
android/pts-opp.txt
android/pts-pan.txt
android/pts-pbap.txt
android/pts-rfcomm.txt
android/pts-scpp.txt
android/pts-sdp.txt [new file with mode: 0644]
android/pts-sm.txt
android/pts-spp.txt
android/scpp.c
android/socket.c
android/system-emulator.c
android/tester-gatt.c
android/tester-main.c
android/tester-main.h
attrib/att.c
attrib/att.h
attrib/client.c [deleted file]
attrib/gatt-service.c
attrib/gatt-service.h
attrib/gatt.c
attrib/gatt.h
attrib/gattrib.c
attrib/gattrib.h
attrib/gatttool.c
attrib/interactive.c
attrib/utils.c
bluez.manifest
btio/btio.c
client/agent.c
client/display.c
client/display.h
client/gatt.c [new file with mode: 0644]
client/gatt.h [new file with mode: 0644]
client/main.c
configure.ac [changed mode: 0755->0644]
doc/adapter-api.txt
doc/device-api.txt
doc/gatt-api.txt
doc/maintainer-guidelines.txt [new file with mode: 0644]
doc/mgmt-api.txt
doc/profile-api.txt
doc/settings-storage.txt
doc/test-coverage.txt
emulator/amp.c
emulator/b1ee.c
emulator/bthost.c
emulator/bthost.h
emulator/hciemu.c
emulator/hfp.c
emulator/le.c
emulator/main.c
emulator/phy.c
emulator/serial.c
emulator/server.c
emulator/smp.c
emulator/vhci.c
gdbus/.gdbus.h.swp [deleted file]
gdbus/client.c
gdbus/gdbus.h
gdbus/object.c
gdbus/watch.c
gobex/gobex-apparam.c
gobex/gobex-header.h
gobex/gobex-packet.h
gobex/gobex-transfer.c
gobex/gobex.h
lib/bluetooth.c
lib/bluetooth.h
lib/hci.c
lib/hci.h
lib/mgmt.h
lib/uuid.c
lib/uuid.h
monitor/avctp.c
monitor/bt.h
monitor/btsnoop.c
monitor/control.c
monitor/hcidump.c
monitor/l2cap.c
monitor/l2cap.h
monitor/main.c
monitor/packet.c
monitor/rfcomm.c
monitor/sdp.c
obexd/client/bluetooth.c
obexd/client/dbus.c
obexd/client/driver.c
obexd/client/ftp.c
obexd/client/manager.c
obexd/client/manager.h
obexd/client/map-event.c
obexd/client/map.c
obexd/client/mns.c
obexd/client/opp.c
obexd/client/pbap.c
obexd/client/session.c
obexd/client/session.h
obexd/client/sync.c
obexd/client/transfer.c
obexd/client/transport.c
obexd/plugins/.phonebook.h.swp [deleted file]
obexd/plugins/bluetooth.c
obexd/plugins/filesystem.c
obexd/plugins/ftp.c
obexd/plugins/irmc.c
obexd/plugins/mas.c
obexd/plugins/messages-dummy.c
obexd/plugins/opp.c
obexd/plugins/pbap.c
obexd/plugins/pcsuite.c
obexd/plugins/phonebook-dummy.c
obexd/plugins/phonebook-ebook.c
obexd/plugins/phonebook-tracker.c
obexd/plugins/syncevolution.c
obexd/plugins/vcard.c
obexd/src/main.c
obexd/src/manager.c
obexd/src/obex.c
obexd/src/server.c
packaging/bluez.spec [changed mode: 0755->0644]
plugins/autopair.c
plugins/dbusoob.c
plugins/gatt-example.c
plugins/hostname.c
plugins/neard.c
plugins/policy.c
plugins/service.c [deleted file]
plugins/sixaxis.c
plugins/wiimote.c
profiles/alert/server.c
profiles/audio/a2dp.c
profiles/audio/a2dp.h
profiles/audio/avctp.c
profiles/audio/avdtp.c
profiles/audio/avdtp.h
profiles/audio/avrcp.c
profiles/audio/control.c
profiles/audio/media.c
profiles/audio/player.c
profiles/audio/sink.c
profiles/audio/source.c
profiles/audio/transport.c
profiles/cups/hcrp.c
profiles/cups/main.c
profiles/cups/sdp.c
profiles/cups/spp.c
profiles/cyclingspeed/cyclingspeed.c
profiles/deviceinfo/deviceinfo.c
profiles/gap/gas.c
profiles/health/hdp.c
profiles/health/hdp_main.c
profiles/health/hdp_manager.c
profiles/health/hdp_util.c
profiles/heartrate/heartrate.c
profiles/iap/main.c
profiles/input/device.c
profiles/input/hog.c
profiles/input/manager.c
profiles/input/server.c
profiles/network/bnep.c
profiles/network/bnep.h
profiles/network/connection.c
profiles/network/manager.c
profiles/network/server.c
profiles/proximity/immalert.c
profiles/proximity/linkloss.c
profiles/proximity/main.c
profiles/proximity/manager.c
profiles/proximity/monitor.c
profiles/proximity/reporter.c
profiles/sap/main.c
profiles/sap/manager.c
profiles/sap/sap-dummy.c
profiles/sap/server.c
profiles/sap/server.h
profiles/scanparam/scan.c
profiles/thermometer/thermometer.c
profiles/time/server.c
src/adapter.c
src/adapter.h
src/adapter_le_vsc_features.c [new file with mode: 0644]
src/adapter_le_vsc_features.h [new file with mode: 0644]
src/agent.c
src/agent.h
src/attrib-server.c
src/attrib-server.h
src/bluetooth.conf [changed mode: 0755->0644]
src/bluetooth.service.in [changed mode: 0755->0644]
src/dbus-common.c
src/device.c
src/device.h
src/eir.c
src/error.c
src/gatt-client.c
src/gatt-database.c [new file with mode: 0644]
src/gatt-database.h [new file with mode: 0644]
src/gatt-dbus.c
src/gatt-dbus.h
src/gatt.c
src/gatt.h
src/log.c
src/main.c
src/main.conf [deleted file]
src/main_m.conf
src/main_w.conf
src/org.bluez.service [changed mode: 0755->0644]
src/oui.c
src/oui.h
src/plugin.c
src/profile.c
src/profile.h
src/rfkill.c
src/sdp-client.c
src/sdp-xml.c
src/sdp-xml.h
src/sdpd-database.c
src/sdpd-request.c
src/sdpd-server.c
src/sdpd-service.c
src/sdpd.h
src/service.c
src/service.h
src/shared/att-types.h
src/shared/att.c
src/shared/att.h
src/shared/crypto.c
src/shared/ecc.c
src/shared/gap.c
src/shared/gatt-client.c
src/shared/gatt-client.h
src/shared/gatt-db.c
src/shared/gatt-db.h
src/shared/gatt-helpers.c
src/shared/gatt-helpers.h
src/shared/gatt-server.c
src/shared/hci.c
src/shared/hfp.c
src/shared/io-mainloop.c
src/shared/mainloop.c [moved from monitor/mainloop.c with 95% similarity]
src/shared/mainloop.h [moved from monitor/mainloop.h with 96% similarity]
src/shared/queue.c
src/shared/tester.c
src/shared/timeout-mainloop.c
src/shared/util.c
src/shared/util.h
src/storage.c
src/uuid-helper.c
test/pbap-client [changed mode: 0755->0644]
tools/3dsp.c
tools/amptest.c
tools/avinfo.c
tools/avtest.c
tools/bccmd.c
tools/bdaddr.c
tools/bluemoon.c
tools/bluetooth-player.c
tools/btattach.c
tools/btgatt-client.c
tools/btgatt-server.c
tools/btinfo.c
tools/btiotest.c
tools/btmgmt.c
tools/btproxy.c
tools/btsnoop.c
tools/ciptool.c
tools/cltest.c
tools/csr.c
tools/csr_hci.c
tools/gap-tester.c
tools/gatt-example [new file with mode: 0644]
tools/gatt-service.c
tools/hciattach.c
tools/hciattach_ath3k.c
tools/hciattach_bcm43xx.c
tools/hciattach_intel.c
tools/hciattach_qualcomm.c
tools/hciattach_st.c
tools/hciattach_ti.c
tools/hciattach_tialt.c
tools/hciconfig.c
tools/hcieventmask.c
tools/hcisecfilter.c
tools/hcitool.1
tools/hcitool.c
tools/hex2hcd.c
tools/hid2hci.1
tools/hid2hci.c
tools/hwdb.c
tools/ibeacon.c
tools/l2cap-tester.c
tools/l2ping.c
tools/l2test.c
tools/mcaptest.c
tools/mgmt-tester.c
tools/mpris-player.c [deleted file]
tools/mpris-proxy.c
tools/obex-client-tool.c
tools/obex-server-tool.c
tools/obexctl.c
tools/oobtest.c [new file with mode: 0644]
tools/parser/hci.c
tools/rctest.c
tools/rfcomm-tester.c
tools/rfcomm.c
tools/scotest.c
tools/sdptool.c
tools/update_compids.sh [changed mode: 0755->0644]
unit/test-avdtp.c
unit/test-eir.c
unit/test-gatt.c
unit/test-gattrib.c
unit/test-gdbus-client.c
unit/test-gobex-apparam.c
unit/test-gobex-header.c
unit/test-gobex-packet.c
unit/test-gobex-transfer.c
unit/test-gobex.c
unit/test-queue.c
unit/test-uuid.c
unit/util.c
unit/util.h

index dacede1..2c38828 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+ver 5.28:
+       Fix issue with GATT device discovery and probing.
+       Fix issue with bearer selection for dual-mode devices.
+       Fix issue with device removal while connected.
+       Fix issue with device name setting from inquiry response.
+       Fix issue with missing termination of name characteristic.
+       Fix issue with UTF-8 length handling for device name.
+       Fix issue with AVCTP key auto release handling.
+       Fix issue with AVCTP key press repetition handling.
+       Fix issue with payload sizes and GATT notifications.
+       Fix issue with memory corruption and GATT notifications.
+       Add support for HID proxy switching and CSR 8510 A10 devices.
+       Add support for Broadcom hex2hcd conversion utility.
+
 ver 5.27:
        Fix issue with endian handling and management interface.
        Fix issue with pending GATT operations when disconnecting.
old mode 100755 (executable)
new mode 100644 (file)
index 9dcc13a..70f31c9
@@ -43,21 +43,13 @@ endif
 
 if SYSTEMD
 systemdsystemunitdir = @SYSTEMD_SYSTEMUNITDIR@
-#if USBBT
-#systemdsystemunit_DATA = src/common/bluetooth.service
-#else
 systemdsystemunit_DATA = src/bluetooth.service
-#endif
 
 dbussystembusdir = @DBUS_SYSTEMBUSDIR@
 dbussystembus_DATA = src/org.bluez.service
 endif
 
-if USBBT
-#EXTRA_DIST += src/common/bluetooth.service.in src/org.bluez.service
-else
 EXTRA_DIST += src/bluetooth.service.in src/org.bluez.service
-endif
 
 plugindir = $(libdir)/bluetooth/plugins
 
@@ -88,7 +80,7 @@ include_HEADERS += $(lib_headers)
 lib_LTLIBRARIES += lib/libbluetooth.la
 
 lib_libbluetooth_la_SOURCES = $(lib_headers) $(lib_sources)
-lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 21:0:18
+lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 21:1:18
 lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
 endif
 
@@ -134,12 +126,12 @@ src_libshared_glib_la_SOURCES = $(shared_sources) \
 src_libshared_mainloop_la_SOURCES = $(shared_sources) \
                                src/shared/io-mainloop.c \
                                src/shared/timeout-mainloop.c \
-                               monitor/mainloop.h monitor/mainloop.c
+                               src/shared/mainloop.h src/shared/mainloop.c
 
 attrib_sources = attrib/att.h attrib/att-database.h attrib/att.c \
                attrib/gatt.h attrib/gatt.c \
-               attrib/gattrib.h attrib/gattrib.c attrib/client.h \
-               attrib/client.c attrib/gatt-service.h attrib/gatt-service.c
+               attrib/gattrib.h attrib/gattrib.c  \
+               attrib/gatt-service.h attrib/gatt-service.c
 
 btio_sources = btio/btio.h btio/btio.c
 
@@ -175,6 +167,7 @@ src_bluetoothd_SOURCES = $(builtin_sources) \
                        src/sdpd-server.c src/sdpd-request.c \
                        src/sdpd-service.c src/sdpd-database.c \
                        src/attrib-server.h src/attrib-server.c \
+                       src/gatt-database.h src/gatt-database.c \
                        src/sdp-xml.h src/sdp-xml.c \
                        src/sdp-client.h src/sdp-client.c \
                        src/textfile.h src/textfile.c \
@@ -185,6 +178,7 @@ src_bluetoothd_SOURCES = $(builtin_sources) \
                        src/agent.h src/agent.c \
                        src/error.h src/error.c \
                        src/adapter.h src/adapter.c \
+                       src/adapter_le_vsc_features.h src/adapter_le_vsc_features.c \
                        src/profile.h src/profile.c \
                        src/service.h src/service.c \
                        src/gatt-dbus.h src/gatt-dbus.c \
@@ -200,17 +194,10 @@ src_bluetoothd_LDADD = lib/libbluetooth-internal.la \
 src_bluetoothd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic \
                                -Wl,--version-script=$(srcdir)/src/bluetooth.ver
 
-if USBBT
-src_bluetoothd_DEPENDENCIES = lib/libbluetooth-internal.la \
-                               gdbus/libgdbus-internal.la \
-                               src/libshared-glib.la \
-                               src/common/bluetooth.service
-else
 src_bluetoothd_DEPENDENCIES = lib/libbluetooth-internal.la \
                                gdbus/libgdbus-internal.la \
                                src/libshared-glib.la \
                                src/bluetooth.service
-endif
 
 src_bluetoothd_CFLAGS = $(AM_CFLAGS) -DBLUETOOTH_PLUGIN_BUILTIN \
                                        -DPLUGINDIR=\""$(build_plugindir)"\"
@@ -277,7 +264,7 @@ EXTRA_DIST += tools/magic.btsnoop
 
 AM_CFLAGS += @DBUS_CFLAGS@ @GLIB_CFLAGS@
 
-AM_CPPFLAGS = -I$(builddir)/lib -I$(srcdir)/gdbus
+AM_CPPFLAGS = -I$(builddir)/lib
 
 
 unit_tests += unit/test-eir
index 3c97bdc..42135a9 100644 (file)
@@ -7,15 +7,6 @@ dbussessionbusdir = @DBUS_SESSIONBUSDIR@
 dbussessionbus_DATA = obexd/src/org.bluez.obex.service
 endif
 
-# Start of __TIZEN_PATCH__
-
-# Even though systemd is not used,
-# obexd should be launched using dbus auto activation.
-dbussessionbusdir = @DBUS_SESSIONBUSDIR@
-dbussessionbus_DATA = obexd/src/org.bluez.obex.service
-
-# End of __TIZEN_PATCH__
-
 EXTRA_DIST += obexd/src/obex.service.in obexd/src/org.bluez.obex.service
 
 obex_plugindir = $(libdir)/obex/plugins
@@ -98,7 +89,7 @@ obexd_src_obexd_LDFLAGS = -Wl,--export-dynamic
 obexd_src_obexd_CFLAGS = $(AM_CFLAGS) @GLIB_CFLAGS@ @DBUS_CFLAGS@ \
                                @ICAL_CFLAGS@ -DOBEX_PLUGIN_BUILTIN \
                                -DPLUGINDIR=\""$(obex_plugindir)"\" \
-                               -fPIC -D_FILE_OFFSET_BITS=64
+                               -fPIC -D_FILE_OFFSET_BITS=64 -pie
 
 obexd_src_obexd_CPPFLAGS = -I$(builddir)/lib -I$(builddir)/obexd/src  \
                                -I$(srcdir)/obexd/src -I$(srcdir)/btio \
index ce2d2e1..b850878 100644 (file)
@@ -30,15 +30,17 @@ if EXPERIMENTAL
 if TIZEN_UNUSED_PLUGIN
 builtin_modules += neard
 builtin_sources += plugins/neard.c
+endif
 
+if TIZEN_SAP_PLUGIN
 builtin_modules += sap
 builtin_sources += profiles/sap/main.c profiles/sap/manager.h \
                        profiles/sap/manager.c profiles/sap/server.h \
                        profiles/sap/server.c profiles/sap/sap.h \
-                       profiles/sap/sap-dummy.c
+                       profiles/sap/sap-u8500.c
 
-noinst_LIBRARIES += profiles/sap/libsap.a
-profiles_sap_libsap_a_SOURCES = profiles/sap/sap.h profiles/sap/sap-u8500.c
+#noinst_LIBRARIES += profiles/sap/libsap.a
+#profiles_sap_libsap_a_SOURCES = profiles/sap/sap.h profiles/sap/sap-u8500
 endif
 endif
 
@@ -84,7 +86,7 @@ endif
 endif
 
 if EXPERIMENTAL
-if TIZEN_UNUSED_PLUGIN
+if TIZEN_HEALTH_PLUGIN
 builtin_modules += health
 builtin_sources += profiles/health/mcap.h profiles/health/mcap.c \
                        profiles/health/hdp_main.c profiles/health/hdp_types.h \
@@ -142,11 +144,3 @@ plugins_sixaxis_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
                                                -no-undefined @UDEV_LIBS@
 plugins_sixaxis_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden @UDEV_CFLAGS@
 endif
-
-if SERVICE
-plugin_LTLIBRARIES += plugins/service.la
-plugins_service_la_SOURCES = plugins/service.c
-plugins_service_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
-                                                               -no-undefined
-plugins_service_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden
-endif
old mode 100755 (executable)
new mode 100644 (file)
index 5bce254..0dba04a
@@ -5,6 +5,7 @@ bin_PROGRAMS += client/bluetoothctl
 client_bluetoothctl_SOURCES = client/main.c \
                                        client/display.h client/display.c \
                                        client/agent.h client/agent.c \
+                                       client/gatt.h client/gatt.c \
                                        monitor/uuid.h monitor/uuid.c
 client_bluetoothctl_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@ \
                                -lreadline
@@ -117,13 +118,11 @@ tools_hci_tester_SOURCES = tools/hci-tester.c monitor/bt.h
 tools_hci_tester_LDADD = src/libshared-glib.la @GLIB_LIBS@
 endif
 
-#tools/mpris-proxy tools/mcaptest
-
 if TOOLS
 bin_PROGRAMS += tools/hciattach tools/hciconfig tools/hcitool tools/hcidump \
                        tools/rfcomm tools/rctest tools/l2test tools/l2ping \
                        tools/sdptool tools/ciptool tools/bccmd \
-                       tools/bluemoon
+                       tools/bluemoon tools/hex2hcd tools/mpris-proxy
 
 tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
                                                tools/hciattach_st.c \
@@ -133,7 +132,7 @@ tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
                                                tools/hciattach_qualcomm.c \
                                                tools/hciattach_intel.c \
                                                tools/hciattach_bcm43xx.c
-#                                              src/log.c
+#                                              src/log.c 
 #                                              tools/hciattach_bcm43xx.c
 tools_hciattach_LDADD = lib/libbluetooth-internal.la
 
@@ -192,14 +191,16 @@ tools_bccmd_LDADD = lib/libbluetooth-internal.la
 tools_bluemoon_SOURCES = tools/bluemoon.c monitor/bt.h
 tools_bluemoon_LDADD = src/libshared-mainloop.la
 
-#tools_mpris_proxy_SOURCES = tools/mpris-proxy.c
-#tools_mpris_proxy_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
+tools_hex2hcd_SOURCES = tools/hex2hcd.c
+
+tools_mpris_proxy_SOURCES = tools/mpris-proxy.c
+tools_mpris_proxy_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
 
-#tools_mcaptest_SOURCES = tools/mcaptest.c \
-#                              btio/btio.h btio/btio.c \
-#                              src/log.c src/log.h \
-#                              profiles/health/mcap.h profiles/health/mcap.c
-#tools_mcaptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@ -lrt
+tools_mcaptest_SOURCES = tools/mcaptest.c \
+                               btio/btio.h btio/btio.c \
+                               src/log.c src/log.h \
+                               profiles/health/mcap.h profiles/health/mcap.c
+tools_mcaptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@ -lrt
 
 dist_man_MANS += tools/hciattach.1 tools/hciconfig.1 \
                        tools/hcitool.1 tools/hcidump.1 \
@@ -229,10 +230,10 @@ noinst_PROGRAMS += tools/bdaddr tools/avinfo tools/avtest \
                        tools/scotest tools/amptest tools/hwdb \
                        tools/hcieventmask tools/hcisecfilter \
                        tools/btmgmt tools/btinfo tools/btattach \
-                       tools/btsnoop tools/btproxy tools/btiotest \
-                       tools/cltest tools/seq2bseq tools/hex2hcd \
-                       tools/ibeacon tools/btgatt-client \
-                       tools/btgatt-server tools/mpris-player
+                       tools/btsnoop tools/btproxy \
+                       tools/btiotest tools/mcaptest tools/cltest \
+                       tools/oobtest tools/seq2bseq tools/ibeacon \
+                       tools/btgatt-client tools/btgatt-server
 
 tools_bdaddr_SOURCES = tools/bdaddr.c src/oui.h src/oui.c
 tools_bdaddr_LDADD = lib/libbluetooth-internal.la @UDEV_LIBS@
@@ -249,8 +250,9 @@ tools_hwdb_LDADD = lib/libbluetooth-internal.la
 
 tools_hcieventmask_LDADD = lib/libbluetooth-internal.la
 
-tools_btmgmt_SOURCES = tools/btmgmt.c src/uuid-helper.c
-tools_btmgmt_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la
+tools_btmgmt_SOURCES = tools/btmgmt.c src/uuid-helper.c client/display.c
+tools_btmgmt_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la \
+                               -lreadline -lncurses
 
 tools_btinfo_SOURCES = tools/btinfo.c monitor/bt.h
 tools_btinfo_LDADD = src/libshared-mainloop.la
@@ -267,14 +269,19 @@ tools_btproxy_LDADD = src/libshared-mainloop.la
 tools_btiotest_SOURCES = tools/btiotest.c btio/btio.h btio/btio.c
 tools_btiotest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 
+tools_mcaptest_SOURCES = tools/mcaptest.c \
+                               btio/btio.h btio/btio.c \
+                               src/log.c src/log.h \
+                               profiles/health/mcap.h profiles/health/mcap.c
+tools_mcaptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
 tools_cltest_SOURCES = tools/cltest.c
-tools_mpris_player_SOURCES = tools/mpris-player.c
-tools_mpris_player_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
 tools_cltest_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la
 
-tools_seq2bseq_SOURCES = tools/seq2bseq.c
+tools_oobtest_SOURCES = tools/oobtest.c
+tools_oobtest_LDADD = lib/libbluetooth-internal.la src/libshared-mainloop.la
 
-tools_hex2hcd_SOURCES = tools/hex2hcd.c
+tools_seq2bseq_SOURCES = tools/seq2bseq.c
 
 tools_ibeacon_SOURCES = tools/ibeacon.c monitor/bt.h
 tools_ibeacon_LDADD = src/libshared-mainloop.la
diff --git a/TODO b/TODO
index ca3779b..65e19ee 100644 (file)
--- a/TODO
+++ b/TODO
@@ -99,12 +99,6 @@ Low Energy
 ATT/GATT (new shared stack)
 ===========================
 
-- shared/att currently doesn't handle signed writes. It should be extended to
-  support signing outgoing and verify incoming ATT PDUs.
-
-  Priority: Medium
-  Complexity: C1
-
 - Add complete GATT test coverage in unit/test-gatt following the GATT test
   spec. This could use shared/gatt-client and shared/gatt-server at the same
   time to test both against eachother. We should definitely have tests for
@@ -113,6 +107,16 @@ ATT/GATT (new shared stack)
   Priority: High
   Complexity: C4
 
+- Write an example using client D-Bus API using C.
+
+  Priority: High
+  Complexity: C2
+
+- Write an example using client D-Bus API using python.
+
+  Priority: High
+  Complexity: C2
+
 - Define packed structs for ATT protocol PDUs in shared/att-types to improve
   readability. We should probably do this once there are extensive unit tests
   for gatt-client/gatt-server so that we don't accidentally break working code.
@@ -126,41 +130,19 @@ ATT/GATT (new shared stack)
   Priority: Medium
   Complexity: C1
 
-- Introduce a handler interface to shared/gatt-client which can be used by the
-  upper layer to determine when the link has been disconnected or an ATT
-  protocol request times out.
+- Persist client attribute cache across reboots.
 
   Priority: Medium
-  Complexity: C2
-
-- Introduce long-term caching of attributes to shared/gatt-client, such that the
-  services, characteristics, and descriptors obtained from a peripheral are
-  remembered in the case of bonding. This may involve storing data about GATT
-  services to disk.
-
-  Priority: Low
   Complexity: C4
 
 - Move all daemon plugins and profiles that are GATT based to use
   shared/gatt-client instead of attrib/*. This is a complicated task that
   potentially needs a new plugin/profile probing interface and a lot of
-  rewriting that can cause regressions in existing functionality. The biggest
-  challenge here is that an instance of bt_att (shared/att) and GAttrib
-  (attrib/gattrib) cannot coexist on the same file descriptor, since they will
-  cause ATT protocol violations by breaking the sequential request-response
-  structure. A special shared/gatt-client-gattrib implementation may be
-  necessary to move each profile/plugin to the new API before actually switching
-  to the shared/att based implementation.
+  rewriting that can cause regressions in existing functionality.
 
   Priority: Medium
   Complexity: C4
 
-- Implement the client portion of doc/gatt-api.txt using shared/gatt-client once
-  plugin/profile code uses it.
-
-  Priority: Medium
-  Complexity: C2
-
 - Introduce a way for shared/gatt-server to check security permissions on the
   current connection through bt_att.
 
@@ -180,6 +162,50 @@ ATT/GATT (new shared stack)
   Priority: Medium
   Complexity: C4
 
+- Send out indications from the "Service Changed" characteristic upon
+  reconnection if a bonded device is not connected when the local database is
+  modified.
+
+  Priority: High
+  Complexity: C2
+
+- Unify the GATT server and client D-Bus implementations into a single module.
+  While these don't share a lot of code, keeping them all in src/gatt-dbus seems
+  to make more sense from an organizational perspective.
+
+  Priority: Low
+  Complexity: C1
+
+- Isolate all GATT code inside the daemon into its own module and perform
+  interaction with other modules (e.g. src/device.c) via callbacks. This
+  includes client/server management, tracking incoming/outgoing connections for
+  ATT, and callbacks to perform profile probing.
+
+  Priority: Low
+  Complexity: C4
+
+- Support included services in the GATT D-Bus client API.
+
+  Priority: Medium
+  Complexity: C1
+
+- The recently added support for ATT signed writes requires the following kernel
+  modules to be enabled:
+
+     CONFIG_CRYPTO_USER_API
+     CONFIG_CRYPTO_USER_API_HASH
+     CONFIG_CRYPTO_USER_API_SKCIPHER
+
+  Currently, if these are not enabled, bt_att_new silently returns NULL. We
+  should handle this more gracefully by not supporting signed writes if we can't
+  initialize bt_crypto while succeeding bt_att initialization regardless.
+
+  This behavior should be documented in the README.
+
+  Priority: High
+  Complexity: C1
+
+
 ATT/GATT (old/outdated)
 =======================
 
index 960d54c..bc39c6d 100644 (file)
@@ -21,6 +21,7 @@ AC_DEFUN([COMPILER_FLAGS], [
                with_cflags="$with_cflags -Wredundant-decls"
                with_cflags="$with_cflags -Wcast-align"
                with_cflags="$with_cflags -Wswitch-enum"
+               with_cflags="$with_cflags -Wformat -Wformat-security"
                with_cflags="$with_cflags -DG_DISABLE_DEPRECATED"
                with_cflags="$with_cflags -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_28"
                with_cflags="$with_cflags -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_28"
index c1a9eff..6c0eda8 100644 (file)
@@ -15,6 +15,8 @@ pathmap_INCL += glib:external/bluetooth/glib \
 BLUEZ_COMMON_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\" \
                        -DANDROID_VERSION=$(ANDROID_VERSION) \
                        -DANDROID_STORAGEDIR=\"/data/misc/bluetooth\" \
+                       -DHAVE_LINUX_IF_ALG_H \
+                       -DHAVE_LINUX_TYPES_H \
 
 # Enable warnings enabled in autotools build
 BLUEZ_COMMON_CFLAGS += -Wall -Wextra \
@@ -154,11 +156,16 @@ LOCAL_SHARED_LIBRARIES := \
 LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
 
 LOCAL_MODULE := bluetooth.default
-LOCAL_MODULE_RELATIVE_PATH := hw
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_CLASS := SHARED_LIBRARIES
 LOCAL_REQUIRED_MODULES := bluetoothd bluetoothd-snoop init.bluetooth.rc
 
+ifeq ($(ANDROID_GE_5_0_0), 1)
+LOCAL_MODULE_RELATIVE_PATH := hw
+else
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+endif
+
 include $(BUILD_SHARED_LIBRARY)
 
 #
@@ -261,6 +268,8 @@ LOCAL_SRC_FILES := \
        bluez/btio/btio.c \
        bluez/lib/bluetooth.c \
        bluez/lib/hci.c \
+       bluez/src/shared/util.c \
+       bluez/src/shared/queue.c \
 
 LOCAL_C_INCLUDES += \
        $(LOCAL_PATH)/bluez \
@@ -289,7 +298,6 @@ include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
        bluez/monitor/main.c \
-       bluez/monitor/mainloop.c \
        bluez/monitor/display.c \
        bluez/monitor/hcidump.c \
        bluez/monitor/control.c \
@@ -311,6 +319,7 @@ LOCAL_SRC_FILES := \
        bluez/src/shared/queue.c \
        bluez/src/shared/crypto.c \
        bluez/src/shared/btsnoop.c \
+       bluez/src/shared/mainloop.c \
        bluez/lib/hci.c \
        bluez/lib/bluetooth.c \
 
@@ -338,7 +347,7 @@ include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
        bluez/tools/btproxy.c \
-       bluez/monitor/mainloop.c \
+       bluez/src/shared/mainloop.c \
        bluez/src/shared/util.c \
 
 LOCAL_C_INCLUDES := \
@@ -378,10 +387,15 @@ LOCAL_SHARED_LIBRARIES := \
 LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS) -Wno-declaration-after-statement
 LOCAL_LDFLAGS := -ldl
 
-LOCAL_MODULE_RELATIVE_PATH := hw
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := audio.a2dp.default
 
+ifeq ($(ANDROID_GE_5_0_0), 1)
+LOCAL_MODULE_RELATIVE_PATH := hw
+else
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+endif
+
 include $(BUILD_SHARED_LIBRARY)
 
 #
@@ -404,10 +418,15 @@ LOCAL_SHARED_LIBRARIES := \
 
 LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS) -Wno-declaration-after-statement
 
-LOCAL_MODULE_RELATIVE_PATH := hw
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := audio.sco.default
 
+ifeq ($(ANDROID_GE_5_0_0), 1)
+LOCAL_MODULE_RELATIVE_PATH := hw
+else
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+endif
+
 include $(BUILD_SHARED_LIBRARY)
 
 #
@@ -445,7 +464,7 @@ include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
        bluez/android/bluetoothd-snoop.c \
-       bluez/monitor/mainloop.c \
+       bluez/src/shared/mainloop.c \
        bluez/src/shared/btsnoop.c \
        bluez/android/log.c \
 
@@ -486,16 +505,18 @@ LOCAL_SRC_FILES := \
        bluez/tools/btmgmt.c \
        bluez/lib/bluetooth.c \
        bluez/lib/sdp.c \
-       bluez/monitor/mainloop.c \
+       bluez/src/shared/mainloop.c \
        bluez/src/shared/io-mainloop.c \
        bluez/src/shared/mgmt.c \
        bluez/src/shared/queue.c \
        bluez/src/shared/util.c \
        bluez/src/shared/gap.c \
        bluez/src/uuid-helper.c \
+       bluez/client/display.c \
 
 LOCAL_C_INCLUDES := \
        $(LOCAL_PATH)/bluez \
+       $(LOCAL_PATH)/bluez/android/compat \
 
 LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
 
@@ -539,6 +560,34 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
 include $(BUILD_EXECUTABLE)
 
 #
+# hciconfig
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+       bluez/tools/hciconfig.c \
+       bluez/tools/csr.c \
+       bluez/lib/bluetooth.c \
+       bluez/lib/hci.c \
+
+LOCAL_C_INCLUDES := \
+       $(LOCAL_PATH)/bluez \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
+
+LOCAL_STATIC_LIBRARIES := \
+       bluetooth-headers \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE := hciconfig
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/bluez/configure.ac
+
+include $(BUILD_EXECUTABLE)
+
+#
 # l2ping
 #
 
@@ -549,6 +598,9 @@ LOCAL_SRC_FILES := \
        bluez/lib/bluetooth.c \
        bluez/lib/hci.c \
 
+LOCAL_C_INCLUDES := \
+       $(LOCAL_PATH)/bluez \
+
 LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
 
 LOCAL_STATIC_LIBRARIES := \
@@ -573,6 +625,9 @@ LOCAL_SRC_FILES := \
        bluez/lib/bluetooth.c \
        bluez/lib/hci.c \
 
+LOCAL_C_INCLUDES := \
+       $(LOCAL_PATH)/bluez \
+
 LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
 
 LOCAL_STATIC_LIBRARIES := \
@@ -604,6 +659,9 @@ LOCAL_SRC_FILES := \
        bluez/lib/bluetooth.c \
        bluez/lib/hci.c \
 
+LOCAL_C_INCLUDES := \
+       $(LOCAL_PATH)/bluez \
+
 LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS)
 
 LOCAL_STATIC_LIBRARIES := \
index 9e73be4..676daab 100644 (file)
@@ -102,6 +102,8 @@ noinst_PROGRAMS += android/avdtptest
 android_avdtptest_SOURCES = android/avdtptest.c \
                                src/log.h src/log.c \
                                btio/btio.h btio/btio.c \
+                               src/shared/util.h src/shared/util.c \
+                               src/shared/queue.h src/shared/queue.c \
                                android/avdtp.h android/avdtp.c
 android_avdtptest_CFLAGS = $(AM_CFLAGS)
 android_avdtptest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
@@ -218,6 +220,9 @@ android_test_ipc_LDADD = src/libshared-glib.la @GLIB_LIBS@
 endif
 
 EXTRA_DIST += android/Android.mk android/README \
+                               android/compat/readline/history.h \
+                               android/compat/readline/readline.h \
+                               android/compat/wordexp.h \
                                android/bluetoothd-wrapper.c \
                                android/log.c \
                                android/bluetoothd.te \
@@ -252,6 +257,7 @@ EXTRA_DIST += android/Android.mk android/README \
                                android/pics-scpp.txt \
                                android/pics-dis.txt \
                                android/pics-avdtp.txt \
+                               android/pics-gavdp.txt \
                                android/pixit-l2cap.txt \
                                android/pixit-gap.txt \
                                android/pixit-did.txt \
@@ -277,6 +283,8 @@ EXTRA_DIST += android/Android.mk android/README \
                                android/pixit-rfcomm.txt \
                                android/pixit-spp.txt \
                                android/pixit-avdtp.txt \
+                               android/pixit-gavdp.txt \
+                               android/pixit-sdp.txt \
                                android/pts-rfcomm.txt \
                                android/pts-spp.txt \
                                android/pts-l2cap.txt \
@@ -301,4 +309,6 @@ EXTRA_DIST += android/Android.mk android/README \
                                android/pts-hogp.txt \
                                android/pts-scpp.txt \
                                android/pts-dis.txt \
-                               android/pts-avdtp.txt
+                               android/pts-avdtp.txt \
+                               android/pts-gavdp.txt \
+                               android/pts-sdp.txt
index 7b1f126..9aa9a37 100644 (file)
@@ -403,7 +403,11 @@ recommended Android fixes that are not part of latest AOSP release supported by
 BlueZ.
 
 For Android 5.0 Lollipop:
-<TBD>
+https://android-review.googlesource.com/99761
+https://android-review.googlesource.com/100297
+https://android-review.googlesource.com/102882
+https://android-review.googlesource.com/132733
+https://android-review.googlesource.com/132763
 
 For Android 4.4 KitKat:
 https://android-review.googlesource.com/82757
index 10f5523..f219042 100644 (file)
@@ -38,6 +38,7 @@
 #include "lib/sdp.h"
 #include "lib/sdp_lib.h"
 #include "profiles/audio/a2dp-codecs.h"
+#include "src/shared/queue.h"
 #include "src/log.h"
 #include "hal-msg.h"
 #include "ipc-common.h"
@@ -65,6 +66,8 @@ static bool audio_retrying = false;
 static struct ipc *hal_ipc = NULL;
 static struct ipc *audio_ipc = NULL;
 
+static struct queue *lseps = NULL;
+
 struct a2dp_preset {
        void *data;
        int8_t len;
@@ -115,7 +118,7 @@ static void unregister_endpoint(void *data)
        struct a2dp_endpoint *endpoint = data;
 
        if (endpoint->sep)
-               avdtp_unregister_sep(endpoint->sep);
+               avdtp_unregister_sep(lseps, endpoint->sep);
 
        if (endpoint->caps)
                preset_free(endpoint->caps);
@@ -620,6 +623,7 @@ static void signaling_connect_cb(GIOChannel *chan, GError *err,
                                                        gpointer user_data)
 {
        struct a2dp_device *dev = user_data;
+       struct avdtp *session;
        uint16_t imtu, omtu;
        GError *gerr = NULL;
        int fd;
@@ -643,10 +647,12 @@ static void signaling_connect_cb(GIOChannel *chan, GError *err,
        fd = g_io_channel_unix_get_fd(chan);
 
        /* FIXME: Add proper version */
-       dev->session = avdtp_new(fd, imtu, omtu, 0x0100);
-       if (!dev->session)
+       session = avdtp_new(fd, imtu, omtu, 0x0100, lseps);
+       if (!session)
                goto failed;
 
+       dev->session = session;
+
        avdtp_add_disconnect_cb(dev->session, disconnect_cb, dev);
 
        /* Proceed to stream setup if initiator */
@@ -1327,7 +1333,7 @@ static uint8_t register_endpoint(const uint8_t *uuid, uint8_t codec,
        endpoint = g_new0(struct a2dp_endpoint, 1);
        endpoint->id = g_slist_length(endpoints) + 1;
        endpoint->codec = codec;
-       endpoint->sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE,
+       endpoint->sep = avdtp_register_sep(lseps, AVDTP_SEP_TYPE_SOURCE,
                                                AVDTP_MEDIA_TYPE_AUDIO,
                                                codec, FALSE, &sep_ind,
                                                &sep_cfm, endpoint);
@@ -1624,6 +1630,8 @@ static void bt_audio_unregister(void)
 
        ipc_cleanup(audio_ipc);
        audio_ipc = NULL;
+
+       queue_destroy(lseps, NULL);
 }
 
 static bool bt_audio_register(ipc_disconnect_cb disconnect)
@@ -1691,6 +1699,8 @@ bool bt_a2dp_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
 
        bacpy(&adapter_addr, addr);
 
+       lseps = queue_new();
+
        server = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
                                BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
                                BT_IO_OPT_PSM, AVDTP_PSM,
index a70ed52..758dbd4 100644 (file)
 #include <fcntl.h>
 #include <netinet/in.h>
 
-#include <bluetooth/sdp.h>
-
 #include <glib.h>
 
+#include "lib/sdp.h"
+
 #include "src/log.h"
 #include "src/uinput.h"
 
index 853fdf3..e4fd2b7 100644 (file)
 
 #include "lib/bluetooth.h"
 #include "src/log.h"
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
 #include "avdtp.h"
 #include "../profiles/audio/a2dp-codecs.h"
 
 #define MAX_SEID 0x3E
+static unsigned int seids;
 
 #ifndef MAX
 # define MAX(x, y) ((x) > (y) ? (x) : (y))
@@ -373,14 +376,13 @@ struct avdtp {
 
        uint16_t version;
 
-       struct avdtp_server *server;
-
        guint auth_id;
 
        GIOChannel *io;
        guint io_id;
 
        GSList *seps; /* Elements of type struct avdtp_remote_sep * */
+       struct queue *lseps; /* Elements of type struct avdtp_local_sep * */
 
        GSList *streams; /* Elements of type struct avdtp_stream * */
 
@@ -404,8 +406,6 @@ struct avdtp {
        bool shutdown;
 };
 
-static GSList *lseps = NULL;
-
 static int send_request(struct avdtp *session, gboolean priority,
                        struct avdtp_stream *stream, uint8_t signal_id,
                        void *buffer, size_t size);
@@ -991,6 +991,9 @@ static void avdtp_free(void *data)
        g_slist_free_full(session->seps, sep_free);
        g_slist_free_full(session->disconnect, g_free);
 
+       /* Free copy of the SEP list */
+       session->lseps = NULL;
+
        g_free(session->buf);
 
        g_free(session);
@@ -1048,18 +1051,18 @@ struct avdtp *avdtp_ref(struct avdtp *session)
        return session;
 }
 
-static struct avdtp_local_sep *find_local_sep_by_seid(uint8_t seid)
+static bool match_by_seid(const void *data, const void *user_data)
 {
-       GSList *l;
+       const struct avdtp_local_sep *sep = data;
+       uint8_t seid = PTR_TO_UINT(user_data);
 
-       for (l = lseps; l != NULL; l = g_slist_next(l)) {
-               struct avdtp_local_sep *sep = l->data;
-
-               if (sep->info.seid == seid)
-                       return sep;
-       }
+       return sep->info.seid == seid;
+}
 
-       return NULL;
+static struct avdtp_local_sep *find_local_sep_by_seid(struct avdtp *session,
+                                                               uint8_t seid)
+{
+       return queue_find(session->lseps, match_by_seid, INT_TO_PTR(seid));
 }
 
 struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
@@ -1159,15 +1162,23 @@ static gboolean avdtp_unknown_cmd(struct avdtp *session, uint8_t transaction,
                                                        signal_id, NULL, 0);
 }
 
+static void copy_seps(void *data, void *user_data)
+{
+       struct avdtp_local_sep *sep = data;
+       struct seid_info **p = user_data;
+
+       memcpy(*p, &sep->info, sizeof(struct seid_info));
+       *p = *p + 1;
+}
+
 static gboolean avdtp_discover_cmd(struct avdtp *session, uint8_t transaction,
                                                        void *buf, int size)
 {
-       GSList *l;
-       unsigned int rsp_size, sep_count, i;
-       struct seid_info *seps;
+       unsigned int rsp_size, sep_count;
+       struct seid_info *seps, *p;
        gboolean ret;
 
-       sep_count = g_slist_length(lseps);
+       sep_count = queue_length(session->lseps);
 
        if (sep_count == 0) {
                uint8_t err = AVDTP_NOT_SUPPORTED_COMMAND;
@@ -1178,12 +1189,9 @@ static gboolean avdtp_discover_cmd(struct avdtp *session, uint8_t transaction,
        rsp_size = sep_count * sizeof(struct seid_info);
 
        seps = g_new0(struct seid_info, sep_count);
+       p = seps;
 
-       for (l = lseps, i = 0; l != NULL; l = l->next, i++) {
-               struct avdtp_local_sep *sep = l->data;
-
-               memcpy(&seps[i], &sep->info, sizeof(struct seid_info));
-       }
+       queue_foreach(session->lseps, copy_seps, &p);
 
        ret = avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
                                AVDTP_DISCOVER, seps, rsp_size);
@@ -1209,7 +1217,7 @@ static gboolean avdtp_getcap_cmd(struct avdtp *session, uint8_t transaction,
                goto failed;
        }
 
-       sep = find_local_sep_by_seid(req->acp_seid);
+       sep = find_local_sep_by_seid(session, req->acp_seid);
        if (!sep) {
                err = AVDTP_BAD_ACP_SEID;
                goto failed;
@@ -1291,7 +1299,7 @@ static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction,
                return FALSE;
        }
 
-       sep = find_local_sep_by_seid(req->acp_seid);
+       sep = find_local_sep_by_seid(session, req->acp_seid);
        if (!sep) {
                err = AVDTP_BAD_ACP_SEID;
                goto failed;
@@ -1379,7 +1387,7 @@ static gboolean avdtp_getconf_cmd(struct avdtp *session, uint8_t transaction,
 
        memset(buf, 0, sizeof(buf));
 
-       sep = find_local_sep_by_seid(req->acp_seid);
+       sep = find_local_sep_by_seid(session, req->acp_seid);
        if (!sep) {
                err = AVDTP_BAD_ACP_SEID;
                goto failed;
@@ -1495,7 +1503,7 @@ static gboolean avdtp_open_cmd(struct avdtp *session, uint8_t transaction,
                return FALSE;
        }
 
-       sep = find_local_sep_by_seid(req->acp_seid);
+       sep = find_local_sep_by_seid(session, req->acp_seid);
        if (!sep) {
                err = AVDTP_BAD_ACP_SEID;
                goto failed;
@@ -1555,7 +1563,7 @@ static gboolean avdtp_start_cmd(struct avdtp *session, uint8_t transaction,
        for (i = 0; i < seid_count; i++, seid++) {
                failed_seid = seid->seid;
 
-               sep = find_local_sep_by_seid(req->first_seid.seid);
+               sep = find_local_sep_by_seid(session, req->first_seid.seid);
                if (!sep || !sep->stream) {
                        err = AVDTP_BAD_ACP_SEID;
                        goto failed;
@@ -1605,7 +1613,7 @@ static gboolean avdtp_close_cmd(struct avdtp *session, uint8_t transaction,
                return FALSE;
        }
 
-       sep = find_local_sep_by_seid(req->acp_seid);
+       sep = find_local_sep_by_seid(session, req->acp_seid);
        if (!sep || !sep->stream) {
                err = AVDTP_BAD_ACP_SEID;
                goto failed;
@@ -1666,7 +1674,7 @@ static gboolean avdtp_suspend_cmd(struct avdtp *session, uint8_t transaction,
        for (i = 0; i < seid_count; i++, seid++) {
                failed_seid = seid->seid;
 
-               sep = find_local_sep_by_seid(req->first_seid.seid);
+               sep = find_local_sep_by_seid(session, req->first_seid.seid);
                if (!sep || !sep->stream) {
                        err = AVDTP_BAD_ACP_SEID;
                        goto failed;
@@ -1713,7 +1721,7 @@ static gboolean avdtp_abort_cmd(struct avdtp *session, uint8_t transaction,
                return FALSE;
        }
 
-       sep = find_local_sep_by_seid(req->acp_seid);
+       sep = find_local_sep_by_seid(session, req->acp_seid);
        if (!sep || !sep->stream)
                return TRUE;
 
@@ -1751,7 +1759,7 @@ static gboolean avdtp_delayreport_cmd(struct avdtp *session,
                return FALSE;
        }
 
-       sep = find_local_sep_by_seid(req->acp_seid);
+       sep = find_local_sep_by_seid(session, req->acp_seid);
        if (!sep || !sep->stream) {
                err = AVDTP_BAD_ACP_SEID;
                goto failed;
@@ -2103,12 +2111,16 @@ static int set_priority(int fd, int priority)
        return err;
 }
 
-struct avdtp *avdtp_new(int fd, size_t imtu, size_t omtu, uint16_t version)
+struct avdtp *avdtp_new(int fd, size_t imtu, size_t omtu, uint16_t version,
+                                                       struct queue *lseps)
 {
        struct avdtp *session;
        GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
        int new_fd;
 
+       if (!lseps)
+               return NULL;
+
        new_fd = dup(fd);
        if (new_fd < 0) {
                error("dup(): %s (%d)", strerror(errno), errno);
@@ -2136,6 +2148,8 @@ struct avdtp *avdtp_new(int fd, size_t imtu, size_t omtu, uint16_t version)
                                                (GIOFunc) session_cb, session,
                                                NULL);
 
+       session->lseps = lseps;
+
        return avdtp_ref(session);
 }
 
@@ -2910,7 +2924,6 @@ gboolean avdtp_stream_set_transport(struct avdtp_stream *stream, int fd,
        g_io_channel_unref(io);
 
        return TRUE;
-
 }
 
 gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock,
@@ -3342,7 +3355,8 @@ int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
                                                        &req, sizeof(req));
 }
 
-struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
+struct avdtp_local_sep *avdtp_register_sep(struct queue *lseps, uint8_t type,
+                                               uint8_t media_type,
                                                uint8_t codec_type,
                                                gboolean delay_reporting,
                                                struct avdtp_sep_ind *ind,
@@ -3350,14 +3364,15 @@ struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
                                                void *user_data)
 {
        struct avdtp_local_sep *sep;
+       uint8_t seid = util_get_uid(&seids, MAX_SEID);
 
-       if (g_slist_length(lseps) > MAX_SEID)
+       if (!seid)
                return NULL;
 
        sep = g_new0(struct avdtp_local_sep, 1);
 
        sep->state = AVDTP_STATE_IDLE;
-       sep->info.seid = g_slist_length(lseps) + 1;
+       sep->info.seid = seid;
        sep->info.type = type;
        sep->info.media_type = media_type;
        sep->codec = codec_type;
@@ -3368,7 +3383,11 @@ struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
 
        DBG("SEP %p registered: type:%d codec:%d seid:%d", sep,
                        sep->info.type, sep->codec, sep->info.seid);
-       lseps = g_slist_append(lseps, sep);
+
+       if (!queue_push_tail(lseps, sep)) {
+               g_free(sep);
+               return NULL;
+       }
 
        return sep;
 }
@@ -3380,19 +3399,19 @@ void avdtp_sep_set_vendor_codec(struct avdtp_local_sep *sep, uint32_t vendor_id,
        sep->vndcodec_codec = codec_id;
 }
 
-int avdtp_unregister_sep(struct avdtp_local_sep *sep)
+int avdtp_unregister_sep(struct queue *lseps, struct avdtp_local_sep *sep)
 {
        if (!sep)
                return -EINVAL;
 
-       lseps = g_slist_remove(lseps, sep);
-
        if (sep->stream)
                release_stream(sep->stream, sep->stream->session);
 
        DBG("SEP %p unregistered: type:%d codec:%d seid:%d", sep,
                        sep->info.type, sep->codec, sep->info.seid);
 
+       util_clear_uid(&seids, sep->info.seid);
+       queue_remove(lseps, sep);
        g_free(sep);
 
        return 0;
index d5335e4..07516a8 100644 (file)
@@ -205,7 +205,8 @@ typedef void (*avdtp_discover_cb_t) (struct avdtp *session, GSList *seps,
                                        struct avdtp_error *err, void *user_data);
 typedef void (*avdtp_disconnect_cb_t) (void *user_data);
 
-struct avdtp *avdtp_new(int fd, size_t imtu, size_t omtu, uint16_t version);
+struct avdtp *avdtp_new(int fd, size_t imtu, size_t omtu, uint16_t version,
+                                                       struct queue *lseps);
 
 unsigned int avdtp_add_disconnect_cb(struct avdtp *session,
                                                avdtp_disconnect_cb_t cb,
@@ -265,7 +266,8 @@ int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream);
 int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
                                                        uint16_t delay);
 
-struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
+struct avdtp_local_sep *avdtp_register_sep(struct queue *lseps, uint8_t type,
+                                               uint8_t media_type,
                                                uint8_t codec_type,
                                                gboolean delay_reporting,
                                                struct avdtp_sep_ind *ind,
@@ -278,7 +280,7 @@ void avdtp_sep_set_vendor_codec(struct avdtp_local_sep *sep, uint32_t vendor_id,
 struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
                                                struct avdtp_local_sep *lsep);
 
-int avdtp_unregister_sep(struct avdtp_local_sep *sep);
+int avdtp_unregister_sep(struct queue *lseps, struct avdtp_local_sep *sep);
 
 avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep);
 
index ce39519..f42f664 100644 (file)
 #include <stdbool.h>
 #include <errno.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-
 #include <glib.h>
 
-#include "src/shared/util.h"
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+
 #include "btio/btio.h"
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
 #include "avdtp.h"
 
 static GMainLoop *mainloop = NULL;
@@ -57,6 +58,7 @@ static uint16_t version = 0x0103;
 static guint media_player = 0;
 static guint media_recorder = 0;
 static guint idle_id = 0;
+static struct queue *lseps = NULL;
 
 static bool fragment = false;
 
@@ -411,7 +413,7 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
                return;
        }
 
-       avdtp = avdtp_new(fd, imtu, omtu, version);
+       avdtp = avdtp_new(fd, imtu, omtu, version, lseps);
        if (!avdtp) {
                printf("Failed to create avdtp instance\n");
                g_main_loop_quit(mainloop);
@@ -864,13 +866,15 @@ int main(int argc, char *argv[])
                }
        }
 
-       local_sep = avdtp_register_sep(dev_role, AVDTP_MEDIA_TYPE_AUDIO,
+       local_sep = avdtp_register_sep(lseps, dev_role, AVDTP_MEDIA_TYPE_AUDIO,
                                        0x00, TRUE, &sep_ind, &sep_cfm, NULL);
        if (!local_sep) {
                printf("Failed to register sep\n");
                exit(0);
        }
 
+       queue_push_tail(lseps, local_sep);
+
        if (!bacmp(&dst, BDADDR_ANY)) {
                printf("Listening...\n");
                io = do_listen(&err);
@@ -889,6 +893,8 @@ int main(int argc, char *argv[])
 
        printf("Done\n");
 
+       queue_destroy(lseps, NULL);
+
        avdtp_unref(avdtp);
        avdtp = NULL;
 
index cff37a8..23dea62 100644 (file)
@@ -1905,9 +1905,9 @@ static gboolean list_attributes_rsp(struct avctp *conn,
                goto done;
        }
 
-       number = pdu->params[0];
+       number = rsp->number;
        if (number > 0)
-               attrs = &pdu->params[1];
+               attrs = rsp->params;
 
        err = 0;
 
index e5e9837..dcbf9de 100644 (file)
 
 #include "src/log.h"
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
 #include "src/shared/util.h"
 #include "src/shared/queue.h"
 
@@ -43,6 +46,7 @@
 #include "android/bas.h"
 
 #define ATT_NOTIFICATION_HEADER_SIZE 3
+#define ATT_READ_RESPONSE_HEADER_SIZE 1
 
 struct bt_bas {
        int ref_count;
@@ -225,11 +229,17 @@ static void discover_desc(struct bt_bas *bas, GAttrib *attrib,
        free(req);
 }
 
-static void value_cb(const guint8 *pdu, guint16 len, gpointer user_data)
+static void notification_cb(const guint8 *pdu, guint16 len, gpointer user_data)
 {
        DBG("Battery Level at %u", pdu[ATT_NOTIFICATION_HEADER_SIZE]);
 }
 
+static void read_value_cb(guint8 status, const guint8 *pdu, guint16 len,
+                                       gpointer user_data)
+{
+       DBG("Battery Level at %u", pdu[ATT_READ_RESPONSE_HEADER_SIZE]);
+}
+
 static void ccc_written_cb(guint8 status, const guint8 *pdu,
                                        guint16 plen, gpointer user_data)
 {
@@ -247,7 +257,8 @@ static void ccc_written_cb(guint8 status, const guint8 *pdu,
        DBG("Battery Level: notification enabled");
 
        bas->id = g_attrib_register(bas->attrib, ATT_OP_HANDLE_NOTIFY,
-                                       bas->handle, value_cb, bas, NULL);
+                                       bas->handle, notification_cb, bas,
+                                       NULL);
 }
 
 static void write_ccc(struct bt_bas *bas, GAttrib *attrib, uint16_t handle,
@@ -318,6 +329,8 @@ static void bas_discovered_cb(uint8_t status, GSList *chars, void *user_data)
 
        DBG("Battery handle: 0x%04x", bas->handle);
 
+       read_char(bas, bas->attrib, bas->handle, read_value_cb, bas);
+
        start = chr->value_handle + 1;
        end = bas->primary->range.end;
 
index eff5b08..4d0cd48 100644 (file)
 #include "utils.h"
 #include "bluetooth.h"
 
-/*
- * bits in bitmask as defined in table 6.3 of Multi Profile Specification
- * HFP AG + A2DP SRC + AVRCP TG + PAN (NAP/PANU) + PBAP PSE
- */
-#define MPS_DEFAULT_MPSD ((1ULL << 0) | (1ULL << 2) | (1ULL << 4) | \
-                               (1ULL << 6) | (1ULL << 8) | (1ULL << 10) | \
-                               (1ULL << 12) | (1ULL << 26) | (1ULL << 28) | \
-                               (1ULL << 30) | (1ULL << 32) | (1ULL << 34) | \
-                               (1ULL << 36))
-
-/*
- * bits in bitmask as defined in table 6.4 of Multi Profile Specification
- * HFP AG + A2DP SRC + AVRCP TG + PAN (NAP/PANU) + PBAP PSE
- */
-#define MPS_DEFAULT_MPMD ((1ULL << 1) | (1ULL << 3) | (1ULL << 5) | \
-                               (1ULL << 6) | (1ULL << 8) | (1ULL << 10) | \
-                               (1ULL << 12) | (1ULL << 15) | (1ULL << 17))
-
-/*
- * bits in bitmask as defined in table 6.5 of Multi Profile Specification
- * Note that in this table spec starts bit positions from 1 (bit 0 unused?)
- */
-#define MPS_DEFAULT_DEPS ((1 << 1) | (1 << 2) | (1 << 3))
-
-/* MPSD bit dependent on HFP AG support */
-#define MPS_MPSD_HFP_AG_DEP ((1ULL << 0) | (1ULL << 2) | (1ULL << 4) | \
-                               (1ULL << 6) | (1ULL << 8) | (1ULL << 10) | \
-                               (1ULL << 12) | (1ULL << 14) | (1ULL << 16) | \
-                               (1ULL << 18) | (1ULL << 26) | (1ULL << 28) | \
-                               (1ULL << 30))
-
-/* MPMD bit dependent on HFP AG support */
-#define MPS_MPMD_HFP_AG_DEP (1ULL << 6)
-
 #define DUT_MODE_FILE "/sys/kernel/debug/bluetooth/hci%u/dut_mode"
 
 #define SETTINGS_FILE ANDROID_STORAGEDIR"/settings"
@@ -137,6 +103,8 @@ struct device {
 
        bool in_white_list;
 
+       bool connected;
+
        char *name;
        char *friendly_name;
 
@@ -152,10 +120,12 @@ struct device {
        unsigned int confirm_id; /* mgtm command id if command pending */
 
        bool valid_remote_csrk;
+       bool remote_csrk_auth;
        uint8_t remote_csrk[16];
        uint32_t remote_sign_cnt;
 
        bool valid_local_csrk;
+       bool local_csrk_auth;
        uint8_t local_csrk[16];
        uint32_t local_sign_cnt;
        uint16_t gatt_ccc;
@@ -917,7 +887,7 @@ static void send_paired_notification(void *data, void *user_data)
        bt_paired_device_cb cb = data;
        struct device *dev = user_data;
 
-       cb(&dev->bdaddr, dev->bdaddr_type);
+       cb(&dev->bdaddr);
 }
 
 static void update_device_state(struct device *dev, uint8_t addr_type,
@@ -1864,7 +1834,7 @@ static void update_new_device(struct device *dev, int8_t rssi,
 }
 
 static void update_device(struct device *dev, int8_t rssi,
-                               const struct eir_data *eir, uint8_t bdaddr_type)
+                                               const struct eir_data *eir)
 {
        uint8_t buf[IPC_MTU];
        struct hal_ev_remote_device_props *ev = (void *) buf;
@@ -1880,13 +1850,6 @@ static void update_device(struct device *dev, int8_t rssi,
 
        old_type = get_device_android_type(dev);
 
-       if (bdaddr_type == BDADDR_BREDR) {
-               dev->bredr = true;
-       } else {
-               dev->le = true;
-               dev->bdaddr_type = bdaddr_type;
-       }
-
        new_type = get_device_android_type(dev);
 
        if (old_type != new_type) {
@@ -1961,10 +1924,14 @@ static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
 
        dev = get_device(bdaddr, bdaddr_type);
 
-       if (bdaddr_type == BDADDR_BREDR)
+       if (bdaddr_type == BDADDR_BREDR) {
+               dev->bredr = true;
                dev->bredr_seen = time(NULL);
-       else
+       } else {
+               dev->le = true;
+               dev->bdaddr_type = bdaddr_type;
                dev->le_seen = time(NULL);
+       }
 
        /*
         * Device found event needs to be send also for known device if this is
@@ -1973,14 +1940,13 @@ static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
        if (is_new_device(dev, eir.flags, bdaddr_type))
                update_new_device(dev, rssi, &eir);
        else
-               update_device(dev, rssi, &eir, bdaddr_type);
+               update_device(dev, rssi, &eir);
 
        eir_data_free(&eir);
 
        /* Notify Gatt if its registered for LE events */
        if (bdaddr_type != BDADDR_BREDR && gatt_device_found_cb) {
-               bdaddr_t *addr;
-               uint8_t addr_type;
+               const bdaddr_t *addr;
 
                /*
                 * If RPA is set it means that IRK was received and ID address
@@ -1988,16 +1954,13 @@ static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
                 * it needs to be used also in GATT notifications. Also GATT
                 * HAL implementation is using RPA for devices matching.
                 */
-               if (bacmp(&dev->rpa, BDADDR_ANY)) {
+               if (bacmp(&dev->rpa, BDADDR_ANY))
                        addr = &dev->rpa;
-                       addr_type = dev->rpa_type;
-               } else {
+               else
                        addr = &dev->bdaddr;
-                       addr_type = dev->bdaddr_type;
-               }
 
-               gatt_device_found_cb(addr, addr_type, rssi, data_len, data,
-                                               connectable, dev->le_bonded);
+               gatt_device_found_cb(addr, rssi, data_len, data, connectable,
+                                                               dev->le_bonded);
        }
 
        if (!dev->bredr_paired && !dev->le_paired)
@@ -2072,12 +2035,16 @@ static void mgmt_device_connected_event(uint16_t index, uint16_t length,
        const struct mgmt_ev_device_connected *ev = param;
        struct hal_ev_acl_state_changed hal_ev;
        struct device *dev;
+       char addr[18];
 
        if (length < sizeof(*ev)) {
                error("Too short device connected event (%u bytes)", length);
                return;
        }
 
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("%s type %u", addr, ev->addr.type);
+
        update_found_device(&ev->addr.bdaddr, ev->addr.type, 0, false, false,
                                        &ev->eir[0], le16_to_cpu(ev->eir_len));
 
@@ -2088,6 +2055,8 @@ static void mgmt_device_connected_event(uint16_t index, uint16_t length,
        if (!dev)
                return;
 
+       dev->connected = true;
+
        get_device_android_addr(dev, hal_ev.bdaddr);
 
        ipc_send_notif(hal_ipc, HAL_SERVICE_ID_BLUETOOTH,
@@ -2135,6 +2104,8 @@ static void mgmt_device_disconnected_event(uint16_t index, uint16_t length,
        if (device_is_paired(dev, type) && !device_is_bonded(dev))
                update_device_state(dev, type, HAL_STATUS_SUCCESS, false,
                                                                false, false);
+
+       dev->connected = false;
 }
 
 static uint8_t status_mgmt2hal(uint8_t mgmt)
@@ -2347,6 +2318,9 @@ static void store_csrk(struct device *dev)
                                                        dev->local_csrk[i]);
 
                g_key_file_set_string(key_file, addr, "LocalCSRK", key_str);
+
+               g_key_file_set_boolean(key_file, addr, "LocalCSRKAuthenticated",
+                                                       dev->local_csrk_auth);
        }
 
        if (dev->valid_remote_csrk) {
@@ -2355,6 +2329,10 @@ static void store_csrk(struct device *dev)
                                                        dev->remote_csrk[i]);
 
                g_key_file_set_string(key_file, addr, "RemoteCSRK", key_str);
+
+               g_key_file_set_boolean(key_file, addr,
+                                               "RemoteCSRKAuthenticated",
+                                               dev->remote_csrk_auth);
        }
 
        data = g_key_file_to_data(key_file, &length, NULL);
@@ -2381,19 +2359,23 @@ static void new_csrk_callback(uint16_t index, uint16_t length,
        if (!dev)
                return;
 
-       switch (ev->key.master) {
+       switch (ev->key.type) {
        case 0x00:
+       case 0x02:
                memcpy(dev->local_csrk, ev->key.val, 16);
                dev->local_sign_cnt = 0;
                dev->valid_local_csrk = true;
+               dev->local_csrk_auth = ev->key.type == 0x02;
                break;
        case 0x01:
+       case 0x03:
                memcpy(dev->remote_csrk, ev->key.val, 16);
                dev->remote_sign_cnt = 0;
                dev->valid_remote_csrk = true;
+               dev->remote_csrk_auth = ev->key.type == 0x03;
                break;
        default:
-               error("Unknown CSRK key type 02%02x", ev->key.master);
+               error("Unknown CSRK key type 02%02x", ev->key.type);
                return;
        }
 
@@ -2975,27 +2957,6 @@ static struct device *create_device_from_info(GKeyFile *key_file,
                dev->bredr = g_key_file_get_boolean(key_file, peer, "BREDR",
                                                                        NULL);
 
-       str = g_key_file_get_string(key_file, peer, "LinkKey", NULL);
-       if (str) {
-               g_free(str);
-               dev->bredr_paired = true;
-               dev->bredr_bonded = true;
-       }
-
-       str = g_key_file_get_string(key_file, peer, "LongTermKey", NULL);
-       if (str) {
-               g_free(str);
-               dev->le_paired = true;
-               dev->le_bonded = true;
-       }
-
-       str = g_key_file_get_string(key_file, peer, "SlaveLongTermKey", NULL);
-       if (str) {
-               g_free(str);
-               dev->le_paired = true;
-               dev->le_bonded = true;
-       }
-
        str = g_key_file_get_string(key_file, peer, "LocalCSRK", NULL);
        if (str) {
                int i;
@@ -3008,6 +2969,9 @@ static struct device *create_device_from_info(GKeyFile *key_file,
 
                dev->local_sign_cnt = g_key_file_get_integer(key_file, peer,
                                                "LocalCSRKSignCounter", NULL);
+
+               dev->local_csrk_auth = g_key_file_get_boolean(key_file, peer,
+                                               "LocalCSRKAuthenticated", NULL);
        }
 
        str = g_key_file_get_string(key_file, peer, "RemoteCSRK", NULL);
@@ -3022,6 +2986,10 @@ static struct device *create_device_from_info(GKeyFile *key_file,
 
                dev->remote_sign_cnt = g_key_file_get_integer(key_file, peer,
                                                "RemoteCSRKSignCounter", NULL);
+
+               dev->remote_csrk_auth = g_key_file_get_boolean(key_file, peer,
+                                               "RemoteCSRKAuthenticated",
+                                               NULL);
        }
 
        str = g_key_file_get_string(key_file, peer, "GattCCC", NULL);
@@ -3248,19 +3216,30 @@ static void load_devices_info(bt_bluetooth_ready cb)
                struct mgmt_ltk_info *slave_ltk_info;
                struct device *dev;
 
+               dev = create_device_from_info(key_file, devs[i]);
+
                key_info = get_key_info(key_file, devs[i]);
                irk_info = get_irk_info(key_file, devs[i]);
                ltk_info = get_ltk_info(key_file, devs[i], true);
                slave_ltk_info = get_ltk_info(key_file, devs[i], false);
 
-               if (!key_info && !ltk_info && !slave_ltk_info) {
+               /*
+                * Skip devices that have no permanent keys
+                * (CSRKs are loaded by create_device_from_info())
+                */
+               if (!dev->valid_local_csrk && !dev->valid_remote_csrk &&
+                                               !key_info && !ltk_info &&
+                                               !slave_ltk_info && !irk_info) {
                        error("Failed to load keys for %s, skipping", devs[i]);
-
+                       free_device(dev);
                        continue;
                }
 
-               if (key_info)
+               if (key_info) {
                        keys = g_slist_prepend(keys, key_info);
+                       dev->bredr_paired = true;
+                       dev->bredr_bonded = true;
+               }
 
                if (irk_info)
                        irks = g_slist_prepend(irks, irk_info);
@@ -3271,7 +3250,11 @@ static void load_devices_info(bt_bluetooth_ready cb)
                if (slave_ltk_info)
                        ltks = g_slist_prepend(ltks, slave_ltk_info);
 
-               dev = create_device_from_info(key_file, devs[i]);
+               if (dev->valid_local_csrk || dev->valid_remote_csrk ||
+                               irk_info || ltk_info || slave_ltk_info) {
+                       dev->le_paired = true;
+                       dev->le_bonded = true;
+               }
 
                bonded_devices = g_slist_prepend(bonded_devices, dev);
        }
@@ -3309,75 +3292,18 @@ static void set_adapter_class(void)
        error("Failed to set class of device");
 }
 
-static sdp_record_t *mps_record(void)
-{
-       sdp_data_t *mpsd_features, *mpmd_features, *dependencies;
-       sdp_list_t *svclass_id, *pfseq, *root;
-       uuid_t root_uuid, svclass_uuid;
-       sdp_profile_desc_t profile;
-       sdp_record_t *record;
-       uint64_t mpsd_feat, mpmd_feat;
-       uint16_t deps;
-
-       record = sdp_record_alloc();
-       if (!record)
-               return NULL;
-
-       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-       root = sdp_list_append(NULL, &root_uuid);
-       sdp_set_browse_groups(record, root);
-
-       sdp_uuid16_create(&svclass_uuid, MPS_SVCLASS_ID);
-       svclass_id = sdp_list_append(NULL, &svclass_uuid);
-       sdp_set_service_classes(record, svclass_id);
-
-       sdp_uuid16_create(&profile.uuid, MPS_PROFILE_ID);
-       profile.version = 0x0100;
-       pfseq = sdp_list_append(NULL, &profile);
-       sdp_set_profile_descs(record, pfseq);
-
-       mpsd_feat = MPS_DEFAULT_MPSD;
-       mpmd_feat = MPS_DEFAULT_MPMD;
-
-       /* TODO should be configurable based on HFP AG support */
-       if (false) {
-               mpsd_feat &= MPS_MPSD_HFP_AG_DEP;
-               mpmd_feat &= MPS_MPMD_HFP_AG_DEP;
-       }
-
-       mpsd_features = sdp_data_alloc(SDP_UINT64, &mpsd_feat);
-       sdp_attr_add(record, SDP_ATTR_MPSD_SCENARIOS, mpsd_features);
-
-       mpmd_features = sdp_data_alloc(SDP_UINT64, &mpmd_feat);
-       sdp_attr_add(record, SDP_ATTR_MPMD_SCENARIOS, mpmd_features);
-
-       deps = MPS_DEFAULT_DEPS;
-       dependencies = sdp_data_alloc(SDP_UINT16, &deps);
-       sdp_attr_add(record, SDP_ATTR_MPS_DEPENDENCIES, dependencies);
-
-       sdp_set_info_attr(record, "Multi Profile", 0, 0);
-
-       sdp_list_free(pfseq, NULL);
-       sdp_list_free(root, NULL);
-       sdp_list_free(svclass_id, NULL);
-
-       return record;
-}
-
-static void add_mps_record(void)
+static void enable_mps(void)
 {
-       sdp_record_t *rec;
+       uuid_t uuid, *uuid128;
 
-       rec = mps_record();
-       if (!rec) {
-               error("Failed to allocate MPS record");
+       sdp_uuid16_create(&uuid, MPS_SVCLASS_ID);
+       uuid128 = sdp_uuid_to_uuid128(&uuid);
+       if (!uuid128)
                return;
-       }
 
-       if (bt_adapter_add_record(rec, 0) < 0) {
-               error("Failed to register MPS record");
-               sdp_record_free(rec);
-       }
+       register_mps(true);
+       adapter.uuids = g_slist_prepend(adapter.uuids, uuid128);
+       add_uuid(0, uuid128);
 }
 
 static void clear_auto_connect_list_complete(uint8_t status,
@@ -3466,7 +3392,7 @@ static void read_info_complete(uint8_t status, uint16_t length,
 
        set_io_capability();
        set_device_id();
-       add_mps_record();
+       enable_mps();
 
        missing_settings = adapter.current_settings ^
                                                adapter.supported_settings;
@@ -3474,9 +3400,6 @@ static void read_info_complete(uint8_t status, uint16_t length,
        if (missing_settings & MGMT_SETTING_SSP)
                set_mode(MGMT_OP_SET_SSP, 0x01);
 
-       if (missing_settings & MGMT_SETTING_SECURE_CONN)
-               set_mode(MGMT_OP_SET_SECURE_CONN, 0x01);
-
        if (missing_settings & MGMT_SETTING_BONDABLE)
                set_mode(MGMT_OP_SET_BONDABLE, 0x01);
 
@@ -4171,22 +4094,33 @@ bool bt_read_device_rssi(const bdaddr_t *addr, bt_read_device_rssi_done cb,
        return true;
 }
 
-bool bt_get_csrk(const bdaddr_t *addr, enum bt_csrk_type type, uint8_t key[16],
-                                                       uint32_t *sign_cnt)
+bool bt_get_csrk(const bdaddr_t *addr, bool local, uint8_t key[16],
+                                       uint32_t *sign_cnt, bool *authenticated)
 {
        struct device *dev;
-       bool local = (type == LOCAL_CSRK);
 
        dev = find_device(addr);
        if (!dev)
                return false;
 
        if (local && dev->valid_local_csrk) {
-               memcpy(key, dev->local_csrk, 16);
-               *sign_cnt = dev->local_sign_cnt;
+               if (key)
+                       memcpy(key, dev->local_csrk, 16);
+
+               if (sign_cnt)
+                       *sign_cnt = dev->local_sign_cnt;
+
+               if (authenticated)
+                       *authenticated = dev->local_csrk_auth;
        } else if (!local && dev->valid_remote_csrk) {
-               memcpy(key, dev->remote_csrk, 16);
-               *sign_cnt = dev->remote_sign_cnt;
+               if (key)
+                       memcpy(key, dev->remote_csrk, 16);
+
+               if (sign_cnt)
+                       *sign_cnt = dev->remote_sign_cnt;
+
+               if (authenticated)
+                       *authenticated = dev->remote_csrk_auth;
        } else {
                return false;
        }
@@ -4194,12 +4128,11 @@ bool bt_get_csrk(const bdaddr_t *addr, enum bt_csrk_type type, uint8_t key[16],
        return true;
 }
 
-static void store_sign_counter(struct device *dev, enum bt_csrk_type type)
+static void store_sign_counter(struct device *dev, bool local)
 {
        const char *sign_cnt_s;
        uint32_t sign_cnt;
        GKeyFile *key_file;
-       bool local = (type == LOCAL_CSRK);
 
        gsize length = 0;
        char addr[18];
@@ -4225,8 +4158,7 @@ static void store_sign_counter(struct device *dev, enum bt_csrk_type type)
        g_key_file_free(key_file);
 }
 
-void bt_update_sign_counter(const bdaddr_t *addr, enum bt_csrk_type type,
-                                                               uint32_t val)
+void bt_update_sign_counter(const bdaddr_t *addr, bool local, uint32_t val)
 {
        struct device *dev;
 
@@ -4234,12 +4166,12 @@ void bt_update_sign_counter(const bdaddr_t *addr, enum bt_csrk_type type,
        if (!dev)
                return;
 
-       if (type == LOCAL_CSRK)
+       if (local)
                dev->local_sign_cnt = val;
        else
                dev->remote_sign_cnt = val;
 
-       store_sign_counter(dev, type);
+       store_sign_counter(dev, local);
 }
 
 static uint8_t set_adapter_scan_mode(const void *buf, uint16_t len)
@@ -4467,7 +4399,7 @@ static void send_unpaired_notification(void *data, void *user_data)
        bt_unpaired_device_cb cb = data;
        struct mgmt_addr_info *addr = user_data;
 
-       cb(&addr->bdaddr, addr->type);
+       cb(&addr->bdaddr);
 }
 
 static void unpair_device_complete(uint8_t status, uint16_t length,
@@ -4489,7 +4421,9 @@ static void unpair_device_complete(uint8_t status, uint16_t length,
                                                                false, false);
 
        /* Cast rp->addr to (void *) since queue_foreach don't take const */
-       queue_foreach(unpaired_cb_list, send_unpaired_notification,
+
+       if (!dev->le_paired && !dev->bredr_paired)
+               queue_foreach(unpaired_cb_list, send_unpaired_notification,
                                                        (void *)&rp->addr);
 }
 
@@ -5221,17 +5155,20 @@ static void handle_get_connection_state(const void *buf, uint16_t len)
 {
        const struct hal_cmd_get_connection_state *cmd = buf;
        struct hal_rsp_get_connection_state rsp;
+       struct device *dev;
        char address[18];
        bdaddr_t bdaddr;
 
        android2bdaddr(cmd->bdaddr, &bdaddr);
        ba2str(&bdaddr, address);
 
-       DBG("%s", address);
-
-       /* TODO */
+       dev = find_device_android(cmd->bdaddr);
+       if (dev && dev->connected)
+               rsp.connection_state = 1;
+       else
+               rsp.connection_state = 0;
 
-       rsp.connection_state = 0;
+       DBG("%s %u", address, rsp.connection_state);
 
        ipc_send_rsp_full(hal_ipc, HAL_SERVICE_ID_BLUETOOTH,
                                HAL_OP_GET_CONNECTION_STATE, sizeof(rsp), &rsp,
@@ -5376,6 +5313,10 @@ bool bt_bluetooth_register(struct ipc *ipc, uint8_t mode)
                goto failed;
        }
 
+       /* Requested mode is set now, let's enable secure connection */
+       if (missing_settings & MGMT_SETTING_SECURE_CONN)
+               set_mode(MGMT_OP_SET_SECURE_CONN, 0x01);
+
        /* Set initial default name */
        if (!adapter.name) {
                adapter.name = g_strdup(bt_config_get_model());
index 9e7ab2c..4b17209 100644 (file)
  *
  */
 
-enum bt_csrk_type {
-       LOCAL_CSRK,
-       REMOTE_CSRK,
-};
-
 typedef void (*bt_bluetooth_ready)(int err, const bdaddr_t *addr);
 bool bt_bluetooth_start(int index, bool mgmt_dbg, bt_bluetooth_ready cb);
 
@@ -40,10 +35,9 @@ void bt_bluetooth_unregister(void);
 int bt_adapter_add_record(sdp_record_t *rec, uint8_t svc_hint);
 void bt_adapter_remove_record(uint32_t handle);
 
-typedef void (*bt_le_device_found)(const bdaddr_t *addr, uint8_t addr_type,
-                                       int rssi, uint16_t eir_len,
-                                       const void *eir, bool connectable,
-                                       bool bonded);
+typedef void (*bt_le_device_found)(const bdaddr_t *addr, int rssi,
+                                       uint16_t eir_len, const void *eir,
+                                       bool connectable, bool bonded);
 bool bt_le_register(bt_le_device_found cb);
 void bt_le_unregister(void);
 
@@ -69,11 +63,10 @@ typedef void (*bt_read_device_rssi_done)(uint8_t status, const bdaddr_t *addr,
 bool bt_read_device_rssi(const bdaddr_t *addr, bt_read_device_rssi_done cb,
                                                        void *user_data);
 
-bool bt_get_csrk(const bdaddr_t *addr, enum bt_csrk_type type,
-                                       uint8_t key[16], uint32_t *sign_cnt);
+bool bt_get_csrk(const bdaddr_t *addr, bool local, uint8_t key[16],
+                               uint32_t *sign_cnt, bool *authenticated);
 
-void bt_update_sign_counter(const bdaddr_t *addr, enum bt_csrk_type type,
-                                                               uint32_t val);
+void bt_update_sign_counter(const bdaddr_t *addr, bool local, uint32_t val);
 
 void bt_store_gatt_ccc(const bdaddr_t *addr, uint16_t value);
 
@@ -87,11 +80,11 @@ bool bt_auto_connect_add(const bdaddr_t *addr);
 
 void bt_auto_connect_remove(const bdaddr_t *addr);
 
-typedef void (*bt_unpaired_device_cb)(const bdaddr_t *addr, uint8_t type);
+typedef void (*bt_unpaired_device_cb)(const bdaddr_t *addr);
 bool bt_unpaired_register(bt_unpaired_device_cb cb);
 void bt_unpaired_unregister(bt_unpaired_device_cb cb);
 
-typedef void (*bt_paired_device_cb)(const bdaddr_t *addr, uint8_t type);
+typedef void (*bt_paired_device_cb)(const bdaddr_t *addr);
 bool bt_paired_register(bt_paired_device_cb cb);
 void bt_paired_unregister(bt_paired_device_cb cb);
 bool bt_is_pairing(const bdaddr_t *addr);
index 776dca7..035875a 100644 (file)
@@ -36,7 +36,7 @@
 #include "lib/hci.h"
 #include "lib/mgmt.h"
 
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
 #include "src/shared/btsnoop.h"
 #include "src/log.h"
 
index 52573a0..3980764 100644 (file)
@@ -67,10 +67,13 @@ static void cleanup_p(int argc, const char **argv)
 }
 
 /* send_pass_through_cmd */
-
 static void send_pass_through_cmd_c(int argc, const char **argv,
                                        enum_func *enum_func, void **user)
 {
+       if (argc == 3) {
+               *user = NULL;
+               *enum_func = enum_devices;
+       }
 }
 
 static void send_pass_through_cmd_p(int argc, const char **argv)
@@ -81,15 +84,15 @@ static void send_pass_through_cmd_p(int argc, const char **argv)
        RETURN_IF_NULL(if_rc);
        VERIFY_ADDR_ARG(2, &addr);
 
-       if (argc <= 4) {
-               haltest_error("No key code specified");
+       if (argc < 4) {
+               haltest_error("No key code specified\n");
                return;
        }
 
        key_code = (uint8_t) atoi(argv[3]);
 
-       if (argc <= 5) {
-               haltest_error("No key state specified");
+       if (argc < 5) {
+               haltest_error("No key state specified\n");
                return;
        }
 
@@ -100,8 +103,7 @@ static void send_pass_through_cmd_p(int argc, const char **argv)
 
 static struct method methods[] = {
        STD_METHOD(init),
-       STD_METHODCH(send_pass_through_cmd,
-                                       "<bd_addr> <key_code> <key_state>"),
+       STD_METHODCH(send_pass_through_cmd, "<bd_addr> <key_code> <key_state>"),
        STD_METHOD(cleanup),
        END_METHOD
 };
similarity index 69%
rename from attrib/client.h
rename to android/compat/readline/history.h
index 08e7988..decc2f4 100644 (file)
@@ -2,8 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2010  Nokia Corporation
- *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 1987-2011 Free Software Foundation, Inc.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
  *
  */
 
-#ifdef __TIZEN_PATCH__
-GSList *attrib_client_register(DBusConnection *connection,
-                                       struct btd_device *device, int psm,
-                                       GAttrib *attrib, GSList *primaries);
-void attrib_client_unregister(GSList *services);
+#ifndef _HISTORY_H_
+#define _HISTORY_H_
+
+static inline void add_history(const char *c)
+{
+}
 
-#define GATT_FIND_INFO_RESP_OPCODE_LEN         1
 #endif
diff --git a/android/compat/readline/readline.h b/android/compat/readline/readline.h
new file mode 100644 (file)
index 0000000..aaf6f31
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 1987-2011 Free Software Foundation, Inc.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef _READLINE_H_
+#define _READLINE_H_
+
+typedef void (*rl_vcpfunc_t)(char *c);
+typedef void (*rl_compdisp_func_t)(char **c, int i, int j);
+typedef char *(*rl_compentry_func_t)(const char *c, int i);
+typedef char **(*rl_completion_func_t)(const char *c, int i, int j);
+
+#define RL_STATE_DONE 0x1000000
+#define RL_ISSTATE(x) (rl_readline_state & (x))
+
+static int rl_end;
+static int rl_point;
+static int rl_readline_state;
+static int rl_erase_empty_line;
+static int rl_attempted_completion_over;
+static char *rl_prompt;
+static char *rl_line_buffer;
+static rl_compdisp_func_t rl_completion_display_matches_hook;
+static rl_completion_func_t rl_attempted_completion_function;
+
+static inline void rl_callback_handler_install(const char *c, rl_vcpfunc_t f)
+{
+       printf("readline not available\n");
+       exit(1);
+}
+
+static inline int rl_set_prompt(const char *c)
+{
+       return -1;
+}
+
+static inline void rl_replace_line(const char *c, int i)
+{
+}
+
+static inline void rl_redisplay(void)
+{
+}
+
+static inline char **rl_completion_matches(const char *c, rl_compentry_func_t f)
+{
+       return NULL;
+}
+
+static inline int rl_insert_text(const char *c)
+{
+       return -1;
+}
+
+static inline int rl_crlf(void)
+{
+       return -1;
+}
+
+static inline void rl_callback_read_char(void)
+{
+}
+
+static inline int rl_message(const char *c, ...)
+{
+       return -1;
+}
+
+static inline void rl_callback_handler_remove(void)
+{
+}
+
+static inline char *rl_copy_text(int i, int j)
+{
+       return NULL;
+}
+
+static inline void rl_save_prompt(void)
+{
+}
+
+static inline void rl_restore_prompt(void)
+{
+}
+
+static inline int rl_forced_update_display(void)
+{
+       return -1;
+}
+
+#endif
diff --git a/android/compat/wordexp.h b/android/compat/wordexp.h
new file mode 100644 (file)
index 0000000..ff1f21c
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 1991-2013 Free Software Foundation, Inc.
+ *
+ *
+ *  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 _WORDEXP_H_
+#define _WORDEXP_H_
+
+#define WRDE_NOCMD 0
+
+typedef struct {
+       size_t we_wordc;
+       char **we_wordv;
+       size_t we_offs;
+} wordexp_t;
+
+static inline int wordexp(const char *c, wordexp_t *w, int _i)
+{
+       return -1;
+}
+
+static inline void wordfree(wordexp_t *__wordexp)
+{
+}
+
+#endif
index 635ba90..75dbe3d 100644 (file)
 
 #include "src/log.h"
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
 #include "src/shared/util.h"
 #include "src/shared/queue.h"
 
index 3a35bd6..9c2a280 100644 (file)
@@ -44,6 +44,7 @@
 #include "utils.h"
 #include "src/shared/util.h"
 #include "src/shared/queue.h"
+#include "src/shared/att.h"
 #include "src/shared/gatt-db.h"
 #include "attrib/gattrib.h"
 #include "attrib/att.h"
@@ -152,7 +153,6 @@ struct notification_data {
 
 struct gatt_device {
        bdaddr_t bdaddr;
-       uint8_t bdaddr_type;
 
        gatt_device_state_t state;
 
@@ -166,7 +166,6 @@ struct gatt_device {
        guint ind_id;
 
        int ref;
-       int conn_cnt;
 
        struct queue *autoconnect_apps;
 
@@ -348,11 +347,6 @@ static struct gatt_app *find_app_by_id(int32_t id)
        return queue_find(gatt_apps, match_app_by_id, INT_TO_PTR(id));
 }
 
-static bool match_by_value(const void *data, const void *user_data)
-{
-       return data == user_data;
-}
-
 static bool match_device_by_bdaddr(const void *data, const void *user_data)
 {
        const struct gatt_device *dev = data;
@@ -544,6 +538,9 @@ static void destroy_notification(void *data)
        struct notification_data *notification = data;
        struct gatt_app *app;
 
+       if (!notification)
+               return;
+
        if (--notification->ref)
                return;
 
@@ -562,7 +559,7 @@ static void unregister_notification(void *data)
         * triggered afterwards, but once client unregisters, device stays if
         * used by others. Then just unregister single handle.
         */
-       if (!queue_find(gatt_devices, match_by_value, dev))
+       if (!queue_find(gatt_devices, NULL, dev))
                return;
 
        if (notification->notif_id && dev)
@@ -576,6 +573,9 @@ static void device_set_state(struct gatt_device *dev, uint32_t state)
 {
        char bda[18];
 
+       if (dev->state == state)
+               return;
+
        ba2str(&dev->bdaddr, bda);
        DBG("gatt: Device %s state changed %s -> %s", bda,
                        device_state_str[dev->state], device_state_str[state]);
@@ -587,32 +587,17 @@ static bool auto_connect_le(struct gatt_device *dev)
 {
        /*  For LE devices use auto connect feature if possible */
        if (bt_kernel_conn_control()) {
-               const bdaddr_t *bdaddr;
-
-               /*
-                * If address type is random it might be that IRK was received
-                * and random is just for faking Android Framework. ID address
-                * should be used for connection if present.
-                */
-               if (dev->bdaddr_type == BDADDR_LE_RANDOM) {
-                       bdaddr = bt_get_id_addr(&dev->bdaddr, NULL);
-                       if (!bdaddr)
-                               return -EINVAL;
-               } else {
-                       bdaddr = &dev->bdaddr;
-               }
-
-               return bt_auto_connect_add(bdaddr);
-       }
-
-       /* Trigger discovery if not already started */
-       if (!scanning) {
-               if (!bt_le_discovery_start()) {
+               if (!bt_auto_connect_add(bt_get_id_addr(&dev->bdaddr, NULL)))
+                       return false;
+       } else {
+               /* Trigger discovery if not already started */
+               if (!scanning && !bt_le_discovery_start()) {
                        error("gatt: Could not start scan");
                        return false;
                }
        }
 
+       device_set_state(dev, DEVICE_CONNECT_INIT);
        return true;
 }
 
@@ -636,8 +621,7 @@ static void connection_cleanup(struct gatt_device *device)
                        g_attrib_unregister(device->attrib, device->server_id);
 
                if (device->ind_id > 0)
-                       g_attrib_unregister(device->attrib,
-                                                       device->ind_id);
+                       g_attrib_unregister(device->attrib, device->ind_id);
 
                device->attrib = NULL;
                g_attrib_cancel_all(attrib);
@@ -660,18 +644,19 @@ static void connection_cleanup(struct gatt_device *device)
 
        device_set_state(device, DEVICE_DISCONNECTED);
 
-       if (!queue_isempty(device->autoconnect_apps)) {
+       if (!queue_isempty(device->autoconnect_apps))
                auto_connect_le(device);
-               device_set_state(device, DEVICE_CONNECT_INIT);
-       } else {
+       else
                bt_auto_connect_remove(&device->bdaddr);
-       }
 }
 
 static void destroy_gatt_app(void *data)
 {
        struct gatt_app *app = data;
 
+       if (!app)
+               return;
+
        /*
         * First we want to get all notifications and unregister them.
         * We don't pass unregister_notification to queue_destroy,
@@ -692,12 +677,6 @@ static void destroy_gatt_app(void *data)
        free(app);
 }
 
-enum pend_req_state {
-       REQUEST_INIT,
-       REQUEST_PENDING,
-       REQUEST_DONE,
-};
-
 struct pending_request {
        struct gatt_db_attribute *attrib;
        int length;
@@ -707,7 +686,7 @@ struct pending_request {
        uint8_t *filter_value;
        uint16_t filter_vlen;
 
-       enum pend_req_state state;
+       bool completed;
        uint8_t error;
 };
 
@@ -715,6 +694,9 @@ static void destroy_pending_request(void *data)
 {
        struct pending_request *entry = data;
 
+       if (!entry)
+               return;
+
        free(entry->value);
        free(entry->filter_value);
        free(entry);
@@ -797,141 +779,127 @@ static struct gatt_device *create_device(const bdaddr_t *addr)
        return device_ref(dev);
 }
 
-static void send_client_connection_notify(struct app_connection *connection,
+static void send_client_connect_status_notify(struct app_connection *conn,
                                                                int32_t status)
 {
        struct hal_ev_gatt_client_connect ev;
 
-       if (connection->app->func) {
-               connection->app->func(&connection->device->bdaddr,
+       if (conn->app->func) {
+               conn->app->func(&conn->device->bdaddr,
                                        status == GATT_SUCCESS ? 0 : -ENOTCONN,
-                                       connection->device->attrib);
+                                       conn->device->attrib);
                return;
        }
 
-       ev.client_if = connection->app->id;
-       ev.conn_id = connection->id;
+       ev.client_if = conn->app->id;
+       ev.conn_id = conn->id;
        ev.status = status;
 
-       bdaddr2android(&connection->device->bdaddr, &ev.bda);
+       bdaddr2android(&conn->device->bdaddr, &ev.bda);
 
        ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT, HAL_EV_GATT_CLIENT_CONNECT,
                                                        sizeof(ev), &ev);
 }
 
-static void send_server_connection_notify(struct app_connection *connection,
+static void send_server_connection_state_notify(struct app_connection *conn,
                                                                bool connected)
 {
        struct hal_ev_gatt_server_connection ev;
 
-       if (connection->app->func) {
-               connection->app->func(&connection->device->bdaddr,
+       if (conn->app->func) {
+               conn->app->func(&conn->device->bdaddr,
                                        connected ? 0 : -ENOTCONN,
-                                       connection->device->attrib);
+                                       conn->device->attrib);
                return;
        }
 
-       ev.server_if = connection->app->id;
-       ev.conn_id = connection->id;
+       ev.server_if = conn->app->id;
+       ev.conn_id = conn->id;
        ev.connected = connected;
 
-       bdaddr2android(&connection->device->bdaddr, &ev.bdaddr);
+       bdaddr2android(&conn->device->bdaddr, &ev.bdaddr);
 
        ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
                                HAL_EV_GATT_SERVER_CONNECTION, sizeof(ev), &ev);
 }
 
-static void send_client_disconnection_notify(struct app_connection *connection,
+static void send_client_disconnect_status_notify(struct app_connection *conn,
                                                                int32_t status)
 {
        struct hal_ev_gatt_client_disconnect ev;
 
-       if (connection->app->func) {
-               connection->app->func(&connection->device->bdaddr, -ENOTCONN,
-                                               connection->device->attrib);
+       if (conn->app->func) {
+               conn->app->func(&conn->device->bdaddr, -ENOTCONN,
+                                               conn->device->attrib);
                return;
        }
 
-       ev.client_if = connection->app->id;
-       ev.conn_id = connection->id;
+       ev.client_if = conn->app->id;
+       ev.conn_id = conn->id;
        ev.status = status;
 
-       bdaddr2android(&connection->device->bdaddr, &ev.bda);
+       bdaddr2android(&conn->device->bdaddr, &ev.bda);
 
        ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
                                HAL_EV_GATT_CLIENT_DISCONNECT, sizeof(ev), &ev);
 
 }
 
-static void send_app_disconnect_notify(struct app_connection *connection,
+static void notify_app_disconnect_status(struct app_connection *conn,
                                                                int32_t status)
 {
-       if (!connection->app)
+       if (!conn->app)
                return;
 
-       if (connection->app->type == GATT_CLIENT)
-               send_client_disconnection_notify(connection, status);
+       if (conn->app->type == GATT_CLIENT)
+               send_client_disconnect_status_notify(conn, status);
        else
-               send_server_connection_notify(connection, !!status);
+               send_server_connection_state_notify(conn, !!status);
 }
 
-static void send_app_connect_notify(struct app_connection *connection,
+static void notify_app_connect_status(struct app_connection *conn,
                                                                int32_t status)
 {
-       if (!connection->app)
+       if (!conn->app)
                return;
 
-       if (connection->app->type == GATT_CLIENT)
-               send_client_connection_notify(connection, status);
-       else if (connection->app->type == GATT_SERVER)
-               send_server_connection_notify(connection, !status);
+       if (conn->app->type == GATT_CLIENT)
+               send_client_connect_status_notify(conn, status);
+       else
+               send_server_connection_state_notify(conn, !status);
 }
 
-static void disconnect_notify_by_device(void *data, void *user_data)
+static void destroy_connection(void *data)
 {
        struct app_connection *conn = data;
-       struct gatt_device *dev = user_data;
 
-       if (dev != conn->device || !conn->app)
+       if (!conn)
                return;
 
-       if (dev->state == DEVICE_CONNECTED)
-               send_app_disconnect_notify(conn, GATT_SUCCESS);
-       else if (dev->state == DEVICE_CONNECT_INIT ||
-                                       dev->state == DEVICE_CONNECT_READY)
-               send_app_connect_notify(conn, GATT_FAILURE);
-}
-
-static void destroy_connection(void *data)
-{
-       struct app_connection *conn = data;
-
        if (conn->timeout_id > 0)
                g_source_remove(conn->timeout_id);
 
-       if (!queue_find(gatt_devices, match_by_value, conn->device))
-               goto cleanup;
+       switch (conn->device->state) {
+       case DEVICE_CONNECTED:
+               notify_app_disconnect_status(conn, GATT_SUCCESS);
+               break;
+       case DEVICE_CONNECT_INIT:
+       case DEVICE_CONNECT_READY:
+               notify_app_connect_status(conn, GATT_FAILURE);
+               break;
+       case DEVICE_DISCONNECTED:
+               break;
+       }
 
-       conn->device->conn_cnt--;
-       if (conn->device->conn_cnt == 0)
+       if (!queue_find(app_connections, match_connection_by_device,
+                                                       conn->device))
                connection_cleanup(conn->device);
 
-cleanup:
        queue_destroy(conn->transactions, free);
        device_unref(conn->device);
        free(conn);
 }
 
-static void device_disconnect_clients(struct gatt_device *dev)
-{
-       /* Notify disconnection to all clients */
-       queue_foreach(app_connections, disconnect_notify_by_device, dev);
-
-       /* Remove all clients by given device's */
-       queue_remove_all(app_connections, match_connection_by_device, dev,
-                                                       destroy_connection);
-}
-
 static gboolean disconnected_cb(GIOChannel *io, GIOCondition cond,
                                                        gpointer user_data)
 {
@@ -944,20 +912,71 @@ static gboolean disconnected_cb(GIOChannel *io, GIOCondition cond,
        if (!getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len))
                DBG("%s (%d)", strerror(err), err);
 
-       device_disconnect_clients(dev);
+       queue_remove_all(app_connections, match_connection_by_device, dev,
+                                                       destroy_connection);
 
        return FALSE;
 }
 
+static bool get_local_mtu(struct gatt_device *dev, uint16_t *mtu)
+{
+       GIOChannel *io;
+       uint16_t imtu, omtu;
+
+       io = g_attrib_get_channel(dev->attrib);
+
+       if (!bt_io_get(io, NULL, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_OMTU, &omtu,
+                                                       BT_IO_OPT_INVALID)) {
+               error("gatt: Failed to get local MTU");
+               return false;
+       }
+
+       /*
+        * Limit MTU to  MIN(IMTU, OMTU). This is to avoid situation where
+        * local OMTU < MIN(remote MTU, IMTU)
+        */
+       if (mtu)
+               *mtu = MIN(imtu, omtu);
+
+       return true;
+}
+
+static bool update_mtu(struct gatt_device *device, uint16_t rmtu)
+{
+       uint16_t mtu, lmtu;
+
+       if (!get_local_mtu(device, &lmtu))
+               return false;
+
+       DBG("remote_mtu:%d local_mtu:%d", rmtu, lmtu);
+
+       if (rmtu < ATT_DEFAULT_LE_MTU) {
+               error("gatt: remote MTU invalid (%u bytes)", rmtu);
+               return false;
+       }
+
+       mtu = MIN(lmtu, rmtu);
+
+       if (mtu == ATT_DEFAULT_LE_MTU)
+               return true;
+
+       if (!g_attrib_set_mtu(device->attrib, mtu)) {
+               error("gatt: Failed to set MTU");
+               return false;
+       }
+
+       return true;
+}
+
 static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data);
 
 static void exchange_mtu_cb(guint8 status, const guint8 *pdu, guint16 plen,
                                                        gpointer user_data)
 {
        struct gatt_device *device = user_data;
-       GIOChannel *io;
-       GError *gerr = NULL;
-       uint16_t rmtu, mtu, imtu;
+       uint16_t rmtu;
+
+       DBG("");
 
        if (status) {
                error("gatt: MTU exchange: %s", att_ecode2str(status));
@@ -969,29 +988,7 @@ static void exchange_mtu_cb(guint8 status, const guint8 *pdu, guint16 plen,
                goto failed;
        }
 
-       if (rmtu < ATT_DEFAULT_LE_MTU) {
-               error("gatt: MTU exchange: mtu error");
-               goto failed;
-       }
-
-       io = g_attrib_get_channel(device->attrib);
-
-       bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_INVALID);
-       if (gerr) {
-               error("gatt: Could not get imtu: %s", gerr->message);
-               g_error_free(gerr);
-
-               return;
-       }
-
-       mtu = MIN(rmtu, imtu);
-       if (mtu != imtu && !g_attrib_set_mtu(device->attrib, mtu)) {
-               error("gatt: MTU exchange failed");
-               goto failed;
-       }
-
-       DBG("MTU exchange succeeded: rmtu:%d, old mtu:%d, new mtu:%d", rmtu,
-                                                               imtu, mtu);
+       update_mtu(device, rmtu);
 
 failed:
        device_unref(device);
@@ -999,21 +996,14 @@ failed:
 
 static void send_exchange_mtu_request(struct gatt_device *device)
 {
-       GIOChannel *io;
-       GError *gerr = NULL;
-       uint16_t imtu;
-
-       io = g_attrib_get_channel(device->attrib);
-
-       bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_INVALID);
-       if (gerr) {
-               error("gatt: Could not get imtu: %s", gerr->message);
-               g_error_free(gerr);
+       uint16_t mtu;
 
+       if (!get_local_mtu(device, &mtu))
                return;
-       }
 
-       if (!gatt_exchange_mtu(device->attrib, imtu, exchange_mtu_cb,
+       DBG("mtu %u", mtu);
+
+       if (!gatt_exchange_mtu(device->attrib, mtu, exchange_mtu_cb,
                                                        device_ref(device)))
                device_unref(device);
 }
@@ -1059,9 +1049,7 @@ static void notify_att_range_change(struct gatt_device *dev,
                break;
        }
 
-       if (length)
-               g_attrib_send(dev->attrib, 0, pdu, length,
-                                               confirmation_cb, NULL, NULL);
+       g_attrib_send(dev->attrib, 0, pdu, length, confirmation_cb, NULL, NULL);
 }
 
 static struct app_connection *create_connection(struct gatt_device *device,
@@ -1093,7 +1081,6 @@ static struct app_connection *create_connection(struct gatt_device *device,
        }
 
        new_conn->device = device_ref(device);
-       new_conn->device->conn_cnt++;
 
        return new_conn;
 }
@@ -1366,9 +1353,9 @@ static void discover_primary_cb(uint8_t status, GSList *services,
 
 static guint search_dev_for_srvc(struct app_connection *conn, bt_uuid_t *uuid)
 {
-       struct discover_srvc_data *cb_data =
-                                       new0(struct discover_srvc_data, 1);
+       struct discover_srvc_data *cb_data;
 
+       cb_data = new0(struct discover_srvc_data, 1);
        if (!cb_data) {
                error("gatt: Cannot allocate cb data");
                return 0;
@@ -1382,7 +1369,6 @@ static guint search_dev_for_srvc(struct app_connection *conn, bt_uuid_t *uuid)
                                        discover_srvc_by_uuid_cb, cb_data);
        }
 
-
        if (conn->app)
                return gatt_discover_primary(conn->device->attrib, NULL,
                                                discover_srvc_all_cb, cb_data);
@@ -1396,13 +1382,13 @@ struct connect_data {
        int32_t status;
 };
 
-static void send_app_connect_notifications(void *data, void *user_data)
+static void notify_app_connect_status_by_device(void *data, void *user_data)
 {
        struct app_connection *conn = data;
        struct connect_data *con_data = user_data;
 
        if (conn->device == con_data->dev)
-               send_app_connect_notify(conn, con_data->status);
+               notify_app_connect_status(conn, con_data->status);
 }
 
 static struct app_connection *find_conn_without_app(struct gatt_device *dev)
@@ -1419,7 +1405,7 @@ static struct app_connection *find_conn_without_app(struct gatt_device *dev)
 static struct app_connection *find_conn(const bdaddr_t *addr, int32_t app_id)
 {
        struct app_connection conn_match;
-       struct gatt_device *dev = NULL;
+       struct gatt_device *dev;
        struct gatt_app *app;
 
        /* Check if app is registered */
@@ -1464,7 +1450,6 @@ static void ind_handler(const uint8_t *cmd, uint16_t cmd_len,
        struct gatt_device *dev = user_data;
        uint16_t resp_length = 0;
        size_t length;
-
        uint8_t *opdu = g_attrib_get_buffer(dev->attrib, &length);
 
        /*
@@ -1474,9 +1459,7 @@ static void ind_handler(const uint8_t *cmd, uint16_t cmd_len,
         */
 
        resp_length = enc_confirmation(opdu, length);
-       if (resp_length)
-               g_attrib_send(dev->attrib, 0, opdu, resp_length, NULL, NULL,
-                                                                       NULL);
+       g_attrib_send(dev->attrib, 0, opdu, resp_length, NULL, NULL, NULL);
 }
 
 static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
@@ -1485,9 +1468,9 @@ static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
        struct connect_data data;
        struct att_range range;
        uint32_t status;
+       GError *err = NULL;
        GAttrib *attrib;
-       uint16_t mtu;
-       uint16_t cid;
+       uint16_t mtu, cid;
 
        if (dev->state != DEVICE_CONNECT_READY) {
                error("gatt: Device not in a connecting state!?");
@@ -1507,8 +1490,27 @@ static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
                goto reply;
        }
 
-       if (!bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &mtu, BT_IO_OPT_CID, &cid,
-                               BT_IO_OPT_INVALID) || cid == ATT_CID)
+       if (!bt_io_get(io, &err, BT_IO_OPT_IMTU, &mtu, BT_IO_OPT_CID, &cid,
+                                                       BT_IO_OPT_INVALID)) {
+               error("gatt: Could not get imtu or cid: %s", err->message);
+               device_set_state(dev, DEVICE_DISCONNECTED);
+               status = GATT_FAILURE;
+               g_error_free(err);
+               goto reply;
+       }
+
+       /* on BR/EDR MTU must not be less then minimal allowed MTU */
+       if (cid != ATT_CID && mtu < ATT_DEFAULT_L2CAP_MTU) {
+               error("gatt: MTU too small (%u bytes)", mtu);
+               device_set_state(dev, DEVICE_DISCONNECTED);
+               status = GATT_FAILURE;
+               goto reply;
+       }
+
+       DBG("mtu %u cid %u", mtu, cid);
+
+       /* on LE we always start with default MTU */
+       if (cid == ATT_CID)
                mtu = ATT_DEFAULT_LE_MTU;
 
        attrib = g_attrib_new(io, mtu);
@@ -1536,7 +1538,10 @@ static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
 
        /* Send exchange mtu request as we assume being client and server */
        /* TODO: Dont exchange mtu if no client apps */
-       send_exchange_mtu_request(dev);
+
+       /* MTU exchange shall not be used on BR/EDR - Vol 3. Part G. 4.3.1 */
+       if (cid == ATT_CID)
+               send_exchange_mtu_request(dev);
 
        /*
         * Service Changed Characteristic and CCC Descriptor handles
@@ -1563,7 +1568,7 @@ reply:
         */
        queue_foreach(dev->autoconnect_apps, create_app_connection, dev);
 
-       if (!dev->conn_cnt) {
+       if (!queue_find(app_connections, match_connection_by_device, dev)) {
                struct app_connection *conn;
 
                if (!dev->attrib)
@@ -1593,7 +1598,8 @@ reply:
 
        data.dev = dev;
        data.status = status;
-       queue_foreach(app_connections, send_app_connect_notifications, &data);
+       queue_foreach(app_connections, notify_app_connect_status_by_device,
+                                                                       &data);
        device_unref(dev);
 
        /* Check if we should restart scan */
@@ -1621,33 +1627,20 @@ static int connect_le(struct gatt_device *dev)
 
        DBG("Connection attempt to: %s", addr);
 
-       /*
-        * If address type is random it might be that IRK was received and
-        * random is just for faking Android Framework. ID address should be
-        * used for connection if present.
-        */
-       if (dev->bdaddr_type == BDADDR_LE_RANDOM) {
-               bdaddr = bt_get_id_addr(&dev->bdaddr, &bdaddr_type);
-               if (!bdaddr)
-                       return -EINVAL;
-       } else {
-               bdaddr = &dev->bdaddr;
-               bdaddr_type = dev->bdaddr_type;
-       }
+       bdaddr = bt_get_id_addr(&dev->bdaddr, &bdaddr_type);
 
        /*
         * This connection will help us catch any PDUs that comes before
         * pairing finishes
         */
        io = bt_io_connect(connect_cb, device_ref(dev), NULL, &gerr,
-                       BT_IO_OPT_SOURCE_BDADDR,
-                       &adapter_addr,
-                       BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC,
-                       BT_IO_OPT_DEST_BDADDR, bdaddr,
-                       BT_IO_OPT_DEST_TYPE, bdaddr_type,
-                       BT_IO_OPT_CID, ATT_CID,
-                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
-                       BT_IO_OPT_INVALID);
+                                       BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+                                       BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC,
+                                       BT_IO_OPT_DEST_BDADDR, bdaddr,
+                                       BT_IO_OPT_DEST_TYPE, bdaddr_type,
+                                       BT_IO_OPT_CID, ATT_CID,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                                       BT_IO_OPT_INVALID);
        if (!io) {
                error("gatt: Failed bt_io_connect(%s): %s", addr,
                                                        gerr->message);
@@ -1658,6 +1651,8 @@ static int connect_le(struct gatt_device *dev)
        /* Keep this, so we can cancel the connection */
        dev->att_io = io;
 
+       device_set_state(dev, DEVICE_CONNECT_READY);
+
        return 0;
 }
 
@@ -1683,10 +1678,9 @@ static void bt_le_discovery_stop_cb(void)
                bt_le_discovery_start();
 }
 
-static void le_device_found_handler(const bdaddr_t *addr, uint8_t addr_type,
-                                               int rssi, uint16_t eir_len,
-                                               const void *eir,
-                                               bool connectable, bool bonded)
+static void le_device_found_handler(const bdaddr_t *addr, int rssi,
+                                       uint16_t eir_len, const void *eir,
+                                       bool connectable, bool bonded)
 {
        uint8_t buf[IPC_MTU];
        struct hal_ev_gatt_client_scan_result *ev = (void *) buf;
@@ -1729,7 +1723,6 @@ done:
                return;
 
        device_set_state(dev, DEVICE_CONNECT_READY);
-       dev->bdaddr_type = addr_type;
 
        /*
         * We are ok to perform connect now. Stop discovery
@@ -1800,8 +1793,9 @@ static void handle_client_register(const void *buf, uint16_t len)
        if (app) {
                ev.client_if = app->id;
                ev.status = GATT_SUCCESS;
-       } else
+       } else {
                ev.status = GATT_FAILURE;
+       }
 
        /* We should send notification with given in cmd UUID */
        memcpy(ev.app_uuid, cmd->uuid, sizeof(ev.app_uuid));
@@ -1855,6 +1849,7 @@ static void handle_client_scan(const void *buf, uint16_t len)
                status = HAL_STATUS_FAILED;
                goto reply;
        }
+
        scanning = true;
        status = HAL_STATUS_SUCCESS;
 
@@ -1863,30 +1858,6 @@ reply:
                                                                        status);
 }
 
-static void trigger_disconnection(struct app_connection *connection)
-{
-       /* Notify client */
-       if (queue_remove(app_connections, connection))
-                       send_app_disconnect_notify(connection, GATT_SUCCESS);
-
-       destroy_connection(connection);
-}
-
-static void app_disconnect_devices(struct gatt_app *client)
-{
-       struct app_connection *conn;
-
-       /* find every connection for client record and trigger disconnect */
-       conn = queue_remove_if(app_connections, match_connection_by_app,
-                                                                       client);
-       while (conn) {
-               trigger_disconnection(conn);
-
-               conn = queue_remove_if(app_connections,
-                                       match_connection_by_app, client);
-       }
-}
-
 static int connect_bredr(struct gatt_device *dev)
 {
        BtIOSecLevel sec_level;
@@ -1908,13 +1879,13 @@ static int connect_bredr(struct gatt_device *dev)
                                                                BT_IO_SEC_LOW;
 
        io = bt_io_connect(connect_cb, device_ref(dev), NULL, &gerr,
-                       BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
-                       BT_IO_OPT_SOURCE_TYPE, BDADDR_BREDR,
-                       BT_IO_OPT_DEST_BDADDR, &dev->bdaddr,
-                       BT_IO_OPT_DEST_TYPE, BDADDR_BREDR,
-                       BT_IO_OPT_PSM, ATT_PSM,
-                       BT_IO_OPT_SEC_LEVEL, sec_level,
-                       BT_IO_OPT_INVALID);
+                                       BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+                                       BT_IO_OPT_SOURCE_TYPE, BDADDR_BREDR,
+                                       BT_IO_OPT_DEST_BDADDR, &dev->bdaddr,
+                                       BT_IO_OPT_DEST_TYPE, BDADDR_BREDR,
+                                       BT_IO_OPT_PSM, ATT_PSM,
+                                       BT_IO_OPT_SEC_LEVEL, sec_level,
+                                       BT_IO_OPT_INVALID);
        if (!io) {
                error("gatt: Failed bt_io_connect(%s): %s", addr,
                                                        gerr->message);
@@ -1930,39 +1901,31 @@ static int connect_bredr(struct gatt_device *dev)
        return 0;
 }
 
-static bool trigger_connection(struct app_connection *connection)
+static bool trigger_connection(struct app_connection *conn, bool direct)
 {
-       bool ret;
-
-       switch (connection->device->state) {
+       switch (conn->device->state) {
        case DEVICE_DISCONNECTED:
                /*
                 *  If device was last seen over BR/EDR connect over it.
                 *  Note: Connection state is handled in connect_bredr() func
                 */
-               if (bt_device_last_seen_bearer(&connection->device->bdaddr) ==
+               if (bt_device_last_seen_bearer(&conn->device->bdaddr) ==
                                                                BDADDR_BREDR)
-                       return connect_bredr(connection->device) == 0;
+                       return connect_bredr(conn->device) == 0;
 
-               /* For LE use auto connect feature */
-               ret = auto_connect_le(connection->device);
-               if (ret)
-                       device_set_state(connection->device,
-                                                       DEVICE_CONNECT_INIT);
-               break;
+               if (direct)
+                       return connect_le(conn->device) == 0;
+
+               return auto_connect_le(conn->device);
        case DEVICE_CONNECTED:
-               send_app_connect_notify(connection, GATT_SUCCESS);
-               ret = true;
-               break;
+               notify_app_connect_status(conn, GATT_SUCCESS);
+               return true;
        case DEVICE_CONNECT_READY:
        case DEVICE_CONNECT_INIT:
        default:
                /* In those cases connection is already triggered. */
-               ret = true;
-               break;
+               return true;
        }
-
-       return ret;
 }
 
 static void remove_autoconnect_device(struct gatt_device *dev)
@@ -1992,7 +1955,8 @@ static uint8_t unregister_app(int client_if)
         * Make sure that there is no devices in auto connect list for this
         * application
         */
-       queue_foreach(gatt_devices, clear_autoconnect_devices, INT_TO_PTR(client_if));
+       queue_foreach(gatt_devices, clear_autoconnect_devices,
+                                                       INT_TO_PTR(client_if));
 
        cl = queue_remove_if(gatt_apps, match_app_by_id, INT_TO_PTR(client_if));
        if (!cl) {
@@ -2002,7 +1966,8 @@ static uint8_t unregister_app(int client_if)
        }
 
        /* Destroy app connections with proper notifications for this app. */
-       app_disconnect_devices(cl);
+       queue_remove_all(app_connections, match_connection_by_app, cl,
+                                                       destroy_connection);
        destroy_gatt_app(cl);
 
        return HAL_STATUS_SUCCESS;
@@ -2069,7 +2034,7 @@ static void handle_client_unregister(const void *buf, uint16_t len)
 
        DBG("");
 
-       listening_client = queue_find(listen_apps, match_by_value,
+       listening_client = queue_find(listen_apps, NULL,
                                                INT_TO_PTR(cmd->client_if));
 
        if (listening_client) {
@@ -2104,7 +2069,7 @@ reply:
                                        HAL_OP_GATT_CLIENT_UNREGISTER, status);
 }
 
-static uint8_t handle_connect(int32_t app_id, const bdaddr_t *addr)
+static uint8_t handle_connect(int32_t app_id, const bdaddr_t *addr, bool direct)
 {
        struct app_connection conn_match;
        struct app_connection *conn;
@@ -2135,7 +2100,7 @@ static uint8_t handle_connect(int32_t app_id, const bdaddr_t *addr)
                        return HAL_STATUS_NOMEM;
        }
 
-       if (!trigger_connection(conn))
+       if (!trigger_connection(conn, direct))
                return HAL_STATUS_FAILED;
 
        return HAL_STATUS_SUCCESS;
@@ -2147,15 +2112,13 @@ static void handle_client_connect(const void *buf, uint16_t len)
        uint8_t status;
        bdaddr_t addr;
 
-       DBG("");
+       DBG("is_direct:%u transport:%u", cmd->is_direct, cmd->transport);
 
        android2bdaddr(&cmd->bdaddr, &addr);
 
-       /* TODO handle is_direct flag */
-
        /* TODO handle transport flag */
 
-       status = handle_connect(cmd->client_if, &addr);
+       status = handle_connect(cmd->client_if, &addr, cmd->is_direct);
 
        ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT, HAL_OP_GATT_CLIENT_CONNECT,
                                                                status);
@@ -2170,9 +2133,9 @@ static void handle_client_disconnect(const void *buf, uint16_t len)
        DBG("");
 
        /* TODO: should we care to match also bdaddr when conn_id is unique? */
-       conn = find_connection_by_id(cmd->conn_id);
-       if (conn)
-               trigger_disconnection(conn);
+       conn = queue_remove_if(app_connections, match_connection_by_id,
+                                               INT_TO_PTR(cmd->conn_id));
+       destroy_connection(conn);
 
        status = HAL_STATUS_SUCCESS;
 
@@ -2196,7 +2159,7 @@ static void handle_client_listen(const void *buf, uint16_t len)
                goto reply;
        }
 
-       listening_client = queue_find(listen_apps, match_by_value,
+       listening_client = queue_find(listen_apps, NULL,
                                                INT_TO_PTR(cmd->client_if));
        /* Start listening */
        if (cmd->start) {
@@ -2233,8 +2196,7 @@ static void handle_client_listen(const void *buf, uint16_t len)
                 */
                if (advertising_cnt > 1) {
                        advertising_cnt--;
-                       queue_remove(listen_apps,
-                                               INT_TO_PTR(cmd->client_if));
+                       queue_remove(listen_apps, INT_TO_PTR(cmd->client_if));
                        status = HAL_STATUS_SUCCESS;
                        goto reply;
                }
@@ -2502,7 +2464,7 @@ failed:
        send_client_incl_service_notify(&service->id, incl, conn->id);
 }
 
-static bool search_included_services(struct app_connection *connection,
+static bool search_included_services(struct app_connection *conn,
                                                        struct service *service)
 {
        struct get_included_data *data;
@@ -2515,7 +2477,7 @@ static bool search_included_services(struct app_connection *connection,
        }
 
        data->prim = service;
-       data->conn = connection;
+       data->conn = conn;
 
        if (service->primary) {
                start = service->prim.range.start;
@@ -2525,8 +2487,8 @@ static bool search_included_services(struct app_connection *connection,
                end = service->incl.range.end;
        }
 
-       gatt_find_included(connection->device->attrib, start, end,
-                                                       get_included_cb, data);
+       gatt_find_included(conn->device->attrib, start, end, get_included_cb,
+                                                                       data);
 
        return true;
 }
@@ -2601,6 +2563,7 @@ static void handle_client_get_included_service(const void *buf, uint16_t len)
                incl_service = queue_peek_head(prim_service->included);
        } else {
                uint8_t inst_id = cmd->incl_srvc_id[0].inst_id;
+
                incl_service = queue_find(prim_service->included,
                                                match_srvc_by_higher_inst_id,
                                                INT_TO_PTR(inst_id));
@@ -2646,8 +2609,8 @@ static void send_client_char_notify(const struct hal_gatt_srvc_id *service,
 }
 
 static void convert_send_client_char_notify(const struct characteristic *ch,
-                                       int32_t conn_id,
-                                       const struct service *service)
+                                               int32_t conn_id,
+                                               const struct service *service)
 {
        struct hal_gatt_srvc_id srvc;
        struct hal_gatt_gatt_id charac;
@@ -2698,6 +2661,7 @@ static void cache_all_srvc_chars(struct service *srvc, GSList *characteristics)
                /* Store end handle to use later for descriptors discovery */
                if (characteristics->next) {
                        struct gatt_char *next = characteristics->next->data;
+
                        ch->end_handle = next->handle - 1;
                } else {
                        ch->end_handle = srvc->primary ? srvc->prim.range.end :
@@ -2725,12 +2689,20 @@ static void discover_char_cb(uint8_t status, GSList *characteristics,
        struct discover_char_data *data = user_data;
        struct service *srvc = data->service;
 
+       if (status) {
+               error("gatt: Failed to get characteristics: %s",
+                                                       att_ecode2str(status));
+               convert_send_client_char_notify(NULL, data->conn_id, srvc);
+               goto done;
+       }
+
        if (queue_isempty(srvc->chars))
                cache_all_srvc_chars(srvc, characteristics);
 
        convert_send_client_char_notify(queue_peek_head(srvc->chars),
                                                        data->conn_id, srvc);
 
+done:
        free(data);
 }
 
@@ -2881,9 +2853,8 @@ reply:
        free(data);
 }
 
-static bool build_descr_cache(struct app_connection *connection,
-                                       struct service *srvc,
-                                       struct characteristic *ch)
+static bool build_descr_cache(struct app_connection *conn, struct service *srvc,
+                                               struct characteristic *ch)
 {
        struct discover_desc_data *cb_data;
        uint16_t start, end;
@@ -2900,11 +2871,11 @@ static bool build_descr_cache(struct app_connection *connection,
        if (!cb_data)
                return false;
 
-       cb_data->conn = connection;
+       cb_data->conn = conn;
        cb_data->srvc = srvc;
        cb_data->ch = ch;
 
-       if (!gatt_discover_desc(connection->device->attrib, start, end, NULL,
+       if (!gatt_discover_desc(conn->device->attrib, start, end, NULL,
                                        gatt_discover_desc_cb, cb_data)) {
                free(cb_data);
                return false;
@@ -3218,8 +3189,9 @@ failed:
         */
        if (status != HAL_STATUS_SUCCESS)
                send_client_read_char_notify(GATT_FAILURE, NULL, 0,
-                                       cmd->conn_id, &srvc_id, &char_id,
-                                       cmd->srvc_id.is_primary);
+                                               cmd->conn_id, &srvc_id,
+                                               &char_id,
+                                               cmd->srvc_id.is_primary);
 }
 
 static void send_client_write_char_notify(int32_t status, int32_t conn_id,
@@ -3263,7 +3235,7 @@ static guint signed_write_cmd(struct gatt_device *dev, uint16_t handle,
 
        memset(csrk, 0, 16);
 
-       if (!bt_get_csrk(&dev->bdaddr, LOCAL_CSRK, csrk, &sign_cnt)) {
+       if (!bt_get_csrk(&dev->bdaddr, true, csrk, &sign_cnt, NULL)) {
                error("gatt: Could not get csrk key");
                return 0;
        }
@@ -3271,11 +3243,11 @@ static guint signed_write_cmd(struct gatt_device *dev, uint16_t handle,
        res = gatt_signed_write_cmd(dev->attrib, handle, value, vlen, crypto,
                                                csrk, sign_cnt, NULL, NULL);
        if (!res) {
-               error("gatt: Could write signed cmd");
+               error("gatt: Signed write command failed");
                return 0;
        }
 
-       bt_update_sign_counter(&dev->bdaddr, LOCAL_CSRK, ++sign_cnt);
+       bt_update_sign_counter(&dev->bdaddr, true, ++sign_cnt);
 
        return res;
 }
@@ -3358,14 +3330,14 @@ static void handle_client_write_characteristic(const void *buf, uint16_t len)
                        goto failed;
                }
 
-               if (get_sec_level(conn->device) != BT_SECURITY_LOW) {
-                       error("gatt: Cannot write signed on encrypted link");
-                       status = HAL_STATUS_FAILED;
-                       goto failed;
-               }
-
-               res = signed_write_cmd(conn->device, ch->ch.value_handle,
-                                                       cmd->value, cmd->len);
+               if (get_sec_level(conn->device) > BT_SECURITY_LOW)
+                       res = gatt_write_cmd(conn->device->attrib,
+                                               ch->ch.value_handle, cmd->value,
+                                               cmd->len, NULL, NULL);
+               else
+                       res = signed_write_cmd(conn->device,
+                                               ch->ch.value_handle, cmd->value,
+                                               cmd->len);
                break;
        default:
                error("gatt: Write type %d unsupported", cmd->write_type);
@@ -4092,7 +4064,7 @@ static void test_command_result(guint8 status, const guint8 *pdu,
 }
 
 static uint8_t test_read_write(bdaddr_t *bdaddr, bt_uuid_t *uuid, uint16_t op,
-                                               uint16_t u2,uint16_t u3,
+                                               uint16_t u2, uint16_t u3,
                                                uint16_t u4, uint16_t u5)
 {
        guint16 length = 0;
@@ -4149,12 +4121,10 @@ static uint8_t test_read_write(bdaddr_t *bdaddr, bt_uuid_t *uuid, uint16_t op,
                return HAL_STATUS_UNSUPPORTED;
        }
 
-       if (!length)
+       if (!g_attrib_send(dev->attrib, 0, pdu, length, test_command_result,
+                                                               NULL, NULL))
                return HAL_STATUS_FAILED;
 
-       g_attrib_send(dev->attrib, 0, pdu, length, test_command_result, NULL,
-                                                                       NULL);
-
        return HAL_STATUS_SUCCESS;
 }
 
@@ -4205,13 +4175,13 @@ static void handle_client_test_command(const void *buf, uint16_t len)
                break;
        case GATT_CLIENT_TEST_CMD_CONNECT:
                /* TODO u1 holds device type, for now assume BLE */
-               status = handle_connect(test_client_if, &bdaddr);
+               status = handle_connect(test_client_if, &bdaddr, false);
                break;
        case GATT_CLIENT_TEST_CMD_DISCONNECT:
                app = queue_find(gatt_apps, match_app_by_id,
                                                INT_TO_PTR(test_client_if));
-               if (app)
-                       app_disconnect_devices(app);
+               queue_remove_all(app_connections, match_connection_by_app, app,
+                                                       destroy_connection);
 
                status = HAL_STATUS_SUCCESS;
                break;
@@ -4289,7 +4259,7 @@ static void handle_server_connect(const void *buf, uint16_t len)
 
        /* TODO: Handle transport flag */
 
-       status = handle_connect(cmd->server_if, &addr);
+       status = handle_connect(cmd->server_if, &addr, cmd->is_direct);
 
        ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT, HAL_OP_GATT_SERVER_CONNECT,
                                                                status);
@@ -4304,9 +4274,9 @@ static void handle_server_disconnect(const void *buf, uint16_t len)
        DBG("");
 
        /* TODO: should we care to match also bdaddr when conn_id is unique? */
-       conn = find_connection_by_id(cmd->conn_id);
-       if (conn)
-               trigger_disconnection(conn);
+       conn = queue_remove_if(app_connections, match_connection_by_id,
+                                               INT_TO_PTR(cmd->conn_id));
+       destroy_connection(conn);
 
        status = HAL_STATUS_SUCCESS;
 
@@ -4432,7 +4402,7 @@ static bool match_pending_dev_request(const void *data, const void *user_data)
 {
        const struct pending_request *pending_request = data;
 
-       return pending_request->state == REQUEST_PENDING;
+       return !pending_request->completed;
 }
 
 static void send_dev_complete_response(struct gatt_device *device,
@@ -4453,6 +4423,17 @@ static void send_dev_complete_response(struct gatt_device *device,
                return;
        }
 
+       val = queue_peek_head(device->pending_requests);
+       if (!val) {
+               error = ATT_ECODE_ATTR_NOT_FOUND;
+               goto done;
+       }
+
+       if (val->error) {
+               error = val->error;
+               goto done;
+       }
+
        switch (opcode) {
        case ATT_OP_READ_BY_TYPE_REQ: {
                struct att_data_list *adl;
@@ -4485,11 +4466,10 @@ static void send_dev_complete_response(struct gatt_device *device,
                        val = queue_pop_head(device->pending_requests);
                }
 
-               adl = att_data_list_alloc(queue_length(temp), sizeof(uint16_t) +
-                                                                       length);
+               adl = att_data_list_alloc(queue_length(temp),
+                                               sizeof(uint16_t) + length);
 
-               if (val)
-                       destroy_pending_request(val);
+               destroy_pending_request(val);
 
                val = queue_pop_head(temp);
                while (val) {
@@ -4513,25 +4493,11 @@ static void send_dev_complete_response(struct gatt_device *device,
                break;
        }
        case ATT_OP_READ_BLOB_REQ:
-               val = queue_pop_head(device->pending_requests);
-               if (val->error) {
-                       error = val->error;
-                       goto done;
-               }
-
                len = enc_read_blob_resp(val->value, val->length, val->offset,
                                                                rsp, mtu);
-               destroy_pending_request(val);
                break;
        case ATT_OP_READ_REQ:
-               val = queue_pop_head(device->pending_requests);
-               if (val->error) {
-                       error = val->error;
-                       goto done;
-               }
-
                len = enc_read_resp(val->value, val->length, rsp, mtu);
-               destroy_pending_request(val);
                break;
        case ATT_OP_READ_BY_GROUP_REQ: {
                struct att_data_list *adl;
@@ -4637,39 +4603,17 @@ static void send_dev_complete_response(struct gatt_device *device,
                break;
        }
        case ATT_OP_EXEC_WRITE_REQ:
-               val = queue_pop_head(device->pending_requests);
-               if (val->error) {
-                       error = val->error;
-                       goto done;
-               }
-
                len = enc_exec_write_resp(rsp);
-               destroy_pending_request(val);
                break;
        case ATT_OP_WRITE_REQ:
-               val = queue_pop_head(device->pending_requests);
-               if (val->error) {
-                       error = val->error;
-                       goto done;
-               }
-
                len = enc_write_resp(rsp);
-               destroy_pending_request(val);
                break;
        case ATT_OP_PREP_WRITE_REQ: {
                uint16_t handle;
 
-               val = queue_pop_head(device->pending_requests);
-               if (val->error) {
-                       error = val->error;
-                       goto done;
-               }
-
                handle = gatt_db_attribute_get_handle(val->attrib);
-
                len = enc_prep_write_resp(handle, val->offset, val->value,
                                                        val->length, rsp, mtu);
-               destroy_pending_request(val);
                break;
        }
        default:
@@ -4703,7 +4647,7 @@ static uint8_t check_device_permissions(struct gatt_device *device,
                                                        BT_IO_OPT_INVALID))
                return ATT_ECODE_UNLIKELY;
 
-       DBG("opcode %u permissions %u sec_level %u", opcode, permissions,
+       DBG("opcode 0x%02x permissions %u sec_level %u", opcode, permissions,
                                                                sec_level);
 
        switch (opcode) {
@@ -4711,9 +4655,15 @@ static uint8_t check_device_permissions(struct gatt_device *device,
                if (!(permissions & GATT_PERM_WRITE_SIGNED))
                                return ATT_ECODE_WRITE_NOT_PERM;
 
-               if ((permissions & GATT_PERM_WRITE_SIGNED_MITM) &&
-                                               sec_level < BT_SECURITY_HIGH)
+               if (permissions & GATT_PERM_WRITE_SIGNED_MITM) {
+                       bool auth;
+
+                       if (bt_get_csrk(&device->bdaddr, true, NULL, NULL,
+                                       &auth) && auth)
+                               break;
+
                        return ATT_ECODE_AUTHENTICATION;
+               }
                break;
        case ATT_OP_READ_BY_TYPE_REQ:
        case ATT_OP_READ_REQ:
@@ -4787,7 +4737,7 @@ static void attribute_read_cb(struct gatt_db_attribute *attrib, int err,
        resp_data->length = length;
        resp_data->error = error;
 
-       resp_data->state = REQUEST_DONE;
+       resp_data->completed = true;
 
        if (!length)
                return;
@@ -4806,6 +4756,7 @@ static void read_requested_attributes(void *data, void *user_data)
 {
        struct pending_request *resp_data = data;
        struct request_processing_data *process_data = user_data;
+       struct bt_att *att = g_attrib_get_att(process_data->device->attrib);
        struct gatt_db_attribute *attrib;
        uint32_t permissions;
        uint8_t error;
@@ -4813,11 +4764,11 @@ static void read_requested_attributes(void *data, void *user_data)
        attrib = resp_data->attrib;
        if (!attrib) {
                resp_data->error = ATT_ECODE_ATTR_NOT_FOUND;
-               resp_data->state = REQUEST_DONE;
+               resp_data->completed = true;
                return;
        }
 
-       gatt_db_attribute_get_permissions(attrib, &permissions);
+       permissions = gatt_db_attribute_get_permissions(attrib);
 
        /*
         * Check if it is attribute we didn't declare permissions, like service
@@ -4831,15 +4782,12 @@ static void read_requested_attributes(void *data, void *user_data)
                                                        permissions);
        if (error != 0) {
                resp_data->error = error;
-               resp_data->state = REQUEST_DONE;
+               resp_data->completed = true;
                return;
        }
 
-       resp_data->state = REQUEST_PENDING;
-
        gatt_db_attribute_read(attrib, resp_data->offset, process_data->opcode,
-                                       &process_data->device->bdaddr,
-                                       attribute_read_cb, resp_data);
+                                       att, attribute_read_cb, resp_data);
 }
 
 static void process_dev_pending_requests(struct gatt_device *device,
@@ -4885,8 +4833,29 @@ static struct pending_trans_data *conn_add_transact(struct app_connection *conn,
        return transaction;
 }
 
+static bool get_dst_addr(struct bt_att *att, bdaddr_t *dst)
+{
+       GIOChannel *io = NULL;
+       GError *gerr = NULL;
+
+       io = g_io_channel_unix_new(bt_att_get_fd(att));
+       if (!io)
+               return false;
+
+       bt_io_get(io, &gerr, BT_IO_OPT_DEST_BDADDR, dst, BT_IO_OPT_INVALID);
+       if (gerr) {
+               error("gatt: bt_io_get: %s", gerr->message);
+               g_error_free(gerr);
+               g_io_channel_unref(io);
+               return false;
+       }
+
+       g_io_channel_unref(io);
+       return true;
+}
+
 static void read_cb(struct gatt_db_attribute *attrib, unsigned int id,
-                       uint16_t offset, uint8_t opcode, bdaddr_t *bdaddr,
+                       uint16_t offset, uint8_t opcode, struct bt_att *att,
                        void *user_data)
 {
        struct pending_trans_data *transaction;
@@ -4894,6 +4863,7 @@ static void read_cb(struct gatt_db_attribute *attrib, unsigned int id,
        struct gatt_app *app;
        struct app_connection *conn;
        int32_t app_id = PTR_TO_INT(user_data);
+       bdaddr_t bdaddr;
 
        DBG("id %u", id);
 
@@ -4903,7 +4873,12 @@ static void read_cb(struct gatt_db_attribute *attrib, unsigned int id,
                goto failed;
        }
 
-       conn = find_conn(bdaddr, app->id);
+       if (!get_dst_addr(att, &bdaddr)) {
+               error("gatt: read_cb, could not obtain dst BDADDR");
+               goto failed;
+       }
+
+       conn = find_conn(&bdaddr, app->id);
        if (!conn) {
                error("gatt: read_cb, cound not found connection");
                goto failed;
@@ -4916,7 +4891,7 @@ static void read_cb(struct gatt_db_attribute *attrib, unsigned int id,
        if (!transaction)
                goto failed;
 
-       bdaddr2android(bdaddr, ev.bdaddr);
+       bdaddr2android(&bdaddr, ev.bdaddr);
        ev.conn_id = conn->id;
        ev.attr_handle = gatt_db_attribute_get_handle(attrib);
        ev.offset = offset;
@@ -4935,7 +4910,7 @@ failed:
 
 static void write_cb(struct gatt_db_attribute *attrib, unsigned int id,
                        uint16_t offset, const uint8_t *value, size_t len,
-                       uint8_t opcode, bdaddr_t *bdaddr, void *user_data)
+                       uint8_t opcode, struct bt_att *att, void *user_data)
 {
        uint8_t buf[IPC_MTU];
        struct hal_ev_gatt_server_request_write *ev = (void *) buf;
@@ -4943,6 +4918,7 @@ static void write_cb(struct gatt_db_attribute *attrib, unsigned int id,
        struct gatt_app *app;
        int32_t app_id = PTR_TO_INT(user_data);
        struct app_connection *conn;
+       bdaddr_t bdaddr;
 
        DBG("id %u", id);
 
@@ -4952,7 +4928,12 @@ static void write_cb(struct gatt_db_attribute *attrib, unsigned int id,
                goto failed;
        }
 
-       conn = find_conn(bdaddr, app->id);
+       if (!get_dst_addr(att, &bdaddr)) {
+               error("gatt: write_cb, could not obtain dst BDADDR");
+               goto failed;
+       }
+
+       conn = find_conn(&bdaddr, app->id);
        if (!conn) {
                error("gatt: write_cb could not found connection");
                goto failed;
@@ -4972,7 +4953,7 @@ static void write_cb(struct gatt_db_attribute *attrib, unsigned int id,
 
        memset(ev, 0, sizeof(*ev));
 
-       bdaddr2android(bdaddr, &ev->bdaddr);
+       bdaddr2android(&bdaddr, &ev->bdaddr);
        ev->attr_handle = gatt_db_attribute_get_handle(attrib);
        ev->offset = offset;
 
@@ -5167,7 +5148,7 @@ static sdp_record_t *get_sdp_record(uuid_t *uuid, uint16_t start, uint16_t end,
        uint16_t lp = ATT_PSM;
 
        record = sdp_record_alloc();
-       if (record == NULL)
+       if (!record)
                return NULL;
 
        sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
@@ -5482,6 +5463,18 @@ failed:
                                HAL_OP_GATT_SERVER_DELETE_SERVICE, status);
 }
 
+static void indication_confirmation_cb(guint8 status, const guint8 *pdu,
+                                               guint16 len, gpointer user_data)
+{
+       struct hal_ev_gatt_server_indication_sent ev;
+
+       ev.status = status;
+       ev.conn_id = PTR_TO_UINT(user_data);
+
+       ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+                       HAL_EV_GATT_SERVER_INDICATION_SENT, sizeof(ev), &ev);
+}
+
 static void handle_server_send_indication(const void *buf, uint16_t len)
 {
        const struct hal_cmd_gatt_server_send_indication *cmd = buf;
@@ -5504,26 +5497,29 @@ static void handle_server_send_indication(const void *buf, uint16_t len)
        pdu = g_attrib_get_buffer(conn->device->attrib, &mtu);
 
        if (cmd->confirm) {
-               /* TODO: Add data to track confirmation for this request */
                length = enc_indication(cmd->attribute_handle,
-                                       (uint8_t *)cmd->value, cmd->len, pdu,
+                                       (uint8_t *) cmd->value, cmd->len, pdu,
                                        mtu);
-               confirmation_cb = ignore_confirmation_cb;
+               confirmation_cb = indication_confirmation_cb;
        } else {
                length = enc_notification(cmd->attribute_handle,
-                                               (uint8_t *)cmd->value, cmd->len,
-                                               pdu, mtu);
+                                               (uint8_t *) cmd->value,
+                                               cmd->len, pdu, mtu);
        }
 
-       if (length == 0) {
-               error("gatt: Failed to encode indication");
+       if (!g_attrib_send(conn->device->attrib, 0, pdu, length,
+                               confirmation_cb, UINT_TO_PTR(conn->id), NULL)) {
+               error("gatt: Failed to send indication");
                status = HAL_STATUS_FAILED;
        } else {
-               g_attrib_send(conn->device->attrib, 0, pdu, length,
-                                               confirmation_cb, NULL, NULL);
                status = HAL_STATUS_SUCCESS;
        }
 
+       /* Here we confirm failed indications and all notifications */
+       if (status || !confirmation_cb)
+               indication_confirmation_cb(status, NULL, 0,
+                                                       UINT_TO_PTR(conn->id));
+
 reply:
        ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
                                HAL_OP_GATT_SERVER_SEND_INDICATION, status);
@@ -5593,7 +5589,7 @@ static void handle_server_send_response(const void *buf, uint16_t len)
 
                /* Cast status to uint8_t, due to (byte) cast in java layer. */
                req->error = err_to_att((uint8_t) cmd->status);
-               req->state = REQUEST_DONE;
+               req->completed = true;
 
                /*
                 * FIXME: Handle situation when not all server applications
@@ -6035,7 +6031,6 @@ static uint8_t read_by_type(const uint8_t *cmd, uint16_t cmd_len,
                        return ATT_ECODE_INSUFF_RESOURCES;
                }
 
-               data->state = REQUEST_INIT;
                data->attrib = attrib;
                if (!queue_push_tail(device->pending_requests, data)) {
                        free(data);
@@ -6088,7 +6083,6 @@ static uint8_t read_request(const uint8_t *cmd, uint16_t cmd_len,
 
        data->offset = offset;
        data->attrib = attrib;
-       data->state = REQUEST_INIT;
        if (!queue_push_tail(dev->pending_requests, data)) {
                free(data);
                return ATT_ECODE_INSUFF_RESOURCES;
@@ -6102,53 +6096,38 @@ static uint8_t read_request(const uint8_t *cmd, uint16_t cmd_len,
 static uint8_t mtu_att_handle(const uint8_t *cmd, uint16_t cmd_len,
                                                        struct gatt_device *dev)
 {
-       uint16_t mtu, imtu, omtu;
+       uint16_t rmtu, mtu, len;
        size_t length;
-       GIOChannel *io;
-       GError *gerr = NULL;
-       uint16_t len;
        uint8_t *rsp;
 
        DBG("");
 
-       len = dec_mtu_req(cmd, cmd_len, &mtu);
+       len = dec_mtu_req(cmd, cmd_len, &rmtu);
        if (!len)
                return ATT_ECODE_INVALID_PDU;
 
-       if (mtu < ATT_DEFAULT_LE_MTU)
-               return ATT_ECODE_REQ_NOT_SUPP;
+       /* MTU exchange shall not be used on BR/EDR - Vol 3. Part G. 4.3.1 */
+       if (get_cid(dev) != ATT_CID)
+               return ATT_ECODE_UNLIKELY;
 
-       io = g_attrib_get_channel(dev->attrib);
+       if (!get_local_mtu(dev, &mtu))
+               return ATT_ECODE_UNLIKELY;
 
-       bt_io_get(io, &gerr,
-                       BT_IO_OPT_IMTU, &imtu,
-                       BT_IO_OPT_OMTU, &omtu,
-                       BT_IO_OPT_INVALID);
-       if (gerr) {
-               error("bt_io_get: %s", gerr->message);
-               g_error_free(gerr);
+       if (!update_mtu(dev, rmtu))
                return ATT_ECODE_UNLIKELY;
-       }
 
        rsp = g_attrib_get_buffer(dev->attrib, &length);
 
-       /* Respond with our IMTU */
-       len = enc_mtu_resp(imtu, rsp, length);
-       if (!len)
+       /* Respond with our MTU */
+       len = enc_mtu_resp(mtu, rsp, length);
+       if (!g_attrib_send(dev->attrib, 0, rsp, len, NULL, NULL, NULL))
                return ATT_ECODE_UNLIKELY;
 
-       g_attrib_send(dev->attrib, 0, rsp, len, NULL, NULL, NULL);
-
-       /* Limit OMTU to received value */
-       mtu = MIN(mtu, omtu);
-       g_attrib_set_mtu(dev->attrib, mtu);
-
        return 0;
 }
 
 static uint8_t find_info_handle(const uint8_t *cmd, uint16_t cmd_len,
-                                               uint8_t *rsp, size_t rsp_size,
-                                               uint16_t *length)
+                               uint8_t *rsp, size_t rsp_size, uint16_t *length)
 {
        struct gatt_db_attribute *attrib;
        struct queue *q, *temp;
@@ -6156,6 +6135,7 @@ static uint8_t find_info_handle(const uint8_t *cmd, uint16_t cmd_len,
        int iterator = 0;
        uint16_t start, end;
        uint16_t len, queue_len;
+       uint8_t format;
        uint8_t ret = 0;
 
        DBG("");
@@ -6230,9 +6210,12 @@ static uint8_t find_info_handle(const uint8_t *cmd, uint16_t cmd_len,
                memcpy(&value[2], &type->value, len);
        }
 
-       len = enc_find_info_resp(len == 2 ? ATT_FIND_INFO_RESP_FMT_16BIT :
-                                       ATT_FIND_INFO_RESP_FMT_128BIT, adl, rsp,
-                                                               rsp_size);
+       if (len == 2)
+               format = ATT_FIND_INFO_RESP_FMT_16BIT;
+       else
+               format = ATT_FIND_INFO_RESP_FMT_128BIT;
+
+       len = enc_find_info_resp(format, adl, rsp, rsp_size);
        if (!len)
                ret = ATT_ECODE_UNLIKELY;
 
@@ -6243,15 +6226,56 @@ static uint8_t find_info_handle(const uint8_t *cmd, uint16_t cmd_len,
        return ret;
 }
 
+struct find_by_type_request_data {
+       struct gatt_device *device;
+       uint8_t *search_value;
+       size_t search_vlen;
+       uint8_t error;
+};
+
+static void find_by_type_request_cb(struct gatt_db_attribute *attrib,
+                                                               void *user_data)
+{
+       struct find_by_type_request_data *find_data = user_data;
+       struct pending_request *request_data;
+
+       if (find_data->error)
+               return;
+
+       request_data = new0(struct pending_request, 1);
+       if (!request_data) {
+               find_data->error = ATT_ECODE_INSUFF_RESOURCES;
+               return;
+       }
+
+       request_data->filter_value = malloc0(find_data->search_vlen);
+       if (!request_data->filter_value) {
+               destroy_pending_request(request_data);
+               find_data->error = ATT_ECODE_INSUFF_RESOURCES;
+               return;
+       }
+
+       request_data->attrib = attrib;
+       request_data->filter_vlen = find_data->search_vlen;
+       memcpy(request_data->filter_value, find_data->search_value,
+                                                       find_data->search_vlen);
+
+       if (!queue_push_tail(find_data->device->pending_requests,
+                                                       request_data)) {
+               destroy_pending_request(request_data);
+               find_data->error = ATT_ECODE_INSUFF_RESOURCES;
+       }
+}
+
 static uint8_t find_by_type_request(const uint8_t *cmd, uint16_t cmd_len,
                                                struct gatt_device *device)
 {
        uint8_t search_value[cmd_len];
        size_t search_vlen;
        uint16_t start, end;
-       struct queue *q;
        bt_uuid_t uuid;
        uint16_t len;
+       struct find_by_type_request_data data;
 
        DBG("");
 
@@ -6263,53 +6287,26 @@ static uint8_t find_by_type_request(const uint8_t *cmd, uint16_t cmd_len,
        if (start > end || start == 0)
                return ATT_ECODE_INVALID_HANDLE;
 
-       q = queue_new();
-       if (!q)
-               return ATT_ECODE_UNLIKELY;
+       data.error = 0;
+       data.search_vlen = search_vlen;
+       data.search_value = search_value;
+       data.device = device;
 
-       gatt_db_find_by_type(gatt_db, start, end, &uuid, q);
-
-       if (queue_isempty(q)) {
+       if (gatt_db_find_by_type(gatt_db, start, end, &uuid,
+                                       find_by_type_request_cb, &data) == 0) {
                size_t mtu;
                uint8_t *rsp = g_attrib_get_buffer(device->attrib, &mtu);
 
                len = enc_error_resp(ATT_OP_FIND_BY_TYPE_REQ, start,
                                        ATT_ECODE_ATTR_NOT_FOUND, rsp, mtu);
                g_attrib_send(device->attrib, 0, rsp, len, NULL, NULL, NULL);
-               queue_destroy(q, NULL);
                return 0;
        }
 
-       while (queue_peek_head(q)) {
-               struct gatt_db_attribute *attrib = queue_pop_head(q);
-               struct pending_request *data;
+       if (!data.error)
+               process_dev_pending_requests(device, ATT_OP_FIND_BY_TYPE_REQ);
 
-               data = new0(struct pending_request, 1);
-               if (!data) {
-                       queue_destroy(q, NULL);
-                       return ATT_ECODE_INSUFF_RESOURCES;
-               }
-
-               data->filter_value = malloc0(search_vlen);
-               if (!data->filter_value) {
-                       destroy_pending_request(data);
-                       queue_destroy(q, NULL);
-                       return ATT_ECODE_INSUFF_RESOURCES;
-               }
-
-               data->state = REQUEST_INIT;
-               data->attrib = attrib;
-               data->filter_vlen = search_vlen;
-               memcpy(data->filter_value, search_value, search_vlen);
-
-               queue_push_tail(device->pending_requests, data);
-       }
-
-       queue_destroy(q, NULL);
-
-       process_dev_pending_requests(device, ATT_OP_FIND_BY_TYPE_REQ);
-
-       return 0;
+       return data.error;
 }
 
 static void write_confirm(struct gatt_db_attribute *attrib,
@@ -6342,14 +6339,14 @@ static void write_cmd_request(const uint8_t *cmd, uint16_t cmd_len,
        if (!attrib)
                return;
 
-       if (!gatt_db_attribute_get_permissions(attrib, &permissions))
-               return;
+       permissions = gatt_db_attribute_get_permissions(attrib);
 
        if (check_device_permissions(dev, cmd[0], permissions))
                return;
 
-       gatt_db_attribute_write(attrib, 0, value, vlen, cmd[0], &dev->bdaddr,
-                                                       write_confirm, NULL);
+       gatt_db_attribute_write(attrib, 0, value, vlen, cmd[0],
+                                               g_attrib_get_att(dev->attrib),
+                                               write_confirm, NULL);
 }
 
 static void write_signed_cmd_request(const uint8_t *cmd, uint16_t cmd_len,
@@ -6377,7 +6374,7 @@ static void write_signed_cmd_request(const uint8_t *cmd, uint16_t cmd_len,
                return;
        }
 
-       if (!bt_get_csrk(&dev->bdaddr, REMOTE_CSRK, csrk, &sign_cnt)) {
+       if (!bt_get_csrk(&dev->bdaddr, false, csrk, &sign_cnt, NULL)) {
                error("gatt: No valid csrk from remote device");
                return;
        }
@@ -6391,7 +6388,7 @@ static void write_signed_cmd_request(const uint8_t *cmd, uint16_t cmd_len,
        if (!attrib)
                return;
 
-       gatt_db_attribute_get_permissions(attrib, &permissions);
+       permissions = gatt_db_attribute_get_permissions(attrib);
 
        if (check_device_permissions(dev, cmd[0], permissions))
                return;
@@ -6419,9 +6416,10 @@ static void write_signed_cmd_request(const uint8_t *cmd, uint16_t cmd_len,
                        return;
                }
                /* Signature OK, proceed with write */
-               bt_update_sign_counter(&dev->bdaddr, REMOTE_CSRK, r_sign_cnt);
+               bt_update_sign_counter(&dev->bdaddr, false, r_sign_cnt);
                gatt_db_attribute_write(attrib, 0, value, vlen, cmd[0],
-                                       &dev->bdaddr, write_confirm, NULL);
+                                               g_attrib_get_att(dev->attrib),
+                                               write_confirm, NULL);
        }
 }
 
@@ -6436,7 +6434,7 @@ static void attribute_write_cb(struct gatt_db_attribute *attrib, int err,
        data->attrib = attrib;
        data->error = error;
 
-       data->state = REQUEST_DONE;
+       data->completed = true;
 }
 
 static uint8_t write_req_request(const uint8_t *cmd, uint16_t cmd_len,
@@ -6462,7 +6460,7 @@ static uint8_t write_req_request(const uint8_t *cmd, uint16_t cmd_len,
        if (!attrib)
                return ATT_ECODE_ATTR_NOT_FOUND;
 
-       gatt_db_attribute_get_permissions(attrib, &permissions);
+       permissions = gatt_db_attribute_get_permissions(attrib);
 
        error = check_device_permissions(dev, cmd[0], permissions);
        if (error)
@@ -6473,7 +6471,6 @@ static uint8_t write_req_request(const uint8_t *cmd, uint16_t cmd_len,
                return ATT_ECODE_INSUFF_RESOURCES;
 
        data->attrib = attrib;
-       data->state = REQUEST_PENDING;
 
        if (!queue_push_tail(dev->pending_requests, data)) {
                free(data);
@@ -6481,8 +6478,8 @@ static uint8_t write_req_request(const uint8_t *cmd, uint16_t cmd_len,
        }
 
        if (!gatt_db_attribute_write(attrib, 0, value, vlen, cmd[0],
-                                       &dev->bdaddr, attribute_write_cb,
-                                       data)) {
+                                               g_attrib_get_att(dev->attrib),
+                                               attribute_write_cb, data)) {
                queue_remove(dev->pending_requests, data);
                free(data);
                return ATT_ECODE_UNLIKELY;
@@ -6518,7 +6515,7 @@ static uint8_t write_prep_request(const uint8_t *cmd, uint16_t cmd_len,
        if (!attrib)
                return ATT_ECODE_ATTR_NOT_FOUND;
 
-       gatt_db_attribute_get_permissions(attrib, &permissions);
+       permissions = gatt_db_attribute_get_permissions(attrib);
 
        error = check_device_permissions(dev, cmd[0], permissions);
        if (error)
@@ -6530,7 +6527,6 @@ static uint8_t write_prep_request(const uint8_t *cmd, uint16_t cmd_len,
 
        data->attrib = attrib;
        data->offset = offset;
-       data->state = REQUEST_PENDING;
 
        if (!queue_push_tail(dev->pending_requests, data)) {
                free(data);
@@ -6541,8 +6537,8 @@ static uint8_t write_prep_request(const uint8_t *cmd, uint16_t cmd_len,
        data->length = vlen;
 
        if (!gatt_db_attribute_write(attrib, offset, value, vlen, cmd[0],
-                                       &dev->bdaddr, attribute_write_cb,
-                                       data)) {
+                                               g_attrib_get_att(dev->attrib),
+                                               attribute_write_cb, data)) {
                queue_remove(dev->pending_requests, data);
                g_free(data->value);
                free(data);
@@ -6575,8 +6571,7 @@ static void send_server_write_execute_notify(void *data, void *user_data)
        ev->trans_id = transaction->id;
 
        ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
-                               HAL_EV_GATT_SERVER_REQUEST_EXEC_WRITE,
-                               sizeof(*ev), ev);
+                       HAL_EV_GATT_SERVER_REQUEST_EXEC_WRITE, sizeof(*ev), ev);
 }
 
 static uint8_t write_execute_request(const uint8_t *cmd, uint16_t cmd_len,
@@ -6604,7 +6599,6 @@ static uint8_t write_execute_request(const uint8_t *cmd, uint16_t cmd_len,
        if (!data)
                return ATT_ECODE_INSUFF_RESOURCES;
 
-       data->state = REQUEST_PENDING;
        if (!queue_push_tail(dev->pending_requests, data)) {
                free(data);
                return ATT_ECODE_INSUFF_RESOURCES;
@@ -6650,8 +6644,6 @@ static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
                break;
        case ATT_OP_WRITE_REQ:
                status = write_req_request(ipdu, len, dev);
-               if (!status)
-                       return;
                break;
        case ATT_OP_WRITE_CMD:
                write_cmd_request(ipdu, len, dev);
@@ -6663,22 +6655,18 @@ static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
                return;
        case ATT_OP_PREP_WRITE_REQ:
                status = write_prep_request(ipdu, len, dev);
-               if (!status)
-                       return;
                break;
        case ATT_OP_FIND_BY_TYPE_REQ:
                status = find_by_type_request(ipdu, len, dev);
                break;
        case ATT_OP_EXEC_WRITE_REQ:
                status = write_execute_request(ipdu, len, dev);
-               if (!status)
-                       return;
                break;
        case ATT_OP_READ_MULTI_REQ:
        default:
                DBG("Unsupported request 0x%02x", ipdu[0]);
                status = ATT_ECODE_REQ_NOT_SUPP;
-               goto done;
+               break;
        }
 
 done:
@@ -6686,24 +6674,18 @@ done:
                resp_length = enc_error_resp(ipdu[0], 0x0000, status, opdu,
                                                                        length);
 
-       if (resp_length)
-               g_attrib_send(dev->attrib, 0, opdu, resp_length, NULL, NULL,
-                                                                       NULL);
+       g_attrib_send(dev->attrib, 0, opdu, resp_length, NULL, NULL, NULL);
 }
 
 static void connect_confirm(GIOChannel *io, void *user_data)
 {
        struct gatt_device *dev;
-       uint8_t dst_type;
        bdaddr_t dst;
        GError *gerr = NULL;
 
        DBG("");
 
-       bt_io_get(io, &gerr,
-                       BT_IO_OPT_DEST_BDADDR, &dst,
-                       BT_IO_OPT_DEST_TYPE, &dst_type,
-                       BT_IO_OPT_INVALID);
+       bt_io_get(io, &gerr, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_INVALID);
        if (gerr) {
                error("gatt: bt_io_get: %s", gerr->message);
                g_error_free(gerr);
@@ -6731,8 +6713,6 @@ static void connect_confirm(GIOChannel *io, void *user_data)
                }
        }
 
-       dev->bdaddr_type = dst_type;
-
        if (!bt_io_accept(io, connect_cb, device_ref(dev), NULL, NULL)) {
                error("gatt: failed to accept connection");
                device_unref(dev);
@@ -6764,7 +6744,7 @@ static struct gap_srvc_handles gap_srvc_data;
 
 static void device_name_read_cb(struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data)
 {
        const char *name = bt_get_adapter_name();
@@ -6818,6 +6798,7 @@ static void register_gap_service(void)
                                                        NULL, NULL, NULL);
        if (gap_srvc_data.priv) {
                uint8_t value;
+
                /* Store privacy into db */
                value = PERIPHERAL_PRIVACY_DISABLE;
                gatt_db_attribute_write(gap_srvc_data.priv, 0,
@@ -6839,7 +6820,7 @@ static void register_gap_service(void)
 
 static void device_info_read_cb(struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data)
 {
        char *buf = user_data;
@@ -6849,7 +6830,7 @@ static void device_info_read_cb(struct gatt_db_attribute *attrib,
 
 static void device_info_read_system_id_cb(struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data)
 {
        uint8_t pdu[8];
@@ -6861,7 +6842,7 @@ static void device_info_read_system_id_cb(struct gatt_db_attribute *attrib,
 
 static void device_info_read_pnp_id_cb(struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data)
 {
        uint8_t pdu[7];
@@ -6886,7 +6867,7 @@ static void register_device_info_service(void)
 
        /* Device Information Service */
        bt_uuid16_create(&uuid, 0x180a);
-       service = gatt_db_add_service(gatt_db, &uuid, true, 15);
+       service = gatt_db_add_service(gatt_db, &uuid, true, 17);
 
        /* User data are not const hence (void *) cast is used */
        data = bt_config_get_name();
@@ -6975,18 +6956,24 @@ static void register_device_info_service(void)
 static void gatt_srvc_change_write_cb(struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
                                        const uint8_t *value, size_t len,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data)
 {
        struct gatt_device *dev;
+       bdaddr_t bdaddr;
 
-       dev = find_device_by_addr(bdaddr);
+       if (!get_dst_addr(att, &bdaddr)) {
+               error("gatt: srvc_change_write_cb, could not obtain BDADDR");
+               return;
+       }
+
+       dev = find_device_by_addr(&bdaddr);
        if (!dev) {
                error("gatt: Could not find device ?!");
                return;
        }
 
-       if (!bt_device_is_bonded(bdaddr)) {
+       if (!bt_device_is_bonded(&bdaddr)) {
                gatt_db_attribute_write_result(attrib, id,
                                                ATT_ECODE_AUTHORIZATION);
                return;
@@ -7000,20 +6987,26 @@ static void gatt_srvc_change_write_cb(struct gatt_db_attribute *attrib,
        }
 
        /* Set services changed indication value */
-       bt_store_gatt_ccc(bdaddr, get_le16(value));
+       bt_store_gatt_ccc(&bdaddr, get_le16(value));
 
        gatt_db_attribute_write_result(attrib, id, 0);
 }
 
 static void gatt_srvc_change_read_cb(struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data)
 {
        struct gatt_device *dev;
        uint8_t pdu[2];
+       bdaddr_t bdaddr;
 
-       dev = find_device_by_addr(bdaddr);
+       if (!get_dst_addr(att, &bdaddr)) {
+               error("gatt: srvc_change_read_cb, could not obtain BDADDR");
+               return;
+       }
+
+       dev = find_device_by_addr(&bdaddr);
        if (!dev) {
                error("gatt: Could not find device ?!");
                return;
@@ -7084,7 +7077,7 @@ static bool start_listening(void)
        return true;
 }
 
-static void gatt_paired_cb(const bdaddr_t *addr, uint8_t type)
+static void gatt_paired_cb(const bdaddr_t *addr)
 {
        struct gatt_device *dev;
        char address[18];
@@ -7094,9 +7087,6 @@ static void gatt_paired_cb(const bdaddr_t *addr, uint8_t type)
        if (!dev)
                return;
 
-       if (dev->bdaddr_type != type)
-               return;
-
        ba2str(addr, address);
        DBG("Paired device %s", address);
 
@@ -7113,7 +7103,7 @@ static void gatt_paired_cb(const bdaddr_t *addr, uint8_t type)
        search_dev_for_srvc(conn, NULL);
 }
 
-static void gatt_unpaired_cb(const bdaddr_t *addr, uint8_t type)
+static void gatt_unpaired_cb(const bdaddr_t *addr)
 {
        struct gatt_device *dev;
        char address[18];
@@ -7122,9 +7112,6 @@ static void gatt_unpaired_cb(const bdaddr_t *addr, uint8_t type)
        if (!dev)
                return;
 
-       if (dev->bdaddr_type != type)
-               return;
-
        ba2str(addr, address);
        DBG("Unpaired device %s", address);
 
@@ -7235,12 +7222,12 @@ void bt_gatt_unregister(void)
        ipc_unregister(hal_ipc, HAL_SERVICE_ID_GATT);
        hal_ipc = NULL;
 
-       queue_destroy(gatt_apps, destroy_gatt_app);
-       gatt_apps = NULL;
-
        queue_destroy(app_connections, destroy_connection);
        app_connections = NULL;
 
+       queue_destroy(gatt_apps, destroy_gatt_app);
+       gatt_apps = NULL;
+
        queue_destroy(gatt_devices, destroy_device);
        gatt_devices = NULL;
 
@@ -7315,7 +7302,7 @@ bool bt_gatt_connect_app(unsigned int id, const bdaddr_t *addr)
 {
        uint8_t status;
 
-       status = handle_connect(id, addr);
+       status = handle_connect(id, addr, false);
 
        return status != HAL_STATUS_FAILED;
 }
@@ -7338,12 +7325,12 @@ bool bt_gatt_disconnect_app(unsigned int id, const bdaddr_t *addr)
        match.device = device;
        match.app = app;
 
-       conn = queue_find(app_connections, match_connection_by_device_and_app,
-                                                                       &match);
+       conn = queue_remove_if(app_connections,
+                               match_connection_by_device_and_app, &match);
        if (!conn)
                return false;
 
-       trigger_disconnection(conn);
+       destroy_connection(conn);
 
        return true;
 }
@@ -7371,8 +7358,7 @@ bool bt_gatt_add_autoconnect(unsigned int id, const bdaddr_t *addr)
        if (queue_isempty(dev->autoconnect_apps))
                device_ref(dev);
 
-       if (!queue_find(dev->autoconnect_apps, match_by_value,
-                                                       INT_TO_PTR(id)))
+       if (!queue_find(dev->autoconnect_apps, NULL, INT_TO_PTR(id)))
                return queue_push_head(dev->autoconnect_apps, INT_TO_PTR(id));
 
        return true;
index f15c12e..77f2f57 100644 (file)
@@ -456,7 +456,7 @@ Commands and responses:
                Command parameters: Socket type (1 octet)
                                    Service name (256 octets)
                                    Service UUID (16 octets)
-                                   Channel (2 octets)
+                                   Channel (4 octets)
                                    Socket flags (1 octet)
                Response parameters: File descriptor (inline)
 
@@ -474,7 +474,7 @@ Commands and responses:
                Command parameters: Remote address (6 octets)
                                    Socket type (1 octet)
                                    Service UUID (16 octets)
-                                   Channel (2 octets)
+                                   Channel (4 octets)
                                    Socket flags (1 octet)
                Response parameters: File descriptor (inline)
 
@@ -2473,8 +2473,9 @@ Notifications:
 
                Valid State values: 0x00 = Disconnected
                                    0x01 = Connecting
-                                   0x02 = SLC Connected
-                                   0x03 = Disconnecting
+                                   0x02 = Connected
+                                   0x03 = SLC Connected
+                                   0x04 = Disconnecting
 
                Peer Features is a bitmask of the supported features. Currently
                available bits:
index ecc1150..0ec07c7 100644 (file)
@@ -2107,8 +2107,9 @@ struct hal_ev_gatt_server_congestion {
 
 #define HAL_HF_CLIENT_CONN_STATE_DISCONNECTED          0x00
 #define HAL_HF_CLIENT_CONN_STATE_CONNECTING            0x01
-#define HAL_HF_CLIENT_CONN_STATE_SLC_CONNECTED         0x02
-#define HAL_HF_CLIENT_CONN_STATE_DISCONNECTING         0x03
+#define HAL_HF_CLIENT_CONN_STATE_CONNECTED             0x02
+#define HAL_HF_CLIENT_CONN_STATE_SLC_CONNECTED         0x03
+#define HAL_HF_CLIENT_CONN_STATE_DISCONNECTING         0x04
 
 #define HAL_HF_CLIENT_PEER_FEAT_3WAY           0x00000001
 #define HAL_HF_CLIENT_PEER_FEAT_ECNR           0x00000002
index e1f2c16..0e2bd40 100644 (file)
@@ -1748,6 +1748,8 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
                goto failed;
        }
 
+       device_set_state(dev, HAL_HF_CLIENT_CONN_STATE_CONNECTED);
+
        return;
 
 failed:
index aadcd41..f1ad5fe 100644 (file)
@@ -127,7 +127,7 @@ struct hf_device {
        int num_active;
        int num_held;
        int setup_state;
-       bool call_hanging_up;
+       guint call_hanging_up;
 
        uint8_t negotiated_codec;
        uint8_t proposed_codec;
@@ -258,9 +258,14 @@ static void device_destroy(struct hf_device *dev)
        if (dev->audio_state == HAL_EV_HANDSFREE_AUDIO_STATE_CONNECTED)
                bt_sco_disconnect(sco);
 
-       g_source_remove(dev->ring);
+       if (dev->ring)
+               g_source_remove(dev->ring);
+
        g_free(dev->clip);
 
+       if (dev->call_hanging_up)
+               g_source_remove(dev->call_hanging_up);
+
        set_audio_state(dev, HAL_EV_HANDSFREE_AUDIO_STATE_DISCONNECTED);
        set_state(dev, HAL_EV_HANDSFREE_CONN_STATE_DISCONNECTED);
 
@@ -313,23 +318,18 @@ static void at_cmd_unknown(const char *command, void *user_data)
        uint8_t buf[IPC_MTU];
        struct hal_ev_handsfree_unknown_at *ev = (void *) buf;
 
-       if (dev->state != HAL_EV_HANDSFREE_CONN_STATE_SLC_CONNECTED) {
-               hfp_gw_send_result(dev->gw, HFP_RESULT_ERROR);
-               hfp_gw_disconnect(dev->gw);
-               return;
-       }
-
        bdaddr2android(&dev->bdaddr, ev->bdaddr);
 
        /* copy while string including terminating NULL */
        ev->len = strlen(command) + 1;
-       memcpy(ev->buf, command, ev->len);
 
        if (ev->len > IPC_MTU - sizeof(*ev)) {
                hfp_gw_send_result(dev->gw, HFP_RESULT_ERROR);
                return;
        }
 
+       memcpy(ev->buf, command, ev->len);
+
        ipc_send_notif(hal_ipc, HAL_SERVICE_ID_HANDSFREE,
                        HAL_EV_HANDSFREE_UNKNOWN_AT, sizeof(*ev) + ev->len, ev);
 }
@@ -971,24 +971,21 @@ static void connect_sco_cb(enum sco_status status, const bdaddr_t *addr)
                return;
        }
 
-       if (status != SCO_STATUS_OK) {
-               error("handsfree: audio connect failed");
-
-               set_audio_state(dev, HAL_EV_HANDSFREE_AUDIO_STATE_DISCONNECTED);
-
-               if (!codec_negotiation_supported(dev))
-                       return;
-
-               /* If other failed, try connecting with CVSD */
-               if (dev->negotiated_codec != CODEC_ID_CVSD) {
-                       info("handsfree: trying fallback with CVSD");
-                       select_codec(dev, CODEC_ID_CVSD);
-               }
+       if (status == SCO_STATUS_OK) {
+               set_audio_state(dev, HAL_EV_HANDSFREE_AUDIO_STATE_CONNECTED);
+               return;
+       }
 
+       /* Try fallback to CVSD first */
+       if (codec_negotiation_supported(dev) &&
+                               dev->negotiated_codec != CODEC_ID_CVSD) {
+               info("handsfree: trying fallback with CVSD");
+               select_codec(dev, CODEC_ID_CVSD);
                return;
        }
 
-       set_audio_state(dev, HAL_EV_HANDSFREE_AUDIO_STATE_CONNECTED);
+       error("handsfree: audio connect failed");
+       set_audio_state(dev, HAL_EV_HANDSFREE_AUDIO_STATE_DISCONNECTED);
 }
 
 static bool connect_sco(struct hf_device *dev)
@@ -1145,6 +1142,8 @@ static void at_cmd_ckpd(struct hfp_context *result, enum hfp_gw_cmd_type type,
 
 static void register_post_slc_at(struct hf_device *dev)
 {
+       hfp_gw_set_command_handler(dev->gw, at_cmd_unknown, dev, NULL);
+
        if (dev->hsp) {
                hfp_gw_register(dev->gw, at_cmd_ckpd, "+CKPD", dev, NULL);
                hfp_gw_register(dev->gw, at_cmd_vgs, "+VGS", dev, NULL);
@@ -1199,11 +1198,14 @@ static void at_cmd_cmer(struct hfp_context *result, enum hfp_gw_cmd_type type,
                if (!hfp_context_get_number(result, &val) || val > 1)
                        break;
 
+               dev->indicators_enabled = val;
+
+               /* skip bfr if present */
+               hfp_context_get_number(result, &val);
+
                if (hfp_context_has_next(result))
                        break;
 
-               dev->indicators_enabled = val;
-
                hfp_gw_send_result(dev->gw, HFP_RESULT_OK);
 
                if (dev->features & HFP_HF_FEAT_3WAY)
@@ -1466,7 +1468,6 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
        g_io_channel_set_close_on_unref(chan, FALSE);
 
        hfp_gw_set_close_on_unref(dev->gw, true);
-       hfp_gw_set_command_handler(dev->gw, at_cmd_unknown, dev, NULL);
        hfp_gw_set_disconnect_handler(dev->gw, disconnect_watch, dev, NULL);
 
        if (dev->hsp) {
@@ -1534,10 +1535,10 @@ drop:
 static void sdp_hsp_search_cb(sdp_list_t *recs, int err, gpointer data)
 {
        struct hf_device *dev = data;
-       sdp_list_t *protos, *classes;
+       sdp_list_t *protos;
        GError *gerr = NULL;
        GIOChannel *io;
-       uuid_t uuid;
+       uuid_t class;
        int channel;
 
        DBG("");
@@ -1548,35 +1549,29 @@ static void sdp_hsp_search_cb(sdp_list_t *recs, int err, gpointer data)
                goto fail;
        }
 
-       if (!recs || !recs->data) {
-               info("handsfree: no HSP SDP records found");
-               goto fail;
+       sdp_uuid16_create(&class, HEADSET_SVCLASS_ID);
+
+       /* Find record with proper service class */
+       for (; recs; recs = recs->next) {
+               sdp_record_t *rec = recs->data;
+
+               if (rec && !sdp_uuid_cmp(&rec->svclass, &class))
+                       break;
        }
 
-       if (sdp_get_service_classes(recs->data, &classes) < 0 || !classes) {
-               error("handsfree: unable to get service classes from record");
+       if (!recs || !recs->data) {
+               info("handsfree: no valid HSP SDP records found");
                goto fail;
        }
 
        if (sdp_get_access_protos(recs->data, &protos) < 0) {
                error("handsfree: unable to get access protocols from record");
-               sdp_list_free(classes, free);
                goto fail;
        }
 
        /* TODO read remote version? */
        /* TODO read volume control support */
 
-       memcpy(&uuid, classes->data, sizeof(uuid));
-       sdp_list_free(classes, free);
-
-       if (!sdp_uuid128_to_uuid(&uuid) || uuid.type != SDP_UUID16 ||
-                       uuid.value.uuid16 != HEADSET_SVCLASS_ID) {
-               sdp_list_free(protos, NULL);
-               error("handsfree: invalid service record or not HSP");
-               goto fail;
-       }
-
        channel = sdp_get_proto_port(protos, RFCOMM_UUID);
        sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
        sdp_list_free(protos, NULL);
@@ -1619,10 +1614,10 @@ static int sdp_search_hsp(struct hf_device *dev)
 static void sdp_hfp_search_cb(sdp_list_t *recs, int err, gpointer data)
 {
        struct hf_device *dev = data;
-       sdp_list_t *protos, *classes;
+       sdp_list_t *protos;
        GError *gerr = NULL;
        GIOChannel *io;
-       uuid_t uuid;
+       uuid_t class;
        int channel;
 
        DBG("");
@@ -1633,6 +1628,16 @@ static void sdp_hfp_search_cb(sdp_list_t *recs, int err, gpointer data)
                goto fail;
        }
 
+       sdp_uuid16_create(&class, HANDSFREE_SVCLASS_ID);
+
+       /* Find record with proper service class */
+       for (; recs; recs = recs->next) {
+               sdp_record_t *rec = recs->data;
+
+               if (rec && !sdp_uuid_cmp(&rec->svclass, &class))
+                       break;
+       }
+
        if (!recs || !recs->data) {
                info("handsfree: no HFP SDP records found, trying HSP");
 
@@ -1644,26 +1649,8 @@ static void sdp_hfp_search_cb(sdp_list_t *recs, int err, gpointer data)
                return;
        }
 
-       if (sdp_get_service_classes(recs->data, &classes) < 0 || !classes) {
-               error("handsfree: unable to get service classes from record");
-               goto fail;
-       }
-
        if (sdp_get_access_protos(recs->data, &protos) < 0) {
                error("handsfree: unable to get access protocols from record");
-               sdp_list_free(classes, free);
-               goto fail;
-       }
-
-       /* TODO read remote version? */
-
-       memcpy(&uuid, classes->data, sizeof(uuid));
-       sdp_list_free(classes, free);
-
-       if (!sdp_uuid128_to_uuid(&uuid) || uuid.type != SDP_UUID16 ||
-                       uuid.value.uuid16 != HANDSFREE_SVCLASS_ID) {
-               sdp_list_free(protos, NULL);
-               error("handsfree: invalid service record or not HFP");
                goto fail;
        }
 
@@ -1675,6 +1662,8 @@ static void sdp_hfp_search_cb(sdp_list_t *recs, int err, gpointer data)
                goto fail;
        }
 
+       /* TODO read remote version? */
+
        io = bt_io_connect(connect_cb, dev, NULL, &gerr,
                                BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
                                BT_IO_OPT_DEST_BDADDR, &dev->bdaddr,
@@ -2262,6 +2251,11 @@ static gboolean ring_cb(gpointer user_data)
 static void phone_state_dialing(struct hf_device *dev, int num_active,
                                                                int num_held)
 {
+       if (dev->call_hanging_up) {
+               g_source_remove(dev->call_hanging_up);
+               dev->call_hanging_up = 0;
+       }
+
        update_indicator(dev, IND_CALLSETUP, 2);
 
        if (num_active == 0 && num_held > 0)
@@ -2274,6 +2268,11 @@ static void phone_state_dialing(struct hf_device *dev, int num_active,
 static void phone_state_alerting(struct hf_device *dev, int num_active,
                                                                int num_held)
 {
+       if (dev->call_hanging_up) {
+               g_source_remove(dev->call_hanging_up);
+               dev->call_hanging_up = 0;
+       }
+
        update_indicator(dev, IND_CALLSETUP, 3);
 }
 
@@ -2305,6 +2304,9 @@ static void phone_state_incoming(struct hf_device *dev, int num_active,
        if (dev->setup_state == HAL_HANDSFREE_CALL_STATE_INCOMING) {
                if (dev->num_active != num_active ||
                                                dev->num_held != num_held) {
+                       if (dev->num_active == num_held &&
+                                               dev->num_held == num_active)
+                               return;
                        /*
                         * calls changed while waiting call ie. due to
                         * termination of active call
@@ -2348,6 +2350,17 @@ static void phone_state_incoming(struct hf_device *dev, int num_active,
        }
 }
 
+static gboolean hang_up_cb(gpointer user_data)
+{
+       struct hf_device *dev = user_data;
+
+       DBG("");
+
+       dev->call_hanging_up = 0;
+
+       return FALSE;
+}
+
 static void phone_state_idle(struct hf_device *dev, int num_active,
                                                                int num_held)
 {
@@ -2370,14 +2383,16 @@ static void phone_state_idle(struct hf_device *dev, int num_active,
                                connect_audio(dev);
                }
 
-               if (num_held > dev->num_held)
+               if (num_held >= dev->num_held && num_held != 0)
                        update_indicator(dev, IND_CALLHELD, 1);
 
                update_indicator(dev, IND_CALLSETUP, 0);
 
-               if (num_active == dev->num_active && num_held == dev->num_held)
-                       dev->call_hanging_up = true;
-
+               if (num_active == 0 && num_held == 0 &&
+                               num_active == dev->num_active &&
+                               num_held == dev->num_held)
+                       dev->call_hanging_up = g_timeout_add(800, hang_up_cb,
+                                                                       dev);
                break;
        case HAL_HANDSFREE_CALL_STATE_DIALING:
        case HAL_HANDSFREE_CALL_STATE_ALERTING:
@@ -2388,11 +2403,15 @@ static void phone_state_idle(struct hf_device *dev, int num_active,
                                        num_held ? (num_active ? 1 : 2) : 0);
 
                update_indicator(dev, IND_CALLSETUP, 0);
+
+               /* disconnect SCO if we hang up while dialing or alerting */
+               if (num_active == 0 && num_held == 0)
+                       disconnect_sco(dev);
                break;
        case HAL_HANDSFREE_CALL_STATE_IDLE:
-
                if (dev->call_hanging_up) {
-                       dev->call_hanging_up = false;
+                       g_source_remove(dev->call_hanging_up);
+                       dev->call_hanging_up = 0;
                        return;
                }
 
@@ -2532,7 +2551,7 @@ static void handle_configure_wbs(const void *buf, uint16_t len)
                /* TODO */
        default:
                status = HAL_STATUS_FAILED;
-               break;
+               goto done;
        }
 
        /*
index b696563..2e589f4 100644 (file)
@@ -1495,7 +1495,7 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
        }
 }
 
-static void hid_unpaired_cb(const bdaddr_t *addr, uint8_t type)
+static void hid_unpaired_cb(const bdaddr_t *addr)
 {
        GSList *l;
        struct hid_device *dev;
index 7f441f1..88a5460 100644 (file)
 #include <sys/stat.h>
 #include <fcntl.h>
 
-#include <bluetooth/bluetooth.h>
-
 #include <glib.h>
 
-#include "src/log.h"
-
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
 #include "src/shared/util.h"
 #include "src/shared/uhid.h"
 #include "src/shared/queue.h"
+#include "src/log.h"
 
 #include "attrib/att.h"
 #include "attrib/gattrib.h"
@@ -99,7 +99,7 @@ struct bt_hog {
        uint16_t                setrep_id;
        struct bt_scpp          *scpp;
        struct bt_dis           *dis;
-       struct bt_bas           *bas;
+       struct queue            *bas;
        GSList                  *instances;
        struct queue            *gatt_op;
 };
@@ -1157,11 +1157,11 @@ static void hog_free(void *data)
 
        bt_hog_detach(hog);
 
+       queue_destroy(hog->bas, (void *) bt_bas_unref);
        g_slist_free_full(hog->instances, hog_free);
 
        bt_scpp_unref(hog->scpp);
        bt_dis_unref(hog->dis);
-       bt_bas_unref(hog->bas);
        bt_uhid_unref(hog->uhid);
        g_slist_free_full(hog->reports, report_free);
        g_free(hog->name);
@@ -1185,10 +1185,18 @@ struct bt_hog *bt_hog_new(const char *name, uint16_t vendor, uint16_t product,
                return NULL;
        }
 
+       hog->bas = queue_new();
+       if (!hog->bas) {
+               queue_destroy(hog->gatt_op, NULL);
+               hog_free(hog);
+               return NULL;
+       }
+
        hog->uhid = bt_uhid_new_default();
        if (!hog->uhid) {
                hog_free(hog);
                queue_destroy(hog->gatt_op, NULL);
+               queue_destroy(hog->bas, NULL);
                return NULL;
        }
 
@@ -1227,54 +1235,24 @@ void bt_hog_unref(struct bt_hog *hog)
 static void find_included_cb(uint8_t status, GSList *services, void *user_data)
 {
        struct gatt_request *req = user_data;
-       struct bt_hog *hog = req->user_data;
-       struct gatt_included *include;
        GSList *l;
 
        DBG("");
 
        destroy_gatt_req(req);
 
-       if (hog->primary)
-               return;
-
        if (status) {
                const char *str = att_ecode2str(status);
                DBG("Find included failed: %s", str);
                return;
        }
 
-       if (!services) {
-               DBG("No included service found");
-               return;
-       }
-
        for (l = services; l; l = l->next) {
-               include = l->data;
+               struct gatt_included *include = l->data;
 
-               if (strcmp(include->uuid, HOG_UUID) == 0)
-                       break;
+               DBG("included: handle %x, uuid %s",
+                       include->handle, include->uuid);
        }
-
-       if (!l) {
-               for (l = services; l; l = l->next) {
-                       include = l->data;
-
-                       find_included(hog, hog->attrib,
-                                       include->range.start,
-                                       include->range.end, find_included_cb,
-                                       hog);
-               }
-               return;
-       }
-
-       hog->primary = g_new0(struct gatt_primary, 1);
-       memcpy(hog->primary->uuid, include->uuid, sizeof(include->uuid));
-       memcpy(&hog->primary->range, &include->range, sizeof(include->range));
-
-       discover_char(hog, hog->attrib, hog->primary->range.start,
-                                               hog->primary->range.end, NULL,
-                                               char_discovered_cb, hog);
 }
 
 static void hog_attach_scpp(struct bt_hog *hog, struct gatt_primary *primary)
@@ -1315,14 +1293,14 @@ static void hog_attach_dis(struct bt_hog *hog, struct gatt_primary *primary)
 
 static void hog_attach_bas(struct bt_hog *hog, struct gatt_primary *primary)
 {
-       if (hog->bas) {
-               bt_bas_attach(hog->bas, hog->attrib);
+       struct bt_bas *instance;
+
+       instance = bt_bas_new(primary);
+       if (!instance)
                return;
-       }
 
-       hog->bas = bt_bas_new(primary);
-       if (hog->bas)
-               bt_bas_attach(hog->bas, hog->attrib);
+       bt_bas_attach(instance, hog->attrib);
+       queue_push_head(hog->bas, instance);
 }
 
 static void hog_attach_hog(struct bt_hog *hog, struct gatt_primary *primary)
@@ -1334,6 +1312,8 @@ static void hog_attach_hog(struct bt_hog *hog, struct gatt_primary *primary)
                discover_char(hog, hog->attrib, primary->range.start,
                                                primary->range.end, NULL,
                                                char_discovered_cb, hog);
+               find_included(hog, hog->attrib, primary->range.start,
+                               primary->range.end, find_included_cb, hog);
                return;
        }
 
@@ -1342,6 +1322,9 @@ static void hog_attach_hog(struct bt_hog *hog, struct gatt_primary *primary)
        if (!instance)
                return;
 
+       find_included(instance, hog->attrib, primary->range.start,
+                       primary->range.end, find_included_cb, instance);
+
        bt_hog_attach(instance, hog->attrib);
        hog->instances = g_slist_append(hog->instances, instance);
 }
@@ -1389,16 +1372,6 @@ static void primary_cb(uint8_t status, GSList *services, void *user_data)
                if (strcmp(primary->uuid, HOG_UUID) == 0)
                        hog_attach_hog(hog, primary);
        }
-
-       if (hog->primary)
-               return;
-
-       for (l = services; l; l = l->next) {
-               primary = l->data;
-
-               find_included(hog, hog->attrib, primary->range.start,
-                               primary->range.end, find_included_cb, hog);
-       }
 }
 
 bool bt_hog_attach(struct bt_hog *hog, void *gatt)
@@ -1422,8 +1395,7 @@ bool bt_hog_attach(struct bt_hog *hog, void *gatt)
        if (hog->dis)
                bt_dis_attach(hog->dis, gatt);
 
-       if (hog->bas)
-               bt_bas_attach(hog->bas, gatt);
+       queue_foreach(hog->bas, (void *) bt_bas_attach, gatt);
 
        for (l = hog->instances; l; l = l->next) {
                struct bt_hog *instance = l->data;
@@ -1457,6 +1429,8 @@ void bt_hog_detach(struct bt_hog *hog)
        if (!hog->attrib)
                return;
 
+       queue_foreach(hog->bas, (void *) bt_bas_detach, NULL);
+
        for (l = hog->instances; l; l = l->next) {
                struct bt_hog *instance = l->data;
 
@@ -1478,9 +1452,6 @@ void bt_hog_detach(struct bt_hog *hog)
        if (hog->dis)
                bt_dis_detach(hog->dis);
 
-       if (hog->bas)
-               bt_bas_detach(hog->bas);
-
        queue_foreach(hog->gatt_op, (void *) cancel_gatt_req, NULL);
        g_attrib_unref(hog->attrib);
        hog->attrib = NULL;
index 09d226a..8013eba 100644 (file)
 #endif
 
 #include <fcntl.h>
+#include <stdarg.h>
 #include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <stdbool.h>
 #include <time.h>
index 58dd9ab..03c8760 100644 (file)
 
 #include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+
 #include "src/log.h"
 #include "src/sdpd.h"
 #include "src/shared/util.h"
 
-#include "lib/bluetooth.h"
-
 #include "ipc-common.h"
 #include "ipc.h"
 #include "bluetooth.h"
@@ -70,7 +71,7 @@
 #define DEFAULT_NAME "BlueZ for Android"
 
 #define STARTUP_GRACE_SECONDS 5
-#define SHUTDOWN_GRACE_SECONDS 10
+#define SHUTDOWN_GRACE_SECONDS 5
 
 static char *config_vendor = NULL;
 static char *config_model = NULL;
index 6131890..2afc92a 100644 (file)
 #define BNEP_PANU_INTERFACE "bt-pan"
 #define BNEP_NAP_INTERFACE "bt-pan%d"
 
-static bdaddr_t adapter_addr;
-static GSList *devices = NULL;
-static uint8_t local_role = HAL_PAN_ROLE_NONE;
-static struct ipc *hal_ipc = NULL;
-
 struct pan_device {
        char            iface[16];
        bdaddr_t        dst;
@@ -78,15 +73,14 @@ struct pan_device {
        guint           watch;
 };
 
-static struct {
-       uint32_t        record_id;
-       GIOChannel      *io;
-       bool            bridge;
-} nap_dev = {
-       .record_id = 0,
-       .io = NULL,
-       .bridge = false,
-};
+static bdaddr_t adapter_addr;
+static GSList *devices = NULL;
+static uint8_t local_role = HAL_PAN_ROLE_NONE;
+static uint32_t nap_rec_id = 0;
+static uint32_t panu_rec_id = 0;
+static GIOChannel *nap_io = NULL;
+static bool nap_bridge_mode = false;
+static struct ipc *hal_ipc = NULL;
 
 static int set_forward_delay(int sk)
 {
@@ -112,7 +106,7 @@ static int nap_create_bridge(void)
 
        DBG("%s", BNEP_BRIDGE);
 
-       if (nap_dev.bridge)
+       if (nap_bridge_mode)
                return 0;
 
        sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
@@ -133,7 +127,7 @@ static int nap_create_bridge(void)
 
        close(sk);
 
-       nap_dev.bridge = err == 0;
+       nap_bridge_mode = err == 0;
 
        return err;
 }
@@ -169,7 +163,7 @@ static int nap_remove_bridge(void)
 
        DBG("%s", BNEP_BRIDGE);
 
-       if (!nap_dev.bridge)
+       if (!nap_bridge_mode)
                return 0;
 
        bridge_if_down();
@@ -187,7 +181,7 @@ static int nap_remove_bridge(void)
        if (err < 0)
                return err;
 
-       nap_dev.bridge = false;
+       nap_bridge_mode = false;
 
        return 0;
 }
@@ -463,6 +457,7 @@ static gboolean nap_watchdog_cb(GIOChannel *chan, GIOCondition cond,
 
        return FALSE;
 }
+
 static gboolean nap_setup_cb(GIOChannel *chan, GIOCondition cond,
                                                        gpointer user_data)
 {
@@ -488,7 +483,7 @@ static gboolean nap_setup_cb(GIOChannel *chan, GIOCondition cond,
 
        /* Highest known control command id BNEP_FILTER_MULT_ADDR_RSP 0x06 */
        if (req->type == BNEP_CONTROL &&
-                       req->ctrl > BNEP_FILTER_MULT_ADDR_RSP) {
+                                       req->ctrl > BNEP_FILTER_MULT_ADDR_RSP) {
                error("cmd not understood");
                bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_CMD_NOT_UNDERSTOOD,
                                                                req->ctrl);
@@ -502,17 +497,11 @@ static gboolean nap_setup_cb(GIOChannel *chan, GIOCondition cond,
        }
 
        rsp = bnep_setup_decode(req, &dst_role, &src_role);
-       if (rsp) {
+       if (rsp != BNEP_SUCCESS) {
                error("bnep_setup_decode failed");
                goto failed;
        }
 
-       rsp = bnep_setup_chk(dst_role, src_role);
-       if (rsp) {
-               error("benp_setup_chk failed");
-               goto failed;
-       }
-
        err = nap_create_bridge();
        if (err < 0) {
                error("pan: Failed to create bridge: %s (%d)", strerror(-err),
@@ -522,8 +511,7 @@ static gboolean nap_setup_cb(GIOChannel *chan, GIOCondition cond,
 
        if (bnep_server_add(sk, dst_role, BNEP_BRIDGE, dev->iface,
                                                        &dev->dst) < 0) {
-               nap_remove_bridge();
-               error("server_connadd failed");
+               error("pan: server_connadd failed");
                rsp = BNEP_CONN_NOT_ALLOWED;
                goto failed;
        }
@@ -616,10 +604,10 @@ static void destroy_nap_device(void)
 
        nap_remove_bridge();
 
-       if (nap_dev.io) {
-               g_io_channel_shutdown(nap_dev.io, FALSE, NULL);
-               g_io_channel_unref(nap_dev.io);
-               nap_dev.io = NULL;
+       if (nap_io) {
+               g_io_channel_shutdown(nap_io, FALSE, NULL);
+               g_io_channel_unref(nap_io);
+               nap_io = NULL;
        }
 }
 
@@ -629,7 +617,7 @@ static int register_nap_server(void)
 
        DBG("");
 
-       nap_dev.io = bt_io_listen(NULL, nap_confirm_cb, NULL, NULL, &gerr,
+       nap_io = bt_io_listen(NULL, nap_confirm_cb, NULL, NULL, &gerr,
                                        BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
                                        BT_IO_OPT_PSM, BNEP_PSM,
                                        BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
@@ -637,11 +625,11 @@ static int register_nap_server(void)
                                        BT_IO_OPT_IMTU, BNEP_MTU,
                                        BT_IO_OPT_INVALID);
 
-       if (!nap_dev.io) {
+       if (!nap_io) {
                destroy_nap_device();
                error("%s", gerr->message);
                g_error_free(gerr);
-               return -EINVAL;
+               return -EIO;
        }
 
        return 0;
@@ -716,10 +704,10 @@ static const struct ipc_handler cmd_handlers[] = {
        { bt_pan_disconnect, false, sizeof(struct hal_cmd_pan_disconnect) },
 };
 
-static sdp_record_t *pan_record(void)
+static sdp_record_t *nap_record(void)
 {
        sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto;
-       uuid_t root_uuid, pan, l2cap, bnep;
+       uuid_t root_uuid, nap, l2cap, bnep;
        sdp_profile_desc_t profile[1];
        sdp_list_t *proto[2];
        sdp_data_t *v, *p;
@@ -738,8 +726,8 @@ static sdp_record_t *pan_record(void)
        record->attrlist = NULL;
        record->pattern = NULL;
 
-       sdp_uuid16_create(&pan, NAP_SVCLASS_ID);
-       svclass = sdp_list_append(NULL, &pan);
+       sdp_uuid16_create(&nap, NAP_SVCLASS_ID);
+       svclass = sdp_list_append(NULL, &nap);
        sdp_set_service_classes(record, svclass);
 
        sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID);
@@ -791,43 +779,124 @@ static sdp_record_t *pan_record(void)
        return record;
 }
 
+static sdp_record_t *panu_record(void)
+{
+       sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto;
+       uuid_t root_uuid, panu, l2cap, bnep;
+       sdp_profile_desc_t profile[1];
+       sdp_list_t *proto[2];
+       sdp_data_t *v, *p;
+       uint16_t psm = BNEP_PSM, version = 0x0100;
+       uint16_t security = 0x0001, type = 0xfffe;
+       uint32_t rate = 0;
+       const char *desc = "PAN User", *name = "Network Service";
+       sdp_record_t *record;
+       uint16_t ptype[] = { 0x0800, /* IPv4 */ 0x0806,  /* ARP */ };
+       sdp_data_t *head, *pseq, *data;
+
+       record = sdp_record_alloc();
+       if (!record)
+               return NULL;
+
+       record->attrlist = NULL;
+       record->pattern = NULL;
+
+       sdp_uuid16_create(&panu, PANU_SVCLASS_ID);
+       svclass = sdp_list_append(NULL, &panu);
+       sdp_set_service_classes(record, svclass);
+
+       sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID);
+       profile[0].version = 0x0100;
+       pfseq = sdp_list_append(NULL, &profile[0]);
+       sdp_set_profile_descs(record, pfseq);
+       sdp_set_info_attr(record, name, NULL, desc);
+       sdp_attr_add_new(record, SDP_ATTR_NET_ACCESS_TYPE, SDP_UINT16, &type);
+       sdp_attr_add_new(record, SDP_ATTR_MAX_NET_ACCESSRATE,
+                                                       SDP_UINT32, &rate);
+
+       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+       root = sdp_list_append(NULL, &root_uuid);
+       sdp_set_browse_groups(record, root);
+
+       sdp_uuid16_create(&l2cap, L2CAP_UUID);
+       proto[0] = sdp_list_append(NULL, &l2cap);
+       p = sdp_data_alloc(SDP_UINT16, &psm);
+       proto[0] = sdp_list_append(proto[0], p);
+       apseq = sdp_list_append(NULL, proto[0]);
+
+       sdp_uuid16_create(&bnep, BNEP_UUID);
+       proto[1] = sdp_list_append(NULL, &bnep);
+       v = sdp_data_alloc(SDP_UINT16, &version);
+       proto[1] = sdp_list_append(proto[1], v);
+
+       head = sdp_data_alloc(SDP_UINT16, &ptype[0]);
+       data = sdp_data_alloc(SDP_UINT16, &ptype[1]);
+       sdp_seq_append(head, data);
+
+       pseq = sdp_data_alloc(SDP_SEQ16, head);
+       proto[1] = sdp_list_append(proto[1], pseq);
+       apseq = sdp_list_append(apseq, proto[1]);
+       aproto = sdp_list_append(NULL, apseq);
+       sdp_set_access_protos(record, aproto);
+       sdp_add_lang_attr(record);
+       sdp_attr_add_new(record, SDP_ATTR_SECURITY_DESC, SDP_UINT16, &security);
+
+       sdp_data_free(p);
+       sdp_data_free(v);
+       sdp_list_free(apseq, NULL);
+       sdp_list_free(root, NULL);
+       sdp_list_free(aproto, NULL);
+       sdp_list_free(proto[0], NULL);
+       sdp_list_free(proto[1], NULL);
+       sdp_list_free(svclass, NULL);
+       sdp_list_free(pfseq, NULL);
+
+       return record;
+}
+
 bool bt_pan_register(struct ipc *ipc, const bdaddr_t *addr, uint8_t mode)
 {
-       sdp_record_t *rec;
+       sdp_record_t *nap_rec, *panu_rec;
        int err;
 
        DBG("");
 
        bacpy(&adapter_addr, addr);
 
-       rec = pan_record();
-       if (!rec) {
-               error("Failed to allocate PAN record");
+       nap_rec = nap_record();
+       if (bt_adapter_add_record(nap_rec, SVC_HINT_NETWORKING) < 0) {
+               sdp_record_free(nap_rec);
+               error("Failed to allocate PAN-NAP sdp record");
                return false;
        }
 
-       if (bt_adapter_add_record(rec, SVC_HINT_NETWORKING) < 0) {
-               error("Failed to register PAN record");
-               sdp_record_free(rec);
+       panu_rec = panu_record();
+       if (bt_adapter_add_record(panu_rec, SVC_HINT_NETWORKING) < 0) {
+               sdp_record_free(nap_rec);
+               sdp_record_free(panu_rec);
+               error("Failed to allocate PAN-PANU sdp record");
                return false;
        }
 
        err = bnep_init();
        if (err < 0) {
-               error("bnep init failed");
-               bt_adapter_remove_record(rec->handle);
+               error("Failed to init BNEP");
+               bt_adapter_remove_record(nap_rec->handle);
+               bt_adapter_remove_record(panu_rec->handle);
                return false;
        }
 
        err = register_nap_server();
        if (err < 0) {
-               error("Failed to register NAP");
-               bt_adapter_remove_record(rec->handle);
+               error("Failed to register NAP server");
+               bt_adapter_remove_record(nap_rec->handle);
+               bt_adapter_remove_record(panu_rec->handle);
                bnep_cleanup();
                return false;
        }
 
-       nap_dev.record_id = rec->handle;
+       nap_rec_id = nap_rec->handle;
+       panu_rec_id = panu_rec->handle;
 
        hal_ipc = ipc;
        ipc_register(hal_ipc, HAL_SERVICE_ID_PAN, cmd_handlers,
@@ -849,7 +918,9 @@ void bt_pan_unregister(void)
        ipc_unregister(hal_ipc, HAL_SERVICE_ID_PAN);
        hal_ipc = NULL;
 
-       bt_adapter_remove_record(nap_dev.record_id);
-       nap_dev.record_id = 0;
+       bt_adapter_remove_record(nap_rec_id);
+       nap_rec_id = 0;
+       bt_adapter_remove_record(panu_rec_id);
+       panu_rec_id = 0;
        destroy_nap_device();
 }
index adac664..1328e7e 100644 (file)
@@ -1,6 +1,6 @@
 A2DP PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
@@ -8,12 +8,24 @@ PTS version: 5.3
 M - mandatory if such role selected
 O - optional
 
+               Profile Version
+-------------------------------------------------------------------------------
+Parameter Name Selected        Description
+-------------------------------------------------------------------------------
+TSPC_A2DP_0_1  False           A2DP 1.0 (C.1)
+TSPC_A2DP_0_2  False           A2DP 1.2 (C.1)
+TSPC_A2DP_0_3  True (*)        A2DP 1.3 (C.1)
+-------------------------------------------------------------------------------
+C.1: It is mandatory to select one of the profile versions.
+-------------------------------------------------------------------------------
+
+
                Roles
 -------------------------------------------------------------------------------
 Parameter Name Selected        Description
 -------------------------------------------------------------------------------
-TSPC_A2DP_1_1  True            Role: Source (C.1)
-TSPC_A2DP_1_2  False (*)       Role: Sink (C.1)
+TSPC_A2DP_1_1  True (*)        Role: Source (C.1)
+TSPC_A2DP_1_2  False           Role: Sink (C.1)
 -------------------------------------------------------------------------------
 C.1: It is mandatory to support at least one of the defined roles.
 -------------------------------------------------------------------------------
@@ -33,15 +45,20 @@ TSPC_A2DP_2_7       True            SRC: Accept connection release (M)
 TSPC_A2DP_2_8  True (*)        SRC: Initiate suspend (O)
 TSPC_A2DP_2_9  True (*)        SRC: Accept suspend (O)
 TSPC_A2DP_2_10 True            SRC: SBC encoder (M)
-TSPC_A2DP_2_10a        False           SRC: Encode Audio Stream (O)
+TSPC_A2DP_2_10a        False           SRC: Encode and Forward Audio Stream (O)
 TSPC_A2DP_2_11 False           SRC: SBC Configurations in 16 KHz sampling (O)
 TSPC_A2DP_2_12 False           SRC: SBC Configurations in 32 KHz sampling (O)
-TSPC_A2DP_2_13 True            SRC: SBC Configurations in 44.1 KHz sampling
-                                       (C.1)
-TSPC_A2DP_2_14 False (*)       SRC: SBC Configurations in 48 KHz sampling
+TSPC_A2DP_2_13 True (*)        SRC: SBC Configurations in 44.1 KHz sampling
                                        (C.1)
+TSPC_A2DP_2_14 True (*)        SRC: SBC Configurations in 48 KHz sampling (C.1)
+TSPC_A2DP_2_15 False           SRC: Delay Reporting (C.2)
+TSPC_A2DP_2_16 False           SRC: SRC video playback via Bluetooth VDP (C.3)
+TSPC_A2DP_2_17 False           SRC: SRC video playback on a local video
+                                       display (C.3)
 -------------------------------------------------------------------------------
 C.1: At least one of the values shall be supported.
+C.2: Mandatory if A2DP 0/3 AND (2/16 OR 2/17) is supported, otherwise excluded.
+C.3: Optional to support if A2DP 0/3 is supported, otherwise excluded.
 -------------------------------------------------------------------------------
 
 
@@ -49,8 +66,39 @@ C.1: At least one of the values shall be supported.
 -------------------------------------------------------------------------------
 Parameter Name Selected        Description
 -------------------------------------------------------------------------------
-TSPC_A2DP_3_1  True            SRC: SBC encoder Codec (M)
-TSPC_A2DP_3_2  True (*)        SRC: Additional encoder Codec (O)
+TSPC_A2DP_3_1  True            SRC: SBC encoder (M)
+TSPC_A2DP_3_1a False           SRC: Encode and Forward SBC Audio Stream (O)
+TSPC_A2DP_3_2  False           SRC: Optional codec (O)
+TSPC_A2DP_3_3  False           SRC: MPEG-1,2 Audio decoder (C.1)
+TSPC_A2DP_3_4  False           SRC: MPEG-1,2 Audio encoder (C.1)
+TSPC_A2DP_3_5  False           SRC: MPEG-2,4 AAC decoder (C.1)
+TSPC_A2DP_3_6  False           SRC: MPEG-2,4 AAC encoder (C.1)
+TSPC_A2DP_3_7  False           SRC: ATRAC family decoder (C.1)
+TSPC_A2DP_3_8  False           SRC: ATRAC family encoder (C.1)
+-------------------------------------------------------------------------------
+C.1: At least one of the implementations shall be supported if 12/2 (Optional
+       codec) is supported, else excluded.
+-------------------------------------------------------------------------------
+
+
+               Supported Codec Features in SRC
+-------------------------------------------------------------------------------
+Parameter Name Selected        Description
+-------------------------------------------------------------------------------
+TSPC_A2DP_3a_1 True            SRC: Channel Mode - Mono (M)
+TSPC_A2DP_3a_2 True (*)        SRC: Channel Mode - Dual Channel (C.1)
+TSPC_A2DP_3a_3 True (*)        SRC: Channel Mode - Stereo (C.1)
+TSPC_A2DP_3a_4 True (*)        SRC: Channel Mode - Joint Stereo (C.1)
+TSPC_A2DP_3a_5 True            SRC: Block Length 4 (M)
+TSPC_A2DP_3a_6 True            SRC: Block Length 8 (M)
+TSPC_A2DP_3a_7 True            SRC: Block Length 12 (M)
+TSPC_A2DP_3a_8 True            SRC: Block Length 16 (M)
+TSPC_A2DP_3a_9 True (*)        SRC: Subbands - 4 (O)
+TSPC_A2DP_3a_10        True            SRC: Subbands - 8 (M)
+TSPC_A2DP_3a_11        True (*)        SRC: Allocation - SNR (O)
+TSPC_A2DP_3a_12        True            SRC: Allocation - Loudness (M)
+-------------------------------------------------------------------------------
+C.1: At least one of the values shall be supported.
 -------------------------------------------------------------------------------
 
 
@@ -68,11 +116,14 @@ TSPC_A2DP_4_7      False (*)       SNK: Accept connection release (M)
 TSPC_A2DP_4_8  False           SNK: Initiate suspend (O)
 TSPC_A2DP_4_9  False           SNK: Accept suspend (O)
 TSPC_A2DP_4_10 False (*)       SNK: SBC decoder (M)
-TSPC_A2DP_4_10a        False (*)       SNK: Decode Audio Stream (O)
+TSPC_A2DP_4_10a        False           SNK: Decode and Forward Audio Stream (O)
 TSPC_A2DP_4_11 False           SNK: SBC Configurations in 16 KHz sampling (O)
 TSPC_A2DP_4_12 False           SNK: SBC Configurations in 32 KHz sampling (O)
 TSPC_A2DP_4_13 False (*)       SNK: SBC Configurations in 44.1 KHz sampling (M)
 TSPC_A2DP_4_14 False (*)       SNK: SBC Configurations in 48 KHz sampling (M)
+TSPC_A2DP_4_15 False           SNK: Delay Reporting (C.1)
+-------------------------------------------------------------------------------
+C.1: Mandatory to support if A2DP 0/3 is supported, otherwise excluded.
 -------------------------------------------------------------------------------
 
 
@@ -80,7 +131,32 @@ TSPC_A2DP_4_14      False (*)       SNK: SBC Configurations in 48 KHz sampling (M)
 -------------------------------------------------------------------------------
 Parameter Name Selected        Description
 -------------------------------------------------------------------------------
-TSPC_A2DP_5_1  False (*)       SNK: SBC decoder Codec (M)
-TSPC_A2DP_5_2  False           SNK: Additional decoder Coded (O)
-TSPC_ALL       False           Enable all test cases when set to False.
+TSPC_A2DP_5_1  False (*)       SNK: SBC decoder (M)
+TSPC_A2DP_5_1a False           SNK: Decode and Forward SBC Audio Stream (O)
+TSPC_A2DP_5_2  False           SNK: Optional codec decoder (O)
+TSPC_A2DP_5_3  False           SNK: MPEG-1,2 Audio (C.1)
+TSPC_A2DP_5_4  False           SNK: MPEG-2,4 AAC (C.1)
+TSPC_A2DP_5_5  False           SNK: ATRAC family (C.1)
+-------------------------------------------------------------------------------
+C.1: At least one codec shall be supported if Table 13/2 (Optional codec
+       decoder) is supported, otherwise excluded.
+-------------------------------------------------------------------------------
+
+
+               Supported Codec Features in SNK
+-------------------------------------------------------------------------------
+Parameter Name Selected        Description
+-------------------------------------------------------------------------------
+TSPC_A2DP_5a_1 False (*)       SNK: Channel Mode - Mono (M)
+TSPC_A2DP_5a_2 False (*)       SNK: Channel Mode - Dual Channel (M)
+TSPC_A2DP_5a_3 False (*)       SNK: Channel Mode - Stereo (M)
+TSPC_A2DP_5a_4 False (*)       SNK: Channel Mode - Joint Stereo (M)
+TSPC_A2DP_5a_5 False (*)       SNK: Block Length 4 (M)
+TSPC_A2DP_5a_6 False (*)       SNK: Block Length 8 (M)
+TSPC_A2DP_5a_7 False (*)       SNK: Block Length 12 (M)
+TSPC_A2DP_5a_8 False (*)       SNK: Block Length 16 (M)
+TSPC_A2DP_5a_9 False (*)       SNK: Subbands - 4 (M)
+TSPC_A2DP_5a_10        False (*)       SNK: Subbands - 8 (M)
+TSPC_A2DP_5a_11        False (*)       SNK: Allocation - SNR (M)
+TSPC_A2DP_5a_12        False (*)       SNK: Allocation - Loudness (M)
 -------------------------------------------------------------------------------
index 0afa33c..4fc599f 100644 (file)
@@ -1,6 +1,6 @@
 AVCTP PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
index ce7b259..191eaa4 100644 (file)
@@ -1,6 +1,6 @@
 AVDTP PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
index da72fe1..a25579e 100644 (file)
@@ -1,6 +1,6 @@
 AVRCP PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
@@ -24,12 +24,14 @@ C.1: Mandatory to support at least one of the defined roles.
 Parameter Name    Selected     Description
 -------------------------------------------------------------------------------
 TSPC_AVRCP_2_1    False (*)    CT: Initiating connection establishment (M)
-TSPC_AVRCP_2_2    False (*)    CT: Accepting connection establishment (M)
+TSPC_AVRCP_2_2    False (*)    CT: Accepting connection establishment for
+                                               control initiated by TG (M)
 TSPC_AVRCP_2_3    False (*)    CT: Initiating connection release (M)
-TSPC_AVRCP_2_4    False (*)    CT: Accepting connection release (M)
+TSPC_AVRCP_2_4    False (*)    CT: Accepting connection release for control
+                                                       initiated by TG (M)
 TSPC_AVRCP_2_5    False                CT: Sending UNIT INFO (O)
 TSPC_AVRCP_2_6    False                CT: Sending SUBUNIT INFO (O)
-TSPC_AVRCP_2_7    False        CT: Sending PASS THROUGH command category 1
+TSPC_AVRCP_2_7    False                CT: Sending PASS THROUGH command category 1
                                        (C.1)
 TSPC_AVRCP_2_8    False                CT: Sending PASS THROUGH command category 2
                                        (C.1)
@@ -45,8 +47,9 @@ TSPC_AVRCP_2_14   False               CT: Get Current Player Application Setting
                                        (C.10)
 TSPC_AVRCP_2_15   False                CT: Set Player Application Setting Value (C.10)
 TSPC_AVRCP_2_16   False                CT: Get Player Application Setting
-                                               Attribute (O)
-TSPC_AVRCP_2_17   False                CT: Get Player Application Setting Value (O)
+                                               Attribute Text (O)
+TSPC_AVRCP_2_17   False                CT: Get Player Application Setting Value Text
+                                       (O)
 TSPC_AVRCP_2_18   False                CT: Inform Displayable Character Set (O)
 TSPC_AVRCP_2_19   False                CT: Inform Battery Status of CT (O)
 TSPC_AVRCP_2_20   False                CT: Get Element Attributes (O)
@@ -89,14 +92,14 @@ TSPC_AVRCP_2_52   False (*) CT: Discoverable Mode (M)
 TSPC_AVRCP_2_53   False                CT: PASSTHROUGH operation supporting press
                                        and hold (O)
 TSPC_AVRCP_2_54   False                CT: Cover Art (O)
-TSPC_AVRCP_2_55   False                CT: GetCapabilities, Cover Art (C.10)
-TSPC_AVRCP_2_56   False                CT: GetImageProperties, Cover Art (C.10)
-TSPC_AVRCP_2_57   False                CT: GetImage, Cover Art (C.9)
-TSPC_AVRCP_2_58   False                CT: GetLinkedThumbnail, CoverArt (C.9)
+TSPC_AVRCP_2_55   False                CT: GetImageProperties (C.14)
+TSPC_AVRCP_2_56   False                CT: GetImage (C.13)
+TSPC_AVRCP_2_57   False                CT: GetLinkedThumbnail (C.13)
 -------------------------------------------------------------------------------
 C.1: Mandatory to support at least one of the defined categories
        (TSPC_AVRCP_2_7 through TSPC_AVRCP_2_10).
-C.2: Mandatory if TSPC_AVRCP_2_20 is supported, otherwise Optional.
+C.2: Mandatory to support at least one of TSPC_AVRCP_2_23 or TSPC_AVRC_2_24
+                       if TSPC_AVRCP_2_20 is supported, otherwise Optional.
 C.3: Mandatory if TSPC_AVRCP_2_8 is supported, otherwise Excluded.
 C.4: Mandatory if TSPC_AVRCP_2_32 is supported, otherwise Excluded.
 C.5: Mandatory if TSPC_AVRCP_2_27 is supported, otherwise Excluded.
@@ -112,12 +115,15 @@ C.10: Mandatory to support either Get or Set Player Application Settings
        or TSPC_AVRCP_2_15 must be supported if Player Application Settings
        feature is supported, in accordance with Player Application Settings
        support requirements.
-C.11: Mandatory if TSPC_AVRCP_2_7 or (TSPC_AVRCP_2_8 AND TSPC_AVRCP_2_49)
-       or TSPC_AVRCP_2_9 is supported, otherwise Optional.
+C.11: Mandatory if TSPC_AVRCP_2_20 or TSPC_AVRCP_2_49 is supported, otherwise
+       Optional.
 C.12: Mandatory if Basic Group Navigation Feature supported. If any item
        TSPC_AVRCP_2_25 or TSPC_AVRCP_2_26 is supported it is mandatory to
        support both, in accordance with Basic Group Navigation support
        requirements, otherwise Excluded.
+C.13: Mandatory to support at least one of the functions if TSPC_AVRCP_2_54
+       (Cover Art) is support, otherwise Excluded.
+C.14: Optional if TSPC_AVRCP_2_54 (Cover Art) is supported, otherwise Excluded.
 -------------------------------------------------------------------------------
 
 
@@ -177,7 +183,6 @@ TSPC_AVRCP_3_30   False             CT: category 1 - Operation id: F1 (C.1)
 TSPC_AVRCP_3_31   False                CT: category 1 - Operation id: F2 (C.1)
 TSPC_AVRCP_3_32   False                CT: category 1 - Operation id: F3 (C.1)
 TSPC_AVRCP_3_33   False                CT: category 1 - Operation id: F4 (C.1)
-TSPC_AVRCP_3_33a  False                CT: category 1 - Operation id: F5 (C.1)
 TSPC_AVRCP_3_34   False                CT: category 1 - Operation id: vendor_unique
                                        (C.1)
 -------------------------------------------------------------------------------
@@ -190,39 +195,38 @@ C.1: Mandatory to support at least one of these operation_ids if the device
 -------------------------------------------------------------------------------
 Parameter Name    Selected     Description
 -------------------------------------------------------------------------------
-TSPC_AVRCP_4_1    False                CT: category 2 - Operation id: 0 (C.2)
-TSPC_AVRCP_4_2    False                CT: category 2 - Operation id: 1 (C.2)
-TSPC_AVRCP_4_3    False                CT: category 2 - Operation id: 2 (C.2)
-TSPC_AVRCP_4_4    False                CT: category 2 - Operation id: 3 (C.2)
-TSPC_AVRCP_4_5    False                CT: category 2 - Operation id: 4 (C.2)
-TSPC_AVRCP_4_6    False                CT: category 2 - Operation id: 5 (C.2)
-TSPC_AVRCP_4_7    False                CT: category 2 - Operation id: 6 (C.2)
-TSPC_AVRCP_4_8    False                CT: category 2 - Operation id: 7 (C.2)
-TSPC_AVRCP_4_9    False                CT: category 2 - Operation id: 8 (C.2)
-TSPC_AVRCP_4_10   False                CT: category 2 - Operation id: 9 (C.2)
-TSPC_AVRCP_4_11   False                CT: category 2 - Operation id: dot (C.2)
-TSPC_AVRCP_4_12   False                CT: category 2 - Operation id: enter (C.2)
-TSPC_AVRCP_4_13   False                CT: category 2 - Operation id: clear (C.2)
+TSPC_AVRCP_4_1    False                CT: category 2 - Operation id: 0 (C.1)
+TSPC_AVRCP_4_2    False                CT: category 2 - Operation id: 1 (C.1)
+TSPC_AVRCP_4_3    False                CT: category 2 - Operation id: 2 (C.1)
+TSPC_AVRCP_4_4    False                CT: category 2 - Operation id: 3 (C.1)
+TSPC_AVRCP_4_5    False                CT: category 2 - Operation id: 4 (C.1)
+TSPC_AVRCP_4_6    False                CT: category 2 - Operation id: 5 (C.1)
+TSPC_AVRCP_4_7    False                CT: category 2 - Operation id: 6 (C.1)
+TSPC_AVRCP_4_8    False                CT: category 2 - Operation id: 7 (C.1)
+TSPC_AVRCP_4_9    False                CT: category 2 - Operation id: 8 (C.1)
+TSPC_AVRCP_4_10   False                CT: category 2 - Operation id: 9 (C.1)
+TSPC_AVRCP_4_11   False                CT: category 2 - Operation id: dot (C.1)
+TSPC_AVRCP_4_12   False                CT: category 2 - Operation id: enter (C.1)
+TSPC_AVRCP_4_13   False                CT: category 2 - Operation id: clear (C.1)
 TSPC_AVRCP_4_14   False                CT: category 2 - Operation id: sound_select
-                                       (C.2)
+                                       (C.1)
 TSPC_AVRCP_4_15   False                CT: category 2 - Operation id: input_select
-                                       (C.2)
+                                       (C.1)
 TSPC_AVRCP_4_16   False                CT: category 2 - Operation id:
-                                       display_information (C.2)
-TSPC_AVRCP_4_17   False                CT: category 2 - Operation id: help (C.2)
-TSPC_AVRCP_4_18   False                CT: category 2 - Operation id: power (C.2)
-TSPC_AVRCP_4_19   False                CT: category 2 - Operation id: volume_up (C.2)
-TSPC_AVRCP_4_20   False                CT: category 2 - Operation id: volume_down (C.2)
-TSPC_AVRCP_4_21   False                CT: category 2 - Operation id: mute (C.2)
-TSPC_AVRCP_4_22   False                CT: category 2 - Operation id: F1 (C.2)
-TSPC_AVRCP_4_23   False                CT: category 2 - Operation id: F2 (C.2)
-TSPC_AVRCP_4_24   False                CT: category 2 - Operation id: F3 (C.2)
-TSPC_AVRCP_4_25   False                CT: category 2 - Operation id: F4 (C.2)
-TSPC_AVRCP_4_25a  False                CT: category 2 - Operation id: F5 (C.2)
+                                       display_information (C.1)
+TSPC_AVRCP_4_17   False                CT: category 2 - Operation id: help (C.1)
+TSPC_AVRCP_4_18   False                CT: category 2 - Operation id: power (C.1)
+TSPC_AVRCP_4_19   False                CT: category 2 - Operation id: volume_up (C.1)
+TSPC_AVRCP_4_20   False                CT: category 2 - Operation id: volume_down (C.1)
+TSPC_AVRCP_4_21   False                CT: category 2 - Operation id: mute (C.1)
+TSPC_AVRCP_4_22   False                CT: category 2 - Operation id: F1 (C.1)
+TSPC_AVRCP_4_23   False                CT: category 2 - Operation id: F2 (C.1)
+TSPC_AVRCP_4_24   False                CT: category 2 - Operation id: F3 (C.1)
+TSPC_AVRCP_4_25   False                CT: category 2 - Operation id: F4 (C.1)
 TSPC_AVRCP_4_26   False                CT: category 2 - Operation id: vendor_unique
-                                       (C.2)
+                                       (C.1)
 -------------------------------------------------------------------------------
-C.2: Mandatory to support at least one of these operation_ids if the device
+C.1: Mandatory to support at least one of these operation_ids if the device
        supports category 2 (TSPC_AVRCP_2_8).
 -------------------------------------------------------------------------------
 
@@ -231,43 +235,42 @@ C.2: Mandatory to support at least one of these operation_ids if the device
 -------------------------------------------------------------------------------
 Parameter Name    Selected     Description
 -------------------------------------------------------------------------------
-TSPC_AVRCP_5_1    False                CT: category 3 - Operation id: 0 (C.3)
-TSPC_AVRCP_5_2    False                CT: category 3 - Operation id: 1 (C.3)
-TSPC_AVRCP_5_3    False                CT: category 3 - Operation id: 2 (C.3)
-TSPC_AVRCP_5_4    False                CT: category 3 - Operation id: 3 (C.3)
-TSPC_AVRCP_5_5    False                CT: category 3 - Operation id: 4 (C.3)
-TSPC_AVRCP_5_6    False                CT: category 3 - Operation id: 5 (C.3)
-TSPC_AVRCP_5_7    False                CT: category 3 - Operation id: 6 (C.3)
-TSPC_AVRCP_5_8    False                CT: category 3 - Operation id: 7 (C.3)
-TSPC_AVRCP_5_9    False                CT: category 3 - Operation id: 8 (C.3)
-TSPC_AVRCP_5_10   False                CT: category 3 - Operation id: 9 (C.3)
-TSPC_AVRCP_5_11   False                CT: category 3 - Operation id: dot (C.3)
-TSPC_AVRCP_5_12   False                CT: category 3 - Operation id: enter (C.3)
-TSPC_AVRCP_5_13   False                CT: category 3 - Operation id: clear (C.3)
-TSPC_AVRCP_5_14   False                CT: category 3 - Operation id: channel up (C.3)
+TSPC_AVRCP_5_1    False                CT: category 3 - Operation id: 0 (C.1)
+TSPC_AVRCP_5_2    False                CT: category 3 - Operation id: 1 (C.1)
+TSPC_AVRCP_5_3    False                CT: category 3 - Operation id: 2 (C.1)
+TSPC_AVRCP_5_4    False                CT: category 3 - Operation id: 3 (C.1)
+TSPC_AVRCP_5_5    False                CT: category 3 - Operation id: 4 (C.1)
+TSPC_AVRCP_5_6    False                CT: category 3 - Operation id: 5 (C.1)
+TSPC_AVRCP_5_7    False                CT: category 3 - Operation id: 6 (C.1)
+TSPC_AVRCP_5_8    False                CT: category 3 - Operation id: 7 (C.1)
+TSPC_AVRCP_5_9    False                CT: category 3 - Operation id: 8 (C.1)
+TSPC_AVRCP_5_10   False                CT: category 3 - Operation id: 9 (C.1)
+TSPC_AVRCP_5_11   False                CT: category 3 - Operation id: dot (C.1)
+TSPC_AVRCP_5_12   False                CT: category 3 - Operation id: enter (C.1)
+TSPC_AVRCP_5_13   False                CT: category 3 - Operation id: clear (C.1)
+TSPC_AVRCP_5_14   False                CT: category 3 - Operation id: channel up (C.1)
 TSPC_AVRCP_5_15   False                CT: category 3 - Operation id: channel down
-                                       (C.3)
+                                       (C.1)
 TSPC_AVRCP_5_16   False                CT: category 3 - Operation id: previous channel
-                                       (C.3)
+                                       (C.1)
 TSPC_AVRCP_5_17   False                CT: category 3 - Operation id: sound_select
-                                       (C.3)
+                                       (C.1)
 TSPC_AVRCP_5_18   False                CT: category 3 - Operation id: input_select
-                                       (C.3)
+                                       (C.1)
 TSPC_AVRCP_5_19   False                CT: category 3 - Operation id:
-                                       display_information (C.3)
-TSPC_AVRCP_5_20   False                CT: category 3 - Operation id: help (C.3)
-TSPC_AVRCP_5_21   False                CT: category 3 - Operation id: power (C.3)
-TSPC_AVRCP_5_22   False                CT: category 3 - Operation id: angle (C.3)
-TSPC_AVRCP_5_23   False                CT: category 3 - Operation id: subpicture(C.3)
-TSPC_AVRCP_5_24   False                CT: category 3 - Operation id: F1 (C.3)
-TSPC_AVRCP_5_25   False                CT: category 3 - Operation id: F2 (C.3)
-TSPC_AVRCP_5_26   False                CT: category 3 - Operation id: F3 (C.3)
-TSPC_AVRCP_5_27   False                CT: category 3 - Operation id: F4 (C.3)
-TSPC_AVRCP_5_27a  False                CT: category 3 - Operation id: F5 (C.3)
+                                       display_information (C.1)
+TSPC_AVRCP_5_20   False                CT: category 3 - Operation id: help (C.1)
+TSPC_AVRCP_5_21   False                CT: category 3 - Operation id: power (C.1)
+TSPC_AVRCP_5_22   False                CT: category 3 - Operation id: angle (C.1)
+TSPC_AVRCP_5_23   False                CT: category 3 - Operation id: subpicture(C.1)
+TSPC_AVRCP_5_24   False                CT: category 3 - Operation id: F1 (C.1)
+TSPC_AVRCP_5_25   False                CT: category 3 - Operation id: F2 (C.1)
+TSPC_AVRCP_5_26   False                CT: category 3 - Operation id: F3 (C.1)
+TSPC_AVRCP_5_27   False                CT: category 3 - Operation id: F4 (C.1)
 TSPC_AVRCP_5_28   False                CT: category 3 - Operation id: vendor_unique
-                                       (C.3)
+                                       (C.1)
 -------------------------------------------------------------------------------
-C.3: Mandatory to support at least one of these operation_ids if the device
+C.1: Mandatory to support at least one of these operation_ids if the device
        supports category 3 (TSPC_AVRCP_2_9).
 -------------------------------------------------------------------------------
 
@@ -276,51 +279,50 @@ C.3: Mandatory to support at least one of these operation_ids if the device
 -------------------------------------------------------------------------------
 Parameter Name    Selected     Description
 -------------------------------------------------------------------------------
-TSPC_AVRCP_6_1    False                CT: category 4 - Operation id: select (C.4)
-TSPC_AVRCP_6_2    False                CT: category 4 - Operation id: up (C.4)
-TSPC_AVRCP_6_3    False                CT: category 4 - Operation id: down (C.4)
-TSPC_AVRCP_6_4    False                CT: category 4 - Operation id: left (C.4)
-TSPC_AVRCP_6_5    False                CT: category 4 - Operation id: right (C.4)
-TSPC_AVRCP_6_6    False                CT: category 4 - Operation id: right up (C.4)
-TSPC_AVRCP_6_7    False                CT: category 4 - Operation id: right down (C.4)
-TSPC_AVRCP_6_8    False                CT: category 4 - Operation id: left up (C.4)
-TSPC_AVRCP_6_9    False                CT: category 4 - Operation id: left down (C.4)
-TSPC_AVRCP_6_10   False                CT: category 4 - Operation id: root menu (C.4)
-TSPC_AVRCP_6_11   False                CT: category 4 - Operation id: setup menu (C.4)
+TSPC_AVRCP_6_1    False                CT: category 4 - Operation id: select (C.1)
+TSPC_AVRCP_6_2    False                CT: category 4 - Operation id: up (C.1)
+TSPC_AVRCP_6_3    False                CT: category 4 - Operation id: down (C.1)
+TSPC_AVRCP_6_4    False                CT: category 4 - Operation id: left (C.1)
+TSPC_AVRCP_6_5    False                CT: category 4 - Operation id: right (C.1)
+TSPC_AVRCP_6_6    False                CT: category 4 - Operation id: right up (C.1)
+TSPC_AVRCP_6_7    False                CT: category 4 - Operation id: right down (C.1)
+TSPC_AVRCP_6_8    False                CT: category 4 - Operation id: left up (C.1)
+TSPC_AVRCP_6_9    False                CT: category 4 - Operation id: left down (C.1)
+TSPC_AVRCP_6_10   False                CT: category 4 - Operation id: root menu (C.1)
+TSPC_AVRCP_6_11   False                CT: category 4 - Operation id: setup menu (C.1)
 TSPC_AVRCP_6_12   False                CT: category 4 - Operation id: contents menu
-                                       (C.4)
+                                       (C.1)
 TSPC_AVRCP_6_13   False                CT: category 4 - Operation id: favorite menu
-                                       (C.4)
-TSPC_AVRCP_6_14   False                CT: category 4 - Operation id: exit (C.4)
-TSPC_AVRCP_6_15   False                CT: category 4 - Operation id: 0 (C.4)
-TSPC_AVRCP_6_16   False                CT: category 4 - Operation id: 1 (C.4)
-TSPC_AVRCP_6_17   False                CT: category 4 - Operation id: 2 (C.4)
-TSPC_AVRCP_6_18   False                CT: category 4 - Operation id: 3 (C.4)
-TSPC_AVRCP_6_19   False                CT: category 4 - Operation id: 4 (C.4)
-TSPC_AVRCP_6_20   False                CT: category 4 - Operation id: 5 (C.4)
-TSPC_AVRCP_6_21   False                CT: category 4 - Operation id: 6 (C.4)
-TSPC_AVRCP_6_22   False                CT: category 4 - Operation id: 7 (C.4)
-TSPC_AVRCP_6_23   False                CT: category 4 - Operation id: 8 (C.4)
-TSPC_AVRCP_6_24   False                CT: category 4 - Operation id: 9 (C.4)
-TSPC_AVRCP_6_25   False                CT: category 4 - Operation id: dot (C.4)
-TSPC_AVRCP_6_26   False                CT: category 4 - Operation id: enter (C.4)
-TSPC_AVRCP_6_27   False                CT: category 4 - Operation id: clear (C.4)
+                                       (C.1)
+TSPC_AVRCP_6_14   False                CT: category 4 - Operation id: exit (C.1)
+TSPC_AVRCP_6_15   False                CT: category 4 - Operation id: 0 (C.1)
+TSPC_AVRCP_6_16   False                CT: category 4 - Operation id: 1 (C.1)
+TSPC_AVRCP_6_17   False                CT: category 4 - Operation id: 2 (C.1)
+TSPC_AVRCP_6_18   False                CT: category 4 - Operation id: 3 (C.1)
+TSPC_AVRCP_6_19   False                CT: category 4 - Operation id: 4 (C.1)
+TSPC_AVRCP_6_20   False                CT: category 4 - Operation id: 5 (C.1)
+TSPC_AVRCP_6_21   False                CT: category 4 - Operation id: 6 (C.1)
+TSPC_AVRCP_6_22   False                CT: category 4 - Operation id: 7 (C.1)
+TSPC_AVRCP_6_23   False                CT: category 4 - Operation id: 8 (C.1)
+TSPC_AVRCP_6_24   False                CT: category 4 - Operation id: 9 (C.1)
+TSPC_AVRCP_6_25   False                CT: category 4 - Operation id: dot (C.1)
+TSPC_AVRCP_6_26   False                CT: category 4 - Operation id: enter (C.1)
+TSPC_AVRCP_6_27   False                CT: category 4 - Operation id: clear (C.1)
 TSPC_AVRCP_6_28   False                CT: category 4 - Operation id:
-                                       display_information (C.4)
-TSPC_AVRCP_6_29   False                CT: category 4 - Operation id: help (C.4)
-TSPC_AVRCP_6_30   False                CT: category 4 - Operation id: page up (C.4)
-TSPC_AVRCP_6_31   False                CT: category 4 - Operation id: page down (C.4)
-TSPC_AVRCP_6_32   False                CT: category 4 - Operation id: power (C.4)
-TSPC_AVRCP_6_33   False                CT: category 4 - Operation id: F1 (C.4)
-TSPC_AVRCP_6_34   False                CT: category 4 - Operation id: F2 (C.4)
-TSPC_AVRCP_6_35   False                CT: category 4 - Operation id: F3 (C.4)
-TSPC_AVRCP_6_36   False                CT: category 4 - Operation id: F4 (C.4)
-TSPC_AVRCP_6_36a  False                CT: category 4 - Operation id: F5 (C.4)
+                                       display_information (C.1)
+TSPC_AVRCP_6_29   False                CT: category 4 - Operation id: help (C.1)
+TSPC_AVRCP_6_30   False                CT: category 4 - Operation id: page up (C.1)
+TSPC_AVRCP_6_31   False                CT: category 4 - Operation id: page down (C.1)
+TSPC_AVRCP_6_32   False                CT: category 4 - Operation id: power (C.1)
+TSPC_AVRCP_6_33   False                CT: category 4 - Operation id: F1 (C.1)
+TSPC_AVRCP_6_34   False                CT: category 4 - Operation id: F2 (C.1)
+TSPC_AVRCP_6_35   False                CT: category 4 - Operation id: F3 (C.1)
+TSPC_AVRCP_6_36   False                CT: category 4 - Operation id: F4 (C.1)
 TSPC_AVRCP_6_37   False                CT: category 4 - Operation id: vendor_unique
-                                       (C.4)
+                                       (C.1)
 -------------------------------------------------------------------------------
-C.4: Mandatory to support at least one of these operation_ids if the device
-       supports category 4 (TSPC_AVRCP_2_9).
+C.1: Mandatory to support at least one of these operation_ids if the device
+       supports category 4 (TSPC_AVRCP_2_10).
 -------------------------------------------------------------------------------
 
 
@@ -328,8 +330,10 @@ C.4: Mandatory to support at least one of these operation_ids if the device
 -------------------------------------------------------------------------------
 Parameter Name    Selected     Description
 -------------------------------------------------------------------------------
-TSPC_AVRCP_7_1    True (*)     TG: Initiating connection establishment (O)
-TSPC_AVRCP_7_2    True         TG: Accept connection establishment (M)
+TSPC_AVRCP_7_1    True (*)     TG: Initiating connection establishment for
+                                       Control (O)
+TSPC_AVRCP_7_2    True         TG: Accept connection establishment for Control
+                                       initiated by CT (M)
 TSPC_AVRCP_7_3    True (*)     TG: Initiating connection release (M)
 TSPC_AVRCP_7_4    True         TG: Accepting connection release (M)
 TSPC_AVRCP_7_5    True         TG: Receiving UNIT INFO (M)
@@ -343,16 +347,20 @@ TSPC_AVRCP_7_9    False           TG: Receiving PASS THROUGH command category 3
 TSPC_AVRCP_7_10   False                TG: Receiving PASS THROUGH command category 4
                                        (C.1)
 TSPC_AVRCP_7_11   True (*)     TG: Get Capabilities Response (C.3)
-TSPC_AVRCP_7_12   False                TG: List Player Application Settings (C.14)
+TSPC_AVRCP_7_12   False                TG: List Player Application Settings Attributes
+                                       Response (C.14)
 TSPC_AVRCP_7_13   False                TG: List Player Application Setting Values
-                                       (C.14)
+                                       Response (C.14)
 TSPC_AVRCP_7_14   False                TG: Get Current Player Application Settings
-                                       (C.14)
-TSPC_AVRCP_7_15   False                TG: Set Player Application Setting Value (C.14)
+                                       Value Response (C.14)
+TSPC_AVRCP_7_15   False                TG: Set Player Application Setting Value
+                                       Response (C.14)
 TSPC_AVRCP_7_16   False                TG: Get Player Application Setting Attribute
+                                       Text Response (O)
+TSPC_AVRCP_7_17   False                TG: Get Player Application Setting Value Text
+                                       Response (O)
+TSPC_AVRCP_7_18   False                TG: Inform Displayable Character Set Response
                                        (O)
-TSPC_AVRCP_7_17   False                TG: Get Player Application Setting Value (O)
-TSPC_AVRCP_7_18   False                TG: Inform Displayable Character Set (O)
 TSPC_AVRCP_7_19   False                TG: Inform Battery Status Of CT Response (O)
 TSPC_AVRCP_7_20   True (*)     TG: Get Element Attributes Response (C.3)
 TSPC_AVRCP_7_21   True (*)     TG: Get Play Status Response (C.2)
@@ -371,7 +379,7 @@ TSPC_AVRCP_7_29   False             TG: Notify Event Response: SYSTEM_STATUS_CHANGED
                                        (O)
 TSPC_AVRCP_7_30   False                TG: Notify Event Response:
                                        PLAYER_APPLICATION_SETTING_CHANGED (O)
-TSPC_AVRCP_7_31   True (*)     TG: Request ContinuingResponse (C.2)
+TSPC_AVRCP_7_31   True (*)     TG: Request Continuing Response (C.2)
 TSPC_AVRCP_7_32   True (*)     TG: Abort ContinuingResponse Response (C.2)
 TSPC_AVRCP_7_34   False                TG: Next Group (C.15)
 TSPC_AVRCP_7_35   False                TG: Previous Group (C.15)
@@ -383,8 +391,8 @@ TSPC_AVRCP_7_39   False             TG: EVENT_AVAILABLE_PLAYERS_CHANGED (C.8)
 TSPC_AVRCP_7_40   False                TG: EVENT_ADDRESSED_PLAYER_CHANGED (C.8)
 TSPC_AVRCP_7_41   False                TG: Supports Multiple Players (O)
 TSPC_AVRCP_7_42   False                TG: Browsing (O)
-TSPC_AVRCP_7_42a  False                TG: Supports initiation of browsing channel
-                                       establishment (O)
+TSPC_AVRCP_7_42a  False                TG: Initiating connection establishment for
+                                       browsing channel (O)
 TSPC_AVRCP_7_43   False                TG: SetBrowsedPlayer (C.6)
 TSPC_AVRCP_7_44   False                TG: ChangePath (C.6)
 TSPC_AVRCP_7_45   False                TG: GetFolderItems(Filesystem) (C.6)
@@ -414,9 +422,9 @@ TSPC_AVRCP_7_65   True              TG: Discoverable Mode (M)
 TSPC_AVRCP_7_66   False                TG: PASSTHROUGH operation supporting press
                                        and hold (O)
 TSPC_AVRCP_7_67   False                TG: Cover Art (O)
-TSPC_AVRCP_7_68   False                TG: GetImageProperties, Cover Art (C.16)
-TSPC_AVRCP_7_69   False                TG: GetImage, Cover Art (C.16)
-TSPC_AVRCP_7_70   False                TG: GetLinkedThumbnail, Cover Art (C.16)
+TSPC_AVRCP_7_68   False                TG: GetImageProperties (C.16)
+TSPC_AVRCP_7_69   False                TG: GetImage (C.16)
+TSPC_AVRCP_7_70   False                TG: GetLinkedThumbnail (C.16)
 -------------------------------------------------------------------------------
 C.1: Mandatory to support at least one of the categories. Supported
        operation_id's are shown in Table 8 to Table 11.
@@ -440,6 +448,7 @@ C.15: Mandatory if Basic Group Navigation Feature supported. If any item
        7/34 or 7/35 is supported it is mandatory to support both,
        in accordance with Basic Group Navigation support requirements,
        otherwise Excluded.
+C.16: Mandatory if 7/67 (Cover Art) is supported, otherwise Excluded.
 -------------------------------------------------------------------------------
 
                Target Profile Version
@@ -494,8 +503,8 @@ TSPC_AVRCP_8_30   False             TG: category 1 - Operation id: F1 (O)
 TSPC_AVRCP_8_31   False                TG: category 1 - Operation id: F2 (O)
 TSPC_AVRCP_8_32   False                TG: category 1 - Operation id: F3 (O)
 TSPC_AVRCP_8_33   False                TG: category 1 - Operation id: F4 (O)
-TSPC_AVRCP_8_3  False                TG: category 1 - Operation id: F5 (O)
-TSPC_AVRCP_8_35   False                TG: category 1 - Operation id: vendor unique (O)
+TSPC_AVRCP_8_33a  False                TG: category 1 - Operation id: F5 (O)
+TSPC_AVRCP_8_34   False                TG: category 1 - Operation id: vendor unique (O)
 -------------------------------------------------------------------------------
 
 
@@ -525,12 +534,12 @@ TSPC_AVRCP_9_18     False         TG: category 2 - Operation id: power (O)
 TSPC_AVRCP_9_19   True         TG: category 2 - Operation id: volume up (C.2)
 TSPC_AVRCP_9_20   True         TG: category 2 - Operation id: volume down (C.2)
 TSPC_AVRCP_9_21   False                TG: category 2 - Operation id: mute (O)
-TSPC_AVRCP_9_22   False                TG: category 2 - Operation id: F1 (O)
-TSPC_AVRCP_9_23   False                TG: category 2 - Operation id: F2 (O)
-TSPC_AVRCP_9_24   False                TG: category 2 - Operation id: F3 (O)
-TSPC_AVRCP_9_25   False                TG: category 2 - Operation id: F4 (O)
-TSPC_AVRCP_9_2  False                TG: category 2 - Operation id: F5 (O)
-TSPC_AVRCP_9_27   False                TG: category 2 - Operation id: vendor unique (O)
+TSPC_AVRCP_9_24   False                TG: category 2 - Operation id: F1 (O)
+TSPC_AVRCP_9_25   False                TG: category 2 - Operation id: F2 (O)
+TSPC_AVRCP_9_26   False                TG: category 2 - Operation id: F3 (O)
+TSPC_AVRCP_9_27   False                TG: category 2 - Operation id: F4 (O)
+TSPC_AVRCP_9_27a  False                TG: category 2 - Operation id: F5 (O)
+TSPC_AVRCP_9_28   False                TG: category 2 - Operation id: vendor unique (O)
 -------------------------------------------------------------------------------
 C.2: Mandatory to support if the device supports category 2 (TSPC_AVRCP_7_8).
 -------------------------------------------------------------------------------
@@ -553,8 +562,8 @@ TSPC_AVRCP_10_10  False             TG: category 3 - Operation id: 9 (O)
 TSPC_AVRCP_10_11  False                TG: category 3 - Operation id: dot (O)
 TSPC_AVRCP_10_12  False                TG: category 3 - Operation id: enter (O)
 TSPC_AVRCP_10_13  False                TG: category 3 - Operation id: clear (O)
-TSPC_AVRCP_10_14  False (*)            TG: category 3 - Operation id: channel up (C.3)
-TSPC_AVRCP_10_15  False (*)            TG: category 3 - Operation id: channel down
+TSPC_AVRCP_10_14  False (*)    TG: category 3 - Operation id: channel up (C.3)
+TSPC_AVRCP_10_15  False (*)    TG: category 3 - Operation id: channel down
                                        (C.3)
 TSPC_AVRCP_10_16  False                TG: category 3 - Operation id: previous channel
                                        (O)
@@ -564,14 +573,14 @@ TSPC_AVRCP_10_19  False           TG: category 3 - Operation id: display
                                        information (O)
 TSPC_AVRCP_10_20  False                TG: category 3 - Operation id: help (O)
 TSPC_AVRCP_10_21  False                TG: category 3 - Operation id: power (O)
-TSPC_AVRCP_10_2 False                TG: category 3 - Operation id: angle (O)
-TSPC_AVRCP_10_2 False                TG: category 3 - Operation id: subpicture (O)
-TSPC_AVRCP_10_24  False                TG: category 3 - Operation id: F1 (O)
-TSPC_AVRCP_10_25  False                TG: category 3 - Operation id: F2 (O)
-TSPC_AVRCP_10_26  False                TG: category 3 - Operation id: F3 (O)
-TSPC_AVRCP_10_27  False                TG: category 3 - Operation id: F4 (O)
-TSPC_AVRCP_10_2 False                TG: category 3 - Operation id: F5 (O)
-TSPC_AVRCP_10_29  False                TG: category 3 - Operation id: vendor unique (O)
+TSPC_AVRCP_10_21a False                TG: category 3 - Operation id: angle (O)
+TSPC_AVRCP_10_21b False                TG: category 3 - Operation id: subpicture (O)
+TSPC_AVRCP_10_22  False                TG: category 3 - Operation id: F1 (O)
+TSPC_AVRCP_10_23  False                TG: category 3 - Operation id: F2 (O)
+TSPC_AVRCP_10_24  False                TG: category 3 - Operation id: F3 (O)
+TSPC_AVRCP_10_25  False                TG: category 3 - Operation id: F4 (O)
+TSPC_AVRCP_10_25a False                TG: category 3 - Operation id: F5 (O)
+TSPC_AVRCP_10_26  False                TG: category 3 - Operation id: vendor unique (O)
 -------------------------------------------------------------------------------
 C.3: Mandatory to support if the device supports category 3 (TSPC_AVRCP_7_9).
 -------------------------------------------------------------------------------
@@ -581,16 +590,16 @@ C.3: Mandatory to support if the device supports category 3 (TSPC_AVRCP_7_9).
 -------------------------------------------------------------------------------
 Parameter Name    Selected     Description
 -------------------------------------------------------------------------------
-TSPC_AVRCP_11_1   False (*)            TG: category 4 - Operation id: select (C.4)
-TSPC_AVRCP_11_2   False (*)            TG: category 4 - Operation id: up (C.4)
-TSPC_AVRCP_11_3   False (*)            TG: category 4 - Operation id: down (C.4)
-TSPC_AVRCP_11_4   False (*)            TG: category 4 - Operation id: left (C.4)
-TSPC_AVRCP_11_5   False (*)            TG: category 4 - Operation id: right (C.4)
+TSPC_AVRCP_11_1   False (*)    TG: category 4 - Operation id: select (C.4)
+TSPC_AVRCP_11_2   False (*)    TG: category 4 - Operation id: up (C.4)
+TSPC_AVRCP_11_3   False (*)    TG: category 4 - Operation id: down (C.4)
+TSPC_AVRCP_11_4   False (*)    TG: category 4 - Operation id: left (C.4)
+TSPC_AVRCP_11_5   False (*)    TG: category 4 - Operation id: right (C.4)
 TSPC_AVRCP_11_6   False                TG: category 4 - Operation id: right up (O)
 TSPC_AVRCP_11_7   False                TG: category 4 - Operation id: right down (O)
 TSPC_AVRCP_11_8   False                TG: category 4 - Operation id: left up (O)
 TSPC_AVRCP_11_9   False                TG: category 4 - Operation id: left down (O)
-TSPC_AVRCP_11_10  False (*)            TG: category 4 - Operation id: root menu (C.4)
+TSPC_AVRCP_11_10  False (*)    TG: category 4 - Operation id: root menu (C.4)
 TSPC_AVRCP_11_11  False                TG: category 4 - Operation id: setup menu (O)
 TSPC_AVRCP_11_12  False                TG: category 4 - Operation id: contents menu (O)
 TSPC_AVRCP_11_13  False                TG: category 4 - Operation id: favorite menu (O)
@@ -617,11 +626,11 @@ TSPC_AVRCP_11_33  False           TG: category 4 - Operation id: F1 (O)
 TSPC_AVRCP_11_34  False                TG: category 4 - Operation id: F2 (O)
 TSPC_AVRCP_11_35  False                TG: category 4 - Operation id: F3 (O)
 TSPC_AVRCP_11_36  False                TG: category 4 - Operation id: F4 (O)
-TSPC_AVRCP_11_3 False                TG: category 4 - Operation id: F5 (O)
-TSPC_AVRCP_11_38  False                TG: category 4 - Operation id: vendor unique (O)
+TSPC_AVRCP_11_36a False                TG: category 4 - Operation id: F5 (O)
+TSPC_AVRCP_11_37  False                TG: category 4 - Operation id: vendor unique (O)
 
-TSPC_AVRCP_12_1   True                 General discoverable mode
-TSPC_AVRCP_13_1   True                 General discoverable mode
+TSPC_AVRCP_12_1   True         General discoverable mode (M)
+TSPC_AVRCP_13_1   True         General discoverable mode (M)
 TSPC_AVRCP_14_1   False                OBEX Connect operation (C.1)
 TSPC_AVRCP_14_2   False                OBEX Get operation (C.1)
 TSPC_AVRCP_14_3   False                OBEX Disconnect operation (C.1)
index b516aa8..da2e090 100644 (file)
@@ -1,6 +1,6 @@
 DID PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
index 169173d..ed207c8 100644 (file)
@@ -1,6 +1,6 @@
 DIS PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 
index 735eca2..466f451 100644 (file)
@@ -1,6 +1,6 @@
 GAP PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 
@@ -403,7 +403,7 @@ C.3: Optional if TSPC_GAP_5_3 is supported, otherwise Excluded.
 -------------------------------------------------------------------------------
 Parameter Name Selected        Description
 -------------------------------------------------------------------------------
-TSPC_GAP_23_1  False (*)       Peripheral: Non-Connectable Mode (C.1)
+TSPC_GAP_23_1  True            Peripheral: Non-Connectable Mode (C.1)
 TSPC_GAP_23_2  True            Peripheral: Directed Connectable Mode (O)
 TSPC_GAP_23_3  True            Peripheral: Undirected Connectable Mode (M)
 TSPC_GAP_23_4  True            Peripheral: Connection Parameter Update
@@ -775,9 +775,9 @@ C.1: Optional if ((SUM ICS 31/14 (Core Spec Version 4.1) or SUM ICS 31/15
 -------------------------------------------------------------------------------
 Parameter Name Selected        Description
 -------------------------------------------------------------------------------
+TSPC_GATT_1_1  True            GATT Client Role (O)
+TSPC_GATT_1_2  True            GATT Server Role (O)
 TSPC_SM_1_1    True            Master Role (Initiator)
 TSPC_SM_1_2    True            Slave Role (Responder)
 TSPC_SM_2_4    True            OOB supported (O)
-TSPC_ALL       False           Turns on all
-TSPC_GATT_1_1  True            GATT Client Role
 -------------------------------------------------------------------------------
index 6ff9c55..ec59853 100644 (file)
@@ -1,6 +1,6 @@
 GATT PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 
@@ -13,8 +13,8 @@ Parameter Name        Selected        Description
 -------------------------------------------------------------------------------
 TSPC_GATT_1_1  True            Generic Attribute Profile Client (C.1)
 TSPC_GATT_1_2  True            Generic Attribute Profile Server (C.2)
-TSPC_GATT_1A_1 True            Complete GATT client (C.3)
-TSPC_GATT_1A_2 True            Complete GATT server (C.4)
+TSPC_GATT_1_3  True            Complete GATT client (C.3)
+TSPC_GATT_1_4  True            Complete GATT server (C.4)
 -------------------------------------------------------------------------------
 C.1: Optional to support IF TSPC_GATT_2_2; else IF TSPC_GATT_2_1 it is mandatory
        to support at least one of TSPC_GATT_1_1 OR TSPC_GATT_1_2
@@ -45,7 +45,7 @@ C.2: Mandatory IF (SUM ICS 12/7 OR SUM ICS 12/9) is supported, otherwise
 -------------------------------------------------------------------------------
 Parameter Name Selected        Description
 -------------------------------------------------------------------------------
-TSPC_GATT_3_1  True            Client: Exchange MTU (C.1)
+TSPC_GATT_3_1  True            Client: Exchange MTU (C.2)
 TSPC_GATT_3_2  True            Client: Discover All Primary Services (C.1)
 TSPC_GATT_3_3  True            Client: Discover Primary Services Service
                                        UUID (C.1)
@@ -118,7 +118,9 @@ TSPC_GATT_3B_36     True            Client: Characteristic Format: utf8s (M)
 TSPC_GATT_3B_37        True            Client: Characteristic Format: utf16s (M)
 TSPC_GATT_3B_38        True            Client: Characteristic Format: struct (M)
 -------------------------------------------------------------------------------
-C.1: Mandatory IF TSPC_GATT_1A_1 is supported, otherwise Optional
+C.1: Mandatory IF TSPC_GATT_1_3 is supported, otherwise Optional
+C.2: Mandatory IF TSPC_GATT_1_3 AND TSPC_GATT_2_2 is supported, otherwise
+       Excluded
 -------------------------------------------------------------------------------
 
 
@@ -162,7 +164,7 @@ C.1: Mandatory IF service definitions on the server can be added, changed, or
        removed, otherwise Optional
 C.2: Mandatory IF GATT TSPC_GATT_4_13 is supported, otherwise Optional
 C.3: Mandatory IF GATT TSPC_GATT_4_15 is supported, otherwise Optional
-C.4: Mandatory IF GATT TSPC_GATT_1A_2 is supported, otherwise Optional
+C.4: Mandatory IF GATT TSPC_GATT_1_4 is supported, otherwise Optional
 -------------------------------------------------------------------------------
 
 
@@ -246,6 +248,15 @@ C.2: Optional IF TSPC_GATT_2_2 is supported, otherwise Excluded
 -------------------------------------------------------------------------------
 
 
+                Attribute Protocol Client Messages
+-------------------------------------------------------------------------------
+Parameter Name  Selected        Description
+-------------------------------------------------------------------------------
+TSPC_GATT_8_1    True            Support for Multiple ATT bearers from same
+       device (O)
+-------------------------------------------------------------------------------
+
+
                Attribute Protocol Client Messages
 -------------------------------------------------------------------------------
 Parameter Name Selected        Description
@@ -266,6 +277,7 @@ TSPC_ATT_3_21       True            Signed Write Command (O)
 TSPC_ATT_3_22  True            Prepare Write Request (O)
 TSPC_ATT_3_24  True            Execute Write Request (C.8)
 TSPC_ATT_3_26  True            Handle Value Notification (M)
+TSPC_ATT_3_28  True            Handle Value Confirmation (M)
 -------------------------------------------------------------------------------
 C.6: Mandatory IF TSPC_ATT_3_16 is supported, otherwise Excluded
 C.8: Mandatory IF TSPC_ATT_3_22 is supported, otherwise Excluded
@@ -288,8 +300,9 @@ TSPC_ATT_4_19       True            Write Response (C.3)
 TSPC_ATT_4_20  True            Write Command (O)
 TSPC_ATT_4_21  True            Signed Write Command (O)
 TSPC_ATT_4_23  True            Prepare Write Response (C.4)
-TSPC_ATT_4_25  True            Execute Write Response (C.5)
+TSPC_ATT_4_25  True            Execute Write Response (C.4)
 TSPC_ATT_4_26  True            Handle Value Notification (O)
+TSPC_ATT_4_27  True            Handle Value Indication (O)
 -------------------------------------------------------------------------------
 C.2: Mandatory IF TSPC_ATT_4_14 is supported, otherwise Excluded
 C.3: Mandatory IF TSPC_ATT_4_18 is supported, otherwise Excluded
diff --git a/android/pics-gavdp.txt b/android/pics-gavdp.txt
new file mode 100644 (file)
index 0000000..1cf12a9
--- /dev/null
@@ -0,0 +1,37 @@
+GAVDP PICS for the PTS tool.
+
+PTS version: 6.0
+
+* - different than PTS defaults
+# - not yet implemented/supported
+
+M - mandatory
+O - optional
+
+               Role
+-------------------------------------------------------------------------------
+Parameter Name Selected        Description
+-------------------------------------------------------------------------------
+TSPC_GAVDP_1_1 True (*)        Initiator (O.1)
+TSPC_GAVDP_1_2 True (*)        Initiator (O.1)
+-------------------------------------------------------------------------------
+
+
+               GAVDP Procedures (Initiator)
+-------------------------------------------------------------------------------
+Parameter Name Selected        Description
+-------------------------------------------------------------------------------
+TSPC_GAVDP_2_1 True            Connection Establishment (M)
+TSPC_GAVDP_2_2 True (*)        Transfer Control -Suspend (O)
+TSPC_GAVDP_2_3 False           Transfer Control â€“ Change Parameters (O)
+-------------------------------------------------------------------------------
+
+
+               GAVDP Procedures (Acceptor)
+-------------------------------------------------------------------------------
+Parameter Name Selected        Description
+-------------------------------------------------------------------------------
+TSPC_GAVDP_2_1 True            Connection Establishment (M)
+TSPC_GAVDP_2_2 True (*)        Transfer Control -Suspend (O)
+TSPC_GAVDP_2_3 False           Transfer Control â€“ Change Parameters (O)
+-------------------------------------------------------------------------------
index 48f7ce1..2f29320 100644 (file)
@@ -1,6 +1,6 @@
 HDP PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
index 65f5112..ea81289 100644 (file)
@@ -1,6 +1,6 @@
 HFP PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
@@ -40,7 +40,7 @@ TSPC_HFP_2_1a True (*)        SLC initiation during active ongoing call (O)
 TSPC_HFP_2_2   True            Phone Status Information (M)
 TSPC_HFP_2_3   True            Audio connection handling (M)
 TSPC_HFP_2_3a  False           Audio connection establishment independent of
-                                       call processing (O)
+                                       call processing (O)
 TSPC_HFP_2_3b  True (*)        eSCO support in Audio Connection (C.10)
 TSPC_HFP_2_3c  True (*)        Codec negotiation (C.7)
 TSPC_HFP_2_4a  False           Accept an incoming voice call
@@ -83,14 +83,14 @@ TSPC_HFP_2_21b      False           Enhanced Call Control (C.3)
 TSPC_HFP_2_21c True (*)        Enhanced Call Status with limited network
                                        notification (C.4)
 TSPC_HFP_2_22  False           Support for automatic link loss recovery (O)
-TSPC_HFP_2_23  True (*)        Individual Indicator Activation (C.9)
+TSPC_HFP_2_23  True            Individual Indicator Activation (C.9)
 TSPC_HFP_2_24  True (*)        Wide Band Speech service (C.8)
 TSPC_HFP_2_25  False           Support roaming function (O)
 TSPC_HFP_2_26  False           HF Indicators (C.11)
 TSPC_HFP_2_27  False           Support CVSD eSCO s4 setting (C.12)
 -------------------------------------------------------------------------------
 C.1:  The AG must support one of item TSPC_HFP_2_4a or TSPC_HFP_2_4b
-C.2:  Mandatory if TSPC_HFP_2_12is TRUE; otherwise excluded
+C.2:  Mandatory if TSPC_HFP_2_12 is TRUE; otherwise excluded
 C.3:  Optional if TSPC_HFP_2_12 is TRUE; otherwise excluded
 C.4:  The AG must support one of item TSPC_HFP_2_21a or TSPC_HFP_2_21c
 C.5:  Mandatory if TSPC_HFP_2_18a or TSPC_HFP_2_18b; otherwise optional
@@ -98,7 +98,7 @@ C.6:  Optional if TSPC_HFP_2_15 is supported, otherwise excluded
 C.7:  Mandatory if TSPC_HFP_2_24 otherwise excluded
 C.8:  Excluded if TSPC_HFP_0_1 otherwise optional
 C.9:  Excluded if TSPC_HFP_0_1 otherwise mandatory
-C.10: Mandatory if TSPC_HFP_2_24 otherwise optional
+C.10: Mandatory if TSPC_HFP_2_27 or TSPC_HFP_2_24 otherwise optional
 C.11: Optional IF HFP v1.5 (TSPC_HFP_0_1) OR HFP v1.6 (TSPC_HFP_0_2) is NOT
        supported, otherwise Excluded.
 C.12: Excluded IF HFP v1.5 (TSPC_HFP_0_1) OR HFP v1.6 (TSPC_HFP_0_2) is
@@ -131,7 +131,6 @@ TSPC_HFP_3_4c       False           Accept an incoming voice call (in-band ring
                                        muting) (O)
 TSPC_HFP_3_5   False (*)       Reject an incoming voice call (M)
 TSPC_HFP_3_6   False (*)       Terminate a call (M)
-
 TSPC_HFP_3_7   False (*)       Audio connection transfer during an ongoing
                                        call (M)
 TSPC_HFP_3_7a  False           HF-initiated Audio transfer to AG during
@@ -166,18 +165,18 @@ TSPC_HFP_3_20     False           Subscriber Number Information (O)
 TSPC_HFP_3_21a False           Enhanced Call Status (O)
 TSPC_HFP_3_21b False           Enhanced Call Control (C.2)
 TSPC_HFP_3_22  False           Support for automatic link loss recovery (O)
-TSPC_HFP_3_23  False           Individual Indicator Activation (C.6)
+TSPC_HFP_3_23  False (*)       Individual Indicator Activation (C.6)
 TSPC_HFP_3_24  False           Wide Band Speech service (C.6)
 TSPC_HFP_3_25  False           HF Indicators (C.8)
-TSPC_HFP_3_36  False           Support CVSD eSCO S4 setting (C.9)
+TSPC_HFP_3_26  False           Support CVSD eSCO S4 setting (C.9)
 -------------------------------------------------------------------------------
 C.1: Mandatory if TSPC_HFP_3_12; otherwise excluded
 C.2: Optional if TSPC_HFP_3_12; otherwise excluded
 C.3: Mandatory if TSPC_HFP_3_18a or TSPC_HFP_3_18b, otherwise optional
-C.4: Mandatory if TSPC_HFP_3_18a, otherwise optional
+C.4: Mandatory if TSPC_HFP_3_18b, otherwise optional
 C.5: Mandatory if TSPC_HFP_3_24 otherwise excluded
 C.6: Excluded if TSPC_HFP_0_1 otherwise optional
-C.7: Mandatory if TSPC_HFP_3_24 otherwise optional
+C.7: Mandatory if TSPC_HFP_3_26 or TSPC_HFP_3_24 otherwise optional
 C.8: Optional IF HFP v1.5 (TSPC_HFP_0_1) OR HFP v1.6 (TSPC_HFP_0_2) is NOT
        supported, otherwise Excluded.
 C.9: Excluded IF HFP v1.5 (TSPC_HFP_0_1) OR HFP v1.6 (TSPC_HFP_0_2) is
@@ -196,9 +195,7 @@ TSPC_HFP_4_2        True (*)        CVSD audio coding over eSCO (Accepting) (C.2)
 -------------------------------------------------------------------------------
 C.1: Mandatory if Wide band speech service is supported TSPC_HFP_2_24 or
        TSPC_HFP_3_24, otherwise excluded
-C.2: Mandatory IF TPSC_HFP_2_3b (eSCO support in Audio Connection - AG) OR
-       TSPC_HFP_3_3b (eSCO support in Audio Connection - HF); otherwise
-       Excluded.
+C.2: Mandatory IF TPSC_HFP_2_3b OR TSPC_HFP_3_3b; otherwise    Excluded.
 -------------------------------------------------------------------------------
 
 
index aa03878..ffd0aff 100644 (file)
@@ -1,6 +1,6 @@
 HID PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
index 61cf56a..e656e0c 100644 (file)
@@ -1,6 +1,6 @@
 HOGP PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
@@ -249,7 +249,7 @@ TSPC_HOGP_11_10     True            Read Report characteristic: Input Report:
 TSPC_HOGP_11_11        True            Report characteristic configuration with 0x0001
                                        (M.1)
 TSPC_HOGP_11_11a True          Report characteristic configuration with 0x0000
-                                       (M.1)
+                                       (O)
 TSPC_HOGP_11_12        True            Read HID Information characteristic (M.1)
 TSPC_HOGP_11_13        False (*)       Suspend State (O)
 TSPC_HOGP_11_14        False (*)       Exit Suspend State (C.1)
@@ -335,23 +335,26 @@ C.2: Mandatory to support if TSPC_HOGP_10_8 is supported, else excluded.
 -------------------------------------------------------------------------------
 Parameter Name Selected        Description
 -------------------------------------------------------------------------------
-TSPC_HOGP_13_1 True            Attribute Protocol supported over LE Transport
-TSPC_HOGP_13_2 True            Generic Attribute Profile Client
-TSPC_HOGP_13_3 True            Discover All Primary Services
-TSPC_HOGP_13_4 False (*)       Discover Primary Services by Service UUID
-TSPC_HOGP_13_5 True            Find Included Services
-TSPC_HOGP_13_6 True            Discover All Characteristics of a Service
-TSPC_HOGP_13_7 False (*)       Discover Characteristics by UUID
-TSPC_HOGP_13_8 True            Discover All Characteristic Descriptors
-TSPC_HOGP_13_9 True            Read Characteristic Value
-TSPC_HOGP_13_10        True            Read using Characteristic UUID
-TSPC_HOGP_13_11        True            Read Long Characteristic Value
-TSPC_HOGP_13_12        True            Read Characteristic Descriptors
-TSPC_HOGP_13_13        True            Write without Response
-TSPC_HOGP_13_14        True            Write Characteristic Value
-TSPC_HOGP_13_15        True            Write Characteristic Descriptors
-TSPC_HOGP_13_16        True            Notifications
-TSPC_HOGP_13_17        True            Exchange MTU
+TSPC_HOGP_13_1 True            Attribute Protocol supported over LE Transport (M)
+TSPC_HOGP_13_2 True            Generic Attribute Profile Client (M)
+TSPC_HOGP_13_3 True            Discover All Primary Services (C.1)
+TSPC_HOGP_13_4 False (*)       Discover Primary Services by Service UUID (C.1)
+TSPC_HOGP_13_5 True            Find Included Services (M)
+TSPC_HOGP_13_6 True            Discover All Characteristics of a Service (C.2)
+TSPC_HOGP_13_7 False (*)       Discover Characteristics by UUID (C.2)
+TSPC_HOGP_13_8 True            Discover All Characteristic Descriptors (M)
+TSPC_HOGP_13_9 True            Read Characteristic Value (M)
+TSPC_HOGP_13_10        True            Read using Characteristic UUID (O)
+TSPC_HOGP_13_11        True            Read Long Characteristic Value (M)
+TSPC_HOGP_13_12        True            Read Characteristic Descriptors (M)
+TSPC_HOGP_13_13        True            Write without Response (M)
+TSPC_HOGP_13_14        True            Write Characteristic Value (M)
+TSPC_HOGP_13_15        True            Write Characteristic Descriptors (M)
+TSPC_HOGP_13_16        True            Notifications (M)
+TSPC_HOGP_13_17        True            Exchange MTU (M)
+-------------------------------------------------------------------------------
+C.1: Mandatory to support at least one of these features.
+C.2: Mandatory to support at least one of these features.
 -------------------------------------------------------------------------------
 
 
@@ -359,20 +362,20 @@ TSPC_HOGP_13_17   True            Exchange MTU
 -------------------------------------------------------------------------------
 Parameter Name Selected        Description
 -------------------------------------------------------------------------------
-TSPC_HOGP_14_1 False (*)       Attribute Protocol supported over LE Transport
-TSPC_HOGP_14_2 False (*)       Generic Attribute Profile Client
-TSPC_HOGP_14_3 False (*)       Discover All Primary Services
-TSPC_HOGP_14_4 False (*)       Discover Primary Services by Service UUID
-TSPC_HOGP_14_5 False (*)       Discover All Characteristics of a Service
-TSPC_HOGP_14_6 False (*)       Discover Characteristics by UUID
-TSPC_HOGP_14_7 False (*)       Discover All Characteristic Descriptors
-TSPC_HOGP_14_8 False (*)       Read Characteristic Value
-TSPC_HOGP_14_9 False (*)       Read using Characteristic UUID
-TSPC_HOGP_14_10        False (*)       Read Characteristic Descriptors
-TSPC_HOGP_14_11        False (*)       Write without Response
-TSPC_HOGP_14_12        False (*)       Write Characteristic Value
-TSPC_HOGP_14_13        False (*)       Write Characteristic Descriptors
-TSPC_HOGP_14_14        False (*)       Notifications
+TSPC_HOGP_14_1 False (*)       Attribute Protocol supported over LE Transport (M)
+TSPC_HOGP_14_2 False (*)       Generic Attribute Profile Client (M)
+TSPC_HOGP_14_3 False (*)       Discover All Primary Services (C.1)
+TSPC_HOGP_14_4 False (*)       Discover Primary Services by Service UUID (C.1)
+TSPC_HOGP_14_5 False (*)       Discover All Characteristics of a Service (O)
+TSPC_HOGP_14_6 False (*)       Discover Characteristics by UUID (O)
+TSPC_HOGP_14_7 False (*)       Discover All Characteristic Descriptors (M)
+TSPC_HOGP_14_8 False (*)       Read Characteristic Value (M)
+TSPC_HOGP_14_9 False (*)       Read using Characteristic UUID (M)
+TSPC_HOGP_14_10        False (*)       Read Characteristic Descriptors (M)
+TSPC_HOGP_14_11        False (*)       Write without Response (M)
+TSPC_HOGP_14_12        False (*)       Write Characteristic Value (M)
+TSPC_HOGP_14_13        False (*)       Write Characteristic Descriptors (M)
+TSPC_HOGP_14_14        False (*)       Notifications (M)
 -------------------------------------------------------------------------------
 
 
@@ -393,9 +396,9 @@ M.2: Mandatory if TSPC_HOGP_1_3 selected
 Parameter Name Selected        Description
 -------------------------------------------------------------------------------
 TSPC_HOGP_16_1 True            No Security Requirements (LE Security Level 1,
-                                       No Security)
+                                       No Security) (M)
 TSPC_HOGP_16_2 True            Unauthenticated no MITM protection (LE Security
-                                       Level 2, Just Works)
+                                       Level 2, Just Works) (M)
 TSPC_HOGP_16_3 True            Authenticated MITM protection (LE Security
-                                       Level 3, Passkey)
+                                       Level 3, Passkey) (O)
 -------------------------------------------------------------------------------
index 7e71b14..3818e74 100644 (file)
@@ -1,6 +1,6 @@
 HSP PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
@@ -82,8 +82,8 @@ TSPC_HSP_3_11 False           Audio volume setting storage by HS (O)
 TSPC_HSP_3_12  False           Remote microphone gain control (C.2)
 TSPC_HSP_3_13  False           HS informs AG about local changes of microphone
                                         gain (O)
-TSPC_HSP_3_14  False (*)       Microphone gain setting storage by HS (O)
-TSPC_HSP_3_15  False           Connection handling with Detach/Page (M)
+TSPC_HSP_3_14  False           Microphone gain setting storage by HS (O)
+TSPC_HSP_3_15  False (*)       Connection handling with Detach/Page (M)
 TSPC_HSP_3_16  False           Connection handling with Park Mode (C.3)
 -------------------------------------------------------------------------------
 C.1: Mandatory if TSPC_HSP_3_10 is supported, otherwise optional
index 1276224..4d07d70 100644 (file)
@@ -1,6 +1,6 @@
 IOPT PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
@@ -78,7 +78,7 @@ ExtendedServiceDiscoveryProfile_IP_PAN                        SDP. Version: IP-PAN
 TSPC_support_                          False           Support for: Extended
 ExtendedServiceDiscoveryProfile_L2CAP                  SDP. Version: L2CAP
 
-TSPC_support_FAXProfile_DE             False           Support for: FAX Profile
+TSPC_support_FAXProfile_DT             False           Support for: FAX Profile
                                                        Role: Data Terminal
 
 TSPC_support_FAXProfile_GW             False           Support for: FAX Profile
@@ -96,7 +96,7 @@ TSPC_support_HealthDeviceProfile_Sink True (*)        Support for: HDP
 TSPC_support_HealthDeviceProfile_Source        False           Support for: HDP
                                                        Role: Source
 
-TSPC_support_NewHandsFreeProfile_AG    True            Support for: HFP
+TSPC_support_NewHandsFreeProfile_AG    True (*)        Support for: HFP
                                                        Role: Audio gateway
 
 TSPC_support_NewHandsFreeProfile_HF    False           Support for: HFP
index dd71ab4..70e0b66 100644 (file)
@@ -1,6 +1,6 @@
 MCAP PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
index b2cf16f..4284da6 100644 (file)
@@ -1,6 +1,6 @@
 OPP PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
index 7c4939a..73461f5 100644 (file)
@@ -1,6 +1,6 @@
 PAN PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
@@ -18,6 +18,9 @@ TSPC_PAN_1_3  True (*)        Role: PAN User (O.1)
 TSPC_PAN_1a_1  True            BNEP: BNEP Connection Setup (M)
 TSPC_PAN_1a_2  True            BNEP: BNEP Data Packet Reception (M)
 TSPC_PAN_1a_3  True            BNEP: BNEP Data Packet Transmission (M)
+TSPC_PAN_1a_3a True            BNEP: BNEP Compressed Packet Transmission (O)
+TSPC_PAN_1a_3b True            BNEP: BNEP Compressed Packet Transmission
+                                                               Source Only (O)
 TSPC_PAN_1a_4  True            BNEP: BNEP Control Message Processing (M)
 TSPC_PAN_1a_5  True            BNEP: BNEP Extension Header Processing (M)
 TSPC_PAN_1a_6  False           BNEP: Network Protocol Filter Message
index cb4126c..afd100b 100644 (file)
@@ -1,6 +1,6 @@
 PBAP PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
@@ -8,26 +8,37 @@ PTS version: 5.3
 M - mandatory
 O - optional
 
-               Major Profile Version (X.Y)
+
+               Roles
+-------------------------------------------------------------------------------
+Parameter Name Selected        Description
+-------------------------------------------------------------------------------
+TSPC_PBAP_1_1  False           Role: PCE (C.1)
+TSPC_PBAP_1_2  True (*)        Role: PSE (C.1)
+-------------------------------------------------------------------------------
+C1: It is mandatory to support at least one of the defined roles.
+-------------------------------------------------------------------------------
+
+
+               Client Major Profile Version (X.Y)
 -------------------------------------------------------------------------------
 Parameter Name Selected        Description
 -------------------------------------------------------------------------------
-TSPC_PBAP_0_1  False           Role: PBAP 1.0 (C.1)
-TSPC_PBAP_0_2  True (*)        Role: PBAP 1.1 (C.1)
-TSPC_PBAP_0_3  False           Role: PBAP 1.2 (C.1)
+TSPC_PBAP_2a_1 False           PBAP 1.0 (C.1)
+TSPC_PBAP_2a_2 False           PBAP 1.1 (C.1)
+TSPC_PBAP_2a_3 False           PBAP 1.2 (C.1)
 -------------------------------------------------------------------------------
 C.1: Mandatory to support one and only one major profile version.
 -------------------------------------------------------------------------------
 
 
-               Roles
+               Client Minor Profile Version (X.Y)
 -------------------------------------------------------------------------------
 Parameter Name Selected        Description
 -------------------------------------------------------------------------------
-TSPC_PBAP_1_1  False           Role: PCE (C.1)
-TSPC_PBAP_1_2  True (*)        Role: PSE (C.1)
+TSPC_PBAP_2b_1 False           PBAP 1.1.1 (C.1)
 -------------------------------------------------------------------------------
-C1: It is mandatory to support at least one of the defined roles.
+C.1: Optional if 2a/2 (PBAP 1.1) is supported, otherwise Excluded.
 -------------------------------------------------------------------------------
 
 
@@ -169,7 +180,29 @@ TSPC_PBAP_8_8      False (*)       PCE: Forbidden (M)
 -------------------------------------------------------------------------------
 
 
-               Supported features ( PSE )
+               Server Major Profile Version (X.Y)
+-------------------------------------------------------------------------------
+Parameter Name Selected        Description
+-------------------------------------------------------------------------------
+TSPC_PBAP_9a_1 False           PBAP 1.0 (C.1)
+TSPC_PBAP_9a_2 True (*)        PBAP 1.1 (C.1)
+TSPC_PBAP_9a_3 False           PBAP 1.2 (C.1)
+-------------------------------------------------------------------------------
+C.1: Mandatory to support one and only one major profile version.
+-------------------------------------------------------------------------------
+
+
+               Server Minor Profile Version (X.Y.Z)
+-------------------------------------------------------------------------------
+Parameter Name Selected        Description
+-------------------------------------------------------------------------------
+TSPC_PBAP_9b_1 False           PBAP 1.1.1 (C.1)
+-------------------------------------------------------------------------------
+C.1: Optional if 9a/2 (PBAP 1.1) is supported, otherwise Excluded.
+-------------------------------------------------------------------------------
+
+
+               Supported features (PSE)
 -------------------------------------------------------------------------------
 Parameter Name Selected        Description
 -------------------------------------------------------------------------------
@@ -430,7 +463,7 @@ C.1: Optional to support if TSPC_PBAP_25_4 (OBEX SRM) is supported,
 -------------------------------------------------------------------------------
 Parameter Name Selected        Description
 -------------------------------------------------------------------------------
-TSPC_PBAP_26_1 False (*)       PSE: GOEP v2.0 or later (M)
+TSPC_PBAP_26_1 False           PSE: GOEP v2.0 or later (M)
 TSPC_PBAP_26_2 False (*)       PSE: GOEP v2 Backwards Compatibility (M)
 TSPC_PBAP_26_3 False           PSE: OBEX over L2CAP (M)
 TSPC_PBAP_26_4 False           PSE: OBEX SRM (M)
index c970363..384f81d 100644 (file)
@@ -1,6 +1,6 @@
 RFCOMM PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
index db97c3a..6e4f599 100644 (file)
@@ -1,6 +1,6 @@
 ScPP PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 
index cb98130..9aae190 100644 (file)
@@ -1,5 +1,8 @@
+SDP PICS for the PTS tool.
 
-* - different than BITE defaults
+PTS version: 6.0
+
+* - different than PTS defaults
 # - not yet implemented/supported
 
 M - mandatory
@@ -10,9 +13,9 @@ O - optional
 -------------------------------------------------------------------------------
 Item           Selected        Description
 -------------------------------------------------------------------------------
-E.1.1          True            Support for 128 bit UUID (M)
-E.1.2          True            Support for 32 bit UUID (M)
-E.1.3          True            Support for 16 bit UUID (M)
+TSPC_SDP_1_1   True            Support for 128 bit UUID (M)
+TSPC_SDP_1_2   True            Support for 32 bit UUID (M)
+TSPC_SDP_1_3   True            Support for 16 bit UUID (M)
 -------------------------------------------------------------------------------
 
 
@@ -20,8 +23,8 @@ E.1.3         True            Support for 16 bit UUID (M)
 -------------------------------------------------------------------------------
 Item           Selected        Description
 -------------------------------------------------------------------------------
-E.1b.1         True            Support for server role (C.1)
-E.1b.2         True            Support for client role (C.1)
+TSPC_SDP_1b_1  True (*)        Support for server role (C.1)
+TSPC_SDP_1b_2  True (*)        Support for client role (C.1)
 -------------------------------------------------------------------------------
 C.1 Mandatory to support at least one of the roles
 -------------------------------------------------------------------------------
@@ -31,11 +34,11 @@ C.1 Mandatory to support at least one of the roles
 -------------------------------------------------------------------------------
 Item           Selected        Description
 -------------------------------------------------------------------------------
-E.2.1          True            Support for respond on search of single
+TSPC_SDP_2_1   True (*)        Support for respond on search of single
                                Service, using ServiceSearchRequest (C.2)
-E.2.2          True            Support for respond on search of Service,
+TSPC_SDP_2_2   True (*)        Support for respond on search of Service,
                                using continuation state (O)
-E.2.3          True            Search for services using the continuation
+TSPC_SDP_2_3   True (*)        Search for services using the continuation
                                state (C.1)
 -------------------------------------------------------------------------------
 C.1 Mandatory to support if the client role is supported (1b/2)
@@ -47,7 +50,7 @@ C.2 Mandatory to support if the server role is supported (1b/1)
 -------------------------------------------------------------------------------
 Item           Selected        Description
 -------------------------------------------------------------------------------
-E.3.1          True            Support for error response on Service search
+TSPC_SDP_3_1   True            Support for error response on Service search
                                request (M)
 -------------------------------------------------------------------------------
 
@@ -56,11 +59,11 @@ E.3.1               True            Support for error response on Service search
 -------------------------------------------------------------------------------
 Item           Selected        Description
 -------------------------------------------------------------------------------
-E.4.1          True            Support for respond on search of
+TSPC_SDP_4_1   True            Support for respond on search of
                                Attribute(s) (M)
-E.4.2          True            Support for respond on search of
+TSPC_SDP_4_2   True (*)        Support for respond on search of
                                Attribute, using continuation state (O)
-E.4.3          True            Support for respond on search on
+TSPC_SDP_4_3   True (*)        Support for respond on search on
                                attribute AdditionalProtocolDescriptorList (O)
 -------------------------------------------------------------------------------
 
@@ -69,7 +72,7 @@ E.4.3         True            Support for respond on search on
 -------------------------------------------------------------------------------
 Item           Selected        Description
 -------------------------------------------------------------------------------
-E.5.1          True            Support for error response on Attribute
+TSPC_SDP_5_1   True            Support for error response on Attribute
                                search request (M)
 -------------------------------------------------------------------------------
 
@@ -78,11 +81,11 @@ E.5.1               True            Support for error response on Attribute
 -------------------------------------------------------------------------------
 Item           Selected        Description
 -------------------------------------------------------------------------------
-E.6.1          True            Support for respond on search for Service(s)
+TSPC_SDP_6_1   True            Support for respond on search for Service(s)
                                and Attribute(s) (M)
-E.6.2          True            Support for respond on search of Attribute,
+TSPC_SDP_6_2   True (*)        Support for respond on search of Attribute,
                                using continuation state (O)
-E.6.3          True            Support for respond on search on attribute
+TSPC_SDP_6_3   True (*)        Support for respond on search on attribute
                                AdditionalProtocolDescriptorList on existing
                                service (O)
 -------------------------------------------------------------------------------
@@ -92,7 +95,7 @@ E.6.3         True            Support for respond on search on attribute
 -------------------------------------------------------------------------------
 Item           Selected        Description
 -------------------------------------------------------------------------------
-E.7.1          True            Support for error response on Service and
+TSPC_SDP_7_1   True            Support for error response on Service and
                                Attribute request (M)
 -------------------------------------------------------------------------------
 
@@ -101,10 +104,10 @@ E.7.1             True            Support for error response on Service and
 -------------------------------------------------------------------------------
 Item           Selected        Description
 -------------------------------------------------------------------------------
-E.8.1          True            Support for browsing, using
+TSPC_SDP_8_1   True (*)        Support for browsing, using
                                SDP_ServiceSearchRequest and
                                SDP_ServiceAttributeRequest (O)
-E.8.2          True            Support for browsing, using
+TSPC_SDP_8_2   True (*)        Support for browsing, using
                                SDP_ServiceSearchAttributeRequest (O)
 -------------------------------------------------------------------------------
 
@@ -113,25 +116,25 @@ E.8.2             True            Support for browsing, using
 -------------------------------------------------------------------------------
 Item           Selected        Description
 -------------------------------------------------------------------------------
-E.9.1          True            ServiceID (O)
-E.9.2          True            ProtocolDescriptorList (O)
-E.9.3          True            ServiceRecordState (O)
-E.9.4          True            ServiceInfoTimeToLive (O)
-E.9.5          True            BrowseGroupList (O)
-E.9.6          True            LanguageBaseAttributeIdList (O)
-E.9.7          True            ServiceAvailability (O)
-E.9.8          True            IconURL (O)
-E.9.9          True            ServiceName (O)
-E.9.10         True            ServiceDescription (O)
-E.9.11         True            ProviderName (O)
-E.9.12         True            VersionNumberList (O)
-E.9.13         True            ServiceDataBaseState (O)
-E.9.14         True            BluetoothProfileDescriptorList (O)
-E.9.15         True            DocumentationURL (O)
-E.9.16         True            ClientExecutableURL (O)
-E.9.17         True            AdditionalProtocolDescriptorList (C.1)
-E.9.18         True            ServiceRecordHandle (M)
-E.9.19         True            ServiceClassIDList (M)
+TSPC_SDP_9_1   True (*)        ServiceID (O)
+TSPC_SDP_9_2   True (*)        ProtocolDescriptorList (O)
+TSPC_SDP_9_3   True (*)        ServiceRecordState (O)
+TSPC_SDP_9_4   True (*)        ServiceInfoTimeToLive (O)
+TSPC_SDP_9_5   True (*)        BrowseGroupList (O)
+TSPC_SDP_9_6   True (*)        LanguageBaseAttributeIdList (O)
+TSPC_SDP_9_7   True (*)        ServiceAvailability (O)
+TSPC_SDP_9_8   True (*)        IconURL (O)
+TSPC_SDP_9_9   True (*)        ServiceName (O)
+TSPC_SDP_9_10  True (*)        ServiceDescription (O)
+TSPC_SDP_9_11  True (*)        ProviderName (O)
+TSPC_SDP_9_12  True (*)        VersionNumberList (O)
+TSPC_SDP_9_13  True (*)        ServiceDataBaseState (O)
+TSPC_SDP_9_14  True (*)        BluetoothProfileDescriptorList (O)
+TSPC_SDP_9_15  True (*)        DocumentationURL (O)
+TSPC_SDP_9_16  True (*)        ClientExecutableURL (O)
+TSPC_SDP_9_17  True (*)        AdditionalProtocolDescriptorList (C.1)
+TSPC_SDP_9_18  True            ServiceRecordHandle (M)
+TSPC_SDP_9_19  True            ServiceClassIDList (M)
 -------------------------------------------------------------------------------
 C.1: Optional if 9/2 is supported, otherwise excluded
 -------------------------------------------------------------------------------
index c1bfe0e..c5caec6 100644 (file)
@@ -1,6 +1,6 @@
 SM PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 
index f015236..d9bb883 100644 (file)
@@ -1,6 +1,6 @@
 SPP PICS for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 # - not yet implemented/supported
index 3e26eac..b6ef742 100644 (file)
@@ -1,6 +1,6 @@
 A2DP PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
@@ -10,7 +10,7 @@ Required PIXIT settings
 -------------------------------------------------------------------------------
 Parameter Name                 Value
 -------------------------------------------------------------------------------
-TSPX_security_enabled          FALSE
+TSPX_security_enabled          TRUE (*)
 TSPX_bd_addr_iut               112233445566 (*&)
 TSPX_SRC_class_of_device       080418
 TSPX_SNK_class_of_device       04041C
@@ -20,7 +20,7 @@ TSPX_time_guard                       300000
 TSPX_use_implicit_send         TRUE
 TSPX_media_directory           C:\Program Files\Bluetooth SIG\Bluetooth PTS\
                                        bin\audio (#)
-TSPX_no_avrcp                  TRUE
+TSPX_no_avrcp                  FALSE (*)
 TSPX_auth_password             0000
 TSPX_auth_user_id              PTS
 TSPX_rfcomm_channel            8
index f380e96..4b2c783 100644 (file)
@@ -1,6 +1,6 @@
 AVCTP PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
index b548ffe..c4b7ed8 100644 (file)
@@ -1,6 +1,6 @@
 AVDTP PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
index f576bd0..c429828 100644 (file)
@@ -1,6 +1,6 @@
 AVRCP PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
@@ -18,7 +18,7 @@ TSPX_pin_code                 0000
 TSPX_delete_link_key           FALSE
 TSPX_time_guard                        300000
 TSPX_avrcp_only                        FALSE
-TSPX_search_string             tomorrow
+TSPX_search_string             3
 TSPX_max_avc_fragments         10
 TSPX_establish_avdtp_stream    TRUE
 TSPX_use_implicit_send         TRUE
index 99f411b..295febc 100644 (file)
@@ -1,6 +1,6 @@
 DID PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
index 71729fe..13fe78f 100644 (file)
@@ -1,6 +1,6 @@
 DIS PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
@@ -22,4 +22,5 @@ TSPX_delete_ltk                                               FALSE
 TSPX_security_enabled                                  TRUE (*)
 TSPX_iut_setup_att_over_br_edr                         FALSE
 TSPX_tester_appearance                                 0000
+TSPX_iut_use_resolvable_random_address                 FALSE
 -------------------------------------------------------------------------------
index 6bde304..7a7107c 100644 (file)
@@ -1,9 +1,10 @@
 GAP PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
+# - should be set to IUT name
 
                Required PIXIT settings
 -------------------------------------------------------------------------------
@@ -30,8 +31,8 @@ TSPX_lim_disc_scan_min                                        10240
 TSPX_gen_disc_scan_min                                 10240
 TSPX_database_file                                     Database-GAP.sig
 TSPX_iut_rx_mtu                                                23
-TSPX_iut_private_address_interval                      10000
-TSPX_iut_privacy_enabled                               True (*)
+TSPX_iut_private_address_interval                      30000 (*)
+TSPX_iut_privacy_enabled                               False
 TSPX_psm                                               1001
 TSPX_iut_valid_connection_interval_min                 00C8
 TSPX_iut_valid_conneciton_interval_max                 0960
@@ -55,4 +56,5 @@ TSPX_iut_mandates_mitm                                        False
 TSPX_encryption_before_service_request                 False
 TSPX_tester_appearance                                 0000
 TSPX_iut_advertising_data_in_broadcasting_mode         [set to default value]
+TSPX_iut_device_name_in_adv_packet_for_random_address  PTS-66DE (#)
 -------------------------------------------------------------------------------
index 191e2c9..04a5d0b 100644 (file)
@@ -1,6 +1,6 @@
 GATT PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
@@ -28,4 +28,5 @@ TSPX_use_dynamic_pin                                  FALSE
 TSPX_delete_ltk                                                FALSE
 TSPX_characteristic_readable                           FALSE
 TSPX_tester_appearance                                 0000
+TSPX_iut_use_resolvable_random_access                  FALSE
 -------------------------------------------------------------------------------
diff --git a/android/pixit-gavdp.txt b/android/pixit-gavdp.txt
new file mode 100644 (file)
index 0000000..98e7790
--- /dev/null
@@ -0,0 +1,32 @@
+GAVDP PIXIT for the PTS tool.
+
+PTS version: 6.0
+
+* - different than PTS defaults
+& - should be set to IUT Bluetooth address
+^ - should be set accordingly
+# - should be set to PTS's bin/audio folder
+
+               Required PIXIT settings
+-------------------------------------------------------------------------------
+Parameter Name                                         Value
+-------------------------------------------------------------------------------
+TSPX_SNK_class_of_device       04041C
+TSPX_SRC_class_of_device       080418
+TSPX_bd_addr_iut               112233445566 (*&)
+TSPX_delete_link_key           FALSE
+TSPX_media_directory           C:\Program Files\Bluetooth SIG\Bluetooth PTS\
+                                       bin\audio (#)
+TSPX_no_avrcp                  FALSE
+TSPX_pin_code                  0000
+TSPX_security_enabled          FALSE
+TSPX_tester_av_role
+TSPX_time_guard                        300000
+TSPX_use_implicit_send         TRUE
+TSPX_auth_password             0000
+TSPX_auth_user_id              PTS
+TSPX_rfcomm_channel            8
+TSPX_l2cap_psm                 1011
+TSPX_no_confirmations          FALSE
+TSPX_cover_art_uuid
+-------------------------------------------------------------------------------
index e19b1e4..ccf0cf3 100644 (file)
@@ -1,6 +1,6 @@
 HDP PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
@@ -12,8 +12,8 @@ Parameter Name                                                Value
 TSPX_security_enabled                                  TRUE
 TSPX_delete_link_key                                   FALSE
 TSPX_bd_addr_iut                                       112233445566 (*&)
-TSPX_sink_device_class_of_device                       00900
-TSPX_source_device_class_of_device                     00900
+TSPX_sink_device_class_of_device                       000900
+TSPX_source_device_class_of_device                     000900
 TSPX_pin_code                                          0000
 TSPX_use_dynamic_pin                                   FALSE
 TSPX_use_implicit_send                                 TRUE
index bf1b7e5..dfae9bf 100644 (file)
@@ -1,6 +1,6 @@
 HFP PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
index 42a3310..3c93fca 100644 (file)
@@ -1,6 +1,6 @@
 HID PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
@@ -27,4 +27,5 @@ TSPX_no_fail_verdicts                                 False
 TSPX_time_reconnect                                    30000
 TSPX_secure_simple_pairing_pass_key_confirmation       False
 TSPX_hid_report_id                                     1
+TSPX_hid_report_data                                   ff00 (*)
 -------------------------------------------------------------------------------
index d32fe69..e72948e 100644 (file)
@@ -1,6 +1,6 @@
 HOGP PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
@@ -25,4 +25,5 @@ TSPX_input_report_data                                        CDA6F8B3AA
 TSPX_output_report_data                                        001234567890EF
 TSPX_feature_report_data                               872D3F45EA
 TSPX_tester_appearance                                 03C0
+TSPX_iut_use_resolvable_random_address FALSE
 -------------------------------------------------------------------------------
index 6be4731..d7a8e3c 100644 (file)
@@ -1,6 +1,6 @@
 HSP PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
index 53837de..4cc6fd4 100644 (file)
@@ -1,6 +1,6 @@
 IOPT PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
index d05a953..f3d33a1 100644 (file)
@@ -1,6 +1,6 @@
 MCAP PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
@@ -11,7 +11,7 @@ Parameter Name                                                Value
 -------------------------------------------------------------------------------
 TSPX_bd_addr_iut                                       112233445566 (*&)
 TSPX_delete_link_key                                   FALSE
-TSPX_MCAP_DC_max                                       1
+TSPX_MCAP_DC_max                                       1 (*)
 TSPX_MCAP_l2cap_psm_control                            1003
 TSPX_MCAP_l2cap_psm_control_B
 TSPX_MCAP_l2cap_psm_data                               1005
index 9cd4bb1..385cc1f 100644 (file)
@@ -1,6 +1,6 @@
 OPP PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
index 680abb2..6c00d27 100644 (file)
@@ -1,9 +1,9 @@
 PAN PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
-& - should be set to IUT or PTS Bluetooth address respectively
+& - should be set to IUT or PTS Bluetooth/MAC address respectively
 
                Required PIXIT settings
 -------------------------------------------------------------------------------
@@ -27,4 +27,13 @@ TSPX_checksum                                                E851
 TSPX_secure_simple_pairing_pass_key_confirmation       False
 TSPX_iut_friendly_bt_name                              gprs-pc
 TSPX_PTS_role_when_iut_is_PANU                         default
+TSPX_auth_password                                     0000
+TSPX_auth_user_id                                      PTS
+TSPX_l2cap_psm                                         000F
+TSPX_rfcomm_channel                                    8
+TSPX_no_confirmations                                  FALSE
+TSPX_UUID_dest_address                                 0000
+TSPX_UUID_source_address                               0000
+TSPX_MAC_dest_address                                  112233445566 (*&)
+TSPX_MAC_source_address                                        112233445566 (*&)
 -------------------------------------------------------------------------------
index f7a93c6..034456a 100644 (file)
@@ -1,6 +1,6 @@
 PBAP PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
index 187f3b4..a3fbb27 100644 (file)
@@ -1,6 +1,6 @@
 RFCOMM PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
index cdf0b01..105c46a 100644 (file)
@@ -1,6 +1,6 @@
 ScPP PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
@@ -21,4 +21,5 @@ TSPX_use_dynamic_pin                                  FALSE
 TSPX_delete_ltk                                                FALSE
 TSPX_security_enabled                                  FALSE
 TSPX_tester_appearance                                 0000
+TSPX_iut_use_resolvable_random_address                 FALSE
 -------------------------------------------------------------------------------
diff --git a/android/pixit-sdp.txt b/android/pixit-sdp.txt
new file mode 100644 (file)
index 0000000..2875256
--- /dev/null
@@ -0,0 +1,45 @@
+SDP PIXIT for the PTS tool.
+
+PTS version: 6.0
+
+* - different than PTS defaults
+& - should be set to IUT Bluetooth address
+^ - should be set accordingly
+# - should be set according to the reported phone number's type
+
+               Required PIXIT settings
+-------------------------------------------------------------------------------
+Parameter Name                                                 Value
+-------------------------------------------------------------------------------
+TSPX_sdp_service_search_pattern                                        0100
+TSPX_sdp_service_search_pattern_no_results                     EEEE
+TSPX_sdp_service_search_additional_protocol_descriptor_list
+TSPX_sdp_service_search_bluetooth_profile_descriptor_list
+TSPX_sdp_service_search_pattern_browse_group_list
+TSPX_sdp_service_search_pattern_client_exe_url
+TSPX_sdp_service_search_pattern_documentation_url
+TSPX_sdp_service_search_pattern_icon_url
+TSPX_sdp_service_search_pattern_language_base_attribute_id_list
+TSPX_sdp_service_search_pattern_protocol_descriptor_list
+TSPX_sdp_service_search_pattern_provider_name
+TSPX_sdp_service_search_pattern_service_availability
+TSPX_sdp_service_search_pattern_service_data_base_state                1000(*)
+TSPX_sdp_service_search_pattern_service_description
+TSPX_sdp_service_search_pattern_service_id
+TSPX_sdp_service_search_pattern_service_info_time_to_live
+TSPX_sdp_service_search_pattern_version_number_list            1000(*)
+TSPX_sdp_service_search_pattern_service_name
+TSPX_sdp_service_search_pattern_service_record_state
+TSPX_sdp_unsupported_attribute_id
+TSPX_security_enabled                                          FALSE
+TSPX_delete_link_key                                           FALSE
+TSPX_bd_addr_iut                                               112233445566(*&)
+TSPX_class_of_device_pts                                       200404
+TSPX_class_of_device_test_pts_initiator                                TRUE
+TSPX_limited_inquiry_used                                      FALSE
+TSPX_pin_code                                                  0000
+TSPX_time_guard                                                        200000
+TSPX_device_search_time                                                20
+TSPX_use_implicit_send                                         TRUE
+TSPX_secure_simple_pairing_pass_key_confirmation               FALSE
+-------------------------------------------------------------------------------
index 2d1442b..98e2ab5 100644 (file)
@@ -1,6 +1,6 @@
 SM PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
index a8a8202..8e2d70f 100644 (file)
@@ -1,6 +1,6 @@
 SPP PIXIT for the PTS tool.
 
-PTS version: 5.3
+PTS version: 6.0
 
 * - different than PTS defaults
 & - should be set to IUT Bluetooth address
index 92c3e15..500c631 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for A2DP
 
-PTS version: 5.3
-Tested: 19-November-2014
+PTS version: 6.0
+Tested: 14-January-2015
 Android version: 5.0
 
 Results:
@@ -15,7 +15,7 @@ N/A   test is disabled due to PICS setup
 Test Name              Result  Notes
 -------------------------------------------------------------------------------
 TC_SRC_CC_BV_09_I      PASS    Start streaming
-TC_SRC_CC_BV_10_I      N/A
+TC_SRC_CC_BV_10_I      PASS
 TC_SRC_REL_BV_01_I     PASS    Connect to PTS from IUT. When requested
                                disconnect from IUT
 TC_SRC_REL_BV_02_I     PASS
@@ -24,12 +24,15 @@ TC_SRC_SET_BV_02_I  PASS
 TC_SRC_SET_BV_03_I     PASS    Start streaming
 TC_SRC_SET_BV_04_I     PASS    Start streaming
 TC_SRC_SET_BV_05_I     PASS    IUT must be moved out of range
+                               JIRA issue BA-314
 TC_SRC_SET_BV_06_I     PASS    IUT must be moved out of range
 TC_SRC_SUS_BV_01_I     PASS    Stop streaming
 TC_SRC_SUS_BV_02_I     PASS
 TC_SRC_SDP_BV_01_I     PASS
 TC_SRC_AS_BV_01_I      PASS    Requires checking if the output on the IUT is
                                correct
+TC_SRC_AS_BV_02_I      N/A
+TC_SRC_AS_BV_03_I      N/A
 -------------------------------------------------------------------------------
 
 
index 7a5f4ce..d05aa05 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for AVCTP
 
-PTS version: 5.3
-Tested: 03-December-2014
+PTS version: 6.0
+Tested: 11-February-2015
 Android version: 5.0
 
 Results:
@@ -21,6 +21,7 @@ TC_CT_CCM_BV_04_C     N/A
 TC_CT_CCM_BI_01_C      N/A
 TC_CT_NFR_BV_01_C      N/A
 TC_CT_NFR_BV_04_C      PASS    haltest: rc set_volume 5
+                               Note: IUT must be connectable and discoverable
 TC_CT_FRA_BV_01_C      N/A
 TC_CT_FRA_BV_04_C      N/A
 -------------------------------------------------------------------------------
index 6ff8624..683ba6d 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for AVDTP
 
-PTS version: 5.3
-Tested: 24-November-2014
+PTS version: 6.0
+Tested: 16-January-2015
 Android version: 5.0
 
 Results:
@@ -56,9 +56,7 @@ TC_ACP_SNK_SIG_SMG_BI_34_C            N/A
 TC_ACP_SNK_SIG_SMG_ESR04_BI_28_C       PASS    avdtptest -d SINK -l
 TC_ACP_SNK_SIG_SMG_ESR05_BI_15_C       N/A
 TC_ACP_SNK_SIG_SYN_BV_01_C             PASS    avdtptest -d SINK -l
-TC_ACP_SNK_SIG_SYN_BV_02_C             PASS    avdtptest -d SINK -l -p
 TC_ACP_SNK_SIG_SYN_BV_03_C             PASS    avdtptest -d SINK -l
-TC_ACP_SNK_SIG_SYN_BV_04_C             PASS    avdtptest -d SINK -l -p
 TC_ACP_SNK_TRA_BTR_BI_01_C             PASS    avdtptest -d SINK -l
 TC_ACP_SNK_TRA_BTR_BV_02_C             PASS    avdtptest -d SINK -l
 TC_ACP_SNK_TRA_MUX_BI_01_C             N/A
index e6711ed..955b37e 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for AVRCP
 
-PTS version: 5.3
-Tested: 20-November-2014
+PTS version: 6.0
+Tested: 21-January-2015
 Android version: 5.0
 
 Results:
@@ -83,10 +83,11 @@ TC_CT_VLH_BI_03_C   PASS    Send SetAbsolute Volume command by pressing
 TC_CT_VLH_BI_04_C      PASS    adb logcat: check VOLUME_CHANGED value
 TC_CT_VLH_BV_01_C      PASS    Send SetAbsolute Volume command by pressing
                                volume up or down buttons
-TC_CT_VLH_BV_01_I      PASS    adb logcat: check VOLUME_CHANGED value
-TC_CT_VLH_BV_02_I      PASS    Send SetAbsolute Volume command by pressing
+TC_CT_VLH_BV_03_C      PASS    adb logcat: check VOLUME_CHANGED value
+TC_CT_VLH_BV_01_I      PASS    Send SetAbsolute Volume command by pressing
+                               volume up or down buttons
+TC_CT_VLH_BV_02_I      PASS    Send SetAbsolute Volume command by pressing
                                volume up or down buttons
-TC_CT_VLH_BV_03_C      PASS
 -------------------------------------------------------------------------------
 
 
@@ -188,8 +189,10 @@ TC_TG_PTT_BV_02_I  PASS
 TC_TG_PTT_BV_03_I      N/A
 TC_TG_PTT_BV_04_I      N/A
 TC_TG_PTT_BV_05_I      N/A
-TC_TG_RCR_BV_02_C      PASS    One can use: lame --ta/tl for creating metadata
-TC_TG_RCR_BV_04_C      PASS
+TC_TG_RCR_BV_02_C      PASS    Use modified media metadata (artist, title,
+                                       album etc.) to be larger than 512 byte.
+TC_TG_RCR_BV_04_C      PASS    Use modified media metadata (artist, title,
+                                       album etc.) to be larger than 512 byte.
 TC_TG_VLH_BI_01_C      N/A
 TC_TG_VLH_BI_02_C      N/A
 TC_TG_VLH_BV_01_I      N/A
index fedf779..8fd434d 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for DID
 
-PTS version: 5.3
-Tested: 07-November-2014
+PTS version: 6.0
+Tested: 22-January-2015
 Android version: 5.0
 
 Results:
index fb67687..857a149 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for DIS
 
-PTS version: 5.3
-Tested: 26-November-2014
+PTS version: 6.0
+Tested: 22-January-2015
 Android version: 5.0
 
 Results:
index c597258..9c8be0f 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for GAP
 
-PTS version: 5.3
-Tested: 05-December-2014
+PTS version: 6.0
+Tested: 19-January-2015
 Android version: 5.0
 Kernel version: 3.18
 
@@ -46,20 +46,24 @@ TC_DISC_LIMM_BV_03_C        PASS    btmgmt connectable on
                                btmgmt discov off
                                <answer NO to non-connectable adv question>
                                btmgmt discov limited 30
+                               btmgmt advertising on
 TC_DISC_LIMM_BV_04_C   PASS    btmgmt connectable on
                                btmgmt discov off
                                btmgmt power off
                                btmgmt bredr off
                                btmgmt power on
                                btmgmt discov limited 30
+                               btmgmt advertising on
 TC_DISC_GENM_BV_01_C   PASS    btmgmt connectable on
                                btmgmt discov on
+                               btmgmt advertising on
                                <answer NO to non-connectable adv question>
 TC_DISC_GENM_BV_02_C   PASS    btmgmt connectable on
                                btmgmt advertising on
                                btmgmt discov on
 TC_DISC_GENM_BV_03_C   PASS    btmgmt connectable on
                                btmgmt discov on
+                               btmgmt advertising on
                                <answer NO to non-connectable adv question>
 TC_DISC_GENM_BV_04_C   PASS    btmgmt connectable on
                                btmgmt power off
@@ -90,12 +94,12 @@ TC_DISC_GENP_BV_05_C        PASS    btmgmt find -l
                                PTS AD flags must have bit 1 and bit 0 unset
 TC_IDLE_GIN_BV_01_C    PASS    Start discovery from IUT
 TC_IDLE_LIN_BV_01_C    PASS    hcitool scan --iac=liac
-TC_IDLE_NAMP_BV_01_C   PASS    possible to PASS using haltest following steps:
-                               gattc - register client, connect to PTS, search
-                               all services, get characteristic and then read
-                               characteristic (name)
-TC_IDLE_NAMP_BV_02_C   PASS    PTS issue #12679
-                               haltest: gatts connect
+TC_IDLE_NAMP_BV_01_C   PASS    haltest: gattc register_client
+                               gattc listen 1
+                               gattc search_service 1 1800
+                               gattc get_characteristic 1 {1800,0,1}
+                               gattc read_characteristic 1 {1800,0,1} {2a00,1}
+TC_IDLE_NAMP_BV_02_C   PASS    btmgmt advertising on
 TC_CONN_NCON_BV_01_C   PASS    btmgmt connectable off
                                btmgmt advertising on
                                <answer NO to non-connectable adv question>
@@ -126,16 +130,12 @@ TC_CONN_GCEP_BV_04_C      N/A
 TC_CONN_SCEP_BV_01_C   PASS    'gattc connect' prior to pressing OK on PTS
 TC_CONN_SCEP_BV_02_C   N/A
 TC_CONN_DCEP_BV_01_C   PASS    'gattc connect' prior to pressing OK on PTS
-TC_CONN_DCEP_BV_02_C   INC     Test Spec. Errata approved - PTS issue #12600
-                               is claimed to be resolved in upcoming ETS 8400
+TC_CONN_DCEP_BV_02_C   N/A
 TC_CONN_DCEP_BV_03_C   PASS    gattc connect
 TC_CONN_DCEP_BV_04_C   N/A
-TC_CONN_CPUP_BV_01_C   PASS    gattc register_client
-                               gattc listen
-TC_CONN_CPUP_BV_02_C   PASS    gattc register_client
-                               gattc listen
-TC_CONN_CPUP_BV_03_C   PASS    gattc register_client
-                               gattc listen
+TC_CONN_CPUP_BV_01_C   PASS    btmgmt advertising on
+TC_CONN_CPUP_BV_02_C   PASS    btmgmt advertising on
+TC_CONN_CPUP_BV_03_C   PASS    btmgmt advertising on
 TC_CONN_CPUP_BV_04_C   PASS    gattc register_client
                                gattc connect
                                gattc disconnect
@@ -148,35 +148,44 @@ TC_CONN_CPUP_BV_06_C      PASS    gattc register_client
                                        0x0960
                                gattc disconnect <client_if> <pts_bdaddr>
                                        <conn_id>
-TC_CONN_TERM_BV_01_C   PASS
+TC_CONN_TERM_BV_01_C   PASS    gattc register_client
+                               gattc listen
+                               gattc disconnect
 TC_CONN_PRDA_BV_01_C   PASS    gattc register_client
                                gattc listen
                                gattc disconnect
-TC_CONN_PRDA_BV_02_C   INC     PTS issue #12310
-                               Note: PTS issues #12207 & #12310 are claimed
-                               to be resolved by the ETS provided in PTS issue
-                               #12312 however it does not solve the problem
-TC_BOND_NBON_BV_01_C   PASS
+TC_CONN_PRDA_BV_02_C   INC     PTS issue #12950
+                               gattc register_client
+                               bluetooth create_bond
+                               gattc connect
+TC_BOND_NBON_BV_01_C   PASS    haltest:
+                               gattc register_client
+                               gattc connect
+                               gatt disconnect
+                               gattc connect
+                               gatt disconnect
 TC_BOND_NBON_BV_02_C   PASS    haltest: gattc register_client
                                gattc connect <client_id> <address>
                                bluetooth create_bond <address>
-                               bluetooth remove_bond <address>
+                               gattc connect <client_id> <address>
+                               bluetooth create_bond <address>
 TC_BOND_NBON_BV_03_C   PASS    haltest: gattc listen
 TC_BOND_BON_BV_01_C    PASS    PTS issue #12503
-                               possible to pass without MITM:
-                               btmgmt power on
-                               btmgmt le on
-                               btmgmt ssp on
-                               btmgmt connectable on
-                               btmgmt discov on
-                               btmgmt advertising on
-                               btmgmt pairable on
-                               To bond with PTS execute
-                               btmgmt pair -t 0x01 -c 0x03 <PTS addr>
-TC_BOND_BON_BV_02_C    PASS
-TC_BOND_BON_BV_03_C    PASS    PTS issue #12678
+                               haltest:
+                               bluetooth set_adapter_property
+                                       BT_PROPERTY_ADAPTER_SCAN_MODE
+                                       BT_SCAN_MODE_CONNECTABLE
                                gattc register_client
                                gattc listen 1
+                               bluetooth create_bond <pts_address>
+TC_BOND_BON_BV_02_C    PASS    gattc regicter_client
+                               gattc scan
+                               gattc connect
+                               bluetooth create_bond
+                               gattc connect
+                               gattc test_command 226 <addr> <uuid> 1
+TC_BOND_BON_BV_03_C    PASS    gattc register_client
+                               gattc listen 1
 TC_BOND_BON_BV_04_C    PASS    haltest: gattc_register_client
                                gattc connect <client_id> <address>
                                gattc disconnect
@@ -187,43 +196,39 @@ TC_SEC_AUT_BV_11_C        PASS    haltest: gattc register_client
                                gatts add_service 2 <uuid> 3
                                gatts add_characteristic 2 1b <uuid> 10 68
                                gatts start_service 2 1b 1
-                               gattc listen
+                               gattc listen 1
                                PTS asks for handle with Insufficient auth
-                               bluetooth ssp_reply <addr> <passkey>
-                               gatts send_response
-TC_SEC_AUT_BV_12_C     INC     PTS issue #12657
-                               haltest: gatts register_server
-                               gatts add_service 2 <uuid> 3
-                               gatts add_characteristic 2 <service_handle>
-                                                               <uuid> 10 68
-                               gatts start_service 2 <service_handle> 1
-                               gatts connect <server_if> <addr>
+                               gatts send_response 1 1 0 1d 0 0x1234
+TC_SEC_AUT_BV_12_C     PASS    haltest: gatts register_server
+                               gatts add_service 1 <uuid> 3
+                               gatts add_characteristic 1 1b <uuid> 10 68
+                               gatts start_service 1 1b 1
+                               gatts connect 1 <addr>
                                PTS asks for handle with Insufficient auth
-                               bluetooth ssp_reply <addr> <passkey>
-                               gatts send_response
-TC_SEC_AUT_BV_13_C     INC     PTS issue #12657
-                               haltest: gatts register_server
-                               gatts add_service 2 <uuid> 3
-                               gatts add_characteristic 2 <service_handle>
-                                                               <uuid> 10 68
-                               gatts start_service 2 <service_handle> 1
-                               gatts connect <server_if> <addr>
+                               gatts send_response 1 1 0 1d 0 0x1234
+TC_SEC_AUT_BV_13_C     PASS    haltest: gatts register_server
+                               gatts add_service 1 <uuid> 3
+                               gatts add_characteristic 1 1b <uuid> 10 68
+                               gatts start_service 1 1b 1
+                               gatts connect 1 <addr>
                                PTS asks for handle with Insufficient auth
-                               bluetooth ssp_reply <addr> <passkey>
-                               gatts send_response
-TC_SEC_AUT_BV_14_C     INC     PTS issue #12657
-                               haltest:gattc register_client
+                               gatts send_response 1 1 0 1d 0 0x1234
+TC_SEC_AUT_BV_14_C     PASS    haltest: gattc register_client
                                gatts register_server
                                gatts add_service 2 <uuid> 3
                                gatts add_characteristic 2 1b <uuid> 10 68
                                gatts start_service 2 1b 1
-                               gattc listen
+                               gattc listen 1
                                PTS asks for handle with Insufficient auth
-                               bluetooth ssp_reply <addr> <passkey>
-                               gatts send_response
+                               gatts send_response 1 1 0 1d 0 0x1234
 TC_SEC_AUT_BV_15_C     N/A
 TC_SEC_AUT_BV_16_C     N/A
-TC_SEC_AUT_BV_17_C     PASS
+TC_SEC_AUT_BV_17_C     PASS    haltest: gattc register_client
+                               gattc connect
+                               gattc search_service
+                               gattc get_characteristic
+                               gattc read_characteristic
+                               bluetooth create_bond
 TC_SEC_AUT_BV_18_C     PASS    haltest: gattc register_client
                                gattc listen
                                gattc search_service
@@ -233,16 +238,12 @@ TC_SEC_AUT_BV_18_C        PASS    haltest: gattc register_client
                                gattc read_characteristic
 TC_SEC_AUT_BV_19_C     PASS
 TC_SEC_AUT_BV_20_C     PASS    haltest: gattc register_client
-                               gattc listen <client_id> 1
-                               Confirm bonding
-                               gattc search_service
-                               gattc get_characteristic
-                               gattc read_characteristic
-                               gattc listen <client_id> 0
-                               Click OK on PTS popup to disconnect
-                               bluetooth remove bond
-                               gattc listen <client_id> 1
-                               gattc read_characteristic
+                               gattc listen 1 1
+                               gattc search_service 2
+                               gattc get_characteristic 2 {1801,1,1}
+                               gattc read_characteristic 2 {1801,1,1} {2a05,1}
+                               gattc read_characteristic 2 {1801,1,1} {2a05,1}
+                                       1
 TC_SEC_AUT_BV_21_C     PASS    haltest: gattc register_client
                                gattc connect
                                bluetooth create_bond
@@ -252,82 +253,69 @@ TC_SEC_AUT_BV_22_C        PASS    btmgmt io-cap 3
                                haltest: gattc register_client
                                gattc listen
                                gattc test_command 226 <addr> <u1> 1
-TC_SEC_AUT_BV_23_C     INC     PTS issue #12657
-                               haltest: gatts register_server
-                               gatts add_service 2 <uuid> 3
-                               gatts add_characteristic 2 <service_handle>
-                                                               <uuid> 10 34
-                               gatts start_service 2 <service_handle> 1
-                               gattc register_client
-                               gattc listen
-                               bluetooth ssp_reply
-                               gatts send_response
-TC_SEC_AUT_BV_24_C     INC     PTS issue #12657
-                               haltest: gatts register_server
+TC_SEC_AUT_BV_23_C     PASS    haltest: gattc register_client
+                               gatts register_server
                                gatts add_service 2 <uuid> 3
-                               gatts add_characteristic 2 <service_handle>
-                                                               <uuid> 10 34
-                               gatts start_service 2 <service_handle> 1
-                               gatts connect <PTS addr>
-                               bluetooth ssp_reply
+                               gatts add_characteristic 2 1b <uuid> 10 34
+                               gatts start_service 2 1b 1
+                               gattc listen 1
+                               PTS asks for handle with insufficient encryption
+                               gatts send_response 3 1 0 1d 0 0x1234
+TC_SEC_AUT_BV_24_C     PASS    haltest: gatts register_server
+                               gatts add_service 1 <uuid> 3
+                               gatts add_characteristic 1 1b <uuid> 10 34
+                               gatts start_service 1 1b 1
+                               gatts connect
                                gatts disconnect
                                gatts connect
                                PTS asks for handle with insufficient encryption
-                               gatts send_response
+                               gatts send_response 2 1 0 1d 0 0x1234
 TC_SEC_CSIGN_BV_01_C   PASS    haltest:
                                gattc connect
                                bluetooth create_bond
                                gattc connect
                                gattc write_characteristic: <write_type> 4
                                gattc disconnect
-TC_SEC_CSIGN_BV_02_C   INC     PTS issue #12675
-                               haltest:
-                               gatts add_service
-                               gatts add_chaaracteristic:
-                                               <properties> 66
-                                               <permissions> 129
-                               gatts start_service
+TC_SEC_CSIGN_BV_02_C   PASS    haltest: gattc register_client
+                               gatts register_server
+                               gatts add_service 2 <uuid> 3
+                               gatts add_characteristic 2 1b <uuid> 66 129
+                               gatts start_service 2 1b 1
+                               gattc listen 1
                                gatts disconnect
-                               gattc disconnect
-TC_SEC_CSIGN_BI_01_C   INC     PTS issue #12675
-                               haltest:
-                               gatts add_service
-                               gatts add_chaaracteristic:
-                                               <properties> 66
-                                               <permissions> 129
-                               gatts start_service
+TC_SEC_CSIGN_BI_01_C   PASS    gattc register_client
+                               gatts register_server
+                               gatts add_service 2 <uuid> 3
+                               gatts add_characteristic 2 1b <uuid> 66 129
+                               gatts start_service 2 1b 1
+                               gattc listen 1
                                gatts disconnect
                                gattc disconnect
-TC_SEC_CSIGN_BI_02_C   INC     PTS issue #12675
-                               haltest:
-                               gatts add_service
-                               gatts add_chaaracteristic:
-                                               <properties> 66
-                                               <permissions> 129
-                               gatts start_service
+TC_SEC_CSIGN_BI_02_C   PASS    gattc register_client
+                               gatts register_server
+                               gatts add_service 2 <uuid> 3
+                               gatts add_characteristic 2 1b <uuid> 66 129
+                               gatts start_service 2 1b 1
+                               gattc listen 1
                                gatts disconnect
                                gattc disconnect
-TC_SEC_CSIGN_BI_03_C   INC     PTS issue #12675
-                               haltest:
-                               gatts add_service
-                               gatts add_characteristic:
-                                               <properties> 64
-                                               <permissions> 128
-                               gatts start_service
-                               gattc listen
-                               bluetooth ssp_reply
+TC_SEC_CSIGN_BI_03_C   PASS    gattc register_client
+                               gatts register_server
+                               gatts add_service 2 <uuid> 3
+                               gatts add_characteristic 2 1b <uuid> 66 129
+                               gatts start_service 2 1b 1
+                               gattc listen 1
                                gatts disconnect
+                               gattc disconnect
                                bluetooth remove_bond
-TC_SEC_CSIGN_BI_04_C   INC     PTS issue #12675
-                               haltest:
-                               gatts add_service
-                               gatts add_characteristic:
-                                               <properties> 64
-                                               <permissions> 256
-                               gatts start_service
-                               gattc listen
-                               bluetooth ssp_reply
+TC_SEC_CSIGN_BI_04_C   PASS    gattc register_client
+                               gatts register_server
+                               gatts add_service 2 <uuid> 3
+                               gatts add_characteristic 2 1b <uuid> 64 256
+                               gatts start_service 2 1b 1
+                               gattc listen 1
                                gatts disconnect
+                               gattc disconnect
 TC_PRIV_CONN_BV_01_C   N/A
 TC_PRIV_CONN_BV_02_C   N/A
 TC_PRIV_CONN_BV_03_C   N/A
@@ -337,12 +325,17 @@ TC_PRIV_CONN_BV_06_C      N/A
 TC_PRIV_CONN_BV_07_C   N/A
 TC_PRIV_CONN_BV_08_C   N/A
 TC_PRIV_CONN_BV_09_C   N/A
-TC_PRIV_CONN_BV_10_C   PASS    PTS issue #12312
-                               Note: currently for this test following PIXITs
-                               are required to be be changed:
+TC_PRIV_CONN_BV_10_C   PASS    PTS issue #12951
+                               Note: PIXITs required to be changed:
                                TSPX_using_public_device_address: FALSE
                                TSPX_using_random_device_address: TRUE
-TC_PRIV_CONN_BV_11_C   INC     PTS issue #12310, JIRA #BA-186
+                               echo 30 > /sys/kernel/debug/bluetooth/hci0/
+                                                               rpa_timeout
+                               btmgmt power off
+                               btmgmt privacy on
+                               btmgmt power on
+TC_PRIV_CONN_BV_11_C   INC     PTS issue #12952
+                               JIRA #BA-186
 TC_ADV_BV_01_C         N/A
 TC_ADV_BV_02_C         PASS    gattc register_client
                                gattc listen 1 1
@@ -372,26 +365,48 @@ TC_GAT_BV_05_C            N/A
 TC_GAT_BV_06_C         N/A
 TC_GAT_BV_07_C         N/A
 TC_GAT_BV_08_C         N/A
-TC_DM_NCON_BV_01_C     PASS    btmgmt connectable off
-TC_DM_CON_BV_01_C      PASS    btmgmt connectable on
-TC_DM_NBON_BV_01_C     PASS
+TC_DM_NCON_BV_01_C     PASS    bluetooth set_adapter_property
+                                       BT_PROPERTY_ADAPTER_SCAN_MODE
+                                       BT_SCAN_MODE_NONE
+                               gattc register_client
+                               gattc listen 1
+TC_DM_CON_BV_01_C      PASS    bluetooth set_adapter_property
+                                       BT_PROPERTY_ADAPTER_SCAN_MODE
+                                       BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE
+                               gattc register_client
+                               gattc listen 1
+TC_DM_NBON_BV_01_C     PASS    btmgmt bondable off
 TC_DM_BON_BV_01_C      PASS    haltest:
                                create_bond and remove_bond when requested
 TC_DM_GIN_BV_01_C      PASS
 TC_DM_LIN_BV_01_C      PASS
 TC_DM_NAD_BV_01_C      PASS    Start discovery from IUT
 TC_DM_NAD_BV_02_C      PASS
-TC_DM_LEP_BV_01_C      PASS    gattc register_client
+TC_DM_LEP_BV_01_C      PASS    PTS issue #12949
+                               bluetooth set_adapter_property
+                                       BT_PROPERTY_ADAPTER_SCAN_MODE
+                                       BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE
+                               gattc register_client
                                gattc listen 1 1
 TC_DM_LEP_BV_02_C      PASS    Use basic rate PTS dongle
                                haltest:
                                bluetooth set_adapter_property
 TC_DM_LEP_BV_04_C      PASS    l2test -n <PTS bdaddr>
 TC_DM_LEP_BV_05_C      PASS    btmgmt find -b
-                               l2test -n 00:1B:DC:06:06:22
-TC_DM_LEP_BV_06_C      PASS
-TC_DM_LEP_BV_07_C      PASS
-TC_DM_LEP_BV_08_C      PASS
+                               l2test -n <PTS bdaddr>
+TC_DM_LEP_BV_06_C      PASS    gattc connect
+TC_DM_LEP_BV_07_C      PASS    PTS issue #12949
+                               bluetooth set_adapter_property
+                                       BT_PROPERTY_ADAPTER_SCAN_MODE
+                                       BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE
+                               gattc register_client
+                               gattc listen 1 1
+TC_DM_LEP_BV_08_C      PASS    PTS issue #12949
+                               bluetooth set_adapter_property
+                                       BT_PROPERTY_ADAPTER_SCAN_MODE
+                                       BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE
+                               gattc register_client
+                               gattc listen 1 1
 TC_DM_LEP_BV_09_C      PASS    haltest:
                                bluetooth enable
                                bluetooth set_adapter_property
@@ -402,7 +417,8 @@ TC_DM_LEP_BV_09_C   PASS    haltest:
                                gattc connect
                                l2test -n -P 31 <PTS addr>
                                disconnect
-TC_DM_LEP_BV_10_C      PASS    haltest:
+TC_DM_LEP_BV_10_C      PASS    PTS issue #12949
+                               haltest:
                                bluetooth enable
                                bluetooth set_adapter_property
                                        BT_PROPERTY_ADAPTER_SCAN_MODE
@@ -418,4 +434,5 @@ TC_DM_LEP_BV_11_C   PASS    haltest:
                                        BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE
                                gattc register_client
                                gattc connect
+                               gattc disconnect
 -------------------------------------------------------------------------------
index a452726..cbb5cee 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for GATT
 
-PTS version: 5.3
-Tested: 05-December-2014
+PTS version: 6.0
+Tested: 02-February-2015
 Android version: 5.0
 
 Results:
@@ -18,8 +18,8 @@ TC_GAC_CL_BV_01_C     PASS    haltest:
                                gattc search_service
                                gattc get_characteristic
                                gattc write_characteristic: type 3
-TC_GAC_SR_BV_01_C      PASS    PTS issue #12357
-                               NOTE: tested with ETS attached to errata
+TC_GAC_SR_BV_01_C      PASS    PTS issue #13073
+                               TSE #6271
                                haltest:
                                gatts add_service
                                gatts add_chaaracteristic:
@@ -49,12 +49,14 @@ TC_GAD_CL_BV_02_C   PASS    haltest:
                                gattc connect
                                gattc refresh
 TC_GAD_CL_BV_03_C      PASS    haltest:
-                                gattc register_client
-                                gattc scan
-                                gattc connect
-                                gattc search_service
+                               gattc register_client
+                               gattc scan
+                               gattc connect
+                               gattc search_service
                                gattc get_included_service
                                gattc_disconnect
+                               gattc connect
+                               gattc refresh
 TC_GAD_CL_BV_04_C      PASS    haltest:
                                when requested: gattc get_characteristic
 TC_GAD_CL_BV_05_C      PASS    haltest:
@@ -696,7 +698,7 @@ TC_GAW_CL_BI_32_C   PASS    haltest:
                                gattc search_service
                                gattc get_characteristic: srvc_id based on
                                                                handle from logs
-                               gattc write_characteristic 2 <long_value>
+                               gattc write_characteristic 3 <value>
                                gattc execute_write
                                gattc disconnect
 TC_GAW_CL_BI_33_C      PASS    haltest:
@@ -991,7 +993,8 @@ TC_GAW_SR_BI_31_C   PASS    haltest:
                                gatts add_descriptor: <permmisions> 17
                                gatts start_service
                                gatts send_response: <status> 12
-TC_GAW_SR_BI_32_C      PASS    haltest:
+TC_GAW_SR_BI_32_C      PASS    PTS issue #12823
+                               haltest:
                                gatts add_service
                                gatts add_characteristic:
                                                <properties> 10 <permissions> 17
@@ -1077,7 +1080,7 @@ TC_GAT_CL_BV_01_C PASS    haltest:
                                gattc get_characteristic: srvc_id based on
                                                                handle from logs
                                gattc read_characcteristic
-                               gattc disconnect
+                               wait for 30 sec timeout
 TC_GAT_CL_BV_02_C      PASS    haltest:
                                gattc connect
                                gattc search_service
@@ -1085,6 +1088,7 @@ TC_GAT_CL_BV_02_C PASS    haltest:
                                                                handle from logs
                                gattc write_characcteristic 2 <short_value>
                                gattc disconnect
+                               wait for 30 sec timeout
 TC_GAT_SR_BV_01_C      PASS    haltest:
                                gatts add_service
                                gatts add_characteristic:
diff --git a/android/pts-gavdp.txt b/android/pts-gavdp.txt
new file mode 100644 (file)
index 0000000..4f6253d
--- /dev/null
@@ -0,0 +1,23 @@
+PTS test results for GAVDP
+
+PTS version: 6.0
+Tested: 20-February-2015
+Android version: 5.0
+
+Results:
+PASS   test passed
+FAIL   test failed
+INC    test is inconclusive
+N/A    test is disabled due to PICS setup
+NONE   test result is none
+
+-------------------------------------------------------------------------------
+Test Name                              Result  Notes
+-------------------------------------------------------------------------------
+TC_ACP_APP_CON_BV_01_C                 PASS
+TC_ACP_APP_TRC_BV_01_C                 N/A
+TC_ACP_APP_TRC_BV_02_C                 PASS
+TC_INT_APP_CON_BV_01_C                 PASS
+TC_INT_APP_TRC_BV_01_C                 N/A
+TC_INT_APP_TRC_BV_02_C                 PASS
+-------------------------------------------------------------------------------
index 1d25848..f6bf5cc 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for HDP
 
-PTS version: 5.3
-Tested: 07-November-2014
+PTS version: 6.0
+Tested: 16-February-2015
 Android version: 5.0
 
 Results:
@@ -14,12 +14,6 @@ N/A  test is disabled due to PICS setup
 Test Name              Result  Notes
 -------------------------------------------------------------------------------
 TC_SRC_CON_BV_01_I     PASS    haltest:
-                               bluetooth enable
-
-                               bluetooth set_adapter_property
-                               BT_PROPERTY_ADAPTER_SCAN_MODE
-                               BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE
-
                                hl register_application <args>
                                for instance:
                                hl register_application health intel heartrate
@@ -31,7 +25,8 @@ TC_SRC_CON_BV_01_I    PASS    haltest:
                                for instance:
                                bluetooth ssp_reply <bdaddr>
                                BT_SSP_VARIANT_CONSENT 1
-TC_SRC_CON_BV_02_I     PASS
+                               Note: IUT must be discoverable, connectable
+TC_SRC_CON_BV_02_I     PASS    Note: IUT must be in discoverable mode
 TC_SRC_CON_BV_03_I     PASS    when prompted: bluetooth ssp_reply <args>
 TC_SRC_CON_BV_04_I     PASS    haltest:
                                hl connect_channel <app_id> <bd_addr>
@@ -39,13 +34,16 @@ TC_SRC_CON_BV_04_I  PASS    haltest:
 
                                when prompted: bluetooth ssp_reply <args>
 TC_SRC_CON_BV_05_I     PASS    when prompted: bluetooth ssp_reply <args>
+                               Note: IUT must be in connectable mode
 TC_SRC_CON_BV_06_I     PASS    haltest:
                                hl connect_channel <app_id> <bd_addr>
                                <mdep_cfg_index>
 
                                when prompted: bluetooth ssp_reply <args>
-TC_SRC_CON_BV_07_I     PASS    when prompted: bluetooth start_discovery
-TC_SRC_CON_BV_08_I     PASS    when prompted: bluetooth ssp_reply <args>
+TC_SRC_CON_BV_07_I     PASS    bluetooth start_discovery
+                               Note: PTS HDP device must be discovered
+TC_SRC_CON_BV_08_I     PASS    bluetooth remove_bond <PTS addr>
+                               when prompted: bluetooth ssp_reply <args>
 TC_SRC_CON_BV_09_I     PASS    haltest:
                                hl connect_channel <app_id> <bd_addr>
                                <mdep_cfg_index>
@@ -58,6 +56,7 @@ TC_SRC_CC_BV_01_C     PASS    haltest:
 
                                when prompted: bluetooth ssp_reply <args>
 TC_SRC_CC_BV_02_C      PASS    when prompted: bluetooth ssp_reply <args>
+                               Note: IUT must be discoverable, connectable
 TC_SRC_CC_BV_03_C      PASS    haltest:
                                hl register_application bluez-android Bluez
                                bluez-hdp health-device-profile 1
@@ -68,12 +67,12 @@ TC_SRC_CC_BV_03_C   PASS    haltest:
                                <mdep_cfg_index>
 
                                when prompted: bluetooth ssp_reply <args>
-
 TC_SRC_CC_BV_05_C      PASS    haltest:
                                hl register_application bluez-android Bluez
                                bluez-hdp health-device-profile 1
                                BTHL_MDEP_ROLE_SOURCE 4100
                                BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter
+                               Note: IUT must be discoverable, connectable
 TC_SRC_CC_BV_07_C      PASS    haltest:
                                hl register_application bluez-android Bluez
                                bluez-hdp health-device-profile 2
@@ -99,11 +98,13 @@ TC_SRC_CC_BV_09_C   PASS    haltest:
                                BTHL_CHANNEL_TYPE_STREAMING pulse-oximeter
 
                                when prompted: bluetooth ssp_reply <args>
+                               Note: IUT must be discoverable, connectable
 TC_SRC_CC_BI_12_C      PASS    haltest:
                                hl register_application bluez-android Bluez
                                bluez-hdp health-device-profile 1
                                BTHL_MDEP_ROLE_SOURCE 4100
                                BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter
+                               Note: IUT must be discoverable, connectable
 TC_SRC_HCT_BV_01_I     PASS    haltest:
                                hl register_application bluez-android Bluez
                                bluez-hdp health-device-profile 1
@@ -119,6 +120,7 @@ TC_SRC_HCT_BV_02_I  PASS    haltest:
                                bluez-hdp health-device-profile 1
                                BTHL_MDEP_ROLE_SOURCE 4100
                                BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter
+                               Note: IUT must be discoverable, connectable
 TC_SRC_HCT_BV_03_I     N/A
 TC_SRC_HCT_BV_04_I     PASS    haltest:
                                hl register_application bluez-android Bluez
@@ -127,6 +129,7 @@ TC_SRC_HCT_BV_04_I  PASS    haltest:
                                BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter
 
                                when prompted: bluetooth ssp_reply <args>
+                               Note: IUT must be discoverable, connectable
 TC_SRC_HCT_BV_05_C     N/A
 TC_SRC_HCT_BV_06_C     PASS    haltest:
                                hl register_application bluez-android Bluez
@@ -135,6 +138,7 @@ TC_SRC_HCT_BV_06_C  PASS    haltest:
                                BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter
 
                                when prompted: bluetooth ssp_reply <args>
+                               Note: IUT must be discoverable, connectable
 TC_SRC_HCT_BV_07_C     PASS    haltest:
                                hl register_application bluez-android Bluez
                                bluez-hdp health-device-profile 1
@@ -146,6 +150,7 @@ TC_SRC_DE_BV_02_I   PASS    haltest:
                                bluez-hdp health-device-profile 1
                                BTHL_MDEP_ROLE_SOURCE 4100
                                BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter
+                               Note: IUT must be discoverable, connectable
 TC_SRC_DEP_BV_01_I     N/A
 TC_SRC_DEP_BV_02_I     N/A
 TC_SNK_CON_BV_01_I     PASS    haltest:
@@ -160,21 +165,27 @@ TC_SNK_CON_BV_01_I        PASS    haltest:
                                for instance:
                                bluetooth ssp_reply <bdaddr>
                                BT_SSP_VARIANT_CONSENT 1
-TC_SNK_CON_BV_02_I     PASS
+                               Note: IUT must be discoverable, connectable
+TC_SNK_CON_BV_02_I     PASS    Note: IUT must be discoverable, connectable
 TC_SNK_CON_BV_03_I     PASS    when prompted: bluetooth ssp_reply <args>
+                               Note: IUT must be discoverable, connectable
 TC_SNK_CON_BV_04_I     PASS    haltest:
                                hl connect_channel <app_id> <bd_addr>
                                <mdep_cfg_index>
 
                                when prompted: bluetooth ssp_reply <args>
+                               Note: IUT must be discoverable, connectable
 TC_SNK_CON_BV_05_I     PASS    when prompted: bluetooth ssp_reply <args>
 TC_SNK_CON_BV_06_I     PASS    haltest:
                                hl connect_channel <app_id> <bd_addr>
                                <mdep_cfg_index>
 
                                when prompted: bluetooth ssp_reply <args>
-TC_SNK_CON_BV_07_I     PASS    when prompted: bluetooth start_discovery
-TC_SNK_CON_BV_08_I     PASS    when prompted: bluetooth ssp_reply <args>
+TC_SNK_CON_BV_07_I     PASS    bluetooth start_discovery
+TC_SNK_CON_BV_08_I     PASS    bluetooth remove_bond <PTS addr>
+
+                               when prompted: bluetooth ssp_reply <args>
+                               Note: IUT must be discoverable, connectable
 TC_SNK_CON_BV_09_I     PASS    haltest:
                                hl connect_channel <app_id> <bd_addr>
                                <mdep_cfg_index>
@@ -187,6 +198,7 @@ TC_SNK_CC_BV_01_C   PASS    haltest:
 
                                when prompted: bluetooth ssp_reply <args>
 TC_SNK_CC_BV_02_C      PASS    when prompted: bluetooth ssp_reply <args>
+                               Note: IUT must be discoverable, connectable
 TC_SNK_CC_BV_04_C      PASS    haltest:
                                hl register_application bluez-android Bluez
                                bluez-hdp health-device-profile 1
@@ -197,7 +209,6 @@ TC_SNK_CC_BV_04_C   PASS    haltest:
                                <mdep_cfg_index>
 
                                when prompted: bluetooth ssp_reply <args>
-
 TC_SNK_CC_BV_06_C      PASS    haltest:
                                hl register_application bluez-android Bluez
                                bluez-hdp health-device-profile 2
@@ -221,7 +232,6 @@ TC_SNK_CC_BV_08_C   PASS    haltest:
                                when prompted:
                                hl connect_channel <app_id> <bd_addr>
                                <mdep_cfg_index>
-
 TC_SNK_CC_BV_10_C      PASS    haltest:
                                hl register_application bluez-android Bluez
                                bluez-hdp health-device-profile 2
@@ -229,11 +239,13 @@ TC_SNK_CC_BV_10_C PASS    haltest:
                                pulse-oximeter
                                BTHL_MDEP_ROLE_SINK 4100 BTHL_CHANNEL_TYPE_STREAMING
                                pulse-oximeter
+                               Note: IUT must be discoverable, connectable
 TC_SNK_CC_BI_11_C      PASS    haltest:
                                hl register_application bluez-android Bluez
                                bluez-hdp health-device-profile 1
                                BTHL_MDEP_ROLE_SINK 4100
                                BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter
+                               Note: IUT must be discoverable, connectable
 TC_SNK_HCT_BV_01_I     PASS    haltest:
                                hl register_application bluez-android Bluez
                                bluez-hdp health-device-profile 1
@@ -249,6 +261,7 @@ TC_SNK_HCT_BV_02_I  PASS    haltest:
                                bluez-hdp health-device-profile 1
                                BTHL_MDEP_ROLE_SINK 4100
                                BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter
+                               Note: IUT must be discoverable, connectable
 TC_SNK_HCT_BV_03_I     N/A
 TC_SNK_HCT_BV_04_I     PASS    haltest:
                                hl register_application bluez-android Bluez
@@ -257,23 +270,27 @@ TC_SNK_HCT_BV_04_I        PASS    haltest:
                                BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter
 
                                when prompted: bluetooth ssp_reply <args>
+                               Note: IUT must be discoverable, connectable
 TC_SNK_HCT_BV_05_C     N/A
 TC_SNK_HCT_BV_06_C     PASS    haltest:
                                hl register_application bluez-android Bluez
                                bluez-hdp health-device-profile 1
                                BTHL_MDEP_ROLE_SINK 4100
                                BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter
+                               Note: IUT must be discoverable, connectable
 TC_SNK_HCT_BV_07_C     PASS    haltest:
                                hl register_application bluez-android Bluez
                                bluez-hdp health-device-profile 1
                                BTHL_MDEP_ROLE_SINK 4100
                                BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter
+                               Note: IUT must be discoverable, connectable
 TC_SNK_DE_BV_01_I      N/A
 TC_SNK_DE_BV_02_I      PASS    haltest:
                                hl register_application bluez-android Bluez
                                bluez-hdp health-device-profile 1
                                BTHL_MDEP_ROLE_SINK 4100
                                BTHL_CHANNEL_TYPE_RELIABLE pulse-oximeter
+                               Note: IUT must be discoverable, connectable
 TC_SNK_DEP_BV_03_I     N/A
 TC_SNK_DEP_BV_04_I     N/A
 -------------------------------------------------------------------------------
index 3fcb645..ed17afe 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for HFP
 
-PTS version: 5.3
-Tested: 02-December-2014
+PTS version: 6.0
+Tested: 16-February-2015
 Android version: 5.0
 
 Results:
@@ -55,7 +55,7 @@ TC_AG_OCM_BV_01_I     PASS
 TC_AG_OCM_BV_02_I      PASS
 TC_AG_OCL_BV_01_I      PASS
 TC_AG_OCL_BV_02_I      PASS
-TC_AG_TWC_BV_01_I      PASS    JIRA #BA-281
+TC_AG_TWC_BV_01_I      PASS
 TC_AG_TWC_BV_02_I      PASS
 TC_AG_TWC_BV_03_I      PASS
 TC_AG_TWC_BV_04_I      PASS
@@ -101,10 +101,10 @@ TC_AG_SLC_BV_06_I PASS
 TC_AG_SLC_BV_07_I      PASS
 TC_AG_SLC_BV_09_I      N/A
 TC_AG_SLC_BV_10_I      N/A
-TC_AG_ACC_BV_08_I      PASS    PTS issue #12039
+TC_AG_ACC_BV_08_I      PASS
 TC_AG_ACC_BV_09_I      PASS
-TC_AG_ACC_BV_10_I      PASS    PTS issue #12039
-TC_AG_ACC_BV_11_I      PASS    PTS issue #12039
+TC_AG_ACC_BV_10_I      PASS
+TC_AG_ACC_BV_11_I      PASS
 TC_AG_ACC_BI_12_I      PASS
 TC_AG_ACC_BI_13_I      PASS
 TC_AG_ACC_BI_14_I      PASS
index 62a79e1..7918650 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for HID
 
-PTS version: 5.3
-Tested: 26-November-2014
+PTS version: 6.0
+Tested: 30-January-2015
 Android version: 5.0
 
 Results:
@@ -22,11 +22,10 @@ TC_HOS_HCR_BV_02_I  PASS
 TC_HOS_HCR_BV_03_I     N/A
 TC_HOS_HCR_BV_04_I     N/A
 TC_HOS_HDT_BV_01_I     PASS
-TC_HOS_HDT_BV_02_I     PASS    from shell execute:
-                               haltest
-                               bluetooth enable
-                               hidhost connect <PTS bdaddr>
-                               hidhost send_data <PTS bdaddr> ff00
+TC_HOS_HDT_BV_02_I     PASS    haltest: hidhost connect <addr>
+                               hidhost send_data <addr> ff00
+                               NOTE: PTS displays wrong report data on popup
+                                       PTS issue #13021
 TC_HOS_HDT_BV_03_I     N/A
 TC_HOS_HDT_BV_04_I     N/A
 TC_HOS_HID_BV_01_C     N/A
@@ -38,11 +37,10 @@ TC_HOS_HID_BV_06_C  N/A
 TC_HOS_HID_BV_08_C     N/A
 TC_HOS_HID_BV_09_C     N/A
 TC_HOS_HID_BV_10_C     N/A
-TC_HOS_DAT_BV_01_C     PASS    from shell execute:
-                               haltest
-                               bluetooth enable
-                               hidhost connect <PTS bdaddr>
-                               hidhost send_data <PTS bdaddr> ff00
+TC_HOS_DAT_BV_01_C     PASS    haltest: hidhost connect <addr>
+                               hidhost send_data <addr> ff00
+                               NOTE: PTS displays wrong report data on popup
+                                       PTS issue #13021
 TC_HOS_DAT_BV_02_C     N/A
 TC_HOS_DAT_BI_01_C     N/A
 TC_HOS_DAT_BI_02_C     N/A
index 98c14d8..827e9b4 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for HoG
 
-PTS version: 5.3
-Tested: 01-December-2014
+PTS version: 6.0
+Tested: 24-February-2015
 Android version: 5.0
 
 Results:
@@ -13,8 +13,7 @@ N/A   test is disabled due to PICS setup
 -------------------------------------------------------------------------------
 Test Name              Result  Notes
 -------------------------------------------------------------------------------
-TC_HGDS_HH_BV_01_I     PASS    PTS issue #12119
-                               This issue affects all PTS test cases
+TC_HGDS_HH_BV_01_I     PASS
 TC_HGDS_HH_BV_02_I     PASS
 TC_HGDS_HH_BV_03_I     PASS
 TC_HGDS_HD_BV_01_I     N/A
@@ -94,7 +93,7 @@ TC_HGCF_BH_BV_03_I    N/A
 TC_HGCF_BH_BV_04_I     N/A
 TC_HGCF_BH_BV_05_I     N/A
 TC_HGCF_BH_BV_06_I     N/A
-TC_HGNF_RH_BV_01_I     PASS
+TC_HGNF_RH_BV_01_I     PASS    PTS issue #12878
 TC_HGNF_RH_BI_01_I     PASS
 TC_HGNF_RH_BI_01_I     PASS
 TC_HGNF_BH_BV_02_I     N/A
index 9f03ead..04a6413 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for HSP
 
-PTS version: 5.3
-Tested: 24-November-2014
+PTS version: 6.0
+Tested: 12-February-2015
 Android version: 5.0
 
 Results:
index f746b1c..7b776a9 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for IOPT
 
-PTS version: 5.3
-Tested: 18-November-2014
+PTS version: 6.0
+Tested: 03-February-2015
 Android version: 5.0
 
 Results:
@@ -14,12 +14,13 @@ N/A test is disabled due to PICS setup
 Test Name      Result  Notes
 -------------------------------------------------------------------------------
 TC_COD_BV_01_I PASS    IUT must be discoverable
-TC_COD_BV_02_I N/A     Under PTS 5.1 test shall be disabled as there is
-                       matching test case in HFP test suit (test No. 15)
-                       PICS settings for HFP shall be disabled for IOPT
-TC_SDSS_BV_02_I        PASS
-TC_SDAS_BV_03_I        PASS
-TC_SDR_BV_04_I PASS    for every PTS bt profile:
-                       haltest: bluetooth get_remote_service_record <addr>
-                                                       <requred 128 sdp uuid>
+TC_COD_BV_02_I N/A
+TC_SDSS_BV_02_I        PASS    Note: HDP sink record should be registered before test
+                               run, e.g. register health app via HDPSample.apk
+TC_SDAS_BV_03_I        PASS    Note: HDP sink record should be registered before test
+                               run, e.g. register health app via HDPSample.apk
+TC_SDR_BV_04_I PASS    For every asked to check PTS bt profile:
+                       haltest: bluetooth get_remote_service_record <PTS addr>
+                               <profile uuid>
+                       Note: 0000xxxx - acceptable 16bit uuid format
 -------------------------------------------------------------------------------
index b5fdb05..b625861 100644 (file)
@@ -14,6 +14,8 @@ N/A    test is disabled due to PICS setup
 -------------------------------------------------------------------------------
 Test Name              Result  Notes
 -------------------------------------------------------------------------------
+                               For all tests daemon should be stopped then:
+                                       setprop ctl.start hciattach
 TC_COS_CED_BV_01_C     PASS    l2test -n -P 4113 <bdaddr>
 TC_COS_CED_BV_03_C     PASS    l2test -y -N 1 -P 4113 <bdaddr>
 TC_COS_CED_BV_04_C     PASS    l2test -n -P 4113 <bdaddr>
@@ -151,9 +153,6 @@ TC_ECF_BV_05_C              N/A
 TC_ECF_BV_06_C         N/A
 TC_ECF_BV_07_C         N/A
 TC_ECF_BV_08_C         N/A
-                               NOTE: for LE tests daemon should be stopped
-                               then:
-                               setprop ctl.start hciattach
 TC_LE_CPU_BV_01_C      PASS    l2test -n -V le_public -J 4
 TC_LE_CPU_BV_02_C      PASS    l2test -n -V le_public -J 4 <braddr>
 TC_LE_CPU_BI_01_C      PASS    l2test -n -V le_public -J 4 <braddr>
index 2aa1848..2ad2858 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for MCAP
 
-PTS version: 5.3
-Tested: 27-November-2014
+PTS version: 6.0
+Tested: 10-February-2015
 Android version: 5.0
 
 Results:
@@ -16,42 +16,28 @@ Note: Test were done with ssp enabled and in most of the cases requires pairing
 -------------------------------------------------------------------------------
 Test Name              Result  Notes
 -------------------------------------------------------------------------------
-TC_MCAP_CE_BV_01_C     INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -dc <PTS addr>
-TC_MCAP_CE_BV_02_C     INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
-TC_MCAP_CE_BV_03_C     INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -c <PTS addr>
-TC_MCAP_CE_BV_04_C     INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -d
+TC_MCAP_CE_BV_01_C     PASS    mcaptest -C 4099 -D 4101 -f 2 -dc <PTS addr>
+TC_MCAP_CE_BV_02_C     PASS    mcaptest -C 4099 -D 4101 -f 2
+TC_MCAP_CE_BV_03_C     PASS    mcaptest -C 4099 -D 4101 -f 2 -c <PTS addr>
+TC_MCAP_CE_BV_04_C     PASS    mcaptest -C 4099 -D 4101 -f 2 -d
 TC_MCAP_CM_ABT_BV_01_C N/A
-TC_MCAP_CM_ABT_BV_02_C INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
+TC_MCAP_CM_ABT_BV_02_C PASS    mcaptest -C 4099 -D 4101 -f 2
 TC_MCAP_CM_ABT_BV_03_C N/A
 TC_MCAP_CM_DEL_BV_01_C N/A
-TC_MCAP_CM_DEL_BV_02_C INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
+TC_MCAP_CM_DEL_BV_02_C PASS    mcaptest -C 4099 -D 4101 -f 2
 TC_MCAP_CM_DEL_BV_03_C N/A
-TC_MCAP_CM_DEL_BV_04_C INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
-TC_MCAP_CM_DIS_BV_01_C PASS    mcaptest -C 4099 -D 4101 -e 2 -f 2
+TC_MCAP_CM_DEL_BV_04_C PASS    mcaptest -C 4099 -D 4101 -f 2
+TC_MCAP_CM_DIS_BV_01_C PASS    mcaptest -C 4099 -D 4101 -ab -e 2 -f 2
 TC_MCAP_CM_DIS_BV_02_C PASS    mcaptest -C 4099 -D 4101
-TC_MCAP_CM_DIS_BV_03_C INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
-TC_MCAP_CM_DIS_BV_04_C PASS    mcaptest -C 4099 -D 4101 -e 2 -f 2
+TC_MCAP_CM_DIS_BV_03_C PASS    mcaptest -C 4099 -D 4101 -n -f 2
+TC_MCAP_CM_DIS_BV_04_C PASS    mcaptest -C 4099 -D 4101 -ab -e 2 -f 2
 TC_MCAP_CM_DIS_BV_05_C PASS    mcaptest -C 4099 -D 4101
 TC_MCAP_CM_REC_BV_01_C N/A
-TC_MCAP_CM_REC_BV_02_C INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
+TC_MCAP_CM_REC_BV_02_C PASS    mcaptest -C 4099 -D 4101 -n -f 2
 TC_MCAP_CM_REC_BV_03_C N/A
-TC_MCAP_CM_REC_BV_04_C INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
-                               Note: It may be necessary to confirm pairing
-                                       twice (second time when IUT is back in
-                                       range).
+TC_MCAP_CM_REC_BV_04_C PASS    mcaptest -C 4099 -D 4101 -n -f 2
 TC_MCAP_CM_REC_BV_05_C N/A
-TC_MCAP_CM_REC_BV_06_C INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
+TC_MCAP_CM_REC_BV_06_C PASS    mcaptest -C 4099 -D 4101 -f 2
 TC_MCAP_CS_ERR_BI_01_C N/A
 TC_MCAP_CS_ERR_BI_02_C N/A
 TC_MCAP_CS_ERR_BI_03_C N/A
@@ -64,56 +50,31 @@ TC_MCAP_CS_R_BV_01_I        N/A
 TC_MCAP_CS_R_BV_02_I   N/A
 TC_MCAP_CS_R_BV_03_C   N/A
 TC_MCAP_CS_T_BV_04_C   N/A
-TC_MCAP_ERR_BI_01_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
-TC_MCAP_ERR_BI_02_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -d
-TC_MCAP_ERR_BI_03_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
-TC_MCAP_ERR_BI_04_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -d
-TC_MCAP_ERR_BI_05_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
-TC_MCAP_ERR_BI_06_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -d
-TC_MCAP_ERR_BI_07_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
-TC_MCAP_ERR_BI_08_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -d
-TC_MCAP_ERR_BI_09_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
-TC_MCAP_ERR_BI_10_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
-TC_MCAP_ERR_BI_11_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -d
-TC_MCAP_ERR_BI_12_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -d
-TC_MCAP_ERR_BI_13_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
-TC_MCAP_ERR_BI_14_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
-TC_MCAP_ERR_BI_15_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -d
-TC_MCAP_ERR_BI_16_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -u
-TC_MCAP_ERR_BI_17_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -d
-TC_MCAP_ERR_BI_18_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -d
+TC_MCAP_ERR_BI_01_C    PASS    mcaptest -C 4099 -D 4101 -f 2
+TC_MCAP_ERR_BI_02_C    PASS    mcaptest -C 4099 -D 4101 -dn -f 2
+TC_MCAP_ERR_BI_03_C    PASS    mcaptest -C 4099 -D 4101 -f 2
+TC_MCAP_ERR_BI_04_C    PASS    mcaptest -C 4099 -D 4101 -dn -f 2
+TC_MCAP_ERR_BI_05_C    PASS    mcaptest -C 4099 -D 4101 -f 2
+TC_MCAP_ERR_BI_06_C    PASS    mcaptest -C 4099 -D 4101 -dn -f 2
+TC_MCAP_ERR_BI_07_C    PASS    mcaptest -C 4099 -D 4101 -f 2
+TC_MCAP_ERR_BI_08_C    PASS    mcaptest -C 4099 -D 4101 -dn -f 2
+TC_MCAP_ERR_BI_09_C    PASS    mcaptest -C 4099 -D 4101 -f 2
+TC_MCAP_ERR_BI_10_C    PASS    mcaptest -C 4099 -D 4101 -f 2
+TC_MCAP_ERR_BI_11_C    PASS    mcaptest -C 4099 -D 4101 -dn -f 2
+TC_MCAP_ERR_BI_12_C    PASS    mcaptest -C 4099 -D 4101 -dn -f 2
+TC_MCAP_ERR_BI_13_C    PASS    mcaptest -C 4099 -D 4101 -f 2
+TC_MCAP_ERR_BI_14_C    PASS    mcaptest -C 4099 -D 4101 -f 2
+TC_MCAP_ERR_BI_15_C    PASS    mcaptest -C 4099 -D 4101 -dn -f 2
+TC_MCAP_ERR_BI_16_C    PASS    mcaptest -C 4099 -D 4101 -u -f 2
+TC_MCAP_ERR_BI_17_C    PASS    mcaptest -C 4099 -D 4101 -dn -f 2
+TC_MCAP_ERR_BI_18_C    PASS    mcaptest -C 4099 -D 4101 -dn -f 2
 TC_MCAP_ERR_BI_19_C    N/A
-TC_MCAP_ERR_BI_20_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -g
+TC_MCAP_ERR_BI_20_C    PASS    mcaptest -C 4099 -D 4101 -g -f 2
 TC_MCAP_INV_BI_01_C    PASS    mcaptest -C 4099 -D 4101 -dc <PTS addr>
-TC_MCAP_INV_BI_02_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -d
-TC_MCAP_INV_BI_03_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -dc <PTS addr>
-TC_MCAP_INV_BI_04_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101 -c <PTS addr>
-TC_MCAP_INV_BI_05_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
-TC_MCAP_INV_BI_06_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
-TC_MCAP_INV_BI_07_C    INC     PTS issue #12693
-                               mcaptest -C 4099 -D 4101
+TC_MCAP_INV_BI_02_C    PASS    mcaptest -C 4099 -D 4101 -dn -f 2
+TC_MCAP_INV_BI_03_C    PASS    mcaptest -C 4099 -D 4101 -d -f 2 -c <PTS addr>
+TC_MCAP_INV_BI_04_C    PASS    mcaptest -C 4099 -D 4101 -f 2 -c <PTS addr>
+TC_MCAP_INV_BI_05_C    PASS    mcaptest -C 4099 -D 4101 -f 2
+TC_MCAP_INV_BI_06_C    PASS    mcaptest -C 4099 -D 4101 -f 2
+TC_MCAP_INV_BI_07_C    PASS    mcaptest -C 4099 -D 4101 -f 2
 -------------------------------------------------------------------------------
index 46efd3c..b1096e6 100644 (file)
@@ -12,14 +12,14 @@ N/A test is disabled due to PICS setup
 NONE   test result is none
 
 Note: Do not use AOSP Music player. Use e.g. MortPlayer or Poweramp.
-For full tests conformance, "Touch sounds" on IUT should be disbaled
+For full tests conformance, "Touch sounds" on IUT should be disabled
 (Settings > Sound&notification > Other sounds)
 
 -------------------------------------------------------------------------------
 Test Name                              Result  Notes
 -------------------------------------------------------------------------------
 TC_AG_PSE_HFPB_CTH_SD_BV_01_I          PASS
-TC_AG_SRC_HFAV_ACT_SD_BV_01_I          INC     JIRA issue #BA-295
+TC_AG_SRC_HFAV_ACT_SD_BV_01_I          PASS    PTS issue #13138
 TC_AG_SRC_HFAV_ACT_SD_BV_02_I          PASS
 TC_AG_SRC_HFAV_ACT_SD_BV_03_I          PASS
 TC_AG_SRC_HFAV_CLH_SD_BV_01_I          PASS
@@ -27,7 +27,7 @@ TC_AG_SRC_HFAV_CLH_SD_BV_02_I         N/A
 TC_AG_SRC_HFAV_CLH_SD_BV_03_I          PASS
 TC_AG_SRC_HFAV_CLH_SD_BV_04_I          PASS
 TC_AG_SRC_HFAV_CLH_SD_BV_05_I          PASS
-TC_AG_SRC_HFAV_CLH_SD_BV_06_I          INC     JIRA issue #BA-296
+TC_AG_SRC_HFAV_CLH_SD_BV_06_I          PASS    PTS issue #13138
 TC_AVP_CTH_SD_BI_01_I                  PASS
 TC_AVP_CTH_SD_BI_02_I                  PASS
 TC_HF_SNK_HFAV_ACT_SD_BV_01_I          N/A
@@ -53,7 +53,7 @@ TC_SRC_TG_HFAV_ACT_MD_BV_01_I         PASS
 TC_SRC_TG_HFAV_CLH_MD_BV_01_I          PASS
 TC_SRC_TG_HFAV_CLH_MD_BV_02_I          PASS
 TC_SRC_TG_HFAV_CLH_MD_BV_03_I          PASS
-TC_SRC_TG_HFAV_CLH_MD_BV_04_I          FAIL    JIRA issue #BA-294
+TC_SRC_TG_HFAV_CLH_MD_BV_04_I          PASS
 TC_SRC_TG_HFAV_CLH_MD_BV_05_I          PASS
 TC_SRC_TG_HFAV_CLH_MD_BV_06_I          PASS
 TC_PAIRING_HF_SNK_CT                   N/A     Pairing helper for MD tests
index 7f81ad9..3f22a33 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for OPP
 
-PTS version: 5.3
-Tested: 17-November-2014
+PTS version: 6.0
+Tested: 30-January-2015
 Android version: 5.0
 
 Results:
index e95a82e..ba4afac 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for PAN
 
-PTS version: 5.3
-Tested: 17-November-2014
+PTS version: 6.0
+Tested: 17-February-2015
 Android version: 5.0
 
 Results:
@@ -13,61 +13,64 @@ N/A test is disabled due to PICS setup
 --------------------------------------------------------------------------------
 Test Name                              Result  Notes
 --------------------------------------------------------------------------------
-TC_BNEP_GN_BROADCAST_0_BV_03_C         N/A
-TC_GN_Ipv4_Autonet_BV_01_I             N/A
-TC_GN_Ipv6_Autonet_BV_02_I             N/A
-TC_GN_IP_DHCP_BV_03_I                  N/A
-TC_GN_IP_LLMNR_BV_01_I                 N/A
-TC_GN_IP_LLMNR_BV_02_I                 N/A
-TC_GN_IP_DNS_BV_01_I                   N/A
-TC_GN_IP_APP_BV_01_I                   N/A
-TC_GN_IP_APP_BV_02_I                   N/A
-TC_GN_IP_APP_BV_03_I                   N/A
-TC_GN_IP_APP_BV_04_I                   N/A
-TC_GN_IP_APP_BV_05_I                   N/A
-TC_SDP_GN_BV_02_C                      N/A
-TC_MISC_GN_UUID_BV_01_C                        N/A
-TC_MISC_GN_UUID_BV_02_C                        N/A
-TC_BNEP_NAP_BROADCAST_0_BV_01_C                N/A
-TC_BNEP_NAP_BROADCAST_0_BV_02_C                N/A
-TC_BNEP_NAP_FORWARD_UNICAST_BV_05_C    N/A
-TC_BNEP_NAP_FORWARD_UNICAST_BV_06_C    N/A
-TC_BNEP_NAP_MULTICAST_0_BV_03_C                N/A
-TC_BNEP_NAP_MULTICAST_0_BV_04_C                N/A
-TC_BNEP_BRIDGE_RX_BV_02_I              INC     PTS issue #12464
-TC_BNEP_BRIDGE_TX_BV_01_I              PASS
-TC_NAP_Ipv4_Autonet_BV_01_I            N/A
-TC_NAP_Ipv6_Autonet_BV_02_I            N/A
-TC_NAP_IP_DHCP_BV_03_I                 N/A
-TC_NAP_IP_LLMNR_BV_01_I                        N/A
-TC_NAP_IP_LLMNR_BV_02_I                        N/A
-TC_NAP_IP_DNS_BV_01_I                  N/A
-TC_NAP_IP_APP_BV_01_I                  N/A
-TC_NAP_IP_APP_BV_02_I                  N/A
-TC_NAP_IP_APP_BV_03_I                  N/A
-TC_NAP_IP_APP_BV_04_I                  N/A
-TC_NAP_IP_APP_BV_05_I                  N/A
-TC_SDP_NAP_BV_01_C                     PASS
-TC_MISC_NAP_UUID_BV_01_C               PASS
-TC_MISC_NAP_UUID_BV_02_C               PASS
-TC_BNEP_PANU_BROADCAST_0_BV_04_C       N/A
-TC_PANU_Ipv4_Autonet_BV_01_I           PASS    After DHCP request fail send
-                                               DHCP address request.
-                                               From IUT: send address request
-                                               dhcpcd -r 169.254.x.x bt-pan
-TC_PANU_Ipv6_Autonet_BV_02_I           N/A
-TC_PANU_IP_LLMNR_BV_01_I               N/A     SE #3558, TSE #4382, TCW #448
-TC_PANU_IP_LLMNR_BV_02_I               N/A
-TC_PANU_IP_DHCP_BV_03_I                        N/A
-TC_PANU_IP_DNS_BV_01_I                 N/A
-TC_PANU_IP_APP_BV_01_I                 N/A
-TC_PANU_IP_APP_BV_02_I                 N/A
-TC_PANU_IP_APP_BV_03_I                 N/A
-TC_PANU_IP_APP_BV_04_I                 N/A
-TC_PANU_IP_APP_BV_05_I                 PASS
-TC_SDP_PANU_BV_01_C                    N/A
-TC_MISC_PANU_UUID_BV_01_C              N/A
-TC_MISC_PANU_UUID_BV_02_C              N/A
-TC_MISC_ROLE_BV_01_C                   N/A
-TC_MISC_ROLE_BV_BV_02_C                        N/A
+TC_BNEP_BROADCAST_0_BV_01_C                    N/A
+TC_BNEP_BROADCAST_0_BV_02_C                    N/A
+TC_BNEP_MULTICAST_0_BV_03_C                    N/A
+TC_BNEP_MULTICAST_0_BV_04_C                    N/A
+TC_BNEP_FORWARD_UNICAST_BV_05_C                        N/A
+TC_BNEP_FORWARD_UNICAST_BV_06_C                        N/A
+TC_BNEP_EXTENSION_0_BV_07_C_TESTER_1           N/A
+TC_BNEP_EXTENSION_0_BV_07_C_TESTER_2           N/A
+TC_BNEP_FORWARD_BV_08_C_TESTER_1               N/A
+TC_BNEP_FORWARD_BV_08_C_TESTER_2               N/A
+TC_BNEP_FORWARD_BROADCAST_BV_09_C_TESTER_1     N/A
+TC_BNEP_FORWARD_BROADCAST_BV_09_C_TESTER_2     N/A
+TC_BNEP_FORWARD_BROADCAST_BV_09_C_TESTER_3     N/A
+TC_BNEP_FILTER_BV_10_C_TESTER_1                        N/A
+TC_BNEP_FILTER_BV_10_C_TESTER_2                        N/A
+TC_BNEP_FILTER_BV_11_C_TESTER_1                        N/A
+TC_BNEP_FILTER_BV_11_C_TESTER_2                        N/A
+TC_BNEP_FILTER_BV_12_C_TESTER_1                        N/A
+TC_BNEP_FILTER_BV_12_C_TESTER_2                        N/A
+TC_BNEP_FILTER_BV_13_C_TESTER_1                        N/A
+TC_BNEP_FILTER_BV_13_C_TESTER_2                        N/A
+TC_BNEP_FILTER_BV_14_C_TESTER_1                        N/A
+TC_BNEP_FILTER_BV_14_C_TESTER_2                        N/A
+TC_BNEP_FILTER_BV_15_C_TESTER_1                        N/A
+TC_BNEP_FILTER_BV_15_C_TESTER_2                        N/A
+TC_BRIDGE_TX_BV_01_I                           PASS
+TC_BRIDGE_RX_BV_02_I                           PASS
+                                               To initiate general ethernet
+                                               use for e.g. ping.
+TC_IPv4_AUTONET_BV_01_I                                PASS
+                                               To initiate general ethernet
+                                               use for e.g. ping.
+TC_IPv6_AUTONET_BV_02_I                                N/A
+TC_IP_DHCP_BV_03_I                             PASS
+TC_IP_LLMNR_BV_01_I                            N/A
+TC_IP_LLMNR_BV_02_I                            N/A
+TC_IP_DNS_BV_01_I                              N/A
+TC_IP_APP_BV_03_I                              ip neighbour add <PTS IP addr>
+                                                       lladdr <PTS HW addr>
+                                                       dev bt-pan
+                                               ping -c 1 <PTS IP addr>
+                                               Note: Add ARP record if bt-pan
+                                                       connection is
+                                                       established
+TC_IP_APP_BV_05_I                              ip neighbour add <PTS IP addr>
+                                                       lladdr <PTS HW addr>
+                                                       dev bt-pan
+                                               Note: Add of ARP record should
+                                                       be done immediately
+                                                       after establish of
+                                                       bt-pan, because PTS
+                                                       treat other than ICMP
+                                                       frames as error.
+TC_MISC_ROLE_BV_01_C                           N/A
+TC_MISC_ROLE_BV_02_C                           N/A
+TC_MISC_UUID_BV_01_C                           PASS
+TC_MISC_UUID_BV_02_C                           PASS
+TC_SDP_NAP_BV_01_C                             PASS
+TC_SDP_GN_BV_01_C                              N/A
+TC_SDP_PANU_BV_01_C                            PASS
 --------------------------------------------------------------------------------
index 8194bd7..8931690 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for PBAP
 
-PTS version: 5.3
-Tested: 17-November-2014
+PTS version: 6.0
+Tested: 30-January-2015
 Android version: 5.0
 
 Results:
index cf9497d..e9b3f26 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for RFCOMM
 
-PTS version: 5.3
-Tested: 19-November-2014
+PTS version: 6.0
+Tested: 02-February-2015
 Android version: 5.0
 Kernel version: 3.19
 
@@ -18,24 +18,23 @@ Test Name           Result  Notes
 TC_RFC_BV_01_C         PASS    rctest -n -P 1 <btaddr>
 TC_RFC_BV_02_C         PASS    rctest -r -P 1
 TC_RFC_BV_03_C         PASS    rctest -r -P 1
-TC_RFC_BV_04_C         PASS    Note: use ETS provided in PTS issue #12414
-                               rctest -r -P 1
+TC_RFC_BV_04_C         PASS    rctest -r -P 1
 TC_RFC_BV_05_C         PASS    rctest -n -P 4 <btaddr>
                                Note: test requires IUT to connect on the given
                                channel. sdptool browse <btaddr> to check the
                                channel.
 TC_RFC_BV_06_C         PASS    rctest -r -P 1
 TC_RFC_BV_07_C         PASS    rctest -r -P 1
-TC_RFC_BV_08_C         PASS    Note: use ETS provided in PTS issue #12397
-                               rctest -r -P 1
+TC_RFC_BV_08_C         PASS    rctest -r -P 1
 TC_RFC_BV_11_C         PASS    rctest -r -P 1
-TC_RFC_BV_13_C         PASS    Note: use ETS provided in PTS issue #12397
-                               rctest -r -P 1
+TC_RFC_BV_13_C         PASS    rctest -r -P 1
 TC_RFC_BV_14_C         N/A
 TC_RFC_BV_15_C         PASS    rctest -r -P 1
 TC_RFC_BV_17_C         PASS    rctest -d -P 1
 TC_RFC_BV_19_C         PASS
-TC_RFC_BV_21_C         INC     PTS issue #12421
-TC_RFC_BV_22_C         INC     PTS issue #12421
+TC_RFC_BV_21_C         PASS    PTS issue #13011
+                               rctest -w -N 10 -P 1
+TC_RFC_BV_22_C         PASS    PTS issue #13011
+                               rctest -w -N 10 -P 1
 TC_RFC_BV_25_C         PASS    rctest -r -P 1
 -------------------------------------------------------------------------------
index a7c65a2..d747c49 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for ScPP
 
-PTS version: 5.3
-Tested: 25-November-2014
+PTS version: 6.0
+Tested: 02-February-2015
 Android version: 5.0
 
 Results:
@@ -14,11 +14,11 @@ NONE        test result is none
 -------------------------------------------------------------------------------
 Test Name              Result  Notes
 -------------------------------------------------------------------------------
-TC_SPDS_SC_BV_01_I     PASS    PTS issue #12119
-TC_SPDC_SC_BV_01_I     PASS    PTS issue #12119
-TC_SPDC_SC_BV_02_I     PASS    PTS issue #12119
-TC_SPDC_SC_BV_03_I     PASS    PTS issue #12119
-TC_SPWF_SC_BV_01_I     PASS    PTS issue #12119
-TC_SPCF_SC_BV_01_I     PASS    PTS issue #12119
-TC_SPNF_SC_BV_01_I     PASS    PTS issue #12119
+TC_SPDS_SC_BV_01_I     PASS
+TC_SPDC_SC_BV_01_I     PASS
+TC_SPDC_SC_BV_02_I     PASS
+TC_SPDC_SC_BV_03_I     PASS
+TC_SPWF_SC_BV_01_I     PASS
+TC_SPCF_SC_BV_01_I     PASS
+TC_SPNF_SC_BV_01_I     PASS
 -------------------------------------------------------------------------------
diff --git a/android/pts-sdp.txt b/android/pts-sdp.txt
new file mode 100644 (file)
index 0000000..592306e
--- /dev/null
@@ -0,0 +1,77 @@
+PTS test results for SDP
+
+PTS version: 6.0
+Tested: 23-February-2015
+Android version: 5.0
+
+Results:
+PASS   test passed
+FAIL   test failed
+INC    test is inconclusive
+N/A    test is disabled due to PICS setup
+NONE   test result is none
+
+Note: from haltest:
+bluetooth set_adapter_property BT_PROPERTY_ADAPTER_SCAN_MODE
+                                               BT_SCAN_MODE_CONNECTABLE
+bluetooth enable
+socket listen BTSOCK_L2CAP BlueZ 0
+
+-------------------------------------------------------------------------------
+Test Name                      Result  Notes
+-------------------------------------------------------------------------------
+TC_SERVER_BRW_BV_01_C          PASS
+TC_SERVER_BRW_BV_01_C          PASS
+TC_SERVER_SA_BI_01_C           PASS
+TC_SERVER_SA_BI_02_C           PASS
+TC_SERVER_SA_BI_03_C           PASS
+TC_SERVER_SA_BV_01_C           PASS
+TC_SERVER_SA_BV_03_C           PASS
+TC_SERVER_SA_BV_04_C           PASS
+TC_SERVER_SA_BV_05_C           PASS
+TC_SERVER_SA_BV_06_C           PASS
+TC_SERVER_SA_BV_07_C           PASS
+TC_SERVER_SA_BV_08_C           PASS
+TC_SERVER_SA_BV_09_C           PASS
+TC_SERVER_SA_BV_10_C           PASS
+TC_SERVER_SA_BV_11_C           PASS
+TC_SERVER_SA_BV_12_C           PASS
+TC_SERVER_SA_BV_13_C           PASS
+TC_SERVER_SA_BV_14_C           PASS
+TC_SERVER_SA_BV_15_C           PASS
+TC_SERVER_SA_BV_16_C           PASS
+TC_SERVER_SA_BV_17_C           PASS
+TC_SERVER_SA_BV_18_C           PASS
+TC_SERVER_SA_BV_19_C           PASS
+TC_SERVER_SA_BV_20_C           PASS
+TC_SERVER_SA_BV_21_C           PASS
+TC_SERVER_SS_BI_01_C           PASS
+TC_SERVER_SS_BI_02_C           PASS
+TC_SERVER_SS_BV_01_C           PASS
+TC_SERVER_SS_BV_03_C           PASS    PTS issue #12840
+TC_SERVER_SS_BV_04_C           PASS
+TC_SERVER_SSA_BI_01_C          PASS
+TC_SERVER_SSA_BI_02_C          PASS
+TC_SERVER_SSA_BV_01_C          PASS
+TC_SERVER_SSA_BV_02_C          PASS
+TC_SERVER_SSA_BV_03_C          PASS
+TC_SERVER_SSA_BV_04_C          PASS
+TC_SERVER_SSA_BV_06_C          PASS
+TC_SERVER_SSA_BV_07_C          PASS
+TC_SERVER_SSA_BV_08_C          PASS
+TC_SERVER_SSA_BV_09_C          PASS
+TC_SERVER_SSA_BV_10_C          PASS
+TC_SERVER_SSA_BV_11_C          PASS
+TC_SERVER_SSA_BV_12_C          PASS
+TC_SERVER_SSA_BV_13_C          PASS
+TC_SERVER_SSA_BV_14_C          PASS
+TC_SERVER_SSA_BV_15_C          PASS
+TC_SERVER_SSA_BV_16_C          PASS
+TC_SERVER_SSA_BV_17_C          PASS
+TC_SERVER_SSA_BV_18_C          PASS
+TC_SERVER_SSA_BV_19_C          PASS
+TC_SERVER_SSA_BV_20_C          PASS
+TC_SERVER_SSA_BV_21_C          PASS
+TC_SERVER_SSA_BV_22_C          PASS
+TC_SERVER_SSA_BV_23_C          PASS
+-------------------------------------------------------------------------------
index 1ea0570..91737cc 100644 (file)
@@ -1,9 +1,9 @@
 PTS test results for SM
 
-PTS version: 5.3
-Tested: 28-November-2014
+PTS version: 6.0
+Tested: 11-February-2015
 Android version: 5.0
-kernel version: 3.18
+kernel version: 3.20
 
 Results:
 PASS   test passed
@@ -20,10 +20,10 @@ TC_PROT_BV_02_C             PASS    btmgmt advertising on
                                btmgmt pair -c 0x03 -t 0x01 <addr>
 TC_JW_BV_01_C          PASS    btmgmt pairable off
                                btmgmt pair -c 0x03 -t 0x01 <addr>
-TC_JW_BV_02_C          PASS
+TC_JW_BV_02_C          PASS    btmgmt advertising on
 TC_JW_BV_05_C          PASS    btmgmt pair -c 0x03 -t 0x01 <addr>
-TC_JW_BI_01_C          PASS
-TC_JW_BI_02_C          PASS
+TC_JW_BI_01_C          PASS    btmgmt pair -c 0x03 -t 0x01 <addr>
+TC_JW_BI_02_C          PASS    btmgmt pairable on
 TC_JW_BI_03_C          PASS    bluetoothd is NOT running
                                btmgmt power on
                                btmgmt le on
@@ -56,25 +56,39 @@ TC_OOB_BV_01_C              N/A
 TC_OOB_BV_02_C         N/A
 TC_OOB_BV_03_C         N/A
 TC_OOB_BV_04_C         N/A
-TC_OOB_BV_05_C         PASS
-TC_OOB_BV_06_C         PASS
-TC_OOB_BV_07_C         PASS
-TC_OOB_BV_08_C         PASS
+TC_OOB_BV_05_C         PASS    btmgmt pair -c 0x04 -t 0x01 <addr>
+                               Note: Enter valid passkey in PTS
+TC_OOB_BV_06_C         PASS    btmgmt advertising on
+                               btmgmt monitor
+                               Note: Enter valid passkey in PTS
+TC_OOB_BV_07_C         PASS    btmgmt pair -c 0x04 -t 0x01 <addr>
+TC_OOB_BV_08_C         PASS    btmgmt advertising on
+                               btmgmt monitor
+                               Note: Accept pairing in btmgmt monitor
 TC_OOB_BV_09_C         N/A
 TC_OOB_BV_10_C         N/A
 TC_OOB_BI_01_C         N/A
 TC_OOB_BI_02_C         N/A
-TC_EKS_BV_01_C         PASS
-TC_EKS_BV_02_C         PASS
+TC_EKS_BV_01_C         PASS    btmgmt pair -c 0x04 -t 0x01 <addr>
+                               Note: Enter valid passkey in PTS
+TC_EKS_BV_02_C         PASS    btmgmt advertising on
+                               btmgmt monitor
+                               Note: Accept pairing in btmgmt monitor
 TC_EKS_BI_01_C         PASS    btmgmt io-cap 0x03
-TC_EKS_BI_02_C         PASS
+                               btmgmt pair -c 0x03 -t 0x01 <addr>
+TC_EKS_BI_02_C         PASS    btmgmt advertising on
 TC_SIGN_BV_01_C                INC     PTS issue #12305
-TC_SIGN_BV_03_C                PASS    haltest
-                               gattc listen
-
-TC_SIGN_BI_01_C                PASS    haltest
-                               gattc listen
+TC_SIGN_BV_03_C                PASS    haltest:
+                               gattc register_client 1234
+                               gattc listen 1 1
+                               Note: IUT must be connectable and discoverable
+TC_SIGN_BI_01_C                PASS    haltest:
+                               gattc register client 1234
+                               gattc listen 1 1
+                               Note: IUT must be connectable and discoverable
 TC_KDU_BV_01_C         PASS    btmgmt pairable on
+                               btmgmt advertising on
+                               btmgmt connectable on
 TC_KDU_BV_02_C         PASS    PTS issue #12302
                                Note: Can pass it with following instructions:
                                btmgmt privacy on
@@ -93,7 +107,10 @@ TC_KDU_BV_05_C              PASS    PTS issue #12302
                                Set PIXIT TSPX_peer_type to 01
 TC_KDU_BV_06_C         PASS    btmgmt pair -c 0x03 -t 0x01 <addr>
 TC_KDU_BV_07_C         PASS    btmgmt pairable on
-TC_SIP_BV_01_C         PASS    btmgmt pair -c 0x03 -t 0x01 <addr>
-TC_SIP_BV_02_C         PASS    l2test -n -J4 -V le_public <addr>
-TC_SIE_BV_01_C         PASS    btmgmt pair -c 0x03 -t 0x01 <addr>
+TC_SIP_BV_01_C         PASS    btmgmt advertising on
+                               btmgmt pair -c 0x03 -t 0x01 <addr>
+TC_SIP_BV_02_C         PASS    btmgmt advertising off
+                               l2test -n -J4 -V le_public <addr>
+TC_SIE_BV_01_C         PASS    btmgmt advertising on
+                               btmgmt pair -c 0x03 -t 0x01 <addr>
 -------------------------------------------------------------------------------
index ea4e26c..2d2815b 100644 (file)
@@ -1,7 +1,7 @@
 PTS test results for SPP
 
-PTS version: 5.3
-Tested: 12-November-2014
+PTS version: 6.0
+Tested: 29-January-2015
 Android version: 5.0
 
 Results:
@@ -13,11 +13,12 @@ N/A test is disabled due to PICS setup
 -------------------------------------------------------------------------------
 Test Name              Result  Notes
 -------------------------------------------------------------------------------
-TC_DevA_APP_BV_01_C    PASS    rctest -n -P <channel> <bdaddr>
-                               Note: IUT should sdp query PTS in order to
-                               check given channel for COM5
-TC_DevB_APP_BV_02_C    PASS    haltest: socket listen BTSOCK_RFCOMM
-                               <srvc_name> <uuid>
+TC_DevA_APP_BV_01_C    PASS    haltest: socket connect <PTS addr>
+                                       BTSOCK_RFCOMM 00001101 0
+TC_DevB_APP_BV_02_C    PASS    haltest: socket listen BTSOCK_RFCOMM SerialPort
+                                       00001101
+                               Note: IUT must be in connectable, discoverable
+                                       mode.
 TC_APP_BV_03_C         N/A     Missing in PTS
                                PTS issue #12388
                                Note: tests BV_03 : BV_6 currently not supported
index 1d5bf7c..f8f81f3 100644 (file)
 
 #include "src/log.h"
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
 #include "src/shared/util.h"
 #include "src/shared/queue.h"
 
index ec78dcd..15e1bfc 100644 (file)
@@ -98,6 +98,10 @@ static GList *connections = NULL;
 
 static struct rfcomm_channel servers[RFCOMM_CHANNEL_MAX + 1];
 
+static uint32_t test_sdp_record_uuid16 = 0;
+static uint32_t test_sdp_record_uuid32 = 0;
+static uint32_t test_sdp_record_uuid128 = 0;
+
 static int rfsock_set_buffer(struct rfcomm_sock *rfsock)
 {
        socklen_t len = sizeof(int);
@@ -878,6 +882,113 @@ failed:
        return HAL_STATUS_FAILED;
 }
 
+static uint32_t add_test_record(uuid_t *uuid)
+{
+       sdp_record_t *record;
+       sdp_list_t *svclass_id;
+       sdp_list_t *seq, *pbg_seq, *proto_seq, *ap_seq;
+       sdp_list_t *proto, *proto1, *aproto;
+       uuid_t l2cap_uuid, pbg_uuid, ap_uuid;
+
+       record = sdp_record_alloc();
+       if (!record)
+               return 0;
+
+       record->handle =  sdp_next_handle();
+
+       svclass_id = sdp_list_append(NULL, uuid);
+       sdp_set_service_classes(record, svclass_id);
+
+       sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+       proto = sdp_list_append(NULL, &l2cap_uuid);
+       seq = sdp_list_append(NULL, proto);
+
+       proto_seq = sdp_list_append(NULL, seq);
+       sdp_set_access_protos(record, proto_seq);
+
+       sdp_uuid16_create(&pbg_uuid, PUBLIC_BROWSE_GROUP);
+       pbg_seq = sdp_list_append(NULL, &pbg_uuid);
+       sdp_set_browse_groups(record, pbg_seq);
+
+       /* Additional Protocol Descriptor List */
+       sdp_uuid16_create(&ap_uuid, L2CAP_UUID);
+       proto1 = sdp_list_append(NULL, &ap_uuid);
+       ap_seq = sdp_list_append(NULL, proto1);
+       aproto = sdp_list_append(NULL, ap_seq);
+       sdp_set_add_access_protos(record, aproto);
+
+       sdp_set_service_id(record, *uuid);
+       sdp_set_record_state(record, 0);
+       sdp_set_service_ttl(record, 0);
+       sdp_set_service_avail(record, 0);
+       sdp_set_url_attr(record, "http://www.bluez.org",
+                               "http://www.bluez.org", "http://www.bluez.org");
+
+       sdp_list_free(proto, NULL);
+       sdp_list_free(seq, NULL);
+       sdp_list_free(proto_seq, NULL);
+       sdp_list_free(pbg_seq, NULL);
+       sdp_list_free(svclass_id, NULL);
+
+       if (bt_adapter_add_record(record, 0) < 0) {
+               sdp_record_free(record);
+               return 0;
+       }
+
+       return record->handle;
+}
+
+static void test_sdp_cleanup(void)
+{
+       if (test_sdp_record_uuid16) {
+               bt_adapter_remove_record(test_sdp_record_uuid16);
+               test_sdp_record_uuid16 = 0;
+       }
+
+       if (test_sdp_record_uuid32) {
+               bt_adapter_remove_record(test_sdp_record_uuid32);
+               test_sdp_record_uuid32 = 0;
+       }
+
+       if (test_sdp_record_uuid128) {
+               bt_adapter_remove_record(test_sdp_record_uuid128);
+               test_sdp_record_uuid128 = 0;
+       }
+}
+
+static void test_sdp_init(void)
+{
+       char uuid128[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+       uuid_t u;
+
+       sdp_uuid16_create(&u, 0xffff);
+       test_sdp_record_uuid16 = add_test_record(&u);
+
+       sdp_uuid32_create(&u, 0xffffffff);
+       test_sdp_record_uuid32 = add_test_record(&u);
+
+       sdp_uuid128_create(&u, uuid128);
+       test_sdp_record_uuid128 = add_test_record(&u);
+}
+
+static uint8_t l2cap_listen(int chan, const uint8_t *name, const uint8_t *uuid,
+                                               uint8_t flags, int *hal_sock)
+{
+       /* TODO be more strict here? */
+       if (strcmp("BlueZ", (const char *) name)) {
+               error("socket: Only SDP test supported on L2CAP");
+               return HAL_STATUS_UNSUPPORTED;
+       }
+
+       test_sdp_cleanup();
+       test_sdp_init();
+
+       *hal_sock = -1;
+
+       return HAL_STATUS_SUCCESS;
+}
+
 static void handle_listen(const void *buf, uint16_t len)
 {
        const struct hal_cmd_socket_listen *cmd = buf;
@@ -889,8 +1000,11 @@ static void handle_listen(const void *buf, uint16_t len)
                status = rfcomm_listen(cmd->channel, cmd->name, cmd->uuid,
                                                        cmd->flags, &hal_sock);
                break;
-       case HAL_SOCK_SCO:
        case HAL_SOCK_L2CAP:
+               status = l2cap_listen(cmd->channel, cmd->name, cmd->uuid,
+                                                       cmd->flags, &hal_sock);
+               break;
+       case HAL_SOCK_SCO:
                status = HAL_STATUS_UNSUPPORTED;
                break;
        default:
@@ -1193,6 +1307,8 @@ void bt_socket_unregister(void)
 
        DBG("");
 
+       test_sdp_cleanup();
+
        g_list_free_full(connections, cleanup_rfsock);
 
        for (ch = 0; ch <= RFCOMM_CHANNEL_MAX; ch++)
index 4adc109..61fb496 100644 (file)
@@ -32,7 +32,7 @@
 #include <signal.h>
 #include <string.h>
 #include <libgen.h>
-#include <sys/poll.h>
+#include <poll.h>
 #include <sys/wait.h>
 #include <sys/param.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#include "monitor/mainloop.h"
+#ifndef WAIT_ANY
+#define WAIT_ANY (-1)
+#endif
+
+#include "src/shared/mainloop.h"
 
 static char exec_dir[PATH_MAX];
 
index f6b0492..b8b088b 100644 (file)
 
 #define ATT_HANDLE_SIZE        2
 
+#define L2CAP_ATT_ERROR                        0x01
 #define L2CAP_ATT_EXCHANGE_MTU_REQ     0x02
 #define L2CAP_ATT_EXCHANGE_MTU_RSP     0x03
+#define L2CAP_ATT_FIND_BY_TYPE_REQ     0x06
 #define L2CAP_ATT_READ_REQ             0x0a
 #define L2CAP_ATT_READ_RSP             0x0b
 #define L2CAP_ATT_WRITE_REQ            0x12
@@ -39,6 +41,8 @@
 #define GATT_STATUS_FAILURE    0x00000101
 #define GATT_STATUS_INS_AUTH   0x08
 
+#define GATT_ERR_INVAL_ATTR_VALUE_LEN  0x0D
+
 #define GATT_SERVER_DISCONNECTED       0
 #define GATT_SERVER_CONNECTED          1
 
 
 static struct queue *list; /* List of gatt test cases */
 
-static int srvc1_handle;
-static int inc_srvc1_handle;
-static int char1_handle;
+static uint16_t srvc1_handle;
+static uint16_t inc_srvc1_handle;
+static uint16_t char1_handle;
+
+static struct iovec char1_handle_v = {
+       .iov_base = &char1_handle,
+       .iov_len = sizeof(char1_handle),
+};
 
 struct set_att_data {
        char *to;
@@ -92,7 +101,7 @@ struct set_att_data {
 };
 
 struct att_write_req_data {
-       int *attr_handle;
+       uint16_t *attr_handle;
        uint8_t *value;
 };
 
@@ -109,6 +118,10 @@ static bt_uuid_t app2_uuid = {
 static uint8_t value_1[] = {0x01};
 
 static uint8_t att_write_req_value_1[] = {0x00, 0x01, 0x02, 0x03};
+static struct iovec att_write_req_value_1_v = {
+       .iov_base = att_write_req_value_1,
+       .iov_len = sizeof(att_write_req_value_1),
+};
 
 struct gatt_connect_data {
        const int app_id;
@@ -189,12 +202,12 @@ struct add_service_data {
 
 struct add_included_service_data {
        int app_id;
-       int *inc_srvc_handle;
-       int *srvc_handle;
+       uint16_t *inc_srvc_handle;
+       uint16_t *srvc_handle;
 };
 struct add_char_data {
        int app_id;
-       int *srvc_handle;
+       uint16_t *srvc_handle;
        bt_uuid_t *uuid;
        int properties;
        int permissions;
@@ -202,30 +215,30 @@ struct add_char_data {
 
 struct add_desc_data {
        int app_id;
-       int *srvc_handle;
+       uint16_t *srvc_handle;
        bt_uuid_t *uuid;
        int permissions;
 };
 
 struct start_srvc_data {
        int app_id;
-       int *srvc_handle;
+       uint16_t *srvc_handle;
        int transport;
 };
 
 struct stop_srvc_data {
        int app_id;
-       int *srvc_handle;
+       uint16_t *srvc_handle;
 };
 
 struct delete_srvc_data {
        int app_id;
-       int *srvc_handle;
+       uint16_t *srvc_handle;
 };
 
 struct send_indication_data {
        int app_id;
-       int *attr_handle;
+       uint16_t *attr_handle;
        int conn_id;
        int len;
        int confirm;
@@ -255,6 +268,12 @@ static bt_property_t prop_emu_remotes_default_le_set[] = {
                                                &emu_remote_ble_device_type },
 };
 
+static struct bt_action_data prop_test_remote_ble_bdaddr_req = {
+       .addr = &emu_remote_bdaddr_val,
+       .prop_type = BT_PROPERTY_BDADDR,
+       .prop = &prop_emu_remotes_default_set[0],
+};
+
 static bt_scan_mode_t setprop_scan_mode_conn_val =
                                        BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE;
 
@@ -531,7 +550,7 @@ static struct add_service_data add_sec_service_data_1 = {
        .num_handles = 1
 };
 
-static int srvc_bad_handle = -1;
+static uint16_t srvc_bad_handle = 0xffff;
 
 static struct add_included_service_data add_inc_service_data_1 = {
        .app_id = APP1_ID,
@@ -634,7 +653,7 @@ static struct delete_srvc_data delete_bad_srvc_data_1 = {
        .srvc_handle = &srvc_bad_handle
 };
 
-static int srvc_indication_handle_1 = 0x01;
+static uint16_t srvc_indication_handle_1 = 0x01;
 
 static struct send_indication_data send_indication_data_1 = {
        .app_id = APP1_ID,
@@ -836,6 +855,13 @@ static struct send_resp_data send_resp_data_2 = {
        .response = &response_2,
 };
 
+static struct send_resp_data send_resp_data_2_error = {
+       .conn_id = CONN1_ID,
+       .trans_id = TRANS1_ID,
+       .status = GATT_ERR_INVAL_ATTR_VALUE_LEN,
+       .response = &response_2,
+};
+
 #define SEARCH_SERVICE_SINGLE_SUCCESS_PDUS                             \
        raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),              \
        raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x00, 0x18),        \
@@ -869,12 +895,33 @@ static struct iovec search_service_3[] = {
        end_pdu
 };
 
+static struct iovec search_service_4[] = {
+       raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
+       raw_pdu(0x11, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x18),
+       end_pdu
+};
+
 static struct iovec get_characteristic_1[] = {
        SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
        READ_BY_TYPE_SINGLE_CHARACTERISTIC_PDUS,
        end_pdu
 };
 
+static struct iovec get_characteristic_2[] = {
+       SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
+       raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),
+       raw_pdu(0x09, 0x07, 0x00, 0x00, 0x04, 0x00, 0x00, 0x19, 0x00),
+       end_pdu
+};
+
+static struct iovec get_descriptor_0[] = {
+       SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
+       READ_BY_TYPE_SINGLE_CHARACTERISTIC_PDUS,
+       raw_pdu(0x04, 0x01, 0x00, 0x10, 0x00),
+       raw_pdu(0x05, 0x01, 0x00, 0x00, 0x00, 0x29),
+       end_pdu
+};
+
 static struct iovec get_descriptor_1[] = {
        SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
        READ_BY_TYPE_SINGLE_CHARACTERISTIC_PDUS,
@@ -903,6 +950,13 @@ static struct iovec get_descriptor_3[] = {
        end_pdu
 };
 
+static struct iovec get_included_0[] = {
+       SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
+       raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x02, 0x28),
+       raw_pdu(0x09, 0x08, 0x00, 0x00, 0x15, 0x00, 0x19, 0x00, 0xff, 0xfe),
+       end_pdu
+};
+
 static struct iovec get_included_1[] = {
        SEARCH_SERVICE_SINGLE_SUCCESS_PDUS,
        raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x02, 0x28),
@@ -1065,59 +1119,21 @@ static struct iovec send_notification_1[] = {
        end_pdu
 };
 
-static struct att_write_req_data att_write_req_data_1  = {
-       .attr_handle = &char1_handle,
-       .value = att_write_req_value_1,
+static struct iovec search_range_1[] = {
+       raw_pdu(0x01, 0xff, 0xff, 0xff),
+       end_pdu
 };
 
-/* att commands define raw pdus */
-static struct iovec att_read_req = raw_pdu(0x0a, 0x00, 0x00);
-static struct iovec att_write_req_1 = raw_pdu(0x12, 0x00, 0x00, 0x00, 0x00,
-                                                               0x00, 0x00);
-
-static void gatt_att_pdu_modify(void)
-{
-       struct test_data *data = tester_get_data();
-       struct step *current_data_step = queue_peek_head(data->steps);
-       struct iovec *store_pdu = current_data_step->set_data_to;
-       struct step *step = g_new0(struct step, 1);
-       unsigned char *raw_pdu = store_pdu->iov_base;
-       int set_data_len = current_data_step->set_data_len;
-
-       switch (raw_pdu[0]) {
-       case L2CAP_ATT_READ_REQ: {
-               uint16_t handle = *((int *)current_data_step->set_data);
-
-               memcpy(raw_pdu + 1, &handle, set_data_len);
-               tester_debug("gatt: modify pdu read request handle to 0x%02x",
-                                                                       handle);
-
-               break;
-       }
-
-       case L2CAP_ATT_WRITE_REQ: {
-               struct att_write_req_data *pdu_set_data =
-                                               current_data_step->set_data;
-               uint16_t handle = *((int *)(pdu_set_data->attr_handle));
-               uint8_t *value = pdu_set_data->value;
-
-               memcpy(raw_pdu + 1, &handle, sizeof(handle));
-               memcpy(raw_pdu + 3, value, set_data_len - sizeof(handle));
-
-               tester_debug("gatt: modify pdu write request handle to 0x%02x",
-                                                                       handle);
-
-               break;
-       }
-       default:
-               tester_debug("modify att pdu with opcode 0x%02x not handled",
-                                                               raw_pdu[0]);
+static struct iovec primary_type = raw_pdu(0x00, 0x28);
 
-               break;
-       }
+/* att commands define raw pdus */
+static struct iovec att_read_req_op_v = raw_pdu(L2CAP_ATT_READ_REQ);
+static struct iovec att_write_req_op_v = raw_pdu(L2CAP_ATT_WRITE_REQ);
+static struct iovec att_find_by_type_req_op_v =
+                                       raw_pdu(L2CAP_ATT_FIND_BY_TYPE_REQ);
 
-       schedule_action_verification(step);
-}
+static struct iovec svc_change_ccc_handle_v = raw_pdu(0x1c, 0x00);
+static struct iovec svc_change_ccc_value_v = raw_pdu(0x00, 0x01);
 
 static void gatt_client_register_action(void)
 {
@@ -1607,6 +1623,14 @@ static void gatt_cid_hook_cb(const void *data, uint16_t len, void *user_data)
        tester_debug("Received att pdu with opcode 0x%02x", pdu[0]);
 
        switch (pdu[0]) {
+       case L2CAP_ATT_ERROR:
+               step = g_new0(struct step, 1);
+
+               step->callback = CB_EMU_ATT_ERROR;
+               step->callback_result.error = pdu[4];
+
+               schedule_callback_verification(step);
+               break;
        case L2CAP_ATT_EXCHANGE_MTU_REQ:
                tester_print("Exchange MTU request received.");
 
@@ -1626,7 +1650,7 @@ static void gatt_cid_hook_cb(const void *data, uint16_t len, void *user_data)
                step->callback = CB_EMU_VALUE_INDICATION;
 
                schedule_callback_verification(step);
-               break;
+               goto respond;
        case L2CAP_ATT_HANDLE_VALUE_NOTIFY:
                step = g_new0(struct step, 1);
 
@@ -1663,6 +1687,7 @@ static void gatt_cid_hook_cb(const void *data, uint16_t len, void *user_data)
                        break;
                }
 
+respond:
                if (memcmp(gatt_pdu->iov_base, data, len)) {
                        tester_print("Incoming data mismatch");
                        break;
@@ -1704,17 +1729,44 @@ static void gatt_remote_send_raw_pdu_action(void)
        struct bthost *bthost = hciemu_client_get_host(data->hciemu);
        struct step *current_data_step = queue_peek_head(data->steps);
        struct iovec *pdu = current_data_step->set_data;
+       struct iovec *pdu2 = current_data_step->set_data_2;
+       struct iovec *pdu3 = current_data_step->set_data_3;
        struct step *step = g_new0(struct step, 1);
 
        if (cid_data.handle && cid_data.cid) {
-               bthost_send_cid_v(bthost, cid_data.handle, cid_data.cid,
-                                                                       pdu, 1);
+               struct iovec rsp[3];
+               size_t len = 0;
+
+               if (!pdu) {
+                       step->action_status = BT_STATUS_FAIL;
+                       goto done;
+               }
+
+               rsp[0].iov_base = pdu->iov_base;
+               rsp[0].iov_len = pdu->iov_len;
+               len++;
+
+               if (pdu2) {
+                       rsp[1].iov_base = pdu2->iov_base;
+                       rsp[1].iov_len = pdu2->iov_len;
+                       len++;
+               }
+
+               if (pdu3) {
+                       rsp[2].iov_base = pdu3->iov_base;
+                       rsp[2].iov_len = pdu3->iov_len;
+                       len++;
+               }
+
+               bthost_send_cid_v(bthost, cid_data.handle, cid_data.cid, rsp,
+                                                                       len);
                step->action_status = BT_STATUS_SUCCESS;
        } else {
                tester_debug("No connection set up");
                step->action_status = BT_STATUS_FAIL;
        }
 
+done:
        schedule_action_verification(step);
 }
 
@@ -2113,6 +2165,27 @@ static struct test_case test_cases[] = {
                ACTION_SUCCESS(bluetooth_disable_action, NULL),
                CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
        ),
+       TEST_CASE_BREDRLE("Gatt Client - Search Service - Incorrect rsp",
+               ACTION_SUCCESS(init_pdus, search_service_4),
+               ACTION_SUCCESS(bluetooth_enable_action, NULL),
+               CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_ON),
+               ACTION_SUCCESS(emu_setup_powered_remote_action, NULL),
+               ACTION_SUCCESS(emu_set_ssp_mode_action, NULL),
+               ACTION_SUCCESS(emu_set_connect_cb_action, gatt_conn_cb),
+               ACTION_SUCCESS(gatt_client_register_action, &app1_uuid),
+               CALLBACK_STATUS(CB_GATTC_REGISTER_CLIENT, BT_STATUS_SUCCESS),
+               ACTION_SUCCESS(gatt_client_start_scan_action, NULL),
+               CLLBACK_GATTC_SCAN_RES(prop_emu_remotes_default_set, 1, TRUE),
+               ACTION_SUCCESS(gatt_client_stop_scan_action, NULL),
+               ACTION_SUCCESS(gatt_client_connect_action, &app1_conn_req),
+               CALLBACK_GATTC_CONNECT(GATT_STATUS_SUCCESS,
+                                               prop_emu_remotes_default_set,
+                                               CONN1_ID, APP1_ID),
+               ACTION_SUCCESS(gatt_client_search_services, &search_services_1),
+               CALLBACK_GATTC_SEARCH_COMPLETE(GATT_STATUS_SUCCESS, CONN1_ID),
+               ACTION_SUCCESS(bluetooth_disable_action, NULL),
+               CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+       ),
        TEST_CASE_BREDRLE("Gatt Client - Get Characteristic - Single",
                ACTION_SUCCESS(init_pdus, get_characteristic_1),
                ACTION_SUCCESS(bluetooth_enable_action, NULL),
@@ -2138,6 +2211,31 @@ static struct test_case test_cases[] = {
                ACTION_SUCCESS(bluetooth_disable_action, NULL),
                CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
        ),
+       TEST_CASE_BREDRLE("Gatt Client - Get Characteristic - Incorrect rsp",
+               ACTION_SUCCESS(init_pdus, get_characteristic_2),
+               ACTION_SUCCESS(bluetooth_enable_action, NULL),
+               CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_ON),
+               ACTION_SUCCESS(emu_setup_powered_remote_action, NULL),
+               ACTION_SUCCESS(emu_set_ssp_mode_action, NULL),
+               ACTION_SUCCESS(emu_set_connect_cb_action, gatt_conn_cb),
+               ACTION_SUCCESS(gatt_client_register_action, &app1_uuid),
+               CALLBACK_STATUS(CB_GATTC_REGISTER_CLIENT, BT_STATUS_SUCCESS),
+               ACTION_SUCCESS(gatt_client_start_scan_action, NULL),
+               CLLBACK_GATTC_SCAN_RES(prop_emu_remotes_default_set, 1, TRUE),
+               ACTION_SUCCESS(gatt_client_stop_scan_action, NULL),
+               ACTION_SUCCESS(gatt_client_connect_action, &app1_conn_req),
+               CALLBACK_GATTC_CONNECT(GATT_STATUS_SUCCESS,
+                                               prop_emu_remotes_default_set,
+                                               CONN1_ID, APP1_ID),
+               ACTION_SUCCESS(gatt_client_search_services, &search_services_1),
+               CALLBACK_GATTC_SEARCH_COMPLETE(GATT_STATUS_SUCCESS, CONN1_ID),
+               ACTION_SUCCESS(gatt_client_get_characteristic_action,
+                                                       &get_char_data_1),
+               CALLBACK_GATTC_GET_CHARACTERISTIC_CB(GATT_STATUS_FAILURE,
+                               CONN1_ID, &service_1, NULL, 0),
+               ACTION_SUCCESS(bluetooth_disable_action, NULL),
+               CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+       ),
        TEST_CASE_BREDRLE("Gatt Client - Get Characteristic - None",
                ACTION_SUCCESS(init_pdus, get_characteristic_1),
                ACTION_SUCCESS(bluetooth_enable_action, NULL),
@@ -2164,6 +2262,35 @@ static struct test_case test_cases[] = {
                ACTION_SUCCESS(bluetooth_disable_action, NULL),
                CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
        ),
+       TEST_CASE_BREDRLE("Gatt Client - Get Descriptor - Incorrect rsp",
+               ACTION_SUCCESS(init_pdus, get_descriptor_0),
+               ACTION_SUCCESS(bluetooth_enable_action, NULL),
+               CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_ON),
+               ACTION_SUCCESS(emu_setup_powered_remote_action, NULL),
+               ACTION_SUCCESS(emu_set_ssp_mode_action, NULL),
+               ACTION_SUCCESS(emu_set_connect_cb_action, gatt_conn_cb),
+               ACTION_SUCCESS(gatt_client_register_action, &app1_uuid),
+               CALLBACK_STATUS(CB_GATTC_REGISTER_CLIENT, BT_STATUS_SUCCESS),
+               ACTION_SUCCESS(gatt_client_start_scan_action, NULL),
+               CLLBACK_GATTC_SCAN_RES(prop_emu_remotes_default_set, 1, TRUE),
+               ACTION_SUCCESS(gatt_client_stop_scan_action, NULL),
+               ACTION_SUCCESS(gatt_client_connect_action, &app1_conn_req),
+               CALLBACK_GATTC_CONNECT(GATT_STATUS_SUCCESS,
+                                               prop_emu_remotes_default_set,
+                                               CONN1_ID, APP1_ID),
+               ACTION_SUCCESS(gatt_client_search_services, &search_services_1),
+               CALLBACK_GATTC_SEARCH_COMPLETE(GATT_STATUS_SUCCESS, CONN1_ID),
+               ACTION_SUCCESS(gatt_client_get_characteristic_action,
+                                                       &get_char_data_1),
+               CALLBACK_GATTC_GET_CHARACTERISTIC_CB(GATT_STATUS_SUCCESS,
+                               CONN1_ID, &service_1, &characteristic_1, 4),
+               ACTION_SUCCESS(gatt_client_get_descriptor_action,
+                                                       &get_desc_data_1),
+               CALLBACK_GATTC_GET_DESCRIPTOR(GATT_STATUS_FAILURE, CONN1_ID,
+                               &service_1, &characteristic_1, NULL),
+               ACTION_SUCCESS(bluetooth_disable_action, NULL),
+               CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+       ),
        TEST_CASE_BREDRLE("Gatt Client - Get Descriptor - Single",
                ACTION_SUCCESS(init_pdus, get_descriptor_1),
                ACTION_SUCCESS(bluetooth_enable_action, NULL),
@@ -2258,6 +2385,31 @@ static struct test_case test_cases[] = {
                ACTION_SUCCESS(bluetooth_disable_action, NULL),
                CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
        ),
+       TEST_CASE_BREDRLE("Gatt Client - Get Included Services - Incorrect rsp",
+               ACTION_SUCCESS(init_pdus, get_included_0),
+               ACTION_SUCCESS(bluetooth_enable_action, NULL),
+               CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_ON),
+               ACTION_SUCCESS(emu_setup_powered_remote_action, NULL),
+               ACTION_SUCCESS(emu_set_ssp_mode_action, NULL),
+               ACTION_SUCCESS(emu_set_connect_cb_action, gatt_conn_cb),
+               ACTION_SUCCESS(gatt_client_register_action, &app1_uuid),
+               CALLBACK_STATUS(CB_GATTC_REGISTER_CLIENT, BT_STATUS_SUCCESS),
+               ACTION_SUCCESS(gatt_client_start_scan_action, NULL),
+               CLLBACK_GATTC_SCAN_RES(prop_emu_remotes_default_set, 1, TRUE),
+               ACTION_SUCCESS(gatt_client_stop_scan_action, NULL),
+               ACTION_SUCCESS(gatt_client_connect_action, &app1_conn_req),
+               CALLBACK_GATTC_CONNECT(GATT_STATUS_SUCCESS,
+                                               prop_emu_remotes_default_set,
+                                               CONN1_ID, APP1_ID),
+               ACTION_SUCCESS(gatt_client_search_services, &search_services_1),
+               CALLBACK_GATTC_SEARCH_COMPLETE(GATT_STATUS_SUCCESS, CONN1_ID),
+               ACTION_SUCCESS(gatt_client_get_included_action,
+                                                       &get_incl_data_1),
+               CALLBACK_GATTC_GET_INCLUDED(GATT_STATUS_FAILURE, CONN1_ID,
+                                                       &service_1, NULL),
+               ACTION_SUCCESS(bluetooth_disable_action, NULL),
+               CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+               ),
        TEST_CASE_BREDRLE("Gatt Client - Get Included Service - 16 UUID",
                ACTION_SUCCESS(init_pdus, get_included_1),
                ACTION_SUCCESS(bluetooth_enable_action, NULL),
@@ -3245,6 +3397,7 @@ static struct test_case test_cases[] = {
                ACTION_SUCCESS(gatt_server_send_indication_action,
                                                &send_indication_data_1),
                CALLBACK(CB_EMU_VALUE_INDICATION),
+               CALLBACK_GATTS_NOTIF_CONF(CONN1_ID, GATT_STATUS_SUCCESS),
                ACTION_SUCCESS(bluetooth_disable_action, NULL),
                CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
        ),
@@ -3268,6 +3421,7 @@ static struct test_case test_cases[] = {
                                                CONN1_ID, APP1_ID),
                ACTION_SUCCESS(gatt_server_send_indication_action,
                                                &send_indication_data_2),
+               CALLBACK_GATTS_NOTIF_CONF(CONN1_ID, GATT_STATUS_SUCCESS),
                CALLBACK(CB_EMU_VALUE_NOTIFICATION),
                ACTION_SUCCESS(bluetooth_disable_action, NULL),
                CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
@@ -3325,10 +3479,9 @@ static struct test_case test_cases[] = {
                CALLBACK_GATTS_CONNECTION(GATT_SERVER_CONNECTED,
                                                prop_emu_remotes_default_set,
                                                CONN1_ID, APP1_ID),
-               MODIFY_DATA(GATT_STATUS_SUCCESS, gatt_att_pdu_modify,
-                                               &char1_handle, &att_read_req,
-                                               ATT_HANDLE_SIZE),
-               ACTION_SUCCESS(gatt_remote_send_raw_pdu_action, &att_read_req),
+               PROCESS_DATA(GATT_STATUS_SUCCESS,
+                               gatt_remote_send_raw_pdu_action,
+                               &att_read_req_op_v, &char1_handle_v, NULL),
                CALLBACK_GATTS_REQUEST_READ(CONN1_ID, TRANS1_ID,
                                                prop_emu_remotes_default_set,
                                                &char1_handle, 0, false),
@@ -3369,12 +3522,10 @@ static struct test_case test_cases[] = {
                CALLBACK_GATTS_CONNECTION(GATT_SERVER_CONNECTED,
                                                prop_emu_remotes_default_set,
                                                CONN1_ID, APP1_ID),
-               MODIFY_DATA(GATT_STATUS_SUCCESS, gatt_att_pdu_modify,
-                                       &att_write_req_data_1, &att_write_req_1,
-                                       sizeof(att_write_req_value_1) +
-                                       ATT_HANDLE_SIZE),
-               ACTION_SUCCESS(gatt_remote_send_raw_pdu_action,
-                                                       &att_write_req_1),
+               PROCESS_DATA(GATT_STATUS_SUCCESS,
+                                       gatt_remote_send_raw_pdu_action,
+                                       &att_write_req_op_v, &char1_handle_v,
+                                       &att_write_req_value_1_v),
                CALLBACK_GATTS_REQUEST_WRITE(CONN1_ID, TRANS1_ID,
                                                prop_emu_remotes_default_set,
                                                &char1_handle, 0,
@@ -3387,6 +3538,126 @@ static struct test_case test_cases[] = {
                ACTION_SUCCESS(bluetooth_disable_action, NULL),
                CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
        ),
+       TEST_CASE_BREDRLE("Gatt Server - Find By Type - Attribute not found",
+               ACTION_SUCCESS(bluetooth_enable_action, NULL),
+               CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_ON),
+               ACTION_SUCCESS(emu_setup_powered_remote_action, NULL),
+               ACTION_SUCCESS(emu_set_ssp_mode_action, NULL),
+               ACTION_SUCCESS(emu_set_connect_cb_action, gatt_conn_cb),
+               ACTION_SUCCESS(gatt_server_register_action, &app1_uuid),
+               CALLBACK_STATUS(CB_GATTS_REGISTER_SERVER, BT_STATUS_SUCCESS),
+               ACTION_SUCCESS(gatt_server_add_service_action,
+                                                       &add_service_data_5),
+               CALLBACK_GATTS_SERVICE_ADDED(GATT_STATUS_SUCCESS, APP1_ID,
+                                                       &service_add_1, NULL,
+                                                       &srvc1_handle),
+               ACTION_SUCCESS(gatt_server_add_char_action, &add_char_data_2),
+               CALLBACK_GATTS_CHARACTERISTIC_ADDED(GATT_STATUS_SUCCESS,
+                                                       APP1_ID, &app1_uuid,
+                                                       &srvc1_handle, NULL,
+                                                       &char1_handle),
+               ACTION_SUCCESS(gatt_server_start_srvc_action,
+                                                       &start_srvc_data_2),
+               CALLBACK_GATTS_SERVICE_STARTED(GATT_STATUS_SUCCESS, APP1_ID,
+                                                               &srvc1_handle),
+               ACTION_SUCCESS(bt_start_discovery_action, NULL),
+               CALLBACK_STATE(CB_BT_DISCOVERY_STATE_CHANGED,
+                                                       BT_DISCOVERY_STARTED),
+               CALLBACK_DEVICE_FOUND(prop_emu_remotes_default_le_set, 2),
+               ACTION_SUCCESS(bt_cancel_discovery_action, NULL),
+               ACTION_SUCCESS(gatt_server_connect_action, &app1_conn_req),
+               CALLBACK_GATTS_CONNECTION(GATT_SERVER_CONNECTED,
+                                               prop_emu_remotes_default_set,
+                                               CONN1_ID, APP1_ID),
+               PROCESS_DATA(GATT_STATUS_SUCCESS,
+                                               gatt_remote_send_raw_pdu_action,
+                                               &att_find_by_type_req_op_v,
+                                               &search_range_1,
+                                               &primary_type),
+               CALLBACK_ERROR(CB_EMU_ATT_ERROR, 0x0a),
+               ACTION_SUCCESS(bluetooth_disable_action, NULL),
+               CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+       ),
+       /* This tests embeded ccc */
+       TEST_CASE_BREDRLE("Gatt Server - Srvc change write req. success",
+               ACTION_SUCCESS(bluetooth_enable_action, NULL),
+               CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_ON),
+               ACTION_SUCCESS(emu_setup_powered_remote_action, NULL),
+               ACTION_SUCCESS(emu_set_ssp_mode_action, NULL),
+               ACTION_SUCCESS(emu_set_connect_cb_action, gatt_conn_cb),
+               ACTION_SUCCESS(gatt_server_register_action, &app1_uuid),
+               CALLBACK_STATUS(CB_GATTS_REGISTER_SERVER, BT_STATUS_SUCCESS),
+               ACTION_SUCCESS(bt_start_discovery_action, NULL),
+               CALLBACK_STATE(CB_BT_DISCOVERY_STATE_CHANGED,
+                                                       BT_DISCOVERY_STARTED),
+               CALLBACK_DEVICE_FOUND(prop_emu_remotes_default_le_set, 2),
+               ACTION_SUCCESS(bt_cancel_discovery_action, NULL),
+               ACTION_SUCCESS(gatt_server_connect_action, &app1_conn_req),
+               CALLBACK_GATTS_CONNECTION(GATT_SERVER_CONNECTED,
+                                               prop_emu_remotes_default_set,
+                                               CONN1_ID, APP1_ID),
+               /* For CCC we need to be bonded */
+               ACTION_SUCCESS(bt_create_bond_action,
+                                       &prop_test_remote_ble_bdaddr_req),
+               CALLBACK_BOND_STATE(BT_BOND_STATE_BONDED,
+                                       &prop_emu_remotes_default_set[0], 1),
+               /* Write and receive confirmation */
+               PROCESS_DATA(GATT_STATUS_SUCCESS,
+                               gatt_remote_send_raw_pdu_action,
+                               &att_write_req_op_v, &svc_change_ccc_handle_v,
+                               &svc_change_ccc_value_v),
+               CALLBACK(CB_EMU_WRITE_RESPONSE),
+               /* Shutdown */
+               ACTION_SUCCESS(bluetooth_disable_action, NULL),
+               CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+       ),
+       TEST_CASE_BREDRLE("Gatt Server - Send error resp to write char request",
+               ACTION_SUCCESS(bluetooth_enable_action, NULL),
+               CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_ON),
+               ACTION_SUCCESS(emu_setup_powered_remote_action, NULL),
+               ACTION_SUCCESS(emu_set_ssp_mode_action, NULL),
+               ACTION_SUCCESS(emu_set_connect_cb_action, gatt_conn_cb),
+               ACTION_SUCCESS(gatt_server_register_action, &app1_uuid),
+               CALLBACK_STATUS(CB_GATTS_REGISTER_SERVER, BT_STATUS_SUCCESS),
+               ACTION_SUCCESS(gatt_server_add_service_action,
+                                                       &add_service_data_5),
+               CALLBACK_GATTS_SERVICE_ADDED(GATT_STATUS_SUCCESS, APP1_ID,
+                                                       &service_add_1, NULL,
+                                                       &srvc1_handle),
+               ACTION_SUCCESS(gatt_server_add_char_action, &add_char_data_2),
+               CALLBACK_GATTS_CHARACTERISTIC_ADDED(GATT_STATUS_SUCCESS,
+                                                       APP1_ID, &app1_uuid,
+                                                       &srvc1_handle, NULL,
+                                                       &char1_handle),
+               ACTION_SUCCESS(gatt_server_start_srvc_action,
+                                                       &start_srvc_data_2),
+               CALLBACK_GATTS_SERVICE_STARTED(GATT_STATUS_SUCCESS, APP1_ID,
+                                                               &srvc1_handle),
+               ACTION_SUCCESS(bt_start_discovery_action, NULL),
+               CALLBACK_STATE(CB_BT_DISCOVERY_STATE_CHANGED,
+                                                       BT_DISCOVERY_STARTED),
+               CALLBACK_DEVICE_FOUND(prop_emu_remotes_default_le_set, 2),
+               ACTION_SUCCESS(bt_cancel_discovery_action, NULL),
+               ACTION_SUCCESS(gatt_server_connect_action, &app1_conn_req),
+               CALLBACK_GATTS_CONNECTION(GATT_SERVER_CONNECTED,
+                                               prop_emu_remotes_default_set,
+                                               CONN1_ID, APP1_ID),
+               PROCESS_DATA(GATT_STATUS_SUCCESS,
+                                       gatt_remote_send_raw_pdu_action,
+                                       &att_write_req_op_v, &char1_handle_v,
+                                       &att_write_req_value_1_v),
+               CALLBACK_GATTS_REQUEST_WRITE(CONN1_ID, TRANS1_ID,
+                                               prop_emu_remotes_default_set,
+                                               &char1_handle, 0,
+                                               sizeof(att_write_req_value_1),
+                                               true, false,
+                                               att_write_req_value_1),
+               ACTION_SUCCESS(gatt_server_send_response_action,
+                                               &send_resp_data_2_error),
+               CALLBACK_ERROR(CB_EMU_ATT_ERROR, GATT_ERR_INVAL_ATTR_VALUE_LEN),
+               ACTION_SUCCESS(bluetooth_disable_action, NULL),
+               CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_OFF),
+               ),
 };
 
 struct queue *get_gatt_tests(void)
index 336a9a8..2506548 100644 (file)
@@ -121,6 +121,7 @@ static struct {
        DBG_CB(CB_GATTS_REQUEST_WRITE),
        DBG_CB(CB_GATTS_REQUEST_EXEC_WRITE),
        DBG_CB(CB_GATTS_RESPONSE_CONFIRMATION),
+       DBG_CB(CB_GATTS_INDICATION_SEND),
 
        /* Map client */
        DBG_CB(CB_MAP_CLIENT_REMOTE_MAS_INSTANCES),
@@ -134,6 +135,7 @@ static struct {
        DBG_CB(CB_EMU_VALUE_NOTIFICATION),
        DBG_CB(CB_EMU_READ_RESPONSE),
        DBG_CB(CB_EMU_WRITE_RESPONSE),
+       DBG_CB(CB_EMU_ATT_ERROR),
 };
 
 static gboolean check_callbacks_called(gpointer user_data)
@@ -1036,6 +1038,13 @@ static bool match_data(struct step *step)
                return false;
        }
 
+       if (exp->callback_result.error != step->callback_result.error) {
+               tester_debug("Err mismatch: %d vs %d",
+                               exp->callback_result.error,
+                               step->callback_result.error);
+               return false;
+       }
+
        if (exp->store_srvc_handle)
                memcpy(exp->store_srvc_handle,
                                        step->callback_result.srvc_handle,
@@ -1992,6 +2001,18 @@ static void gatts_request_write_cb(int conn_id, int trans_id, bt_bdaddr_t *bda,
        schedule_callback_verification(step);
 }
 
+static void gatts_indication_send_cb(int conn_id, int status)
+{
+       struct step *step = g_new0(struct step, 1);
+
+       step->callback = CB_GATTS_INDICATION_SEND;
+
+       step->callback_result.conn_id = conn_id;
+       step->callback_result.status = status;
+
+       schedule_callback_verification(step);
+}
+
 static const btgatt_server_callbacks_t btgatt_server_callbacks = {
        .register_server_cb = gatts_register_server_cb,
        .connection_cb = gatts_connection_cb,
@@ -2005,7 +2026,9 @@ static const btgatt_server_callbacks_t btgatt_server_callbacks = {
        .request_read_cb = gatts_request_read_cb,
        .request_write_cb = gatts_request_write_cb,
        .request_exec_write_cb = NULL,
-       .response_confirmation_cb = NULL
+       .response_confirmation_cb = NULL,
+       .indication_sent_cb = gatts_indication_send_cb,
+       .congestion_cb = NULL,
 };
 
 static const btgatt_callbacks_t btgatt_callbacks = {
index dc1a2bb..8a7384c 100644 (file)
@@ -68,10 +68,18 @@ struct pdu_set {
                .action_status = status, \
                .action = modif_fun, \
                .set_data = from, \
-               .set_data_to = to, \
+               .set_data_2 = to, \
                .set_data_len = len, \
        }
 
+#define PROCESS_DATA(status, proc_fun, data1, data2, data3) { \
+               .action_status = status, \
+               .action = proc_fun, \
+               .set_data = data1, \
+               .set_data_2 = data2, \
+               .set_data_3 = data3, \
+       }
+
 #define ACTION(status, act_fun, data_set) { \
                .action_status = status, \
                .action = act_fun, \
@@ -98,6 +106,11 @@ struct pdu_set {
                .callback_result.status = cb_res, \
        }
 
+#define CALLBACK_ERROR(cb, cb_err) { \
+               .callback = cb, \
+               .callback_result.error = cb_err, \
+       }
+
 #define CALLBACK_ADAPTER_PROPS(props, prop_cnt) { \
                .callback = CB_BT_ADAPTER_PROPERTIES, \
                .callback_result.properties = props, \
@@ -240,6 +253,12 @@ struct pdu_set {
                .callback_result.gatt_app_id = cb_server_id, \
        }
 
+#define CALLBACK_GATTS_NOTIF_CONF(cb_conn_id, cb_status) { \
+               .callback = CB_GATTS_INDICATION_SEND, \
+               .callback_result.conn_id = cb_conn_id, \
+               .callback_result.status = cb_status, \
+       }
+
 #define CALLBACK_GATTS_SERVICE_ADDED(cb_res, cb_server_id, cb_service, \
                                                cb_srvc_handle, \
                                                cb_store_srvc_handle) { \
@@ -527,6 +546,7 @@ typedef enum {
        CB_GATTS_REQUEST_WRITE,
        CB_GATTS_REQUEST_EXEC_WRITE,
        CB_GATTS_RESPONSE_CONFIRMATION,
+       CB_GATTS_INDICATION_SEND,
 
        /* Map client */
        CB_MAP_CLIENT_REMOTE_MAS_INSTANCES,
@@ -540,6 +560,7 @@ typedef enum {
        CB_EMU_VALUE_NOTIFICATION,
        CB_EMU_READ_RESPONSE,
        CB_EMU_WRITE_RESPONSE,
+       CB_EMU_ATT_ERROR,
 } expected_bt_callback_t;
 
 struct test_data {
@@ -651,11 +672,11 @@ struct bt_callback_data {
        int offset;
        bool is_long;
        int connected;
-       int *attr_handle;
-       int *srvc_handle;
-       int *inc_srvc_handle;
-       int *char_handle;
-       int *desc_handle;
+       uint16_t *attr_handle;
+       uint16_t *srvc_handle;
+       uint16_t *inc_srvc_handle;
+       uint16_t *char_handle;
+       uint16_t *desc_handle;
        btgatt_srvc_id_t *service;
        btgatt_gatt_id_t *characteristic;
        btgatt_gatt_id_t *descriptor;
@@ -669,6 +690,7 @@ struct bt_callback_data {
        uint8_t *value;
        bool need_rsp;
        bool is_prep;
+       uint8_t error;
 
        btpan_control_state_t ctrl_state;
        btpan_connection_state_t conn_state;
@@ -706,12 +728,13 @@ struct step {
        struct bt_callback_data callback_result;
 
        void *set_data;
-       void *set_data_to;
+       void *set_data_2;
+       void *set_data_3;
        int set_data_len;
 
-       int *store_srvc_handle;
-       int *store_char_handle;
-       int *store_desc_handle;
+       uint16_t *store_srvc_handle;
+       uint16_t *store_char_handle;
+       uint16_t *store_desc_handle;
 };
 
 struct test_case {
index 71f2a59..4d39de1 100644 (file)
 #include <stdint.h>
 #include <stdlib.h>
 
-#include <bluetooth/bluetooth.h>
-
 #include <glib.h>
 
-#include "src/shared/util.h"
+#include "lib/bluetooth.h"
 #include "lib/uuid.h"
+
+#include "src/shared/util.h"
 #include "att.h"
 
 static inline void put_uuid_le(const bt_uuid_t *src, void *dst)
index bae400c..e80aeda 100644 (file)
@@ -107,6 +107,8 @@ struct att_range {
 };
 
 #ifdef __TIZEN_PATCH__
+void get_uuid(uint8_t type, const void *val, bt_uuid_t *uuid);
+
 static inline bt_uuid_t att_get_uuid(const void *ptr, uint8_t len)
 {
        bt_uuid_t uuid;
@@ -218,6 +220,3 @@ uint16_t enc_exec_write_req(uint8_t flags, uint8_t *pdu, size_t len);
 uint16_t dec_exec_write_req(const uint8_t *pdu, size_t len, uint8_t *flags);
 uint16_t enc_exec_write_resp(uint8_t *pdu);
 uint16_t dec_exec_write_resp(const uint8_t *pdu, size_t len);
-#ifdef __TIZEN_PATCH__
-void get_uuid(uint8_t type, const void *val, bt_uuid_t *uuid);
-#endif
diff --git a/attrib/client.c b/attrib/client.c
deleted file mode 100644 (file)
index 80e165b..0000000
+++ /dev/null
@@ -1,1411 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2010  Nokia Corporation
- *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef __TIZEN_PATCH__
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <glib.h>
-
-#include <bluetooth/bluetooth.h>
-
-#include "lib/uuid.h"
-#include "src/adapter.h"
-#include "src/device.h"
-#include "src/log.h"
-#include "gdbus/gdbus.h"
-#include "src/error.h"
-#include "src/dbus-common.h"
-#include "btio/btio.h"
-#include "src/storage.h"
-
-
-#include "att.h"
-#include "gattrib.h"
-#include "src/attio.h"
-#include "gatt.h"
-#include "client.h"
-#include "src/shared/util.h"
-
-#define CHAR_INTERFACE "org.bluez.Characteristic"
-
-#define ATT_MAX_MTU 256
-struct format {
-       guint8 format;
-       guint8 exponent;
-       guint16 unit;
-       guint8 namespace;
-       guint16 desc;
-} __attribute__ ((packed));
-
-struct query {
-       DBusMessage *msg;
-       GSList *list;
-};
-
-struct gatt_service {
-       struct btd_device *dev;
-       struct gatt_primary *prim;
-       DBusConnection *conn;
-       GAttrib *attrib;
-       guint attioid;
-       int psm;
-       char *path;
-       GSList *chars;
-       GSList *offline_chars;
-       GSList *watchers;
-       struct query *query;
-};
-
-struct characteristic {
-       struct gatt_service *gatt;
-       char *path;
-       uint16_t handle;
-       uint16_t end;
-       uint8_t perm;
-       char type[MAX_LEN_UUID_STR + 1];
-       char *name;
-       char *desc;
-       struct format *format;
-       uint8_t *value;
-       size_t vlen;
-};
-
-struct query_data {
-       struct gatt_service *gatt;
-       struct characteristic *chr;
-       uint16_t handle;
-};
-
-struct watcher {
-       guint id;
-       char *name;
-       char *path;
-       struct gatt_service *gatt;
-};
-
-typedef enum {
-       BT_IO_L2CAP,
-} BtIOType;
-
-struct discover_charecteristics {
-       GAttrib *attrib;
-       bt_uuid_t *uuid;
-       uint16_t end;
-       GSList *characteristics;
-       gatt_cb_t cb;
-       void *user_data;
-};
-
-static GSList *gatt_services = NULL;
-
-static void characteristic_free(void *user_data)
-{
-       struct characteristic *chr = user_data;
-
-       g_free(chr->path);
-       g_free(chr->desc);
-       g_free(chr->format);
-       g_free(chr->value);
-       g_free(chr->name);
-       g_free(chr);
-}
-
-static void watcher_free(void *user_data)
-{
-       struct watcher *watcher = user_data;
-
-       g_free(watcher->path);
-       g_free(watcher->name);
-       g_free(watcher);
-}
-
-static void gatt_service_free(struct gatt_service *gatt)
-{
-       g_slist_free_full(gatt->watchers, watcher_free);
-       g_slist_free_full(gatt->chars, characteristic_free);
-       g_slist_free(gatt->offline_chars);
-       g_free(gatt->path);
-       btd_device_unref(gatt->dev);
-       dbus_connection_unref(gatt->conn);
-       g_free(gatt);
-}
-
-static void remove_attio(struct gatt_service *gatt)
-{
-       if (gatt->offline_chars || gatt->watchers || gatt->query)
-               return;
-
-       if (gatt->attioid) {
-               btd_device_remove_attio_callback(gatt->dev, gatt->attioid);
-               gatt->attioid = 0;
-       }
-}
-
-static void gatt_get_address(struct gatt_service *gatt, bdaddr_t *sba,
-                                       bdaddr_t *dba, uint8_t *bdaddr_type)
-{
-       struct btd_device *device = gatt->dev;
-       struct btd_adapter *adapter;
-
-       adapter = device_get_adapter(device);
-       sba = (bdaddr_t *)btd_adapter_get_address(adapter);
-       dba = (bdaddr_t *)device_get_address(device);
-       *bdaddr_type = btd_device_get_bdaddr_type(device);
-}
-
-static int characteristic_handle_cmp(gconstpointer a, gconstpointer b)
-{
-       const struct characteristic *chr = a;
-       uint16_t handle = GPOINTER_TO_UINT(b);
-
-       return chr->handle - handle;
-}
-
-static int watcher_cmp(gconstpointer a, gconstpointer b)
-{
-       const struct watcher *watcher = a;
-       const struct watcher *match = b;
-       int ret;
-
-       ret = g_strcmp0(watcher->name, match->name);
-       if (ret != 0)
-               return ret;
-
-       return g_strcmp0(watcher->path, match->path);
-}
-
-
-static void watcher_exit(DBusConnection *conn, void *user_data)
-{
-       struct watcher *watcher = user_data;
-       struct gatt_service *gatt = watcher->gatt;
-
-       DBG("%s watcher %s exited", gatt->path, watcher->name);
-
-       gatt->watchers = g_slist_remove(gatt->watchers, watcher);
-       g_dbus_remove_watch(gatt->conn, watcher->id);
-       remove_attio(gatt);
-}
-
-static int characteristic_set_value(struct characteristic *chr,
-                                       const uint8_t *value, size_t vlen)
-{
-       chr->value = g_try_realloc(chr->value, vlen);
-       if (chr->value == NULL)
-               return -ENOMEM;
-
-       memcpy(chr->value, value, vlen);
-       chr->vlen = vlen;
-
-       return 0;
-}
-
-static void update_watchers(gpointer data, gpointer user_data)
-{
-       struct watcher *w = data;
-       struct characteristic *chr = user_data;
-       DBusConnection *conn = w->gatt->conn;
-       DBusMessage *msg;
-
-       msg = dbus_message_new_method_call(w->name, w->path,
-                               "org.bluez.Watcher", "ValueChanged");
-       if (msg == NULL)
-               return;
-
-       dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &chr->path,
-                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
-                       &chr->value, chr->vlen, DBUS_TYPE_INVALID);
-
-       dbus_message_set_no_reply(msg, TRUE);
-       g_dbus_send_message(conn, msg);
-}
-
-static void events_handler(const uint8_t *pdu, uint16_t len,
-                                                       gpointer user_data)
-{
-       struct gatt_service *gatt = user_data;
-       struct characteristic *chr;
-       GSList *l;
-       uint8_t opdu[ATT_MAX_MTU];
-       guint handle;
-       uint16_t olen;
-
-       if (len < 3) {
-               DBG("Malformed notification/indication packet (opcode 0x%02x)",
-                                                                       pdu[0]);
-               return;
-       }
-
-       handle = get_le16(&pdu[1]);
-
-       l = g_slist_find_custom(gatt->chars, GUINT_TO_POINTER(handle),
-                                               characteristic_handle_cmp);
-       if (!l)
-               return;
-
-       chr = l->data;
-
-       if (chr == NULL) {
-               DBG("Attribute handle 0x%02x not found", handle);
-               return;
-       }
-
-       switch (pdu[0]) {
-       case ATT_OP_HANDLE_IND:
-               olen = enc_confirmation(opdu, sizeof(opdu));
-               g_attrib_send(gatt->attrib, 0, opdu, olen,
-                                               NULL, NULL, NULL);
-       case ATT_OP_HANDLE_NOTIFY:
-               if (characteristic_set_value(chr, &pdu[3], len - 3) < 0)
-                       DBG("Can't change Characteristic 0x%02x", handle);
-
-               g_slist_foreach(gatt->watchers, update_watchers, chr);
-               break;
-       }
-}
-
-static void offline_char_written(gpointer user_data)
-{
-       struct characteristic *chr = user_data;
-       struct gatt_service *gatt = chr->gatt;
-
-       gatt->offline_chars = g_slist_remove(gatt->offline_chars, chr);
-
-       remove_attio(gatt);
-}
-
-static void offline_char_write(gpointer data, gpointer user_data)
-{
-       struct characteristic *chr = data;
-       GAttrib *attrib = user_data;
-
-       gatt_write_cmd(attrib, chr->handle, chr->value, chr->vlen,
-                                               offline_char_written, chr);
-}
-
-static void char_discovered_cb(uint8_t status, GSList *characteristics,
-                                                               void *user_data);
-
-static void attio_connected(GAttrib *attrib, gpointer user_data)
-{
-       struct gatt_service *gatt = user_data;
-
-       gatt->attrib = g_attrib_ref(attrib);
-
-       g_attrib_register(gatt->attrib, ATT_OP_HANDLE_NOTIFY, GATTRIB_ALL_HANDLES,
-                                       events_handler, gatt, NULL);
-       g_attrib_register(gatt->attrib, ATT_OP_HANDLE_IND, GATTRIB_ALL_HANDLES,
-                                       events_handler, gatt, NULL);
-
-       g_slist_foreach(gatt->offline_chars, offline_char_write, attrib);
-
-       if (gatt->query) {
-               struct gatt_primary *prim = gatt->prim;
-               struct query_data *qchr;
-
-               qchr = g_slist_nth_data(gatt->query->list, 0);
-               gatt_discover_char(gatt->attrib, prim->range.start,
-                                               prim->range.end, NULL,
-                                               char_discovered_cb, qchr);
-       }
-}
-
-static void attio_disconnected(gpointer user_data)
-{
-       struct gatt_service *gatt = user_data;
-
-       if (gatt->query && gatt->query->msg) {
-               DBusMessage *reply;
-
-               reply = btd_error_failed(gatt->query->msg,
-                                       "ATT IO channel was disconnected");
-               g_dbus_send_message(gatt->conn, reply);
-               dbus_message_unref(gatt->query->msg);
-       }
-
-       if (gatt->query) {
-               g_slist_free_full(gatt->query->list, g_free);
-               gatt->query = NULL;
-       }
-
-       if (gatt->attrib) {
-               g_attrib_unref(gatt->attrib);
-               gatt->attrib = NULL;
-       }
-}
-
-static DBusMessage *register_watcher(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       const char *sender = dbus_message_get_sender(msg);
-       struct gatt_service *gatt = data;
-       struct watcher *watcher;
-       char *path;
-
-       DBG("register_watcher");
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                                       DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       watcher = g_new0(struct watcher, 1);
-       watcher->name = g_strdup(sender);
-       watcher->gatt = gatt;
-       watcher->path = g_strdup(path);
-       watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
-                                                       watcher, watcher_free);
-
-       if (gatt->attioid == 0)
-               gatt->attioid = btd_device_add_attio_callback(gatt->dev,
-                                                       attio_connected,
-                                                       attio_disconnected,
-                                                       gatt);
-
-       gatt->watchers = g_slist_append(gatt->watchers, watcher);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *unregister_watcher(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       const char *sender = dbus_message_get_sender(msg);
-       struct gatt_service *gatt = data;
-       struct watcher *watcher, *match;
-       GSList *l;
-       char *path;
-       DBG("unregister_watcher");
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                                       DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       match = g_new0(struct watcher, 1);
-       match->name = g_strdup(sender);
-       match->path = g_strdup(path);
-       l = g_slist_find_custom(gatt->watchers, match, watcher_cmp);
-       watcher_free(match);
-       if (!l)
-               return btd_error_not_authorized(msg);
-
-       watcher = l->data;
-       gatt->watchers = g_slist_remove(gatt->watchers, watcher);
-       g_dbus_remove_watch(conn, watcher->id);
-       remove_attio(gatt);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static void write_char_cb(guint8 status, const guint8 *pdu, guint16 plen,
-                                                       gpointer user_data)
-{
-       struct characteristic *chr = user_data;
-       struct gatt_service *gatt = chr->gatt;
-       DBusMessage *reply;
-
-       if (status != 0) {
-               const char *str = att_ecode2str(status);
-               g_printerr("Characteristic write failed: %s\n", str);
-
-               reply = btd_error_failed(gatt->query->msg, str);
-               goto done;
-       }
-
-       if (!dec_write_resp(pdu, plen)) {
-               g_printerr("Protocol error\n");
-               reply = btd_error_failed(gatt->query->msg,
-                                       "Attribute Protocol Error");
-               goto done;
-       }
-
-       reply = dbus_message_new_method_return(gatt->query->msg);
-
-done:
-       dbus_connection_send(gatt->conn, reply, NULL);
-       dbus_connection_flush(gatt->conn);
-       dbus_message_unref(reply);
-       g_free(gatt->query);
-       gatt->query = NULL;
-
-       return;
-}
-
-static DBusMessage *set_value(DBusConnection *conn, DBusMessage *msg,
-                       DBusMessageIter *iter, struct characteristic *chr)
-{
-       struct gatt_service *gatt = chr->gatt;
-       DBusMessageIter sub;
-       uint8_t *value;
-       int len;
-
-       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
-                       dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE)
-               return btd_error_invalid_args(msg);
-
-       dbus_message_iter_recurse(iter, &sub);
-
-       dbus_message_iter_get_fixed_array(&sub, &value, &len);
-
-       characteristic_set_value(chr, value, len);
-
-       if (gatt->attrib)
-               gatt_write_cmd(gatt->attrib, chr->handle, value, len,
-                               NULL, NULL);
-       else
-               gatt->offline_chars = g_slist_append(gatt->offline_chars, chr);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *set_property(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct characteristic *chr = data;
-       DBusMessageIter iter;
-       DBusMessageIter sub;
-       const char *property;
-
-       if (!dbus_message_iter_init(msg, &iter))
-               return btd_error_invalid_args(msg);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-               return btd_error_invalid_args(msg);
-
-       dbus_message_iter_get_basic(&iter, &property);
-       dbus_message_iter_next(&iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
-               return btd_error_invalid_args(msg);
-
-       dbus_message_iter_recurse(&iter, &sub);
-       dbus_message_iter_next(&iter);
-
-       if (g_str_equal("Value", property))
-               return set_value(conn, msg, &sub, chr);
-
-       return btd_error_invalid_args(msg);
-}
-
-static DBusMessage *set_value_request(DBusConnection *conn, DBusMessage *msg,
-                       DBusMessageIter *iter, struct characteristic *chr)
-{
-       struct gatt_service *gatt = chr->gatt;
-       DBusMessageIter sub;
-       uint8_t *value;
-       int len;
-       struct query *query;
-
-       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
-                       dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE)
-               return btd_error_invalid_args(msg);
-
-       dbus_message_iter_recurse(iter, &sub);
-
-       dbus_message_iter_get_fixed_array(&sub, &value, &len);
-
-       characteristic_set_value(chr, value, len);
-
-       if (gatt->attrib) {
-               query = g_new0(struct query, 1);
-               query->msg = dbus_message_ref(msg);
-               gatt->query = query;
-               gatt_write_char(gatt->attrib, chr->handle, value, len,
-                               write_char_cb, chr);
-       } else {
-               gatt->offline_chars = g_slist_append(gatt->offline_chars, chr);
-       }
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *set_property_request(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct characteristic *chr = data;
-       DBusMessageIter iter;
-       DBusMessageIter sub;
-       const char *property;
-
-       if (!dbus_message_iter_init(msg, &iter))
-               return btd_error_invalid_args(msg);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-               return btd_error_invalid_args(msg);
-
-       dbus_message_iter_get_basic(&iter, &property);
-       dbus_message_iter_next(&iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
-               return btd_error_invalid_args(msg);
-
-       dbus_message_iter_recurse(&iter, &sub);
-       dbus_message_iter_next(&iter);
-
-       if (g_str_equal("Value", property))
-               return set_value_request(conn, msg, &sub, chr);
-
-       return btd_error_invalid_args(msg);
-}
-
-static void append_char_dict(DBusMessageIter *iter, struct characteristic *chr)
-{
-       DBusMessageIter dict;
-       const char *name = "";
-       char *uuid;
-       uint16_t permission;
-
-       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);
-
-       uuid = g_strdup(chr->type);
-       dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &uuid);
-       g_free(uuid);
-
-       /* FIXME: Translate UUID to name. */
-       dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &name);
-
-       if (chr->desc)
-               dict_append_entry(&dict, "Description", DBUS_TYPE_STRING,
-                                                               &chr->desc);
-
-       if (chr->value)
-               dict_append_array(&dict, "Value", DBUS_TYPE_BYTE, &chr->value,
-                                                               chr->vlen);
-
-       if (chr->perm) {
-               permission = chr->perm;
-               dict_append_entry(&dict, "Permission", DBUS_TYPE_UINT16, &permission);
-       }
-
-       /* FIXME: Missing Format, Value and Representation */
-
-       dbus_message_iter_close_container(iter, &dict);
-}
-
-static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct characteristic *chr = data;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       append_char_dict(&iter, chr);
-
-       return reply;
-}
-
-static void read_char_cb(guint8 status, const guint8 *pdu, guint16 plen,
-                                                       gpointer user_data)
-{
-       struct characteristic *chr = user_data;
-       struct gatt_service *gatt = chr->gatt;
-       DBusMessage *reply;
-       uint8_t *value = NULL;
-       int vlen;
-
-       if (status != 0) {
-               const char *str = att_ecode2str(status);
-               g_printerr("Characteristic value/descriptor read failed: %s\n",
-                                                       str);
-               reply = btd_error_failed(gatt->query->msg, str);
-               goto done;
-       }
-
-       value = g_malloc(ATT_MAX_MTU * sizeof(unsigned char));
-
-       vlen = dec_read_resp(pdu, plen, value, ATT_MAX_MTU);
-       if (vlen <= 0) {
-               g_printerr("Attribute Protocol Error\n");
-               reply = btd_error_failed(gatt->query->msg,
-                                       "Attribute Protocol Error");
-               goto done;
-       }
-
-       reply = dbus_message_new_method_return(gatt->query->msg);
-       dbus_message_append_args(reply,
-                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &value, vlen,
-                       DBUS_TYPE_INVALID);
-done:
-       dbus_connection_send(gatt->conn, reply, NULL);
-       dbus_connection_flush(gatt->conn);
-       dbus_message_unref(reply);
-       g_free(gatt->query);
-       gatt->query = NULL;
-
-       if (value)
-               g_free(value);
-       return;
-}
-
-static DBusMessage *read_char(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct query *query;
-
-       struct characteristic *chr = data;
-       struct gatt_service *gatt = chr->gatt;
-
-       query = g_new0(struct query, 1);
-       query->msg = dbus_message_ref(msg);
-       gatt->query = query;
-
-       gatt_read_char(gatt->attrib, chr->handle, read_char_cb, chr);
-
-       return NULL;
-}
-
-static void discover_char_descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
-                                                       gpointer user_data)
-{
-       struct characteristic *chr = user_data;
-       struct gatt_service *gatt = chr->gatt;
-       DBusMessage *reply;
-       guint8 format;
-       uint8_t *data;
-
-       if (status != 0) {
-               const char *str = att_ecode2str(status);
-
-               g_printerr("Discover Characteristic Descriptor failed: %s\n", str);
-
-               reply = btd_error_failed(gatt->query->msg, str);
-               goto done;
-       }
-
-       if (!dec_find_info_resp(pdu, plen, &format)) {
-               g_printerr("Att Protocol error\n");
-
-               reply = btd_error_failed(gatt->query->msg,
-                                       "Attribute Protocol Error");
-               goto done;
-       }
-
-       data = (uint8_t *)pdu + GATT_FIND_INFO_RESP_OPCODE_LEN;
-
-       /* Since "user description" and "presentation format" descriptors have 16-bit UUIDs.
-               Only format 0x01 is supported*/
-       reply = dbus_message_new_method_return(gatt->query->msg);
-
-       dbus_message_append_args(reply, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
-               &data, (plen - GATT_FIND_INFO_RESP_OPCODE_LEN), DBUS_TYPE_INVALID);
-
-done:
-       dbus_connection_send(gatt->conn, reply, NULL);
-       dbus_connection_flush(gatt->conn);
-       dbus_message_unref(reply);
-       dbus_message_unref(gatt->query->msg);
-       g_free(gatt->query);
-       gatt->query = NULL;
-
-       return;
-}
-
-static DBusMessage *discover_char_descriptor(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct characteristic *chr = data;
-       struct gatt_service *gatt = chr->gatt;
-       struct query *query;
-
-       if (gatt->query)
-               return btd_error_busy(msg);
-
-       query = g_new0(struct query, 1);
-       query->msg = dbus_message_ref(msg);
-       gatt->query = query;
-
-       if (gatt->attioid == 0) {
-               gatt->attioid = btd_device_add_attio_callback(gatt->dev,
-                                                       NULL, attio_disconnected, gatt);
-       }
-
-       if (gatt->attrib) {
-               gatt_find_info(gatt->attrib, chr->handle+1,
-                                               chr->end, discover_char_descriptor_cb, chr);
-       }
-
-       return NULL;
-}
-
-static const GDBusMethodTable char_methods[] = {
-       { GDBUS_METHOD("GetProperties",
-                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
-                       get_properties) },
-       { GDBUS_METHOD("SetProperty",
-                       GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
-                       set_property) },
-       { GDBUS_METHOD("SetPropertyRequest",
-                       GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
-                       set_property_request) },
-       { GDBUS_ASYNC_METHOD("ReadCharacteristic", NULL,
-                       GDBUS_ARGS({ "value", "ay" }),
-                       read_char) },
-       { GDBUS_ASYNC_METHOD("DiscoverCharacteristicsDescriptor",
-                       NULL, GDBUS_ARGS({ "CharacteristicsDescriptors", "ay" }),
-                       discover_char_descriptor)},
-       { }
-};
-
-static char *characteristic_list_to_string(GSList *chars)
-{
-       GString *characteristics;
-       GSList *l;
-
-       characteristics = g_string_new(NULL);
-
-       for (l = chars; l; l = l->next) {
-               struct characteristic *chr = l->data;
-               char chr_str[64];
-
-               memset(chr_str, 0, sizeof(chr_str));
-
-               snprintf(chr_str, sizeof(chr_str), "%04X#%02X#%04X#%s ",
-                               chr->handle, chr->perm, chr->end, chr->type);
-
-               characteristics = g_string_append(characteristics, chr_str);
-       }
-
-       return g_string_free(characteristics, FALSE);
-}
-
-static void store_characteristics(const bdaddr_t *sba, const bdaddr_t *dba,
-                                       uint8_t bdaddr_type, uint16_t start,
-                                                               GSList *chars)
-{
-       char *characteristics;
-
-       characteristics = characteristic_list_to_string(chars);
-
-       write_device_characteristics(sba, dba, bdaddr_type, start,
-                                                       characteristics);
-
-       g_free(characteristics);
-}
-
-static void register_characteristic(gpointer data, gpointer user_data)
-{
-       struct characteristic *chr = data;
-       DBusConnection *conn = chr->gatt->conn;
-       const char *gatt_path = user_data;
-       DBG("register_characteristic");
-
-       chr->path = g_strdup_printf("%s/characteristic%04x", gatt_path,
-                                                               chr->handle);
-
-       g_dbus_register_interface(conn, chr->path, CHAR_INTERFACE,
-                                       char_methods, NULL, NULL, chr, NULL);
-
-       DBG("Registered: %s", chr->path);
-}
-
-static GSList *string_to_characteristic_list(struct gatt_service *gatt,
-                                                       const char *str)
-{
-       GSList *l = NULL;
-       char **chars;
-       int i;
-
-       if (str == NULL)
-               return NULL;
-
-       chars = g_strsplit(str, " ", 0);
-       if (chars == NULL)
-               return NULL;
-
-       for (i = 0; chars[i]; i++) {
-               struct characteristic *chr;
-               int ret;
-
-               chr = g_new0(struct characteristic, 1);
-
-               ret = sscanf(chars[i], "%04hX#%02hhX#%04hX#%s", &chr->handle,
-                               &chr->perm, &chr->end, chr->type);
-               if (ret < 4) {
-                       g_free(chr);
-                       continue;
-               }
-
-               chr->gatt = gatt;
-               l = g_slist_append(l, chr);
-       }
-
-       g_strfreev(chars);
-
-       return l;
-}
-
-static GSList *load_characteristics(struct gatt_service *gatt, uint16_t start)
-{
-       GSList *chrs_list;
-       bdaddr_t sba, dba;
-       uint8_t bdaddr_type = BDADDR_LE_PUBLIC;
-       char *str;
-
-       gatt_get_address(gatt, &sba, &dba, &bdaddr_type);
-       DBG("load_characteristics");
-
-       str = read_device_characteristics(&sba, &dba, bdaddr_type, start);
-       if (str == NULL)
-               return NULL;
-
-       chrs_list = string_to_characteristic_list(gatt, str);
-
-       free(str);
-
-       return chrs_list;
-}
-
-static void store_attribute(struct gatt_service *gatt, uint16_t handle,
-                               uint16_t type, uint8_t *value, gsize len)
-{
-       struct btd_device *device = gatt->dev;
-       bdaddr_t sba, dba;
-       uint8_t bdaddr_type;
-       bt_uuid_t uuid;
-       char *str, *tmp;
-       guint i;
-
-       str = g_malloc0(MAX_LEN_UUID_STR + len * 2 + 1);
-
-       bt_uuid16_create(&uuid, type);
-       bt_uuid_to_string(&uuid, str, MAX_LEN_UUID_STR);
-
-       str[MAX_LEN_UUID_STR - 1] = '#';
-
-       for (i = 0, tmp = str + MAX_LEN_UUID_STR; i < len; i++, tmp += 2)
-               sprintf(tmp, "%02X", value[i]);
-
-       gatt_get_address(gatt, &sba, &dba, NULL);
-
-       bdaddr_type = btd_device_get_bdaddr_type(device);
-
-       write_device_attribute(&sba, &dba, bdaddr_type, handle, str);
-
-       g_free(str);
-}
-
-static void query_list_append(struct gatt_service *gatt, struct query_data *data)
-{
-       struct query *query = gatt->query;
-
-       query->list = g_slist_append(query->list, data);
-}
-
-static void query_list_remove(struct gatt_service *gatt, struct query_data *data)
-{
-       struct query *query = gatt->query;
-
-       query->list = g_slist_remove(query->list, data);
-       if (query->list != NULL)
-               return;
-
-       g_free(query);
-       gatt->query = NULL;
-
-       remove_attio(gatt);
-}
-
-static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len,
-                                                       gpointer user_data)
-{
-       struct query_data *current = user_data;
-       struct gatt_service *gatt = current->gatt;
-       struct characteristic *chr = current->chr;
-
-       if (status == 0) {
-
-               g_free(chr->desc);
-
-               chr->desc = g_malloc(len);
-               memcpy(chr->desc, pdu + 1, len - 1);
-               chr->desc[len - 1] = '\0';
-
-               store_attribute(gatt, current->handle,
-                               GATT_CHARAC_USER_DESC_UUID,
-                               (void *) chr->desc, len);
-       } else if (status == ATT_ECODE_INSUFF_ENC) {
-               GIOChannel *io = g_attrib_get_channel(gatt->attrib);
-               BtIOSecLevel level = BT_IO_SEC_HIGH;
-
-               bt_io_get(io, BT_IO_L2CAP,
-                               BT_IO_OPT_SEC_LEVEL, &level,
-                               BT_IO_OPT_INVALID);
-
-               if (level < BT_IO_SEC_HIGH)
-                       level++;
-
-               if (bt_io_set(io, BT_IO_L2CAP,
-                               BT_IO_OPT_SEC_LEVEL, level,
-                               BT_IO_OPT_INVALID)) {
-                       gatt_read_char(gatt->attrib, current->handle,
-                                       update_char_desc, current);
-                       return;
-               }
-       }
-
-       query_list_remove(gatt, current);
-       g_free(current);
-}
-
-static void update_char_format(guint8 status, const guint8 *pdu, guint16 len,
-                                                               gpointer user_data)
-{
-       struct query_data *current = user_data;
-       struct gatt_service *gatt = current->gatt;
-       struct characteristic *chr = current->chr;
-
-       if (status != 0)
-               goto done;
-
-       if (len < 8)
-               goto done;
-
-       g_free(chr->format);
-
-       chr->format = g_new0(struct format, 1);
-       memcpy(chr->format, pdu + 1, 7);
-
-       store_attribute(gatt, current->handle, GATT_CHARAC_FMT_UUID,
-                               (void *) chr->format, sizeof(*chr->format));
-
-done:
-       query_list_remove(gatt, current);
-       g_free(current);
-}
-
-static void update_char_value(guint8 status, const guint8 *pdu,
-                                       guint16 len, gpointer user_data)
-{
-       struct query_data *current = user_data;
-       struct gatt_service *gatt = current->gatt;
-       struct characteristic *chr = current->chr;
-
-       if (status == 0)
-               characteristic_set_value(chr, pdu + 1, len - 1);
-       else if (status == ATT_ECODE_INSUFF_ENC) {
-               GIOChannel *io = g_attrib_get_channel(gatt->attrib);
-
-               if (bt_io_set(io, BT_IO_L2CAP,
-                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH,
-                               BT_IO_OPT_INVALID)) {
-                       gatt_read_char(gatt->attrib, chr->handle,
-                                       update_char_value, current);
-                       return;
-               }
-       }
-
-       query_list_remove(gatt, current);
-       g_free(current);
-}
-
-static int uuid_desc16_cmp(bt_uuid_t *uuid, guint16 desc)
-{
-       bt_uuid_t u16;
-
-       bt_uuid16_create(&u16, desc);
-
-       return bt_uuid_cmp(uuid, &u16);
-}
-
-static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
-                                                       gpointer user_data)
-{
-       struct query_data *current = user_data;
-       struct gatt_service *gatt = current->gatt;
-       struct att_data_list *list;
-       guint8 format;
-       int i;
-
-       if (status != 0)
-               goto done;
-
-       DBG("Find Information Response received");
-
-       list = dec_find_info_resp(pdu, plen, &format);
-       if (list == NULL)
-               goto done;
-
-       for (i = 0; i < list->num; i++) {
-               guint16 handle;
-               bt_uuid_t uuid;
-               uint8_t *info = list->data[i];
-               struct query_data *qfmt;
-
-               handle = get_le16(info);
-
-               if (format == 0x01) {
-                       get_uuid(BT_UUID16, &info[2], &uuid);
-/*                     API is not present in bluez 5.25
-                       uuid = att_get_uuid16(&info[2]);*/
-               } else {
-                       /* Currently, only "user description" and "presentation
-                        * format" descriptors are used, and both have 16-bit
-                        * UUIDs. Therefore there is no need to support format
-                        * 0x02 yet. */
-                       continue;
-               }
-               qfmt = g_new0(struct query_data, 1);
-               qfmt->gatt = current->gatt;
-               qfmt->chr = current->chr;
-               qfmt->handle = handle;
-
-               if (uuid_desc16_cmp(&uuid, GATT_CHARAC_USER_DESC_UUID) == 0) {
-                       query_list_append(gatt, qfmt);
-                       gatt_read_char(gatt->attrib, handle, update_char_desc,
-                                                                       qfmt);
-               } else if (uuid_desc16_cmp(&uuid, GATT_CHARAC_FMT_UUID) == 0) {
-                       query_list_append(gatt, qfmt);
-                       gatt_read_char(gatt->attrib, handle,
-                                               update_char_format, qfmt);
-               } else
-                       g_free(qfmt);
-       }
-
-       att_data_list_free(list);
-done:
-       query_list_remove(gatt, current);
-       g_free(current);
-}
-
-static void update_all_chars(gpointer data, gpointer user_data)
-{
-       struct query_data *qdesc, *qvalue;
-       struct characteristic *chr = data;
-       struct gatt_service *gatt = user_data;
-
-       qdesc = g_new0(struct query_data, 1);
-       qdesc->gatt = gatt;
-       qdesc->chr = chr;
-
-       query_list_append(gatt, qdesc);
-
-       gatt_find_info(gatt->attrib, chr->handle + 1, chr->end, descriptor_cb,
-                                                                       qdesc);
-
-       qvalue = g_new0(struct query_data, 1);
-       qvalue->gatt = gatt;
-       qvalue->chr = chr;
-
-       query_list_append(gatt, qvalue);
-
-       gatt_read_char(gatt->attrib, chr->handle, update_char_value, qvalue);
-}
-
-static DBusMessage *create_discover_char_reply(DBusMessage *msg, GSList *chars)
-{
-       DBusMessage *reply;
-       DBusMessageIter iter, array_iter;
-       GSList *l;
-
-       reply = dbus_message_new_method_return(msg);
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                               DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
-
-       for (l = chars; l; l = l->next) {
-               struct characteristic *chr = l->data;
-
-               dbus_message_iter_append_basic(&array_iter,
-                                       DBUS_TYPE_OBJECT_PATH, &chr->path);
-       }
-
-       dbus_message_iter_close_container(&iter, &array_iter);
-
-       return reply;
-}
-
-static void char_discovered_cb(uint8_t status, GSList *characteristics,
-                                                               void *user_data)
-{
-       DBusMessage *reply;
-       struct query_data *current = user_data;
-       struct gatt_service *gatt = current->gatt;
-       struct gatt_primary *prim = gatt->prim;
-       uint16_t *previous_end = NULL;
-       GSList *l;
-       bdaddr_t sba, dba;
-       uint8_t bdaddr_type = BDADDR_LE_PUBLIC;
-
-       DBG("char_discovered_cb status %d", status);
-       if (status != 0) {
-               const char *str = att_ecode2str(status);
-
-               DBG("Discover all characteristics failed: %s", str);
-               reply = btd_error_failed(gatt->query->msg, str);
-               goto fail;
-       }
-
-       for (l = characteristics; l; l = l->next) {
-               struct gatt_char *current_chr = l->data;
-               struct characteristic *chr;
-               guint handle = current_chr->value_handle;
-               GSList *lchr;
-
-               lchr = g_slist_find_custom(gatt->chars,
-                       GUINT_TO_POINTER(handle), characteristic_handle_cmp);
-               if (lchr)
-                       continue;
-
-               chr = g_new0(struct characteristic, 1);
-               chr->gatt = gatt;
-               chr->perm = current_chr->properties;
-               chr->handle = current_chr->value_handle;
-               strncpy(chr->type, current_chr->uuid, sizeof(chr->type));
-
-               if (previous_end)
-                       *previous_end = current_chr->handle;
-
-               previous_end = &chr->end;
-
-               gatt->chars = g_slist_append(gatt->chars, chr);
-               register_characteristic(chr, gatt->path);
-       }
-
-       if (previous_end)
-               *previous_end = prim->range.end;
-
-       gatt_get_address(gatt, &sba, &dba, &bdaddr_type);
-       store_characteristics(&sba, &dba, bdaddr_type, prim->range.start,
-                                                               gatt->chars);
-
-       g_slist_foreach(gatt->chars, update_all_chars, gatt);
-
-       reply = create_discover_char_reply(gatt->query->msg, gatt->chars);
-
-fail:
-       dbus_message_unref(gatt->query->msg);
-       gatt->query->msg = NULL;
-
-       g_dbus_send_message(gatt->conn, reply);
-       query_list_remove(gatt, current);
-       g_free(current);
-}
-
-static DBusMessage *discover_char(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct gatt_service *gatt = data;
-       struct query *query;
-       struct query_data *qchr;
-
-       if (gatt->query)
-               return btd_error_busy(msg);
-
-       DBG("discover_char BP0");
-
-       query = g_new0(struct query, 1);
-
-       qchr = g_new0(struct query_data, 1);
-       qchr->gatt = gatt;
-
-       query->msg = dbus_message_ref(msg);
-
-       if (gatt->attioid == 0) {
-               gatt->attioid = btd_device_add_attio_callback(gatt->dev,
-                                                       attio_connected,
-                                                       attio_disconnected,
-                                                       gatt);
-       } else if (gatt->attrib) {
-               struct gatt_primary *prim = gatt->prim;
-               gatt_discover_char(gatt->attrib, prim->range.start,
-                                               prim->range.end, NULL,
-                                               char_discovered_cb, qchr);
-       }
-
-       gatt->query = query;
-
-       query_list_append(gatt, qchr);
-
-       return NULL;
-}
-
-static DBusMessage *prim_get_properties(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct gatt_service *gatt = data;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       GSList *l;
-       char **chars;
-       const char *uuid;
-       int i;
-
-       DBG("prim_get_properties");
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-       chars = g_new0(char *, g_slist_length(gatt->chars) + 1);
-
-       for (i = 0, l = gatt->chars; l; l = l->next, i++) {
-               struct characteristic *chr = l->data;
-               chars[i] = chr->path;
-       }
-
-       dict_append_array(&dict, "Characteristics", DBUS_TYPE_OBJECT_PATH,
-                                                               &chars, i);
-       uuid = gatt->prim->uuid;
-       dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &uuid);
-
-       g_free(chars);
-
-       dbus_message_iter_close_container(&iter, &dict);
-
-       return reply;
-}
-
-static const GDBusMethodTable prim_methods[] = {
-       { GDBUS_ASYNC_METHOD("DiscoverCharacteristics",
-                       NULL, GDBUS_ARGS({ "characteristics", "ao" }),
-                       discover_char) },
-       { GDBUS_METHOD("RegisterCharacteristicsWatcher",
-                       GDBUS_ARGS({ "agent", "o" }), NULL,
-                       register_watcher) },
-       { GDBUS_METHOD("UnregisterCharacteristicsWatcher",
-                       GDBUS_ARGS({ "agent", "o" }), NULL,
-                       unregister_watcher) },
-       { GDBUS_METHOD("GetProperties",
-                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
-                       prim_get_properties) },
-       { }
-};
-
-static struct gatt_service *primary_register(DBusConnection *conn,
-                                               struct btd_device *device,
-                                               struct gatt_primary *prim,
-                                               int psm)
-{
-       struct gatt_service *gatt;
-       const char *device_path;
-
-       device_path = device_get_path(device);
-
-       gatt = g_new0(struct gatt_service, 1);
-       gatt->dev = btd_device_ref(device);
-       gatt->prim = prim;
-       gatt->psm = psm;
-       gatt->conn = dbus_connection_ref(conn);
-       gatt->path = g_strdup_printf("%s/service%04x", device_path,
-                                               prim->range.start);
-
-       g_dbus_register_interface(gatt->conn, gatt->path,
-                                       CHAR_INTERFACE, prim_methods,
-                                       NULL, NULL, gatt, NULL);
-
-       gatt->chars = load_characteristics(gatt, prim->range.start);
-       g_slist_foreach(gatt->chars, register_characteristic, gatt->path);
-
-       return gatt;
-}
-
-GSList *attrib_client_register(DBusConnection *connection,
-                                       struct btd_device *device, int psm,
-                                       GAttrib *attrib, GSList *primaries)
-{
-       GSList *l, *services;
-
-       for (l = primaries, services = NULL; l; l = l->next) {
-               struct gatt_primary *prim = l->data;
-               struct gatt_service *gatt;
-
-               gatt = primary_register(connection, device, prim, psm);
-
-               DBG("Registered: %s", gatt->path);
-
-               services = g_slist_append(services, g_strdup(gatt->path));
-               gatt_services = g_slist_append(gatt_services, gatt);
-       }
-
-       return services;
-}
-
-static void primary_unregister(struct gatt_service *gatt)
-{
-       GSList *l;
-
-       for (l = gatt->chars; l; l = l->next) {
-               struct characteristic *chr = l->data;
-               g_dbus_unregister_interface(gatt->conn, chr->path,
-                                                       CHAR_INTERFACE);
-       }
-
-       g_dbus_unregister_interface(gatt->conn, gatt->path, CHAR_INTERFACE);
-
-       remove_attio(gatt);
-}
-
-static int path_cmp(gconstpointer data, gconstpointer user_data)
-{
-       const char *path = data;
-       const char *gatt_path = user_data;
-
-       return g_strcmp0(path, gatt_path);
-}
-
-void attrib_client_unregister(GSList *services)
-{
-       GSList *l, *left;
-
-       for (l = gatt_services, left = NULL; l; l = l->next) {
-               struct gatt_service *gatt = l->data;
-
-               if (!g_slist_find_custom(services, gatt->path, path_cmp)) {
-                       left = g_slist_append(left, gatt);
-                       continue;
-               }
-
-               primary_unregister(gatt);
-               gatt_service_free(gatt);
-       }
-
-       g_slist_free(gatt_services);
-       gatt_services = left;
-}
-#endif /* __TIZEN_PATCH__ */
index 159b154..ea14e75 100644 (file)
 
 #include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/uuid.h"
+
 #include "src/adapter.h"
 #include "src/shared/util.h"
-#include "lib/uuid.h"
 #include "attrib/gattrib.h"
 #include "attrib/att.h"
 #include "attrib/gatt.h"
@@ -75,6 +78,10 @@ static GSList *parse_opts(gatt_option opt1, va_list args)
        struct attrib_cb *cb;
        GSList *l = NULL;
 
+#ifdef __TIZEN_PATCH__
+       if (opt == GATT_OPT_INVALID)
+               return NULL;
+#endif
        info = g_new0(struct gatt_info, 1);
        l = g_slist_append(l, info);
 
@@ -380,19 +387,15 @@ static void service_attr_del(struct btd_adapter *adapter, uint16_t start_handle,
 {
        uint16_t handle;
 
-       /* When handles are assigned for primary servies of 128 bit categary,
-        * handles are assigned from (0xffff - num_elements),
-        * ex: start handle 0xfffb, end handle 0xffff
-        * the below conditions enters infinite loop once the handle value reaches to 0xffff,
-        * in the next increament it becomes 0x0000, which is always less than end handle(0xffff),
-        * hence starts deleting the attributes from 0x0000 to 0xffff */
-#ifdef __TIZEN_PATCH__
-       for (handle = start_handle; (handle != 0 && handle <= end_handle); handle++)
-#else
-       for (handle = start_handle; handle <= end_handle; handle++)
-#endif
+       /* For a 128-bit category primary service below handle should be checked
+        * for both non-zero as well as >= 0xffff. As on last iteration the
+        * handle will turn to 0 from 0xffff and loop will be infinite.
+        */
+       for (handle = start_handle; (handle != 0 && handle <= end_handle);
+                                                               handle++) {
                if (attrib_db_del(adapter, handle) < 0)
                        error("Can't delete handle 0x%04x", handle);
+       }
 }
 
 #ifdef __TIZEN_PATCH__
@@ -406,7 +409,7 @@ static int is_gatt_connected(gconstpointer a1, gconstpointer a2)
                return -1;
 }
 
-bool gatt_send_noty_ind(struct btd_adapter *adapter, bt_uuid_t *uuid,
+bool gatt_send_noty_ind(struct btd_adapter *adapter, const bt_uuid_t *uuid,
                                        uint8_t *value, size_t len)
 {
        struct attribute *a;
index 5c4f2be..adb8ddc 100644 (file)
@@ -80,7 +80,7 @@ void attrib_remove_service(struct btd_adapter *adapter, uint16_t start_handle,
                                                        uint16_t end_handle);
 bool gatt_update_db(struct btd_adapter *adapter, const bt_uuid_t *uuid,
                                        uint8_t *value, size_t len);
-bool gatt_send_noty_ind(struct btd_adapter *adapter, bt_uuid_t *uuid,
+bool gatt_send_noty_ind(struct btd_adapter *adapter, const bt_uuid_t *uuid,
                                        uint8_t *value, size_t len);
 bool gatt_send_service_changed_ind(struct btd_adapter *adapter, bt_uuid_t *uuid,
                     uint16_t start_handle, uint16_t end_handle);
index 64e308f..13e5e42 100644 (file)
 
 #include <stdint.h>
 #include <stdlib.h>
+
 #include <glib.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
 
-#include "src/shared/util.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 #include "lib/uuid.h"
+
+#include "src/shared/util.h"
 #include "att.h"
 #include "gattrib.h"
 #include "gatt.h"
@@ -43,6 +45,7 @@ struct discover_primary {
        GAttrib *attrib;
        unsigned int id;
        bt_uuid_t uuid;
+       uint16_t start;
        GSList *primaries;
        gatt_cb_t cb;
        void *user_data;
@@ -54,6 +57,7 @@ struct included_discovery {
        unsigned int    id;
        int             refs;
        int             err;
+       uint16_t        start_handle;
        uint16_t        end_handle;
        GSList          *includes;
        gatt_cb_t       cb;
@@ -71,6 +75,7 @@ struct discover_char {
        unsigned int id;
        bt_uuid_t *uuid;
        uint16_t end;
+       uint16_t start;
        GSList *characteristics;
        gatt_cb_t cb;
        void *user_data;
@@ -81,6 +86,7 @@ struct discover_desc {
        GAttrib *attrib;
        unsigned int id;
        bt_uuid_t *uuid;
+       uint16_t start;
        uint16_t end;
        GSList *descriptors;
        gatt_cb_t cb;
@@ -266,8 +272,19 @@ static void primary_by_uuid_cb(guint8 status, const guint8 *ipdu,
        if (range->end == 0xffff)
                goto done;
 
+       /*
+        * If last handle is lower from previous start handle then it is smth
+        * wrong. Let's stop search, otherwise we might enter infinite loop.
+        */
+       if (range->end < dp->start) {
+               err = ATT_ECODE_UNLIKELY;
+               goto done;
+       }
+
+       dp->start = range->end + 1;
+
        buf = g_attrib_get_buffer(dp->attrib, &buflen);
-       oplen = encode_discover_primary(range->end + 1, 0xffff, &dp->uuid,
+       oplen = encode_discover_primary(dp->start, 0xffff, &dp->uuid,
                                                                buf, buflen);
 
        if (oplen == 0)
@@ -336,12 +353,24 @@ static void primary_all_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
        att_data_list_free(list);
        err = 0;
 
+       /*
+        * If last handle is lower from previous start handle then it is smth
+        * wrong. Let's stop search, otherwise we might enter infinite loop.
+        */
+       if (end < dp->start) {
+               err = ATT_ECODE_UNLIKELY;
+               goto done;
+       }
+
+       dp->start = end + 1;
+
        if (end != 0xffff) {
                size_t buflen;
                uint8_t *buf = g_attrib_get_buffer(dp->attrib, &buflen);
-               guint16 oplen = encode_discover_primary(end + 1, 0xffff, NULL,
+               guint16 oplen = encode_discover_primary(dp->start, 0xffff, NULL,
                                                                buf, buflen);
 
+
                g_attrib_send(dp->attrib, dp->id, buf, oplen, primary_all_cb,
                                                discover_primary_ref(dp),
                                                discover_primary_unref);
@@ -373,6 +402,7 @@ guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
        dp->attrib = g_attrib_ref(attrib);
        dp->cb = func;
        dp->user_data = user_data;
+       dp->start = 0x0001;
 
        if (uuid) {
                dp->uuid = *uuid;
@@ -533,8 +563,19 @@ static void find_included_cb(uint8_t status, const uint8_t *pdu, uint16_t len,
 
        att_data_list_free(list);
 
+       /*
+        * If last handle is lower from previous start handle then it is smth
+        * wrong. Let's stop search, otherwise we might enter infinite loop.
+        */
+       if (last_handle < isd->start_handle) {
+               isd->err = ATT_ECODE_UNLIKELY;
+               goto done;
+       }
+
+       isd->start_handle = last_handle + 1;
+
        if (last_handle < isd->end_handle)
-               find_included(isd, last_handle + 1);
+               find_included(isd, isd->start_handle);
 
 done:
        if (isd->err == 0)
@@ -548,6 +589,7 @@ unsigned int gatt_find_included(GAttrib *attrib, uint16_t start, uint16_t end,
 
        isd = g_new0(struct included_discovery, 1);
        isd->attrib = g_attrib_ref(attrib);
+       isd->start_handle = start;
        isd->end_handle = end;
        isd->cb = func;
        isd->user_data = user_data;
@@ -560,10 +602,16 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
 {
        struct discover_char *dc = user_data;
        struct att_data_list *list;
-       unsigned int i, err = ATT_ECODE_ATTR_NOT_FOUND;
+       unsigned int i, err = 0;
        uint16_t last = 0;
        uint8_t type;
 
+       /* We have all the characteristic now, lets send it up */
+       if (status == ATT_ECODE_ATTR_NOT_FOUND) {
+               err = dc->characteristics ? 0 : status;
+               goto done;
+       }
+
        if (status) {
                err = status;
                goto done;
@@ -609,7 +657,18 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
 
        att_data_list_free(list);
 
-       if (last != 0 && (last + 1 < dc->end)) {
+       /*
+        * If last handle is lower from previous start handle then it is smth
+        * wrong. Let's stop search, otherwise we might enter infinite loop.
+        */
+       if (last < dc->start) {
+               err = ATT_ECODE_UNLIKELY;
+               goto done;
+       }
+
+       dc->start = last + 1;
+
+       if (last != 0 && (dc->start < dc->end)) {
                bt_uuid_t uuid;
                guint16 oplen;
                size_t buflen;
@@ -619,7 +678,7 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
 
                bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
 
-               oplen = enc_read_by_type_req(last + 1, dc->end, &uuid, buf,
+               oplen = enc_read_by_type_req(dc->start, dc->end, &uuid, buf,
                                                                        buflen);
 
                if (oplen == 0)
@@ -633,7 +692,6 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
        }
 
 done:
-       err = (dc->characteristics ? 0 : err);
        dc->cb(err, dc->characteristics, dc->user_data);
 }
 
@@ -661,6 +719,7 @@ guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
        dc->cb = func;
        dc->user_data = user_data;
        dc->end = end;
+       dc->start = start;
        dc->uuid = g_memdup(uuid, sizeof(bt_uuid_t));
 
        dc->id = g_attrib_send(attrib, 0, buf, plen, char_discovered_cb,
@@ -1015,12 +1074,17 @@ static void desc_discovered_cb(guint8 status, const guint8 *ipdu,
 {
        struct discover_desc *dd = user_data;
        struct att_data_list *list;
-       unsigned int i, err = ATT_ECODE_ATTR_NOT_FOUND;
+       unsigned int i, err = 0;
        guint8 format;
        uint16_t last = 0xffff;
        uint8_t type;
        gboolean uuid_found = FALSE;
 
+       if (status == ATT_ECODE_ATTR_NOT_FOUND) {
+               err = dd->descriptors ? 0 : status;
+               goto done;
+       }
+
        if (status) {
                err = status;
                goto done;
@@ -1074,6 +1138,17 @@ static void desc_discovered_cb(guint8 status, const guint8 *ipdu,
 
        att_data_list_free(list);
 
+       /*
+        * If last handle is lower from previous start handle then it is smth
+        * wrong. Let's stop search, otherwise we might enter infinite loop.
+        */
+       if (last < dd->start) {
+               err = ATT_ECODE_UNLIKELY;
+               goto done;
+       }
+
+       dd->start = last + 1;
+
        if (last < dd->end && !uuid_found) {
                guint16 oplen;
                size_t buflen;
@@ -1081,7 +1156,7 @@ static void desc_discovered_cb(guint8 status, const guint8 *ipdu,
 
                buf = g_attrib_get_buffer(dd->attrib, &buflen);
 
-               oplen = enc_find_info_req(last + 1, dd->end, buf, buflen);
+               oplen = enc_find_info_req(dd->start, dd->end, buf, buflen);
                if (oplen == 0)
                        return;
 
@@ -1093,7 +1168,6 @@ static void desc_discovered_cb(guint8 status, const guint8 *ipdu,
        }
 
 done:
-       err = (dd->descriptors ? 0 : err);
        dd->cb(err, dd->descriptors, dd->user_data);
 }
 
@@ -1117,6 +1191,7 @@ guint gatt_discover_desc(GAttrib *attrib, uint16_t start, uint16_t end,
        dd->attrib = g_attrib_ref(attrib);
        dd->cb = func;
        dd->user_data = user_data;
+       dd->start = start;
        dd->end = end;
        dd->uuid = g_memdup(uuid, sizeof(bt_uuid_t));
 
index c6f2f3d..1883b77 100644 (file)
@@ -22,8 +22,6 @@
  *
  */
 
-#include <bluetooth/sdp.h>
-
 /*
  * GATT Characteristic Property bit field
  * Reference: Core SPEC 4.1 page 2183 (Table 3.5: Characteristic Properties
@@ -126,4 +124,8 @@ gboolean gatt_parse_record(const sdp_record_t *rec,
 #ifdef __TIZEN_PATCH__
 guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
                                GAttribResultFunc func, gpointer user_data);
+guint gatt_read_char_by_offset(GAttrib *attrib, uint16_t handle, uint16_t offset,
+                               GAttribResultFunc func, gpointer user_data);
+gboolean gatt_register_internet_protocol_service(struct btd_adapter *adapter);
+gboolean gatt_unregister_internet_protocol_service(struct btd_adapter *adapter);
 #endif
\ No newline at end of file
index e6640f1..699f927 100644 (file)
 #include "config.h"
 #endif
 
+#include <stdio.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <string.h>
-#include <glib.h>
 
-#include <stdio.h>
+#include <glib.h>
 
-#include <bluetooth/bluetooth.h>
+#include "lib/bluetooth.h"
 
 #include "btio/btio.h"
 #include "src/log.h"
@@ -115,6 +115,9 @@ GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu)
        if (!attr->att)
                goto fail;
 
+       bt_att_set_close_on_unref(attr->att, true);
+       g_io_channel_set_close_on_unref(io, FALSE);
+
        if (!bt_att_set_mtu(attr->att, mtu))
                goto fail;
 
index 6e3d2bc..55911ef 100644 (file)
@@ -50,6 +50,7 @@ GIOChannel *g_attrib_get_channel(GAttrib *attrib);
 
 #ifdef __TIZEN_PATCH__
 void g_attrib_channel_unref(GAttrib *attrib);
+struct bt_att *g_attrib_get_att(GAttrib *attrib);
 #endif
 
 gboolean g_attrib_set_destroy_function(GAttrib *attrib,
index b8e0f68..1a40c94 100644 (file)
 #endif
 
 #include <errno.h>
-#include <glib.h>
 #include <stdlib.h>
 #include <unistd.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include <glib.h>
 
-#include "src/shared/util.h"
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
+#include "src/shared/util.h"
 #include "att.h"
 #include "btio/btio.h"
 #include "gattrib.h"
index b353765..4b42182 100644 (file)
 #include <readline/readline.h>
 #include <readline/history.h>
 
-#include "src/shared/util.h"
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
+#include "src/shared/util.h"
 #include "btio/btio.h"
 #include "att.h"
 #include "gattrib.h"
index 8f9a4c0..8e2fc1a 100644 (file)
 #endif
 
 #include <stdlib.h>
-#include <glib.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
 #include "btio/btio.h"
 #include "att.h"
 #include "gattrib.h"
index 18ee128..ce2b940 100644 (file)
@@ -79,6 +79,9 @@
                         <annotation name="com.tizen.smack" value="obexd::public" />
                         <annotation name="com.tizen.smack" value="bt_agent::public" />
                     </method>
+                    <method name="RegisterProfile2">
+                        <annotation name="com.tizen.smack" value="bt-service::platform" />
+                    </method>
                 </interface>
             </node>
         </dbus>
index db731fa..969cd3a 100644 (file)
 #include <sys/types.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/sco.h>
-
 #include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/l2cap.h"
+#include "lib/rfcomm.h"
+#include "lib/sco.h"
+
 #include "btio.h"
 
 #ifndef BT_FLUSHABLE
index 54c83fc..2cbc292 100644 (file)
@@ -28,8 +28,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <readline/readline.h>
-#include <gdbus.h>
 
+#include "gdbus/gdbus.h"
 #include "display.h"
 #include "agent.h"
 
@@ -295,13 +295,11 @@ static DBusMessage *authorize_service(DBusConnection *conn,
 {
        const char *device, *uuid;
        char *str;
-       int fd;
 
        rl_printf("Authorize service\n");
 
        dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
-                               DBUS_TYPE_STRING, &uuid,
-                               DBUS_TYPE_UNIX_FD, &fd, DBUS_TYPE_INVALID);
+                               DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID);
 
        str = g_strdup_printf("Authorize service %s (yes/no): ", uuid);
        agent_prompt(str);
@@ -346,8 +344,7 @@ static const GDBusMethodTable methods[] = {
                        GDBUS_ARGS({ "device", "o" }),
                        NULL, request_authorization) },
        { GDBUS_ASYNC_METHOD("AuthorizeService",
-                       GDBUS_ARGS({ "device", "o" }, { "uuid", "s" },
-                       {"fd", "h"}),
+                       GDBUS_ARGS({ "device", "o" }, { "uuid", "s" }),
                        NULL,  authorize_service) },
        { GDBUS_METHOD("Cancel", NULL, NULL, cancel_request) },
        { }
index 0f212b6..d85b9d0 100644 (file)
@@ -29,6 +29,7 @@
 #include <stdlib.h>
 #include <stdarg.h>
 #include <stdbool.h>
+#include <ctype.h>
 #include <readline/readline.h>
 
 #include "display.h"
@@ -62,3 +63,44 @@ void rl_printf(const char *fmt, ...)
                free(saved_line);
        }
 }
+
+void rl_hexdump(const unsigned char *buf, size_t len)
+{
+       static const char hexdigits[] = "0123456789abcdef";
+       char str[68];
+       size_t i;
+
+       if (!len)
+               return;
+
+       str[0] = ' ';
+
+       for (i = 0; i < len; i++) {
+               str[((i % 16) * 3) + 1] = ' ';
+               str[((i % 16) * 3) + 2] = hexdigits[buf[i] >> 4];
+               str[((i % 16) * 3) + 3] = hexdigits[buf[i] & 0xf];
+               str[(i % 16) + 51] = isprint(buf[i]) ? buf[i] : '.';
+
+               if ((i + 1) % 16 == 0) {
+                       str[49] = ' ';
+                       str[50] = ' ';
+                       str[67] = '\0';
+                       rl_printf("%s\n", str);
+                       str[0] = ' ';
+               }
+       }
+
+       if (i % 16 > 0) {
+               size_t j;
+               for (j = (i % 16); j < 16; j++) {
+                       str[(j * 3) + 1] = ' ';
+                       str[(j * 3) + 2] = ' ';
+                       str[(j * 3) + 3] = ' ';
+                       str[j + 51] = ' ';
+               }
+               str[49] = ' ';
+               str[50] = ' ';
+               str[67] = '\0';
+               rl_printf("%s\n", str);
+       }
+}
index 91a0be9..88dbbd0 100644 (file)
@@ -30,3 +30,4 @@
 #define COLOR_BOLDWHITE        "\x1B[1;37m"
 
 void rl_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+void rl_hexdump(const unsigned char *buf, size_t len);
diff --git a/client/gatt.c b/client/gatt.c
new file mode 100644 (file)
index 0000000..884c4f2
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2014  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/uio.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <glib.h>
+
+#include "gdbus/gdbus.h"
+#include "monitor/uuid.h"
+#include "display.h"
+#include "gatt.h"
+
+/* String display constants */
+#define COLORED_NEW    COLOR_GREEN "NEW" COLOR_OFF
+#define COLORED_CHG    COLOR_YELLOW "CHG" COLOR_OFF
+#define COLORED_DEL    COLOR_RED "DEL" COLOR_OFF
+
+static GList *services;
+static GList *characteristics;
+static GList *descriptors;
+
+static void print_service(GDBusProxy *proxy, const char *description)
+{
+       DBusMessageIter iter;
+       const char *uuid, *text;
+       dbus_bool_t primary;
+
+       if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
+               return;
+
+       dbus_message_iter_get_basic(&iter, &uuid);
+
+       if (g_dbus_proxy_get_property(proxy, "Primary", &iter) == FALSE)
+               return;
+
+       dbus_message_iter_get_basic(&iter, &primary);
+
+       text = uuidstr_to_str(uuid);
+       if (!text)
+               text = uuid;
+
+       rl_printf("%s%s%sService %s %s %s\n",
+                               description ? "[" : "",
+                               description ? : "",
+                               description ? "] " : "",
+                               g_dbus_proxy_get_path(proxy),
+                               text, primary ? "(Primary)" : "(Secondary)");
+}
+
+void gatt_add_service(GDBusProxy *proxy)
+{
+       services = g_list_append(services, proxy);
+
+       print_service(proxy, COLORED_NEW);
+}
+
+void gatt_remove_service(GDBusProxy *proxy)
+{
+       services = g_list_remove(services, proxy);
+
+       print_service(proxy, COLORED_DEL);
+}
+
+static void print_characteristic(GDBusProxy *proxy, const char *description)
+{
+       DBusMessageIter iter;
+       const char *uuid, *text;
+
+       if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
+               return;
+
+       dbus_message_iter_get_basic(&iter, &uuid);
+
+       text = uuidstr_to_str(uuid);
+       if (!text)
+               text = uuid;
+
+       rl_printf("%s%s%sCharacteristic %s %s\n",
+                               description ? "[" : "",
+                               description ? : "",
+                               description ? "] " : "",
+                               g_dbus_proxy_get_path(proxy),
+                               text);
+}
+
+static gboolean characteristic_is_child(GDBusProxy *characteristic)
+{
+       GList *l;
+       DBusMessageIter iter;
+       const char *service, *path;
+
+       if (!g_dbus_proxy_get_property(characteristic, "Service", &iter))
+               return FALSE;
+
+       dbus_message_iter_get_basic(&iter, &service);
+
+       for (l = services; l; l = g_list_next(l)) {
+               GDBusProxy *proxy = l->data;
+
+               path = g_dbus_proxy_get_path(proxy);
+
+               if (!strcmp(path, service))
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
+void gatt_add_characteristic(GDBusProxy *proxy)
+{
+       if (!characteristic_is_child(proxy))
+               return;
+
+       characteristics = g_list_append(characteristics, proxy);
+
+       print_characteristic(proxy, COLORED_NEW);
+}
+
+void gatt_remove_characteristic(GDBusProxy *proxy)
+{
+       if (!characteristic_is_child(proxy))
+               return;
+
+       characteristics = g_list_remove(characteristics, proxy);
+
+       print_characteristic(proxy, COLORED_DEL);
+}
+
+static void print_descriptor(GDBusProxy *proxy, const char *description)
+{
+       DBusMessageIter iter;
+       const char *uuid, *text;
+
+       if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
+               return;
+
+       dbus_message_iter_get_basic(&iter, &uuid);
+
+       text = uuidstr_to_str(uuid);
+       if (!text)
+               text = uuid;
+
+       rl_printf("%s%s%sDescriptor %s %s\n",
+                               description ? "[" : "",
+                               description ? : "",
+                               description ? "] " : "",
+                               g_dbus_proxy_get_path(proxy),
+                               text);
+}
+
+static gboolean descriptor_is_child(GDBusProxy *characteristic)
+{
+       GList *l;
+       DBusMessageIter iter;
+       const char *service, *path;
+
+       if (!g_dbus_proxy_get_property(characteristic, "Characteristic", &iter))
+               return FALSE;
+
+       dbus_message_iter_get_basic(&iter, &service);
+
+       for (l = characteristics; l; l = g_list_next(l)) {
+               GDBusProxy *proxy = l->data;
+
+               path = g_dbus_proxy_get_path(proxy);
+
+               if (!strcmp(path, service))
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
+void gatt_add_descriptor(GDBusProxy *proxy)
+{
+       if (!descriptor_is_child(proxy))
+               return;
+
+       descriptors = g_list_append(descriptors, proxy);
+
+       print_descriptor(proxy, COLORED_NEW);
+}
+
+void gatt_remove_descriptor(GDBusProxy *proxy)
+{
+       if (!descriptor_is_child(proxy))
+               return;
+
+       descriptors = g_list_remove(descriptors, proxy);
+
+       print_descriptor(proxy, COLORED_DEL);
+}
+
+static void list_attributes(const char *path, GList *source)
+{
+       GList *l;
+
+       for (l = source; l; l = g_list_next(l)) {
+               GDBusProxy *proxy = l->data;
+               const char *proxy_path;
+
+               proxy_path = g_dbus_proxy_get_path(proxy);
+
+               if (!g_str_has_prefix(proxy_path, path))
+                       continue;
+
+               if (source == services) {
+                       print_service(proxy, NULL);
+                       list_attributes(proxy_path, characteristics);
+               } else if (source == characteristics) {
+                       print_characteristic(proxy, NULL);
+                       list_attributes(proxy_path, descriptors);
+               } else if (source == descriptors)
+                       print_descriptor(proxy, NULL);
+       }
+}
+
+void gatt_list_attributes(const char *path)
+{
+       list_attributes(path, services);
+}
+
+static GDBusProxy *select_proxy(const char *path, GList *source)
+{
+       GList *l;
+
+       for (l = source; l; l = g_list_next(l)) {
+               GDBusProxy *proxy = l->data;
+
+               if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
+                       return proxy;
+       }
+
+       return NULL;
+}
+
+GDBusProxy *gatt_select_attribute(const char *path)
+{
+       GDBusProxy *proxy;
+
+       proxy = select_proxy(path, services);
+       if (proxy)
+               return proxy;
+
+       proxy = select_proxy(path, characteristics);
+       if (proxy)
+               return proxy;
+
+       return select_proxy(path, descriptors);
+}
+
+static char *attribute_generator(const char *text, int state, GList *source)
+{
+       static int index, len;
+       GList *list;
+
+       if (!state) {
+               index = 0;
+               len = strlen(text);
+       }
+
+       for (list = g_list_nth(source, index); list;
+                                               list = g_list_next(list)) {
+               GDBusProxy *proxy = list->data;
+               const char *path;
+
+               index++;
+
+               path = g_dbus_proxy_get_path(proxy);
+
+               if (!strncmp(path, text, len))
+                       return strdup(path);
+        }
+
+       return NULL;
+}
+
+char *gatt_attribute_generator(const char *text, int state)
+{
+       static GList *list = NULL;
+
+       if (!state) {
+               GList *list1;
+
+               if (list) {
+                       g_list_free(list);
+                       list = NULL;
+               }
+
+               list1 = g_list_copy(characteristics);
+               list1 = g_list_concat(list1, g_list_copy(descriptors));
+
+               list = g_list_copy(services);
+               list = g_list_concat(list, list1);
+       }
+
+       return attribute_generator(text, state, list);
+}
+
+static void read_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+       DBusMessageIter iter, array;
+       uint8_t *value;
+       int len;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to read: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       dbus_message_iter_init(message, &iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
+               rl_printf("Invalid response to read\n");
+               return;
+       }
+
+       dbus_message_iter_recurse(&iter, &array);
+       dbus_message_iter_get_fixed_array(&array, &value, &len);
+
+       if (len < 0) {
+               rl_printf("Unable to parse value\n");
+               return;
+       }
+
+       rl_hexdump(value, len);
+}
+
+static void read_attribute(GDBusProxy *proxy)
+{
+       if (g_dbus_proxy_method_call(proxy, "ReadValue", NULL, read_reply,
+                                                       NULL, NULL) == FALSE) {
+               rl_printf("Failed to read\n");
+               return;
+       }
+
+       rl_printf("Attempting to read %s\n", g_dbus_proxy_get_path(proxy));
+}
+
+void gatt_read_attribute(GDBusProxy *proxy)
+{
+       const char *iface;
+
+       iface = g_dbus_proxy_get_interface(proxy);
+       if (!strcmp(iface, "org.bluez.GattCharacteristic1") ||
+                               !strcmp(iface, "org.bluez.GattDescriptor1")) {
+               read_attribute(proxy);
+               return;
+       }
+
+       rl_printf("Unable to read attribute %s\n",
+                                               g_dbus_proxy_get_path(proxy));
+}
+
+static void write_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to write: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+}
+
+static void write_setup(DBusMessageIter *iter, void *user_data)
+{
+       struct iovec *iov = user_data;
+       DBusMessageIter array;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
+       dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
+                                               &iov->iov_base, iov->iov_len);
+       dbus_message_iter_close_container(iter, &array);
+}
+
+static void write_attribute(GDBusProxy *proxy, char *arg)
+{
+       struct iovec iov;
+       uint8_t value[512];
+       char *entry;
+       int i;
+
+       for (i = 0; (entry = strsep(&arg, " \t")) != NULL; i++) {
+               long int val;
+               char *endptr = NULL;
+
+               if (*entry == '\0')
+                       continue;
+
+               if (i > 512) {
+                       rl_printf("Too much data\n");
+                       return;
+               }
+
+               val = strtol(entry, &endptr, 0);
+               if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
+                       rl_printf("Invalid value at index %d\n", i);
+                       return;
+               }
+
+               value[i] = val;
+       }
+
+       iov.iov_base = value;
+       iov.iov_len = i;
+
+       if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup,
+                                       write_reply, &iov, NULL) == FALSE) {
+               rl_printf("Failed to write\n");
+               return;
+       }
+
+       rl_printf("Attempting to write %s\n", g_dbus_proxy_get_path(proxy));
+}
+
+void gatt_write_attribute(GDBusProxy *proxy, const char *arg)
+{
+       const char *iface;
+
+       iface = g_dbus_proxy_get_interface(proxy);
+       if (!strcmp(iface, "org.bluez.GattCharacteristic1") ||
+                               !strcmp(iface, "org.bluez.GattDescriptor1")) {
+               write_attribute(proxy, (char *) arg);
+               return;
+       }
+
+       rl_printf("Unable to write attribute %s\n",
+                                               g_dbus_proxy_get_path(proxy));
+}
+
+static void notify_reply(DBusMessage *message, void *user_data)
+{
+       bool enable = GPOINTER_TO_UINT(user_data);
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to %s notify: %s\n",
+                               enable ? "start" : "stop", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Notify %s\n", enable == TRUE ? "started" : "stopped");
+}
+
+static void notify_attribute(GDBusProxy *proxy, bool enable)
+{
+       const char *method;
+
+       if (enable == TRUE)
+               method = "StartNotify";
+       else
+               method = "StopNotify";
+
+       if (g_dbus_proxy_method_call(proxy, method, NULL, notify_reply,
+                               GUINT_TO_POINTER(enable), NULL) == FALSE) {
+               rl_printf("Failed to %s notify\n", enable ? "start" : "stop");
+               return;
+       }
+}
+
+void gatt_notify_attribute(GDBusProxy *proxy, bool enable)
+{
+       const char *iface;
+
+       iface = g_dbus_proxy_get_interface(proxy);
+       if (!strcmp(iface, "org.bluez.GattCharacteristic1")) {
+               notify_attribute(proxy, enable);
+               return;
+       }
+
+       rl_printf("Unable to notify attribute %s\n",
+                                               g_dbus_proxy_get_path(proxy));
+}
diff --git a/client/gatt.h b/client/gatt.h
new file mode 100644 (file)
index 0000000..effee5e
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2014  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+void gatt_add_service(GDBusProxy *proxy);
+void gatt_remove_service(GDBusProxy *proxy);
+
+void gatt_add_characteristic(GDBusProxy *proxy);
+void gatt_remove_characteristic(GDBusProxy *proxy);
+
+void gatt_add_descriptor(GDBusProxy *proxy);
+void gatt_remove_descriptor(GDBusProxy *proxy);
+
+void gatt_list_attributes(const char *device);
+GDBusProxy *gatt_select_attribute(const char *path);
+char *gatt_attribute_generator(const char *text, int state);
+
+void gatt_read_attribute(GDBusProxy *proxy);
+void gatt_write_attribute(GDBusProxy *proxy, const char *arg);
+void gatt_notify_attribute(GDBusProxy *proxy, bool enable);
index 9b0a397..b9e2eb7 100644 (file)
 #include <readline/readline.h>
 #include <readline/history.h>
 #include <glib.h>
-#include <gdbus.h>
 
+#include "gdbus/gdbus.h"
 #include "monitor/uuid.h"
 #include "agent.h"
 #include "display.h"
+#include "gatt.h"
 
 /* String display constants */
 #define COLORED_NEW    COLOR_GREEN "NEW" COLOR_OFF
@@ -57,6 +58,8 @@ static GDBusProxy *agent_manager;
 static char *auto_register_agent = NULL;
 
 static GDBusProxy *default_ctrl;
+static GDBusProxy *default_dev;
+static GDBusProxy *default_attr;
 static GList *ctrl_list;
 static GList *dev_list;
 
@@ -155,9 +158,9 @@ static void print_iter(const char *label, const char *name,
        dbus_uint32_t valu32;
        dbus_uint16_t valu16;
        dbus_int16_t vals16;
+       unsigned char byte;
        const char *valstr;
        DBusMessageIter subiter;
-       int type;
 
        if (iter == NULL) {
                rl_printf("%s%s is nil\n", label, name);
@@ -190,23 +193,27 @@ static void print_iter(const char *label, const char *name,
                dbus_message_iter_get_basic(iter, &vals16);
                rl_printf("%s%s: %d\n", label, name, vals16);
                break;
+       case DBUS_TYPE_BYTE:
+               dbus_message_iter_get_basic(iter, &byte);
+               rl_printf("%s%s: 0x%02x\n", label, name, byte);
+               break;
+       case DBUS_TYPE_VARIANT:
+               dbus_message_iter_recurse(iter, &subiter);
+               print_iter(label, name, &subiter);
+               break;
        case DBUS_TYPE_ARRAY:
                dbus_message_iter_recurse(iter, &subiter);
-               rl_printf("%s%s:\n", label, name);
-
-               do {
-                       type = dbus_message_iter_get_arg_type(&subiter);
-                       if (type == DBUS_TYPE_INVALID)
-                               break;
-
-                       if (type == DBUS_TYPE_STRING) {
-                               dbus_message_iter_get_basic(&subiter, &valstr);
-                               rl_printf("\t%s\n", valstr);
-                       }
-
+               while (dbus_message_iter_get_arg_type(&subiter) !=
+                                                       DBUS_TYPE_INVALID) {
+                       print_iter(label, name, &subiter);
                        dbus_message_iter_next(&subiter);
-               } while(true);
-
+               }
+               break;
+       case DBUS_TYPE_DICT_ENTRY:
+               dbus_message_iter_recurse(iter, &subiter);
+               dbus_message_iter_get_basic(&subiter, &valstr);
+               dbus_message_iter_next(&subiter);
+               print_iter(label, valstr, &subiter);
                break;
        default:
                rl_printf("%s%s has unsupported type\n", label, name);
@@ -284,6 +291,29 @@ static gboolean device_is_child(GDBusProxy *device, GDBusProxy *master)
        return FALSE;
 }
 
+static gboolean service_is_child(GDBusProxy *service)
+{
+       GList *l;
+       DBusMessageIter iter;
+       const char *device, *path;
+
+       if (g_dbus_proxy_get_property(service, "Device", &iter) == FALSE)
+               return FALSE;
+
+       dbus_message_iter_get_basic(&iter, &device);
+
+       for (l = dev_list; l; l = g_list_next(l)) {
+               GDBusProxy *proxy = l->data;
+
+               path = g_dbus_proxy_get_path(proxy);
+
+               if (!strcmp(path, device))
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
 static void proxy_added(GDBusProxy *proxy, void *user_data)
 {
        const char *interface;
@@ -311,9 +341,58 @@ static void proxy_added(GDBusProxy *proxy, void *user_data)
                                agent_register(dbus_conn, agent_manager,
                                                        auto_register_agent);
                }
+       } else if (!strcmp(interface, "org.bluez.GattService1")) {
+               if (service_is_child(proxy))
+                       gatt_add_service(proxy);
+       } else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
+               gatt_add_characteristic(proxy);
+       } else if (!strcmp(interface, "org.bluez.GattDescriptor1")) {
+               gatt_add_descriptor(proxy);
        }
 }
 
+static void set_default_device(GDBusProxy *proxy, const char *attribute)
+{
+       char *desc = NULL;
+       DBusMessageIter iter;
+       const char *path;
+
+       default_dev = proxy;
+
+       if (proxy == NULL) {
+               default_attr = NULL;
+               goto done;
+       }
+
+       if (!g_dbus_proxy_get_property(proxy, "Alias", &iter)) {
+               if (!g_dbus_proxy_get_property(proxy, "Address", &iter))
+                       goto done;
+       }
+
+       path = g_dbus_proxy_get_path(proxy);
+
+       dbus_message_iter_get_basic(&iter, &desc);
+       desc = g_strdup_printf(COLOR_BLUE "[%s%s%s]" COLOR_OFF "# ", desc,
+                               attribute ? ":" : "",
+                               attribute ? attribute + strlen(path) : "");
+
+done:
+       rl_set_prompt(desc ? desc : PROMPT_ON);
+       rl_redisplay();
+       g_free(desc);
+}
+
+static void set_default_attribute(GDBusProxy *proxy)
+{
+       const char *path;
+
+       default_attr = proxy;
+
+       path = g_dbus_proxy_get_path(proxy);
+
+       set_default_device(default_dev, path);
+}
+
 static void proxy_removed(GDBusProxy *proxy, void *user_data)
 {
        const char *interface;
@@ -325,6 +404,9 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
                        dev_list = g_list_remove(dev_list, proxy);
 
                        print_device(proxy, COLORED_DEL);
+
+                       if (default_dev == proxy)
+                               set_default_device(NULL, NULL);
                }
        } else if (!strcmp(interface, "org.bluez.Adapter1")) {
                ctrl_list = g_list_remove(ctrl_list, proxy);
@@ -333,6 +415,7 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
 
                if (default_ctrl == proxy) {
                        default_ctrl = NULL;
+                       set_default_device(NULL, NULL);
 
                        g_list_free(dev_list);
                        dev_list = NULL;
@@ -343,6 +426,23 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
                        if (auto_register_agent)
                                agent_unregister(dbus_conn, NULL);
                }
+       } else if (!strcmp(interface, "org.bluez.GattService1")) {
+               if (service_is_child(proxy)) {
+                       gatt_remove_service(proxy);
+
+                       if (default_attr == proxy)
+                               set_default_attribute(NULL);
+               }
+       } else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
+               gatt_remove_characteristic(proxy);
+
+               if (default_attr == proxy)
+                       set_default_attribute(NULL);
+       } else if (!strcmp(interface, "org.bluez.GattDescriptor1")) {
+               gatt_remove_descriptor(proxy);
+
+               if (default_attr == proxy)
+                       set_default_attribute(NULL);
        }
 }
 
@@ -369,6 +469,17 @@ static void property_changed(GDBusProxy *proxy, const char *name,
                        } else
                                str = g_strdup("");
 
+                       if (strcmp(name, "Connected") == 0) {
+                               dbus_bool_t connected;
+
+                               dbus_message_iter_get_basic(iter, &connected);
+
+                               if (connected && default_dev == NULL)
+                                       set_default_device(proxy, NULL);
+                               else if (!connected && default_dev == proxy)
+                                       set_default_device(NULL, NULL);
+                       }
+
                        print_iter(str, name, iter);
                        g_free(str);
                }
@@ -388,6 +499,14 @@ static void property_changed(GDBusProxy *proxy, const char *name,
 
                print_iter(str, name, iter);
                g_free(str);
+       } else if (proxy == default_attr) {
+               char *str;
+
+               str = g_strdup_printf("[" COLORED_CHG "] Attribute %s ",
+                                               g_dbus_proxy_get_path(proxy));
+
+               print_iter(str, name, iter);
+               g_free(str);
        }
 }
 
@@ -775,23 +894,36 @@ static void cmd_scan(const char *arg)
        }
 }
 
-static void cmd_info(const char *arg)
+static struct GDBusProxy *find_device(const char *arg)
 {
        GDBusProxy *proxy;
-       DBusMessageIter iter;
-       const char *address;
 
        if (!arg || !strlen(arg)) {
+               if (default_dev)
+                       return default_dev;
                rl_printf("Missing device address argument\n");
-               return;
+               return NULL;
        }
 
        proxy = find_proxy_by_address(dev_list, arg);
        if (!proxy) {
                rl_printf("Device %s not available\n", arg);
-               return;
+               return NULL;
        }
 
+       return proxy;
+}
+
+static void cmd_info(const char *arg)
+{
+       GDBusProxy *proxy;
+       DBusMessageIter iter;
+       const char *address;
+
+       proxy = find_device(arg);
+       if (!proxy)
+               return;
+
        if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
                return;
 
@@ -836,16 +968,9 @@ static void cmd_pair(const char *arg)
 {
        GDBusProxy *proxy;
 
-       if (!arg || !strlen(arg)) {
-               rl_printf("Missing device address argument\n");
+       proxy = find_device(arg);
+       if (!proxy)
                return;
-       }
-
-       proxy = find_proxy_by_address(dev_list, arg);
-       if (!proxy) {
-               rl_printf("Device %s not available\n", arg);
-               return;
-       }
 
        if (g_dbus_proxy_method_call(proxy, "Pair", NULL, pair_reply,
                                                        NULL, NULL) == FALSE) {
@@ -862,16 +987,9 @@ static void cmd_trust(const char *arg)
        dbus_bool_t trusted;
        char *str;
 
-       if (!arg || !strlen(arg)) {
-               rl_printf("Missing device address argument\n");
-               return;
-       }
-
-       proxy = find_proxy_by_address(dev_list, arg);
-       if (!proxy) {
-               rl_printf("Device %s not available\n", arg);
+       proxy = find_device(arg);
+       if (!proxy)
                return;
-       }
 
        trusted = TRUE;
 
@@ -891,16 +1009,9 @@ static void cmd_untrust(const char *arg)
        dbus_bool_t trusted;
        char *str;
 
-       if (!arg || !strlen(arg)) {
-               rl_printf("Missing device address argument\n");
+       proxy = find_device(arg);
+       if (!proxy)
                return;
-       }
-
-       proxy = find_proxy_by_address(dev_list, arg);
-       if (!proxy) {
-               rl_printf("Device %s not available\n", arg);
-               return;
-       }
 
        trusted = FALSE;
 
@@ -920,16 +1031,9 @@ static void cmd_block(const char *arg)
        dbus_bool_t blocked;
        char *str;
 
-       if (!arg || !strlen(arg)) {
-               rl_printf("Missing device address argument\n");
-               return;
-       }
-
-       proxy = find_proxy_by_address(dev_list, arg);
-       if (!proxy) {
-               rl_printf("Device %s not available\n", arg);
+       proxy = find_device(arg);
+       if (!proxy)
                return;
-       }
 
        blocked = TRUE;
 
@@ -949,16 +1053,9 @@ static void cmd_unblock(const char *arg)
        dbus_bool_t blocked;
        char *str;
 
-       if (!arg || !strlen(arg)) {
-               rl_printf("Missing device address argument\n");
+       proxy = find_device(arg);
+       if (!proxy)
                return;
-       }
-
-       proxy = find_proxy_by_address(dev_list, arg);
-       if (!proxy) {
-               rl_printf("Device %s not available\n", arg);
-               return;
-       }
 
        blocked = FALSE;
 
@@ -1027,6 +1124,7 @@ static void cmd_remove(const char *arg)
 
 static void connect_reply(DBusMessage *message, void *user_data)
 {
+       GDBusProxy *proxy = user_data;
        DBusError error;
 
        dbus_error_init(&error);
@@ -1038,6 +1136,8 @@ static void connect_reply(DBusMessage *message, void *user_data)
        }
 
        rl_printf("Connection successful\n");
+
+       set_default_device(proxy, NULL);
 }
 
 static void cmd_connect(const char *arg)
@@ -1056,7 +1156,7 @@ static void cmd_connect(const char *arg)
        }
 
        if (g_dbus_proxy_method_call(proxy, "Connect", NULL, connect_reply,
-                                                       NULL, NULL) == FALSE) {
+                                                       proxy, NULL) == FALSE) {
                rl_printf("Failed to connect\n");
                return;
        }
@@ -1066,6 +1166,7 @@ static void cmd_connect(const char *arg)
 
 static void disconn_reply(DBusMessage *message, void *user_data)
 {
+       GDBusProxy *proxy = user_data;
        DBusError error;
 
        dbus_error_init(&error);
@@ -1077,30 +1178,163 @@ static void disconn_reply(DBusMessage *message, void *user_data)
        }
 
        rl_printf("Successful disconnected\n");
+
+       if (proxy != default_dev)
+               return;
+
+       set_default_device(NULL, NULL);
 }
 
 static void cmd_disconn(const char *arg)
 {
        GDBusProxy *proxy;
 
+       proxy = find_device(arg);
+       if (!proxy)
+               return;
+
+       if (g_dbus_proxy_method_call(proxy, "Disconnect", NULL, disconn_reply,
+                                                       proxy, NULL) == FALSE) {
+               rl_printf("Failed to disconnect\n");
+               return;
+       }
+
+       rl_printf("Attempting to disconnect from %s\n", arg);
+}
+
+static void cmd_list_attributes(const char *arg)
+{
+       GDBusProxy *proxy;
+
+       proxy = find_device(arg);
+       if (!proxy)
+               return;
+
+       gatt_list_attributes(g_dbus_proxy_get_path(proxy));
+}
+
+static void cmd_select_attribute(const char *arg)
+{
+       GDBusProxy *proxy;
+
        if (!arg || !strlen(arg)) {
-               rl_printf("Missing device address argument\n");
+               rl_printf("Missing attribute argument\n");
                return;
        }
 
-       proxy = find_proxy_by_address(dev_list, arg);
+       if (!default_dev) {
+               rl_printf("No device connected\n");
+               return;
+       }
+
+       proxy = gatt_select_attribute(arg);
+       if (proxy)
+               set_default_attribute(proxy);
+}
+
+static struct GDBusProxy *find_attribute(const char *arg)
+{
+       GDBusProxy *proxy;
+
+       if (!arg || !strlen(arg)) {
+               if (default_attr)
+                       return default_attr;
+               rl_printf("Missing attribute argument\n");
+               return NULL;
+       }
+
+       proxy = gatt_select_attribute(arg);
        if (!proxy) {
-               rl_printf("Device %s not available\n", arg);
+               rl_printf("Attribute %s not available\n", arg);
+               return NULL;
+       }
+
+       return proxy;
+}
+
+static void cmd_attribute_info(const char *arg)
+{
+       GDBusProxy *proxy;
+       DBusMessageIter iter;
+       const char *iface, *uuid, *text;
+
+       proxy = find_attribute(arg);
+       if (!proxy)
                return;
+
+       if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
+               return;
+
+       dbus_message_iter_get_basic(&iter, &uuid);
+
+       text = uuidstr_to_str(uuid);
+       if (!text)
+               text = g_dbus_proxy_get_path(proxy);
+
+       iface = g_dbus_proxy_get_interface(proxy);
+       if (!strcmp(iface, "org.bluez.GattService1")) {
+               rl_printf("Service - %s\n", text);
+
+               print_property(proxy, "UUID");
+               print_property(proxy, "Primary");
+               print_property(proxy, "Characteristics");
+               print_property(proxy, "Includes");
+       } else if (!strcmp(iface, "org.bluez.GattCharacteristic1")) {
+               rl_printf("Characteristic - %s\n", text);
+
+               print_property(proxy, "UUID");
+               print_property(proxy, "Service");
+               print_property(proxy, "Value");
+               print_property(proxy, "Notifying");
+               print_property(proxy, "Flags");
+               print_property(proxy, "Descriptors");
+       } else if (!strcmp(iface, "org.bluez.GattDescriptor1")) {
+               rl_printf("Descriptor - %s\n", text);
+
+               print_property(proxy, "UUID");
+               print_property(proxy, "Characteristic");
+               print_property(proxy, "Value");
        }
+}
 
-       if (g_dbus_proxy_method_call(proxy, "Disconnect", NULL, disconn_reply,
-                                                       NULL, NULL) == FALSE) {
-               rl_printf("Failed to disconnect\n");
+static void cmd_read(const char *arg)
+{
+       if (!default_attr) {
+               rl_printf("No attribute selected\n");
                return;
        }
 
-       rl_printf("Attempting to disconnect from %s\n", arg);
+       gatt_read_attribute(default_attr);
+}
+
+static void cmd_write(const char *arg)
+{
+       if (!arg || !strlen(arg)) {
+               rl_printf("Missing data argument\n");
+               return;
+       }
+
+       if (!default_attr) {
+               rl_printf("No attribute selected\n");
+               return;
+       }
+
+       gatt_write_attribute(default_attr, arg);
+}
+
+static void cmd_notify(const char *arg)
+{
+       dbus_bool_t enable;
+
+       if (parse_argument_on_off(arg, &enable) == FALSE)
+               return;
+
+       if (!default_attr) {
+               rl_printf("No attribute selected\n");
+               return;
+       }
+
+       gatt_notify_attribute(default_attr, enable ? true : false);
 }
 
 static void cmd_version(const char *arg)
@@ -1154,6 +1388,11 @@ static char *dev_generator(const char *text, int state)
        return generic_generator(text, state, dev_list, "Address");
 }
 
+static char *attribute_generator(const char *text, int state)
+{
+       return gatt_attribute_generator(text, state);
+}
+
 static char *capability_generator(const char *text, int state)
 {
        static int index, len;
@@ -1203,24 +1442,34 @@ static const struct {
        { "default-agent",NULL,       cmd_default_agent,
                                "Set agent as the default one" },
        { "scan",         "<on/off>", cmd_scan, "Scan for devices" },
-       { "info",         "<dev>",    cmd_info, "Device information",
+       { "info",         "[dev]",    cmd_info, "Device information",
                                                        dev_generator },
-       { "pair",         "<dev>",    cmd_pair, "Pair with device",
+       { "pair",         "[dev]",    cmd_pair, "Pair with device",
                                                        dev_generator },
-       { "trust",        "<dev>",    cmd_trust, "Trust device",
+       { "trust",        "[dev]",    cmd_trust, "Trust device",
                                                        dev_generator },
-       { "untrust",      "<dev>",    cmd_untrust, "Untrust device",
+       { "untrust",      "[dev]",    cmd_untrust, "Untrust device",
                                                        dev_generator },
-       { "block",        "<dev>",    cmd_block, "Block device",
+       { "block",        "[dev]",    cmd_block, "Block device",
                                                                dev_generator },
-       { "unblock",      "<dev>",    cmd_unblock, "Unblock device",
+       { "unblock",      "[dev]",    cmd_unblock, "Unblock device",
                                                                dev_generator },
        { "remove",       "<dev>",    cmd_remove, "Remove device",
                                                        dev_generator },
        { "connect",      "<dev>",    cmd_connect, "Connect device",
                                                        dev_generator },
-       { "disconnect",   "<dev>",    cmd_disconn, "Disconnect device",
+       { "disconnect",   "[dev]",    cmd_disconn, "Disconnect device",
+                                                       dev_generator },
+       { "list-attributes", "[dev]", cmd_list_attributes, "List attributes",
                                                        dev_generator },
+       { "select-attribute", "<attribute>",  cmd_select_attribute,
+                               "Select attribute", attribute_generator },
+       { "attribute-info", "[attribute]",  cmd_attribute_info,
+                               "Select attribute", attribute_generator },
+       { "read",         NULL,       cmd_read, "Read attribute value" },
+       { "write",        "<data=[xx xx ...]>", cmd_write,
+                                               "Write attribute value" },
+       { "notify",       "<on/off>", cmd_notify, "Notify attribute value" },
        { "version",      NULL,       cmd_version, "Display version" },
        { "quit",         NULL,       cmd_quit, "Quit program" },
        { "exit",         NULL,       cmd_quit },
old mode 100755 (executable)
new mode 100644 (file)
index 5078c98..a58720c
@@ -1,5 +1,5 @@
 AC_PREREQ(2.60)
-AC_INIT(bluez, 5.27)
+AC_INIT(bluez, 5.28)
 
 AM_INIT_AUTOMAKE([foreign subdir-objects color-tests silent-rules
                                        tar-pax no-dist-gzip dist-xz])
@@ -54,6 +54,8 @@ AC_CHECK_LIB(pthread, pthread_create, dummy=yes,
 AC_CHECK_LIB(dl, dlopen, dummy=yes,
                        AC_MSG_ERROR(dynamic linking loader is required))
 
+AC_CHECK_HEADERS(linux/types.h linux/if_alg.h)
+
 PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.28, dummy=yes,
                                AC_MSG_ERROR(GLib >= 2.28 is required))
 AC_SUBST(GLIB_CFLAGS)
@@ -130,8 +132,8 @@ AM_CONDITIONAL(MONITOR, test "${enable_monitor}" != "no")
 AC_ARG_ENABLE(udev, AC_HELP_STRING([--disable-udev],
                [disable udev device support]), [enable_udev=${enableval}])
 if (test "${enable_tools}" != "no" && test "${enable_udev}" != "no"); then
-       PKG_CHECK_MODULES(UDEV, libudev >= 143, dummy=yes,
-                               AC_MSG_ERROR(libudev >= 143 is required))
+       PKG_CHECK_MODULES(UDEV, libudev >= 172, dummy=yes,
+                               AC_MSG_ERROR(libudev >= 172 is required))
        AC_SUBST(UDEV_CFLAGS)
        AC_SUBST(UDEV_LIBS)
        AC_CHECK_LIB(udev, udev_hwdb_new,
@@ -218,7 +220,7 @@ AC_ARG_ENABLE(manpages, AC_HELP_STRING([--enable-manpages],
 AM_CONDITIONAL(MANPAGES, test "${enable_manpages}" = "yes")
 
 AC_ARG_ENABLE(experimental, AC_HELP_STRING([--enable-experimental],
-                       [enable experimental plugins (SAP, NFC, ...)]),
+                       [enable experimental plugins (NFC, ...)]),
                                        [enable_experimental=${enableval}])
 AM_CONDITIONAL(EXPERIMENTAL, test "${enable_experimental}" = "yes")
 
@@ -227,10 +229,6 @@ AC_ARG_ENABLE(wearable, AC_HELP_STRING([--enable-wearable],
                        [enable wearable profile]), [enable_wearable=${enableval}])
 AM_CONDITIONAL(WEARABLE, test "${enable_wearable}" = "yes")
 
-AC_ARG_ENABLE(usbbt, AC_HELP_STRING([--enable-usbbt],
-                [enable usb bluetooth]), [enable_usbbt=${enableval}])
-AM_CONDITIONAL(USBBT, test "${enable_usbbt}" = "yes")
-
 AC_ARG_ENABLE(autopair, AC_HELP_STRING([--enable-autopair],
                        [Enable Autopair Plugin]), [enable_autopair=${enableval}])
 AM_CONDITIONAL(AUTOPAIR, test "${enable_autopair}" = "yes")
@@ -239,9 +237,16 @@ AC_ARG_ENABLE(hid, AC_HELP_STRING([--enable-hid],
                        [Enable HID Plugin]), [enable_hid=${enableval}])
 AM_CONDITIONAL(TIZEN_HID_PLUGIN, test "${enable_hid}" = "yes")
 
+AM_CONDITIONAL(TIZEN_HEALTH_PLUGIN, test "${enable_health}" = "yes")
+
 AC_ARG_ENABLE(tizenunusedplugin, AC_HELP_STRING([--enable-tizenunusedplugin],
                 [Enable Unused Plugin]), [enable_tizenunusedplugin=${enableval}])
 AM_CONDITIONAL(TIZEN_UNUSED_PLUGIN, test "${enable_tizenunusedplugin}" = "yes")
+
+AC_ARG_ENABLE(sap, AC_HELP_STRING([--enable-sap],
+                       [Enable SAP Plugin]), [enable_sap=${enableval}])
+AM_CONDITIONAL(TIZEN_SAP_PLUGIN, test "${enable_sap}" = "yes")
+
 # End of __TIZEN_PATCH__
 
 AC_ARG_ENABLE(sixaxis, AC_HELP_STRING([--enable-sixaxis],
@@ -249,10 +254,6 @@ AC_ARG_ENABLE(sixaxis, AC_HELP_STRING([--enable-sixaxis],
 AM_CONDITIONAL(SIXAXIS, test "${enable_sixaxis}" = "yes" &&
                                         test "${enable_udev}" != "no")
 
-AC_ARG_ENABLE(service, AC_HELP_STRING([--enable-service],
-               [enable service plugin]), [enable_service=${enableval}])
-AM_CONDITIONAL(SERVICE, test "${enable_service}" = "yes")
-
 if (test "${prefix}" = "NONE"); then
        dnl no prefix and no localstatedir, so default to /var
        if (test "$localstatedir" = '${prefix}/var'); then
index fe515b0..5527993 100644 (file)
@@ -302,10 +302,6 @@ Properties string Address [readonly]
 
                        Indicates that a device LE discovery procedure is active.
 
-               boolean Advertising [readonly]
-
-                       Indicates that a advertising procedure is active.
-
                string Version [readonly]
 
                         The Bluetooth version.
index 5c76ba4..290ff7d 100644 (file)
@@ -46,9 +46,11 @@ Methods              void Connect()
                        device. The UUID provided is the remote service
                        UUID for the profile.
 
-                       Possible errors: org.bluez.Error.DoesNotExist
-                                        org.bluez.Error.AlreadyConnected
-                                        org.bluez.Error.ConnectFailed
+                       Possible errors: org.bluez.Error.Failed
+                                        org.bluez.Error.InProgress
+                                        org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.NotAvailable
+                                        org.bluez.Error.NotReady
 
                void DisconnectProfile(string uuid)
 
@@ -60,9 +62,9 @@ Methods               void Connect()
                        as long as the profile is registered this will always
                        succeed.
 
-                       Possible errors: org.bluez.Error.DoesNotExist
-                                        org.bluez.Error.Failed
-                                        org.bluez.Error.NotConnected
+                       Possible errors: org.bluez.Error.Failed
+                                        org.bluez.Error.InProgress
+                                        org.bluez.Error.InvalidArguments
                                         org.bluez.Error.NotSupported
 
 #ifdef __TIZEN_PATCH__
@@ -173,7 +175,11 @@ Properties string Address [readonly]
 
                        Indicates if the remote device is paired.
 
+#ifdef __TIZEN_PATCH__
+               byte Connected [readonly]
+#else
                boolean Connected [readonly]
+#endif
 
                        Indicates if the remote device is currently connected.
                        A PropertiesChanged signal indicate changes to this
index 99c66f7..c5eb827 100644 (file)
@@ -8,7 +8,9 @@ application. Remote refers to GATT services exported by the peer.
 BlueZ acts as a proxy, translating ATT operations to D-Bus method calls and
 Properties (or the opposite). Support for D-Bus Object Manager is mandatory for
 external services to allow seamless GATT declarations (Service, Characteristic
-and Descriptors) discovery.
+and Descriptors) discovery. Each GATT service tree is required to export a D-Bus
+Object Manager at its root that is solely responsible for the objects that
+belong to that service.
 
 Releasing a registered GATT service is not defined yet. Any API extension
 should avoid breaking the defined API, and if possible keep an unified GATT
@@ -75,9 +77,8 @@ Methods               array{byte} ReadValue()
 
                        Possible Errors: org.bluez.Error.Failed
                                         org.bluez.Error.InProgress
-                                        org.bluez.Error.ReadNotPermitted
+                                        org.bluez.Error.NotPermitted
                                         org.bluez.Error.NotAuthorized
-                                        org.bluez.Error.NotPaired
                                         org.bluez.Error.NotSupported
 
                void WriteValue(array{byte} value)
@@ -87,10 +88,9 @@ Methods              array{byte} ReadValue()
 
                        Possible Errors: org.bluez.Error.Failed
                                         org.bluez.Error.InProgress
-                                        org.bluez.Error.WriteNotPermitted
+                                        org.bluez.Error.NotPermitted
                                         org.bluez.Error.InvalidValueLength
                                         org.bluez.Error.NotAuthorized
-                                        org.bluez.Error.NotPaired
                                         org.bluez.Error.NotSupported
 
                void StartNotify()
@@ -175,9 +175,8 @@ Methods             array{byte} ReadValue()
 
                        Possible Errors: org.bluez.Error.Failed
                                         org.bluez.Error.InProgress
-                                        org.bluez.Error.ReadNotPermitted
+                                        org.bluez.Error.NotPermitted
                                         org.bluez.Error.NotAuthorized
-                                        org.bluez.Error.NotPaired
                                         org.bluez.Error.NotSupported
 
                void WriteValue(array{byte} value)
@@ -187,10 +186,9 @@ Methods            array{byte} ReadValue()
 
                        Possible Errors: org.bluez.Error.Failed
                                         org.bluez.Error.InProgress
-                                        org.bluez.Error.WriteNotPermitted
+                                        org.bluez.Error.NotPermitted
                                         org.bluez.Error.InvalidValueLength
                                         org.bluez.Error.NotAuthorized
-                                        org.bluez.Error.NotPaired
                                         org.bluez.Error.NotSupported
 
 Properties     string UUID [read-only]
@@ -209,27 +207,96 @@ Properties        string UUID [read-only]
                        which a PropertiesChanged signal will be emitted.
 
 
-Service Manager hierarchy
-=============================
-
-Service Manager allows external applications to register GATT based
-services. Services must follow the API for Service and Characteristic
-described above.
-
-Local GATT services, characteristics and characteristic descriptors are
-discovered automatically using the D-Bus Object Manager interface.
+Profile hierarcy
+================
+
+Local profile (GATT client) instance. By registering this type of object
+an application effectively indicates support for a specific GATT profile
+and requests automatic connections to be established to devices
+supporting it.
+
+Service                <application dependent>
+Interface      org.bluez.GattProfile1 [Experimental]
+Object path    <application dependent>
+
+Methods                void Release()
+
+                       This method gets called when the service daemon
+                       unregisters the profile. The profile can use it to
+                       do cleanup tasks. There is no need to unregister the
+                       profile, because when this method gets called it has
+                       already been unregistered.
+
+
+GATT Manager hierarchy
+======================
+
+GATT Manager allows external applications to register GATT services and
+profiles.
+
+Registering a profile allows applications to subscribe to *remote* services.
+These must implement the GattProfile1 interface defined above.
+
+Registering a service allows applications to publish a *local* GATT service,
+which then becomes available to remote devices. A GATT service is represented by
+a D-Bus object hierarchy where the root node corresponds to a service and the
+child nodes represent characteristics and descriptors that belong to that
+service. Each node must implement one of GattService1, GattCharacteristic1,
+or GattDescriptor1 interfaces described above, based on the attribute it
+represents. Each node must also implement the standard D-Bus Properties
+interface to expose their properties. These objects collectively represent a
+GATT service definition.
+
+To make service registration simple, BlueZ requires that all objects that belong
+to a GATT service be grouped under a D-Bus Object Manager that solely manages
+the objects of that service. Hence, the standard DBus.ObjectManager interface
+must be available on the root service path. An example application hierarchy
+containing two separate GATT services may look like this:
+
+-> /com/example
+  |
+  -> /com/example/service0
+  | |   - org.freedesktop.DBus.ObjectManager
+  | |   - org.freedesktop.DBus.Properties
+  | |   - org.bluez.GattService1
+  | |
+  | -> /com/example/service0/char0
+  | |     - org.freedesktop.DBus.Properties
+  | |     - org.bluez.GattCharacteristic1
+  | |
+  | -> /com/example/service0/char1
+  |   |   - org.freedesktop.DBus.Properties
+  |   |   - org.bluez.GattCharacteristic1
+  |   |
+  |   -> /com/example/service0/char1/desc0
+  |       - org.freedesktop.DBus.Properties
+  |       - org.bluez.GattDescriptor1
+  |
+  -> /com/example/service1
+    |   - org.freedesktop.DBus.ObjectManager
+    |   - org.freedesktop.DBus.Properties
+    |   - org.bluez.GattService1
+    |
+    -> /com/example/service1/char0
+        - org.freedesktop.DBus.Properties
+        - org.bluez.GattCharacteristic1
+
+When a service is registered, BlueZ will automatically obtain information about
+all objects using the service's Object Manager. Once a service has been
+registered, the objects of a service should not be removed. If BlueZ receives an
+InterfacesRemoved signal from a service's Object Manager, it will immediately
+unregister the service. Similarly, if the application disconnects from the bus,
+all of its registered services will be automatically unregistered.
+InterfacesAdded signals will be ignored.
 
 Service                org.bluez
 Interface      org.bluez.GattManager1 [Experimental]
-Object path    /org/bluez
+Object path    [variable prefix]/{hci0,hci1,...}
 
-Methods                RegisterService(object service, dict options)
+Methods                void RegisterService(object service, dict options)
 
-                       Registers remote application service exported under
-                       interface GattService1. Characteristic objects must
-                       be hierarchical to their service and must use the
-                       interface GattCharacteristic1. D-Bus Object Manager
-                       is used to fetch the exported objects.
+                       Registers a local GATT service hierarchy as described
+                       above.
 
                        "service" object path together with the D-Bus system
                        bus connection ID define the identification of the
@@ -238,7 +305,7 @@ Methods             RegisterService(object service, dict options)
                        Possible errors: org.bluez.Error.InvalidArguments
                                         org.bluez.Error.AlreadyExists
 
-               UnregisterService(object service)
+               void UnregisterService(object service)
 
                        This unregisters the service that has been
                        previously registered. The object path parameter
@@ -248,6 +315,29 @@ Methods            RegisterService(object service, dict options)
                        Possible errors: org.bluez.Error.InvalidArguments
                                         org.bluez.Error.DoesNotExist
 
+               void RegisterProfile(object profile, array{string} UUIDs,
+                                    dict options)
+
+                       Registers a GATT (client role) profile exported
+                       under interface GattProfile1. The array of UUIDs
+                       specifies the mandatory set of remote service
+                       UUIDs that should all be available for the
+                       remote device to match this profile. Matching
+                       devices will be added to the auto-connection
+                       list and connected whenever available.
+
+                       Possible errors: org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.AlreadyExists
+
+               void UnregisterProfile(object profile)
+
+                       This unregisters the profile that has been
+                       previously registered. The object path parameter
+                       must match the same value that has been used
+                       on registration.
+
+                       Possible errors: org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.DoesNotExist
 #ifdef __TIZEN_PATCH__
                GetService(string uuid)
 
diff --git a/doc/maintainer-guidelines.txt b/doc/maintainer-guidelines.txt
new file mode 100644 (file)
index 0000000..fef90c8
--- /dev/null
@@ -0,0 +1,114 @@
+Maintainer guidelines
+*********************
+
+This document is intended for the maintainers of the BlueZ project. It
+serves as basic guidelines for handling patch review and commit access.
+
+
+Rule 1: Keep the GIT tree clean and linear
+==========================================
+
+The bluetooth.git, bluetooth-next.git and bluez.git trees are not your
+private playground. The history is meant to be clean and linear.
+
+       - NO merges
+       - NO branches
+       - NO tags
+
+If anyone needs testing or work on a feature, clone the tree and do
+it in your own copy. The master trees are off limits.
+
+One advise to avoid any accidental errors in this area to set proper
+options in global ~/.gitconfig or local .git/config files.
+
+       [merge]
+               ff = only
+
+Violations of this rule are not acceptable. This rule is enforced. If
+in doubt ask one of the seasoned maintainers.
+
+
+Rule 2: Enforce clean commit messages
+=====================================
+
+The commit messages are required to be clean and follow style guidelines
+to be consistent.
+
+Commit messages should adhere to a 72 characters by line limit. That
+makes it easy to read them via git log in a terminal window. Exceptions
+to this rule are logs, trace or other verbatim copied information.
+
+Every commit requires full names and email addresses. No synonyms or
+nicknames are allowed. It is also important that the Outlook style
+names with lastname, firstname are not allowed. It is the maintainers
+job to ensure we get proper firstname lastname <email> authorship.
+
+It is also important that the committer itself uses a valid name and
+email address when committing patches. So ensure that either the
+global ~/.gitconfig or local .git/config provides proper values.
+
+       [user]
+               name = Peter Mustermann
+               email = peter@mustermann.de
+
+Commit messages for bluez.git shall not contain Signed-off-by
+signatures. They are not used in userspace and with that it is the
+maintainers job to ensure they do not get committed to the repository.
+
+For bluetooth.git and bluetooth-next.git The Signed-off-by process is
+used and the signatures are required.
+
+Tags like Change-Id generated from Gerrit are never acceptable. It is
+the maintainers job to ensure that these are not committed into the
+repositories.
+
+Violations of this rule create a mess in the tree that can not be
+reversed. If in doubt ask one of the seasoned maintainers.
+
+
+Rule 3: Enforce correct coding style
+====================================
+
+The coding style follows roughly the kernel coding style with any
+exceptions documented in doc/coding-style.txt.
+
+To ensure trivial white-space errors don't get committed, have the
+following in your .gitconfig:
+
+       [apply]
+               whitespace = error
+
+It can also be helpful to use the checkpatch.pl script coming with the
+Linux kernel to do some automated checking. Adding the following to your
+.git/hooks/pre-commit and .git/hooks/pre-applypatch is a simple way to
+do this:
+
+       exec git diff --cached | ~/src/linux/scripts/checkpatch.pl -q \
+               --no-tree --no-signoff --show-types \
+               --ignore CAMELCASE,NEW_TYPEDEFS,INITIALISED_STATIC -
+
+The above assumes that a kernel tree resides in ~/src/linux/.
+
+
+Rule 4: Pay extra attention to adding new files to the tree
+===========================================================
+
+New files that are added to the tree require several things to be
+verified first:
+
+       - Check that the names are acceptible with other maintainers
+       - Ensure that the file modes are correct
+       - Verify that the license & copyright headers are correct
+       - If the file is supposed to be part of the release taraball,
+         make sure that it gets picked up by 'make dist' (particularly
+         important for documentation or other files that are not code)
+
+
+Rule 5: Keep the mailing list in sync with the commit process
+=============================================================
+
+When applying patches, be sure to send a response to the mailing list as
+soon as the code has been pushed to the upstream tree. Usually this
+means one email per patch, however patch-sets may only have one response
+covering the entire set. If applying a subset of a patch-set clearly
+state what was applied in your response.
index 39ab162..9bdf177 100644 (file)
@@ -22,7 +22,7 @@ Linux kernel v3.13    Version 1.4
 Linux kernel v3.15     Version 1.5
 Linux kernel v3.16     Version 1.6
 Linux kernel v3.17     Version 1.7
-Linux kernel v3.19     Version 1.8     (not yet released)
+Linux kernel v3.19     Version 1.8
 
 Version 1.1 introduces Set Device ID command.
 
@@ -246,6 +246,10 @@ Read Controller Information Command
        then the configured static address will be used as identity
        address.
 
+       In the case of a dual-mode controller with public address that
+       is configured as Low Energy only device (BR/EDR switched off),
+       the static address is used when set and public address otherwise.
+
        If no short name is set the Short_Name parameter will be empty
        (begin with a nul byte).
 
@@ -267,6 +271,7 @@ Read Controller Information Command
                12      Debug Keys
                13      Privacy
                14      Controller Configuration
+               15      Static Address
 
        This command generates a Command Complete event on success or
        a Command Status event on failure.
@@ -1023,7 +1028,14 @@ Pair Device Command
        This command generates a Command Complete event on success
        or failure.
 
-       Possible errors:        Connect Failed
+       Reject status is used when requested transport is not enabled.
+
+       Not Supported status is used if controller is not capable with
+       requested transport.
+
+       Possible errors:        Rejected
+                               Not Supported
+                               Connect Failed
                                Busy
                                Invalid Parameters
                                Not Powered
@@ -1236,6 +1248,10 @@ Read Local Out Of Band Data Command
        will return P-192 versions of hash and randomizer as well as
        P-256 versions of both.
 
+       Values returned by this command become invalid when the controller
+       is powered down. After each power-cycle it is required to call
+       this command again to get updated values.
+
        This command generates a Command Complete event on success or
        a Command Status event on failure.
 
@@ -1283,6 +1299,21 @@ Add Remote Out Of Band Data Command
        Secure Connections is disabled, then of course this is the
        same as not providing any data at all.
 
+       When providing data for remote LE devices, then the Hash_192 field
+       is used to provide the Security Manager TK Value. The Randomizer_192
+       field is not used and shall be set to zero. The Hash_192 value can
+       also be set to zero and that means that no Out Of Band data for
+       LE legacy pairing is provided.
+
+       The Hash_256 and Randomizer_256 fields can be used for LE secure
+       connections Out Of Band data. If only LE secure connections data
+       is provided the Hash_P192 and Randomizer_P192 fields can be set
+       to zero.
+
+       If Secure Connections Only mode has been enabled, then providing
+       Hash_P192 and Randomizer_P192 is not allowed. They are required
+       to be set to zero values.
+
        This command can be used when the controller is not powered and
        all settings will be programmed once powered.
 
@@ -1507,7 +1538,7 @@ Set Device ID Command
 
                0x0000  Disable Device ID
                0x0001  Bluetooth SIG
-               0x0002  USB Implementerâ\80\99s Forum
+               0x0002  USB Implementer?\99s Forum
 
        The information are put into the EIR data. If the controller does
        not support EIR or if SSP is disabled, this command will still
@@ -1583,7 +1614,7 @@ Set Static Address Command
        Command Code:           0x002B
        Controller Index:       <controller id>
        Command Parameters:     Address (6 Octets)
-       Return Parameters:
+       Return Parameters:      Current_Settings (4 Octets)
 
        This command allows for setting the static random address. It is
        only supported on controllers with LE support. The static random
@@ -1596,7 +1627,9 @@ Set Static Address Command
        to disable the static address.
 
        When a controller has a public address (which is required for
-       all dual-mode controllers), this address is not used. Only when
+       all dual-mode controllers), this address is not used. If a dual-mode
+       controller is configured as Low Energy only devices (BR/EDR has
+       been switched off), then the static address is used. Only when
        the controller information reports BDADDR_ANY (00:00:00:00:00:00),
        it is required to configure a static address first.
 
@@ -1604,6 +1637,9 @@ Set Static Address Command
        LE only without a public address, the static random address is
        used as identity address.
 
+       The Static Address flag from the current settings can also be used
+       to determine if the configured static address is in use or not.
+
        This command generates a Command Complete event on success or a
        Command Status event on failure.
 
@@ -2276,6 +2312,142 @@ Start Service Discovery Command
                                Invalid Index
 
 
+Read Local Out Of Band Extended Data Command
+============================================
+
+       Command Code:           0x003b
+       Controller Index:       <controller id>
+       Command Parameters:     Address_Type (1 Octet)
+       Return Parameters:      Address_Type (1 Octet)
+                               EIR_Data_Length (2 Octets)
+                               EIR_Data (0-65535 Octets)
+
+       This command is used to read the local Out of Band data
+       information and provide them encoded as extended inquiry
+       response information or advertising data.
+
+       Possible values for the Address_Type parameter are a bit-wise or
+       of the following bits:
+
+               0       BR/EDR
+               1       LE Public
+               2       LE Random
+
+       By combining these e.g. the following values are possible:
+
+               1       BR/EDR
+               6       LE (public & random)
+               7       Reserved (not in use)
+
+       For BR/EDR controller (Address_Type 1) the returned information
+       will contain the following information:
+
+               Class of Device
+               Simple Pairing Hash C-192 (optional)
+               Simple Pairing Randomizer R-192 (optional)
+               Simple Pairing Hash C-256 (optional)
+               Simple Pairing Randomizer R-256 (optional)
+               Service Class UUID (optional)
+               Bluetooth Local Name (optional)
+
+       The Simple Pairing Hash C-256 and Simple Pairing Randomizer R-256
+       fields are only included when secure connections has been enabled.
+
+       The Device Address (BD_ADDR) is not included in the EIR_Data and
+       needs to be taken from controller information.
+
+       For LE controller (Address_Type 6) the returned information
+       will contain the following information:
+
+               LE Bluetooth Device Address
+               LE Role
+               Security Manager TK Value (optional)
+               LE Secure Connections Confirmation Value (optional)
+               LE Secure Connections Random Value (optional)
+               Appearance (optional)
+               Local Name (optional)
+               Flags
+
+       The LE Secure Connections Confirmation Value and LE Secure Connections
+       Random Value fields are only included when secure connections has been
+       enabled.
+
+       The returned information from BR/EDR controller and LE controller
+       types are not related to each other. Once they have been used
+       over an Out Of Band link, a new set of information shall be
+       requested.
+
+       When Secure Connections Only mode has been enabled, then the fields
+       for Simple Pairing Hash C-192, Simple Pairing Randomizer R-192 and
+       Security Manager TK Value are not returned. Only the fields for
+       the strong secure connections pairing are included.
+
+       This command can only be used when the controller is powered.
+
+       Values returned by this command become invalid when the controller
+       is powered down. After each power-cycle it is required to call
+       this command again to get updated information.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
+       Possible errors:        Not Supported
+                               Busy
+                               Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+Read Extended Controller Index List Command
+===========================================
+
+       Command Code:           0x003c
+       Controller Index:       <non-controller>
+       Command Parameters:
+       Return Parameters:      Num_Controllers (2 Octets)
+                               Controller_Index[i] (2 Octets)
+                               Controller_Type[i] (1 Octet)
+
+       This command returns the list of currently known controllers. It
+       includes configured, unconfigured and alternate controllers.
+
+       Controllers added or removed after calling this command can be
+       be monitored using the Extended Index Added and Extended Index
+       Removed events.
+
+       The existing Index Added, Index Removed, Unconfigured Index Added
+       and Unconfigured Index Removed are no longer sent after this command
+       has been used at least once.
+
+       Instead of calling Read Controller Index List and Read Unconfigured
+       Controller Index List, this command combines all the information
+       and can be used to retrieve the controller list.
+
+       The Controller_Type parameter has these values:
+
+               0x00    Primary Controller (BR/EDR and/or LE)
+               0x01    Unconfigured Controller (BR/EDR and/or LE)
+               0x02    Alternate MAC/PHY Controller (AMP)
+
+       The 0x00 and 0x01 types indiciate a primary BR/EDR and/or LE
+       controller. The difference is just if they need extra configuration
+       or if they are fully configured.
+
+       Controllers in configured state will be listed as 0x00 and controllers
+       in unconfigured state will be listed as 0x01. A controller that is
+       fully configured and supports configuration changes will be listed
+       as 0x00.
+
+       Alternate MAC/PHY controllers will be listed as 0x02. They do not
+       support the difference between configured and unconfigured state.
+
+       Controllers marked as RAW only operation are currently not listed
+       by this command.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
+
 Command Complete Event
 ======================
 
@@ -2329,6 +2501,10 @@ Index Added Event
        system. It is usually followed by a Read Controller Information
        command.
 
+       Once the Read Extended Controller Index List command has been
+       used at least once, the Extended Index Added event will be
+       send instead of this one.
+
 
 Index Removed Event
 ===================
@@ -2340,6 +2516,10 @@ Index Removed Event
        This event indicates that a controller has been removed from the
        system.
 
+       Once the Read Extended Controller Index List command has been
+       used at least once, the Extended Index Removed event will be
+       send instead of this one.
+
 
 New Settings Event
 ==================
@@ -2861,7 +3041,7 @@ New Signature Resolving Key Event
                                Key {
                                        Address (6 Octets)
                                        Address_Type (1 Octet)
-                                       Master (1 Octet)
+                                       Type (1 Octet)
                                        Value (16 Octets)
                                }
 
@@ -2871,17 +3051,20 @@ New Signature Resolving Key Event
        The Store_Hint parameter indicates whether the host is expected
        to store the key persistently or not.
 
-       When the Master parameter is set to 0x01, then the signature
-       resolving key from the remote peer device is provided. It is
-       the key that is used for signature verification.
+       The Type parameter has the following possible values:
+
+               0x00    Unauthenticated local CSRK
+               0x01    Unauthenticated remote CSRK
+               0x02    Authenticated local CSRK
+               0x03    Authenticated remote CSRK
 
-       When the Master parameter is set to 0x00, then it is the local
-       signature resolving key that is used to sign data. The remote
-       peer device will be using it for signature verification.
+       The local keys are used for signing data to be sent to the
+       remote device, whereas the remote keys are used to verify
+       signatures received from the remote device.
 
        The local signature resolving key will be generated with each
-       pairing request. Only after receiving this event with Master
-       parameter set to 0x00 it is possible to use ATT Signed Write
+       pairing request. Only after receiving this event with the Type
+       indicating a local key is it possible to use ATT Signed Write
        procedures.
 
        Possible values for the Address_Type parameter:
@@ -2980,6 +3163,10 @@ Unconfigured Index Added Event
        be announced with this event. If it supports configuration, but
        does not require it, then an Index Added event will be used.
 
+       Once the Read Extended Controller Index List command has been
+       used at least once, the Extended Index Added event will be
+       send instead of this one.
+
 
 Unconfigured Index Removed Event
 ================================
@@ -2991,6 +3178,10 @@ Unconfigured Index Removed Event
        This event indicates that an unconfigured controller has been
        removed from the system.
 
+       Once the Read Extended Controller Index List command has been
+       used at least once, the Extended Index Removed event will be
+       send instead of this one.
+
 
 New Configuration Options Event
 ===============================
@@ -3001,3 +3192,33 @@ New Configuration Options Event
 
        This event indicates that one or more of the options for the
        controller configuration has changed.
+
+
+Extended Index Added Event
+==========================
+
+       Event Code:             0x0020
+       Controller Index:       <controller id>
+       Event Parameters:       Controller_Type (1 Octet)
+
+       This event indicates that a new controller index has been
+       added to the system.
+
+       This event will only be used after Read Extended Controller Index
+       List has been used at least once. If it has not been used, then
+       Index Added and Unconfigured Index Added are send instead.
+
+
+Extended Index Removed Event
+============================
+
+       Event Code:             0x0021
+       Controller Index:       <controller id>
+       Event Parameters:       Controller_Type (1 Octet)
+
+       This event indicates that an existing controller index has been
+       removed from the system.
+
+       This event will only be used after Read Extended Controller Index
+       List has been used at least once. If it has not been used, then
+       Index Removed and Unconfigured Index Removed are send instead.
index ec18034..0e371b5 100644 (file)
@@ -91,7 +91,100 @@ Object path /org/bluez
 
                        Possible errors: org.bluez.Error.InvalidArguments
                                         org.bluez.Error.AlreadyExists
+#ifdef __TIZEN_PATCH__
+               void RegisterProfile2(object profile, string uuid, string destination,
+               string path,dict options)
 
+                       This registers a profile implementation.
+
+                       If an application disconects/exits, its registered profile
+                       will not be removed and bluez launches an application through
+                       dbus activation when profile is connected.
+
+                       HFP HS UUID: 0000111e-0000-1000-8000-00805f9b34fb
+
+                               Default RFCOMM channel is 6. And this requires
+                               authentication.
+
+                       string Destination
+
+                               Application bus name
+
+                       string Path
+
+                               Applicatoin path name
+
+                       Available options:
+
+                               string Name
+
+                                       Human readable name for the profile
+
+                               string Service
+
+                                       The primary service class UUID
+                                       (if different from the actual
+                                        profile UUID)
+
+                               string Role
+
+                                       For asymmetric profiles that do not
+                                       have UUIDs available to uniquely
+                                       identify each side this
+                                       parameter allows specifying the
+                                       precise local role.
+
+                                       Possible values: "client", "server"
+
+                               uint16 Channel
+
+                                       RFCOMM channel number that is used
+                                       for client and server UUIDs.
+
+                                       If applicable it will be used in the
+                                       SDP record as well.
+
+                               uint16 PSM
+
+                                       PSM number that is used for client
+                                       and server UUIDs.
+
+                                       If applicable it will be used in the
+                                       SDP record as well.
+
+                               boolean RequireAuthentication
+
+                                       Pairing is required before connections
+                                       will be established. No devices will
+                                       be connected if not paired.
+
+                               boolean RequireAuthorization
+
+                                       Request authorization before any
+                                       connection will be established.
+
+                               boolean AutoConnect
+
+                                       In case of a client UUID this will
+                                       force connection of the RFCOMM or
+                                       L2CAP channels when a remote device
+                                       is connected.
+
+                               string ServiceRecord
+
+                                       Provide a manual SDP record.
+
+                               uint16 Version
+
+                                       Profile version (for SDP record)
+
+                               uint16 Features
+
+                                       Profile features (for SDP record)
+
+                       Possible errors: org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.AlreadyExists
+#endif
                void UnregisterProfile(object profile)
 
                        This unregisters the profile that has been previously
index f5945ee..6a95ebf 100644 (file)
@@ -237,6 +237,7 @@ Long term key) related to a remote device.
 
   Same as the [LongTermKey] group, except for slave keys.
 
+
 [ConnectionParameters] group contains:
 
   MinInterval          Integer         Minimum Connection Interval
@@ -247,6 +248,15 @@ Long term key) related to a remote device.
 
   Timeout              Integer         Supervision Timeout
 
+
+[LocalSignatureKey] and [RemoteSignatureKey] groups contain:
+
+  Key                  String          Key in hexadecimal format
+
+  Counter              Integer         Signing counter
+
+  Authenticated                Boolean         True if the key is authenticated
+
 #ifdef __TIZEN_PATCH__
 [IdentityResolvingKey] group contains:
 
index 9070d61..505bb27 100644 (file)
@@ -1,3 +1,4 @@
+
 BlueZ test coverage
 *******************
 
@@ -28,9 +29,9 @@ test-gobex-header       28    OBEX header handling
 test-gobex-apparam       18    OBEX apparam handling
 test-gobex-transfer      36    OBEX transfer handling
 test-gdbus-client        13    D-Bus client handling
-test-gatt                11    GATT qualification test cases
+test-gatt               131    GATT qualification test cases
                        -----
-                        586
+                        706
 
 
 Automated end-to-end testing
@@ -38,15 +39,15 @@ Automated end-to-end testing
 
 Application            Count   Description
 -------------------------------------------
-mgmt-tester             234    Kernel management interface testing
-l2cap-tester             26    Kernel L2CAP implementation testing
+mgmt-tester             243    Kernel management interface testing
+l2cap-tester             27    Kernel L2CAP implementation testing
 rfcomm-tester             9    Kernel RFCOMM implementation testing
 smp-tester                5    Kernel SMP implementation testing
 sco-tester                8    Kernel SCO implementation testing
 gap-tester                1    Daemon D-Bus API testing
 hci-tester               14    Controller hardware testing
                        -----
-                        297
+                        307
 
 
 Android end-to-end testing
@@ -54,10 +55,10 @@ Android end-to-end testing
 
 Application            Count   Description
 -------------------------------------------
-android-tester          187    Android HAL interface testing
+android-tester          194    Android HAL interface testing
 ipc-tester              132    Android IPC resistance testing
                        -----
-                        319
+                        326
 
 
 Android automated unit testing
index ab7f9de..c5c6b81 100644 (file)
 #include <sys/socket.h>
 #include <sys/un.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
 
 #include "src/shared/util.h"
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
 #include "monitor/bt.h"
 
 #include "amp.h"
index 3fb867d..1fe4684 100644 (file)
 #include <netdb.h>
 #include <arpa/inet.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
 
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
 
 #define DEFAULT_SERVER         "b1ee.com"
 #define DEFAULT_HOST_PORT      "45550"         /* 0xb1ee */
index e1b8a5a..16e103d 100644 (file)
@@ -33,7 +33,7 @@
 #include <endian.h>
 #include <stdbool.h>
 
-#include "bluetooth/bluetooth.h"
+#include "lib/bluetooth.h"
 
 #include "src/shared/util.h"
 #include "monitor/bt.h"
@@ -147,6 +147,7 @@ struct btconn {
        uint8_t addr_type;
        uint8_t encr_mode;
        uint16_t next_cid;
+       uint64_t fixed_chan;
        struct l2conn *l2conns;
        struct rcconn *rcconns;
        struct cid_hook *cid_hooks;
@@ -918,6 +919,13 @@ static void init_conn(struct bthost *bthost, uint16_t handle,
 
        if (bthost->new_conn_cb)
                bthost->new_conn_cb(conn->handle, bthost->new_conn_data);
+
+       if (addr_type == BDADDR_BREDR) {
+               struct bt_l2cap_pdu_info_req req;
+               req.type = L2CAP_IT_FIXED_CHAN;
+               l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_INFO_REQ, 1,
+                                                       &req, sizeof(req));
+       }
 }
 
 static void evt_conn_complete(struct bthost *bthost, const void *data,
@@ -1368,6 +1376,7 @@ static bool l2cap_conn_rsp(struct bthost *bthost, struct btconn *conn,
                                uint8_t ident, const void *data, uint16_t len)
 {
        const struct bt_l2cap_pdu_conn_rsp *rsp = data;
+       struct bt_l2cap_pdu_config_req req;
        struct l2conn *l2conn;
 
        if (len < sizeof(*rsp))
@@ -1379,18 +1388,14 @@ static bool l2cap_conn_rsp(struct bthost *bthost, struct btconn *conn,
        else
                return false;
 
-       if (le16_to_cpu(rsp->result) == 0x0001) {
-               struct bt_l2cap_pdu_config_req req;
+       if (rsp->result)
+               return true;
 
-               memset(&req, 0, sizeof(req));
-               req.dcid = rsp->dcid;
+       memset(&req, 0, sizeof(req));
+       req.dcid = rsp->dcid;
 
-               l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_CONFIG_REQ, 0,
+       l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_CONFIG_REQ, 0,
                                                        &req, sizeof(req));
-       } else if (l2conn->psm == 0x0003 && !rsp->result && !rsp->status &&
-                                               bthost->rfcomm_conn_data) {
-               rfcomm_sabm_send(bthost, conn, l2conn, 1, 0);
-       }
 
        return true;
 }
@@ -1426,10 +1431,18 @@ static bool l2cap_config_rsp(struct bthost *bthost, struct btconn *conn,
                                uint8_t ident, const void *data, uint16_t len)
 {
        const struct bt_l2cap_pdu_config_rsp *rsp = data;
+       struct l2conn *l2conn;
 
        if (len < sizeof(*rsp))
                return false;
 
+       l2conn = btconn_find_l2cap_conn_by_scid(conn, rsp->scid);
+       if (!l2conn)
+               return false;
+
+       if (l2conn->psm == 0x0003 && !rsp->result && bthost->rfcomm_conn_data)
+               rfcomm_sabm_send(bthost, conn, l2conn, 1, 0);
+
        return true;
 }
 
@@ -1495,6 +1508,35 @@ static bool l2cap_info_req(struct bthost *bthost, struct btconn *conn,
        return true;
 }
 
+static bool l2cap_info_rsp(struct bthost *bthost, struct btconn *conn,
+                               uint8_t ident, const void *data, uint16_t len)
+{
+       const struct bt_l2cap_pdu_info_rsp *rsp = data;
+       uint16_t type;
+
+       if (len < sizeof(*rsp))
+               return false;
+
+       if (rsp->result)
+               return true;
+
+       type = le16_to_cpu(rsp->type);
+
+       switch (type) {
+       case L2CAP_IT_FIXED_CHAN:
+               if (len < sizeof(*rsp) + 8)
+                       return false;
+               conn->fixed_chan = get_le64(rsp->data);
+               if (conn->smp_data && conn->encr_mode)
+                       smp_conn_encrypted(conn->smp_data, conn->encr_mode);
+               break;
+       default:
+               break;
+       }
+
+       return true;
+}
+
 static void handle_pending_l2reqs(struct bthost *bthost, struct btconn *conn,
                                                uint8_t ident, uint8_t code,
                                                const void *data, uint16_t len)
@@ -1567,6 +1609,11 @@ static void l2cap_sig(struct bthost *bthost, struct btconn *conn,
                                                data + sizeof(*hdr), hdr_len);
                break;
 
+       case BT_L2CAP_PDU_INFO_RSP:
+               ret = l2cap_info_rsp(bthost, conn, hdr->ident,
+                                               data + sizeof(*hdr), hdr_len);
+               break;
+
        default:
                printf("Unknown L2CAP code 0x%02x\n", hdr->code);
                ret = false;
@@ -1991,23 +2038,30 @@ static void rfcomm_mcc_recv(struct bthost *bthost, struct btconn *conn,
        }
 }
 
+#define GET_LEN8(length)       ((length & 0xfe) >> 1)
+#define GET_LEN16(length)      ((length & 0xfffe) >> 1)
+
 static void rfcomm_uih_recv(struct bthost *bthost, struct btconn *conn,
                                struct l2conn *l2conn, const void *data,
                                uint16_t len)
 {
        const struct rfcomm_hdr *hdr = data;
-       uint16_t hdr_len;
+       uint16_t hdr_len, data_len;
        const void *p;
 
        if (len < sizeof(*hdr))
                return;
 
-       if (RFCOMM_TEST_EA(hdr->length))
+       if (RFCOMM_TEST_EA(hdr->length)) {
+               data_len = (uint16_t) GET_LEN8(hdr->length);
                hdr_len = sizeof(*hdr);
-       else
+       } else {
+               uint8_t ex_len = *((uint8_t *)(data + sizeof(*hdr)));
+               data_len = ((uint16_t) hdr->length << 8) | ex_len;
                hdr_len = sizeof(*hdr) + sizeof(uint8_t);
+       }
 
-       if (len < hdr_len)
+       if (len < hdr_len + data_len)
                return;
 
        p = data + hdr_len;
@@ -2017,13 +2071,10 @@ static void rfcomm_uih_recv(struct bthost *bthost, struct btconn *conn,
 
                hook = find_rfcomm_chan_hook(conn,
                                        RFCOMM_GET_CHANNEL(hdr->address));
-               if (!hook)
-                       return;
-
-               hook->func(p, len - hdr_len - sizeof(uint8_t),
-                                                       hook->user_data);
+               if (hook && data_len)
+                       hook->func(p, data_len, hook->user_data);
        } else {
-               rfcomm_mcc_recv(bthost, conn, l2conn, p, len - hdr_len);
+               rfcomm_mcc_recv(bthost, conn, l2conn, p, data_len);
        }
 }
 
@@ -2278,6 +2329,17 @@ void bthost_le_start_encrypt(struct bthost *bthost, uint16_t handle,
        send_command(bthost, BT_HCI_CMD_LE_START_ENCRYPT, &cmd, sizeof(cmd));
 }
 
+uint64_t bthost_conn_get_fixed_chan(struct bthost *bthost, uint16_t handle)
+{
+       struct btconn *conn;
+
+       conn = bthost_find_conn(bthost, handle);
+       if (!conn)
+               return 0;
+
+       return conn->fixed_chan;
+}
+
 void bthost_add_l2cap_server(struct bthost *bthost, uint16_t psm,
                                bthost_l2cap_connect_cb func, void *user_data)
 {
index 207ce77..6beb1f4 100644 (file)
@@ -107,6 +107,8 @@ uint8_t bthost_get_auth_req(struct bthost *bthost);
 void bthost_set_reject_user_confirm(struct bthost *bthost, bool reject);
 bool bthost_get_reject_user_confirm(struct bthost *bthost);
 
+uint64_t bthost_conn_get_fixed_chan(struct bthost *bthost, uint16_t handle);
+
 typedef void (*bthost_rfcomm_connect_cb) (uint16_t handle, uint16_t cid,
                                                void *user_data, bool status);
 
index c5bfa77..fe2f662 100644 (file)
@@ -36,8 +36,8 @@
 
 #include <glib.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
 
 #include "monitor/bt.h"
 #include "emulator/btdev.h"
index 928a729..1edecb9 100644 (file)
@@ -33,7 +33,7 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
 #include "src/shared/hfp.h"
 
 static void hfp_debug(const char *str, void *user_data)
index 30daa63..755c6ae 100644 (file)
 #include <sys/socket.h>
 #include <sys/un.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
 
 #include "src/shared/util.h"
 #include "src/shared/crypto.h"
 #include "src/shared/ecc.h"
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
 #include "monitor/bt.h"
 
 #include "phy.h"
index f9857d0..56246a3 100644 (file)
@@ -31,7 +31,7 @@
 #include <stdbool.h>
 #include <getopt.h>
 
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
 #include "serial.h"
 #include "server.h"
 #include "vhci.h"
index 6852347..c63dc38 100644 (file)
@@ -36,7 +36,7 @@
 #include <time.h>
 
 #include "src/shared/util.h"
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
 
 #include "phy.h"
 
index 8b49dc6..f404b15 100644 (file)
 #include <sys/epoll.h>
 #include <sys/uio.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
 
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
 #include "btdev.h"
 #include "serial.h"
 
index c185edf..76998d9 100644 (file)
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
 
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
 #include "btdev.h"
 #include "server.h"
 
index 5d338b7..e941141 100644 (file)
@@ -35,8 +35,8 @@
 #include <stdbool.h>
 #include <sys/socket.h>
 
-#include "bluetooth/bluetooth.h"
-#include "bluetooth/hci.h"
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
 
 #include "src/shared/util.h"
 #include "src/shared/crypto.h"
@@ -47,6 +47,8 @@
 #define SMP_CID                0x0006
 #define SMP_BREDR_CID  0x0007
 
+#define L2CAP_FC_SMP_BREDR     0x80
+
 #define SMP_PASSKEY_ENTRY_FAILED       0x01
 #define SMP_OOB_NOT_AVAIL              0x02
 #define SMP_AUTH_REQUIREMENTS          0x03
@@ -392,6 +394,9 @@ static void distribute_keys(struct smp_conn *conn)
 
        if (conn->local_key_dist & DIST_ID_KEY) {
                memset(buf, 0, sizeof(buf));
+               smp_send(conn, BT_L2CAP_SMP_IDENT_INFO, buf, sizeof(buf));
+
+               memset(buf, 0, sizeof(buf));
 
                if (conn->out) {
                        buf[0] = conn->ia_type;
@@ -400,10 +405,8 @@ static void distribute_keys(struct smp_conn *conn)
                        buf[0] = conn->ra_type;
                        memcpy(&buf[1], conn->ra, 6);
                }
-               smp_send(conn, BT_L2CAP_SMP_IDENT_ADDR_INFO, buf, 7);
 
-               memset(buf, 0, sizeof(buf));
-               smp_send(conn, BT_L2CAP_SMP_IDENT_INFO, buf, sizeof(buf));
+               smp_send(conn, BT_L2CAP_SMP_IDENT_ADDR_INFO, buf, 7);
        }
 
        if (conn->local_key_dist & DIST_SIGN) {
@@ -462,6 +465,13 @@ static void pairing_rsp(struct smp_conn *conn, const void *data, uint16_t len)
        conn->local_key_dist = conn->prsp[5];
        conn->remote_key_dist = conn->prsp[6];
 
+       if (conn->addr_type == BDADDR_BREDR) {
+               conn->local_key_dist &= ~SC_NO_DIST;
+               conn->remote_key_dist &= ~SC_NO_DIST;
+               distribute_keys(conn);
+               return;
+       }
+
        if (((conn->prsp[3] & 0x08) && (conn->preq[3] & 0x08)) ||
                                        conn->addr_type == BDADDR_BREDR) {
                conn->sc = true;
@@ -788,6 +798,32 @@ int smp_get_ltk(void *smp_data, uint64_t rand, uint16_t ediv, uint8_t *ltk)
        return 0;
 }
 
+static void smp_conn_bredr(struct smp_conn *conn, uint8_t encrypt)
+{
+       struct smp *smp = conn->smp;
+       struct bt_l2cap_smp_pairing_request req;
+       uint64_t fixed_chan;
+
+       if (encrypt != 0x02)
+               return;
+
+       conn->sc = true;
+
+       if (!conn->out)
+               return;
+
+       fixed_chan = bthost_conn_get_fixed_chan(smp->bthost, conn->handle);
+       if (!(fixed_chan & L2CAP_FC_SMP_BREDR))
+               return;
+
+       memset(&req, 0, sizeof(req));
+       req.max_key_size = 0x10;
+       req.init_key_dist = KEY_DIST;
+       req.resp_key_dist = KEY_DIST;
+
+       smp_send(conn, BT_L2CAP_SMP_PAIRING_REQUEST, &req, sizeof(req));
+}
+
 void smp_conn_encrypted(void *conn_data, uint8_t encrypt)
 {
        struct smp_conn *conn = conn_data;
@@ -795,6 +831,11 @@ void smp_conn_encrypted(void *conn_data, uint8_t encrypt)
        if (!encrypt)
                return;
 
+       if (conn->addr_type == BDADDR_BREDR) {
+               smp_conn_bredr(conn, encrypt);
+               return;
+       }
+
        if (conn->out && conn->remote_key_dist)
                return;
 
index 2e35000..0001a4b 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
 
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
 #include "monitor/bt.h"
 #include "btdev.h"
 #include "vhci.h"
diff --git a/gdbus/.gdbus.h.swp b/gdbus/.gdbus.h.swp
deleted file mode 100644 (file)
index 180875d..0000000
Binary files a/gdbus/.gdbus.h.swp and /dev/null differ
index eb68a0f..fe0c0db 100644 (file)
@@ -42,6 +42,7 @@ struct GDBusClient {
        DBusConnection *dbus_conn;
        char *service_name;
        char *base_path;
+       char *root_path;
        guint watch;
        guint added_watch;
        guint removed_watch;
@@ -1107,6 +1108,9 @@ static void get_managed_objects(GDBusClient *client)
 {
        DBusMessage *msg;
 
+       if (!client->connected)
+               return;
+
        if (!client->proxy_added && !client->proxy_removed) {
                refresh_properties(client);
                return;
@@ -1115,9 +1119,10 @@ static void get_managed_objects(GDBusClient *client)
        if (client->get_objects_call != NULL)
                return;
 
-       msg = dbus_message_new_method_call(client->service_name, "/",
-                                       DBUS_INTERFACE_DBUS ".ObjectManager",
-                                                       "GetManagedObjects");
+       msg = dbus_message_new_method_call(client->service_name,
+                                               client->root_path,
+                                               DBUS_INTERFACE_OBJECT_MANAGER,
+                                               "GetManagedObjects");
        if (msg == NULL)
                return;
 
@@ -1142,13 +1147,13 @@ static void service_connect(DBusConnection *conn, void *user_data)
 
        g_dbus_client_ref(client);
 
+       client->connected = TRUE;
+
        if (client->connect_func)
                client->connect_func(conn, client->connect_data);
 
        get_managed_objects(client);
 
-       client->connected = TRUE;
-
        g_dbus_client_unref(client);
 }
 
@@ -1156,13 +1161,13 @@ static void service_disconnect(DBusConnection *conn, void *user_data)
 {
        GDBusClient *client = user_data;
 
+       client->connected = FALSE;
+
        g_list_free_full(client->proxy_list, proxy_free);
        client->proxy_list = NULL;
 
-       if (client->disconn_func) {
+       if (client->disconn_func)
                client->disconn_func(conn, client->disconn_data);
-               client->connected = FALSE;
-       }
 }
 
 static DBusHandlerResult message_filter(DBusConnection *connection,
@@ -1196,10 +1201,18 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
 GDBusClient *g_dbus_client_new(DBusConnection *connection,
                                        const char *service, const char *path)
 {
+       return g_dbus_client_new_full(connection, service, path, "/");
+}
+
+GDBusClient *g_dbus_client_new_full(DBusConnection *connection,
+                                                       const char *service,
+                                                       const char *path,
+                                                       const char *root_path)
+{
        GDBusClient *client;
        unsigned int i;
 
-       if (connection == NULL)
+       if (!connection || !service || !root_path)
                return NULL;
 
        client = g_try_new0(GDBusClient, 1);
@@ -1215,6 +1228,7 @@ GDBusClient *g_dbus_client_new(DBusConnection *connection,
        client->dbus_conn = dbus_connection_ref(connection);
        client->service_name = g_strdup(service);
        client->base_path = g_strdup(path);
+       client->root_path = g_strdup(root_path);
        client->connected = FALSE;
 
        client->match_rules = g_ptr_array_sized_new(1);
@@ -1225,13 +1239,13 @@ GDBusClient *g_dbus_client_new(DBusConnection *connection,
                                                service_disconnect,
                                                client, NULL);
        client->added_watch = g_dbus_add_signal_watch(connection, service,
-                                               "/",
+                                               client->root_path,
                                                DBUS_INTERFACE_OBJECT_MANAGER,
                                                "InterfacesAdded",
                                                interfaces_added,
                                                client, NULL);
        client->removed_watch = g_dbus_add_signal_watch(connection, service,
-                                               "/",
+                                               client->root_path,
                                                DBUS_INTERFACE_OBJECT_MANAGER,
                                                "InterfacesRemoved",
                                                interfaces_removed,
@@ -1305,6 +1319,7 @@ void g_dbus_client_unref(GDBusClient *client)
 
        g_free(client->service_name);
        g_free(client->base_path);
+       g_free(client->root_path);
 
        g_free(client);
 }
@@ -1371,7 +1386,8 @@ gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
        client->property_changed = property_changed;
        client->user_data = user_data;
 
-       get_managed_objects(client);
+       if (proxy_added || proxy_removed || property_changed)
+               get_managed_objects(client);
 
        return TRUE;
 }
index 551c306..9814838 100644 (file)
@@ -355,6 +355,10 @@ gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
 
 GDBusClient *g_dbus_client_new(DBusConnection *connection,
                                        const char *service, const char *path);
+GDBusClient *g_dbus_client_new_full(DBusConnection *connection,
+                                                       const char *service,
+                                                       const char *path,
+                                                       const char *root_path);
 
 GDBusClient *g_dbus_client_ref(GDBusClient *client);
 void g_dbus_client_unref(GDBusClient *client);
index 0cac5ff..d5456d2 100644 (file)
@@ -34,6 +34,7 @@
 #include "gdbus.h"
 
 #ifdef __TIZEN_PATCH__
+#if 0
 #include <syslog.h>
 static void gdbus_dbg(const char *format, ...)
 {
@@ -45,6 +46,7 @@ static void gdbus_dbg(const char *format, ...)
 
        va_end(ap);
 }
+#endif
 #else
 #define info(fmt...)
 #endif
@@ -1095,9 +1097,11 @@ static DBusHandlerResult generic_message(DBusConnection *connection,
                                                iface->user_data) == TRUE)
                        return DBUS_HANDLER_RESULT_HANDLED;
 #ifdef __TIZEN_PATCH__
+#if 0
                gdbus_dbg("%s: %s.%s()", dbus_message_get_path(message),
                                                        iface->name, method->name);
 #endif
+#endif
                return process_message(connection, message, method,
                                                        iface->user_data);
        }
index 0d0054c..b60f650 100644 (file)
@@ -523,9 +523,7 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
        member = dbus_message_get_member(message);
        dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
 
-       /* Sender is always the owner */
-       if (sender == NULL)
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+       /* If sender != NULL it is always the owner */
 
        for (current = listeners; current != NULL; current = current->next) {
                data = current->data;
@@ -533,6 +531,9 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
                if (connection != data->connection)
                        continue;
 
+               if (!sender && data->owner)
+                       continue;
+
                if (data->owner && g_str_equal(sender, data->owner) == FALSE)
                        continue;
 
index cf9daf4..6235ff0 100644 (file)
@@ -154,9 +154,6 @@ gssize g_obex_apparam_encode(GObexApparam *apparam, void *buf, gsize len)
        GHashTableIter iter;
        gpointer key, value;
 
-#ifdef __TIZEN_PATCH__
-       if(g_hash_table_size(apparam->tags) > 0) {
-#endif
        g_hash_table_iter_init(&iter, apparam->tags);
        while (g_hash_table_iter_next(&iter, &key, &value)) {
                struct apparam_tag *tag = value;
@@ -166,19 +163,7 @@ gssize g_obex_apparam_encode(GObexApparam *apparam, void *buf, gsize len)
                        return ret;
 
                count += ret;
-#ifdef __TIZEN_PATCH__
-               count += ret;
-               /* Now remove this key as we have processed it
-                * If we don't remove this key then obexd process will get into
-                * infinite loop because this has been called from
-                * vcard_list_get_next_header which in-turn called
-                * from driver_get_header */
-               g_hash_table_remove(apparam->tags, key);
-#endif
        }
-#ifdef __TIZEN_PATCH__
-       }
-#endif
 
        return count;
 }
index c2f975f..6600b1b 100644 (file)
@@ -25,8 +25,8 @@
 
 #include <glib.h>
 
-#include <gobex/gobex-defs.h>
-#include <gobex/gobex-apparam.h>
+#include "gobex/gobex-defs.h"
+#include "gobex/gobex-apparam.h"
 
 /* Header ID's */
 #define G_OBEX_HDR_INVALID     0x00
index 6121fa7..d1007ea 100644 (file)
@@ -26,8 +26,8 @@
 #include <stdarg.h>
 #include <glib.h>
 
-#include <gobex/gobex-defs.h>
-#include <gobex/gobex-header.h>
+#include "gobex/gobex-defs.h"
+#include "gobex/gobex-header.h"
 
 /* Request opcodes */
 #define G_OBEX_OP_CONNECT                      0x00
index 6720129..fe53530 100644 (file)
@@ -27,8 +27,8 @@
 #include <string.h>
 #include <errno.h>
 
-#include "gobex.h"
-#include "gobex-debug.h"
+#include "gobex/gobex.h"
+#include "gobex/gobex-debug.h"
 
 #define FIRST_PACKET_TIMEOUT 60
 
index fd2b274..5bc9103 100644 (file)
@@ -26,8 +26,8 @@
 #include <stdarg.h>
 #include <glib.h>
 
-#include <gobex/gobex-defs.h>
-#include <gobex/gobex-packet.h>
+#include "gobex/gobex-defs.h"
+#include "gobex/gobex-packet.h"
 
 typedef enum {
        G_OBEX_TRANSPORT_STREAM,
index 57e2744..4fe5941 100644 (file)
@@ -1141,6 +1141,104 @@ const char *bt_compidtostr(int compid)
                return "LM Technologies Ltd";
        case 439:
                return "General Electric Company";
+       case 440:
+               return "i+D3 S.L.";
+       case 441:
+               return "HANA Micron";
+       case 442:
+               return "Stages Cycling LLC";
+       case 443:
+               return "Cochlear Bone Anchored Solutions AB";
+       case 444:
+               return "SenionLab AB";
+       case 445:
+               return "Syszone Co., Ltd";
+       case 446:
+               return "Pulsate Mobile Ltd.";
+       case 447:
+               return "Hong Kong HunterSun Electronic Limited";
+       case 448:
+               return "pironex GmbH";
+       case 449:
+               return "BRADATECH Corp.";
+       case 450:
+               return "Transenergooil AG";
+       case 451:
+               return "Bunch";
+       case 452:
+               return "DME Microelectronics";
+       case 453:
+               return "Bitcraze AB";
+       case 454:
+               return "HASWARE Inc.";
+       case 455:
+               return "Abiogenix Inc.";
+       case 456:
+               return "Poly-Control ApS";
+       case 457:
+               return "Avi-on";
+       case 458:
+               return "Laerdal Medical AS";
+       case 459:
+               return "Fetch My Pet";
+       case 460:
+               return "Sam Labs Ltd.";
+       case 461:
+               return "Chengdu Synwing Technology Ltd";
+       case 462:
+               return "HOUWA SYSTEM DESIGN, k.k.";
+       case 463:
+               return "BSH";
+       case 464:
+               return "Primus Inter Pares Ltd";
+       case 465:
+               return "August";
+       case 466:
+               return "Gill Electronics";
+       case 467:
+               return "Sky Wave Design";
+       case 468:
+               return "Newlab S.r.l.";
+       case 469:
+               return "ELAD srl";
+       case 470:
+               return "G-wearables inc.";
+       case 471:
+               return "Squadrone Systems Inc.";
+       case 472:
+               return "Code Corporation";
+       case 473:
+               return "Savant Systems LLC";
+       case 474:
+               return "Logitech International SA";
+       case 475:
+               return "Innblue Consulting";
+       case 476:
+               return "iParking Ltd.";
+       case 477:
+               return "Koninklijke Philips Electronics N.V.";
+       case 478:
+               return "Minelab Electronics Pty Limited";
+       case 479:
+               return "Bison Group Ltd.";
+       case 480:
+               return "Widex A/S";
+       case 481:
+               return "Jolla Ltd";
+       case 482:
+               return "Lectronix, Inc.";
+       case 483:
+               return "Caterpillar Inc";
+       case 484:
+               return "Freedom Innovations";
+       case 485:
+               return "Dynamic Devices Ltd";
+       case 486:
+               return "Technology Solutions (UK) Ltd";
+       case 487:
+               return "IPS Group Inc.";
+       case 488:
+               return "STIR";
        case 65535:
                return "internal use";
        default:
index f214d81..6ca64b6 100644 (file)
@@ -343,6 +343,16 @@ typedef struct {
        uint8_t data[16];
 } uint128_t;
 
+static inline void bswap_128(const void *src, void *dst)
+{
+       const uint8_t *s = src;
+       uint8_t *d = dst;
+       int i;
+
+       for (i = 0; i < 16; i++)
+               d[15 - i] = s[i];
+}
+
 #if __BYTE_ORDER == __BIG_ENDIAN
 
 #define ntoh64(x) (x)
@@ -354,10 +364,7 @@ static inline void ntoh128(const uint128_t *src, uint128_t *dst)
 
 static inline void btoh128(const uint128_t *src, uint128_t *dst)
 {
-       int i;
-
-       for (i = 0; i < 16; i++)
-               dst->data[15 - i] = src->data[i];
+       bswap_128(src, dst);
 }
 
 #else
@@ -375,10 +382,7 @@ static inline uint64_t ntoh64(uint64_t n)
 
 static inline void ntoh128(const uint128_t *src, uint128_t *dst)
 {
-       int i;
-
-       for (i = 0; i < 16; i++)
-               dst->data[15 - i] = src->data[i];
+       bswap_128(src, dst);
 }
 
 static inline void btoh128(const uint128_t *src, uint128_t *dst)
index c25be9e..bc453f7 100644 (file)
--- a/lib/hci.c
+++ b/lib/hci.c
@@ -156,6 +156,10 @@ char *hci_bustostr(int bus)
                return "PCI";
        case HCI_SDIO:
                return "SDIO";
+#ifdef __TIZEN_PATCH__
+       case HCI_SMD:
+               return "QC_SMD";
+#endif
        default:
                return "UNKNOWN";
        }
index d877d97..8f524ff 100644 (file)
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -56,6 +56,10 @@ extern "C" {
 #define HCI_PCI                5
 #define HCI_SDIO       6
 
+#ifdef __TIZEN_PATCH__
+#define HCI_SMD                7
+#endif
+
 /* HCI controller types */
 #define HCI_BREDR      0x00
 #define HCI_AMP                0x01
index 473d76d..6a8f603 100644 (file)
@@ -98,6 +98,7 @@ struct mgmt_rp_read_index_list {
 #define MGMT_SETTING_DEBUG_KEYS                0x00001000
 #define MGMT_SETTING_PRIVACY           0x00002000
 #define MGMT_SETTING_CONFIGURATION     0x00004000
+#define MGMT_SETTING_STATIC_ADDRESS    0x00008000
 
 #define MGMT_OP_READ_INFO              0x0004
 struct mgmt_rp_read_info {
@@ -602,7 +603,7 @@ struct mgmt_ev_new_irk {
 
 struct mgmt_csrk_info {
        struct mgmt_addr_info addr;
-       uint8_t master;
+       uint8_t type;
        uint8_t val[16];
 } __packed;
 
@@ -779,7 +780,7 @@ struct mgmt_cp_set_advertising_params {
 
 #define MGMT_OP_SET_ADVERTISING_DATA           (TIZEN_OP_CODE_BASE + 0x02)
 struct mgmt_cp_set_advertising_data {
-       uint8_t data[MGMT_MAX_ADVERTISING_LENGTH - 3];  /* Except flag */
+       uint8_t data[MGMT_MAX_ADVERTISING_LENGTH];
 } __packed;
 
 #define MGMT_OP_SET_SCAN_RSP_DATA              (TIZEN_OP_CODE_BASE + 0x03)
@@ -887,7 +888,28 @@ struct mgmt_cp_set_voice_setting {
        uint16_t voice_setting;
 } __packed;
 
+#define MGMT_OP_GET_ADV_TX_POWER               (TIZEN_OP_CODE_BASE + 0x11)
+struct mgmt_rp_get_adv_tx_power {
+       int8_t adv_tx_power;
+} __packed;
+
+#define MGMT_OP_ENABLE_6LOWPAN         (TIZEN_OP_CODE_BASE + 0x12)
+struct mgmt_cp_enable_6lowpan {
+       uint8_t enable_6lowpan;
+} __packed;
+
+#define MGMT_OP_CONNECT_6LOWPAN        (TIZEN_OP_CODE_BASE + 0x13)
+struct mgmt_cp_connect_6lowpan {
+       struct mgmt_addr_info addr;
+} __packed;
+
+#define MGMT_OP_DISCONNECT_6LOWPAN     (TIZEN_OP_CODE_BASE + 0x14)
+struct mgmt_cp_disconnect_6lowpan {
+       struct mgmt_addr_info addr;
+} __packed;
+
 /*  Currently there is no support in kernel for below MGMT cmd opcodes. */
+#if 0 // Not defined in kernel
 #define MGMT_OP_READ_RSSI                      (TIZEN_OP_CODE_BASE + 0x11)
 struct mgmt_cp_read_rssi {
        bdaddr_t bdaddr;
@@ -939,6 +961,8 @@ struct mgmt_rp_read_auth_payload_timeout {
        uint8_t status;
        uint16_t auth_payload_timeout;
 } __packed;
+#endif
+
 
 /* BEGIN TIZEN_Bluetooth :: name update changes */
 #define MGMT_EV_DEVICE_NAME_UPDATE             (TIZEN_EV_BASE + 0x01)
@@ -1002,10 +1026,26 @@ struct mgmt_ev_le_device_found {
        uint8_t eir[0];
 } __packed;
 
+#define MGMT_EV_MULTI_ADV_STATE_CHANGED                        (TIZEN_EV_BASE + 0x0b)
+struct mgmt_ev_vendor_specific_multi_adv_state_changed {
+       uint8_t adv_instance;
+       uint8_t state_change_reason;
+       int16_t connection_handle;
+} __packed;
+
+#define MGMT_EV_6LOWPAN_CONN_STATE_CHANGED             (TIZEN_EV_BASE + 0x0c)
+struct mgmt_ev_6lowpan_conn_state_changed {
+       struct  mgmt_addr_info addr;
+       uint8_t connected;
+} __packed;
+
+/*  Currently there is no support in kernel for below MGMT events. */
+#if 0 // Not defined in kernel
 #define MGMT_EV_NEW_LOCAL_IRK                  (TIZEN_EV_BASE + 0x0b)
 struct mgmt_ev_new_local_irk {
        uint8_t    irk[16];
 } __packed;
+#endif
 
 static const char *mgmt_tizen_op[] = {
        "<0x0000>",
@@ -1024,7 +1064,10 @@ static const char *mgmt_tizen_op[] = {
        "LE Connection Update",
        "Set Manufacturer Data",
        "LE Set Scan Parameters",
-       "Set Voice Setting"
+       "Set Voice Setting",
+       "Get Adv Tx Power",
+       "Connect BT 6LOWPAN",
+       "Disconnect BT 6LOWPAN"
 };
 
 static const char *mgmt_tizen_ev[] = {
@@ -1039,7 +1082,8 @@ static const char *mgmt_tizen_ev[] = {
        "LE Connection Updated",
        "LE Connection Update Failed",
        "LE Device Found",
-       "New Local IRK Generated",
+       "Multi Adv State Change",
+       "BT 6LOWPAN state Change"
 };
 #endif /* End of __TIZEN_PATCH__ */
 
index e3f31df..4f34b17 100644 (file)
@@ -30,6 +30,7 @@
 #include <stdlib.h>
 #include <errno.h>
 
+#include "lib/bluetooth.h"
 #include "uuid.h"
 
 static uint128_t bluetooth_base_uuid = {
@@ -290,3 +291,24 @@ int bt_uuid_strcmp(const void *a, const void *b)
 {
        return strcasecmp(a, b);
 }
+
+int bt_uuid_to_le(const bt_uuid_t *src, void *dst)
+{
+       bt_uuid_t uuid;
+
+       switch (src->type) {
+       case BT_UUID16:
+               bt_put_le16(src->value.u16, dst);
+               return 0;
+       case BT_UUID32:
+               bt_uuid_to_uuid128(src, &uuid);
+               /* Fallthrough */
+       case BT_UUID128:
+               /* Convert from 128-bit BE to LE */
+               bswap_128(&src->value.u128, dst);
+               return 0;
+       case BT_UUID_UNSPEC:
+       default:
+               return -EINVAL;
+       }
+}
index 8303772..05968f1 100644 (file)
@@ -30,7 +30,9 @@ extern "C" {
 #endif
 
 #include <stdint.h>
+#ifdef __TIZEN_PATCH__
 #include <bluetooth/bluetooth.h>
+#endif
 
 #define GENERIC_AUDIO_UUID     "00001203-0000-1000-8000-00805f9b34fb"
 
@@ -140,6 +142,11 @@ extern "C" {
 #define GATT_EXTERNAL_REPORT_REFERENCE                 0x2907
 #define GATT_REPORT_REFERENCE                          0x2908
 
+#ifdef __TIZEN_PATCH__
+/* GATT Service UUIDs : Defined  by SIG */
+#define GATT_IPSP_UUID         0x1820
+#endif
+
 typedef struct {
        enum {
                BT_UUID_UNSPEC = 0,
@@ -168,6 +175,8 @@ void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst);
 int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n);
 int bt_string_to_uuid(bt_uuid_t *uuid, const char *string);
 
+int bt_uuid_to_le(const bt_uuid_t *uuid, void *dst);
+
 static inline int bt_uuid_len(const bt_uuid_t *uuid)
 {
        return uuid->type / 8;
index af91ecc..c599aa4 100644 (file)
@@ -32,7 +32,7 @@
 #include <ctype.h>
 #include <inttypes.h>
 
-#include <bluetooth/bluetooth.h>
+#include "lib/bluetooth.h"
 
 #include "src/shared/util.h"
 #include "bt.h"
@@ -1637,11 +1637,95 @@ static bool avrcp_control_packet(struct avctp_frame *avctp_frame)
        }
 }
 
+static bool avrcp_set_browsed_player(struct avctp_frame *avctp_frame)
+{
+       struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
+       uint32_t items;
+       uint16_t id, uids, charset;
+       uint8_t status, folders, indent = 2;
+
+       if (avctp_frame->hdr & 0x02)
+               goto response;
+
+       if (!l2cap_frame_get_be16(frame, &id))
+               return false;
+
+       print_field("%*cPlayerID: 0x%04x (%u)", indent, ' ', id, id);
+       return true;
+
+response:
+       if (!l2cap_frame_get_u8(frame, &status))
+               return false;
+
+       print_field("%*cStatus: 0x%02x (%s)", indent, ' ', status,
+                                                       error2str(status));
+
+       if (!l2cap_frame_get_be16(frame, &uids))
+               return false;
+
+       print_field("%*cUIDCounter: 0x%04x (%u)", indent, ' ', uids, uids);
+
+       if (!l2cap_frame_get_be32(frame, &items))
+               return false;
+
+       print_field("%*cNumber of Items: 0x%08x (%u)", indent, ' ',
+                                                               items, items);
+
+       if (!l2cap_frame_get_be16(frame, &charset))
+               return false;
+
+       print_field("%*cCharsetID: 0x%04x (%s)", indent, ' ', charset,
+                                                       charset2str(charset));
+
+       if (!l2cap_frame_get_u8(frame, &folders))
+               return false;
+
+       print_field("%*cFolder Depth: 0x%02x (%u)", indent, ' ', folders,
+                                                               folders);
+
+       for (; folders > 0; folders--) {
+               uint8_t len;
+
+               if (!l2cap_frame_get_u8(frame, &len))
+                       return false;
+
+               printf("Folder: ");
+               for (; len > 0; len--) {
+                       uint8_t c;
+
+                       if (!l2cap_frame_get_u8(frame, &c))
+                               return false;
+
+                       printf("%1c", isprint(c) ? c : '.');
+               }
+               printf("\n");
+       }
+
+       return true;
+}
+
 static bool avrcp_browsing_packet(struct avctp_frame *avctp_frame)
 {
        struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
+       uint16_t len;
+       uint8_t pduid;
+
+       if (!l2cap_frame_get_u8(frame, &pduid))
+               return false;
+
+       if (!l2cap_frame_get_be16(frame, &len))
+               return false;
+
+       print_field("AVRCP: %s: len 0x%04x", pdu2str(pduid), len);
+
+       switch (pduid) {
+       case AVRCP_SET_BROWSED_PLAYER:
+               avrcp_set_browsed_player(avctp_frame);
+               break;
+       default:
+               packet_hexdump(frame->data, frame->size);
+       }
 
-       packet_hexdump(frame->data, frame->size);
        return true;
 }
 
index feddca8..0d2a15a 100644 (file)
@@ -675,6 +675,62 @@ struct bt_hci_cmd_flow_spec_modify {
        uint8_t  rx_flow_spec[16];
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_ENHANCED_SETUP_SYNC_CONN    0x043d
+struct bt_hci_cmd_enhanced_setup_sync_conn {
+       uint16_t handle;
+       uint32_t tx_bandwidth;
+       uint32_t rx_bandwidth;
+       uint8_t  tx_coding_format[5];
+       uint8_t  rx_coding_format[5];
+       uint16_t tx_codec_frame_size;
+       uint16_t rx_codec_frame_size;
+       uint32_t input_bandwidth;
+       uint32_t output_bandwidth;
+       uint8_t  input_coding_format[5];
+       uint8_t  output_coding_format[5];
+       uint16_t input_coded_data_size;
+       uint16_t output_coded_data_size;
+       uint8_t  input_pcm_data_format;
+       uint8_t  output_pcm_data_format;
+       uint8_t  input_pcm_msb_position;
+       uint8_t  output_pcm_msb_position;
+       uint8_t  input_data_path;
+       uint8_t  output_data_path;
+       uint8_t  input_unit_size;
+       uint8_t  output_unit_size;
+       uint16_t max_latency;
+       uint16_t pkt_type;
+       uint8_t  retrans_effort;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_ENHANCED_ACCEPT_SYNC_CONN_REQUEST   0x043e
+struct bt_hci_cmd_enhanced_accept_sync_conn_request {
+       uint8_t  bdaddr[6];
+       uint32_t tx_bandwidth;
+       uint32_t rx_bandwidth;
+       uint8_t  tx_coding_format[5];
+       uint8_t  rx_coding_format[5];
+       uint16_t tx_codec_frame_size;
+       uint16_t rx_codec_frame_size;
+       uint32_t input_bandwidth;
+       uint32_t output_bandwidth;
+       uint8_t  input_coding_format[5];
+       uint8_t  output_coding_format[5];
+       uint16_t input_coded_data_size;
+       uint16_t output_coded_data_size;
+       uint8_t  input_pcm_data_format;
+       uint8_t  output_pcm_data_format;
+       uint8_t  input_pcm_msb_position;
+       uint8_t  output_pcm_msb_position;
+       uint8_t  input_data_path;
+       uint8_t  output_data_path;
+       uint8_t  input_unit_size;
+       uint8_t  output_unit_size;
+       uint16_t max_latency;
+       uint16_t pkt_type;
+       uint8_t  retrans_effort;
+} __attribute__ ((packed));
+
 #define BT_HCI_CMD_TRUNCATED_PAGE              0x043f
 struct bt_hci_cmd_truncated_page {
        uint8_t  bdaddr[6];
@@ -1114,6 +1170,13 @@ struct bt_hci_cmd_host_buffer_size {
        uint16_t sco_max_pkt;
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_HOST_NUM_COMPLETED_PACKETS  0x0c35
+struct bt_hci_cmd_host_num_completed_packets {
+       uint8_t  num_handles;
+       uint16_t handle;
+       uint16_t count;
+} __attribute__ ((packed));
+
 #define BT_HCI_CMD_READ_LINK_SUPV_TIMEOUT      0x0c36
 struct bt_hci_cmd_read_link_supv_timeout {
        uint16_t handle;
@@ -1271,6 +1334,17 @@ struct bt_hci_cmd_write_inquiry_tx_power {
        int8_t   level;
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_READ_ERRONEOUS_REPORTING    0x0c5a
+struct bt_hci_rsp_read_erroneous_reporting {
+       uint8_t  status;
+       uint8_t  mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_ERRONEOUS_REPORTING   0x0c5b
+struct bt_hci_cmd_write_erroneous_reporting {
+       uint8_t  mode;
+} __attribute__ ((packed));
+
 #define BT_HCI_CMD_ENHANCED_FLUSH              0x0c5f
 struct bt_hci_cmd_enhanced_flush {
        uint16_t handle;
@@ -1320,6 +1394,25 @@ struct bt_hci_cmd_write_flow_control_mode {
        uint8_t  mode;
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_READ_ENHANCED_TX_POWER      0x0c68
+struct bt_hci_cmd_read_enhanced_tx_power {
+       uint16_t handle;
+       uint8_t  type;
+} __attribute__ ((packed));
+struct bt_hci_rsp_read_enhanced_tx_power {
+       uint8_t  status;
+       uint16_t handle;
+       int8_t   level_gfsk;
+       int8_t   level_dqpsk;
+       int8_t   level_8dpsk;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_SHORT_RANGE_MODE            0x0c6b
+struct bt_hci_cmd_short_range_mode {
+       uint8_t  phy_handle;
+       uint8_t  mode;
+} __attribute__ ((packed));
+
 #define BT_HCI_CMD_READ_LE_HOST_SUPPORTED      0x0c6c
 struct bt_hci_rsp_read_le_host_supported {
        uint8_t  status;
@@ -1422,6 +1515,28 @@ struct bt_hci_rsp_read_local_oob_ext_data {
        uint8_t  randomizer256[16];
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_READ_EXT_PAGE_TIMEOUT       0x0c7e
+struct bt_hci_rsp_read_ext_page_timeout {
+       uint8_t  status;
+       uint16_t timeout;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_EXT_PAGE_TIMEOUT      0x0c7f
+struct bt_hci_cmd_write_ext_page_timeout {
+       uint16_t timeout;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_EXT_INQUIRY_LENGTH     0x0c80
+struct bt_hci_rsp_read_ext_inquiry_length {
+       uint8_t  status;
+       uint16_t interval;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_EXT_INQUIRY_LENGTH    0x0c81
+struct bt_hci_cmd_write_ext_inquiry_length {
+       uint16_t interval;
+} __attribute__ ((packed));
+
 #define BT_HCI_CMD_READ_LOCAL_VERSION          0x1001
 struct bt_hci_rsp_read_local_version {
        uint8_t  status;
@@ -1619,6 +1734,17 @@ struct bt_hci_cmd_set_triggered_clock_capture {
        uint8_t  num_filter;
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_READ_LOOPBACK_MODE          0x1801
+struct bt_hci_rsp_read_loopback_mode {
+       uint8_t  status;
+       uint8_t  mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_LOOPBACK_MODE         0x1802
+struct bt_hci_cmd_write_loopback_mode {
+       uint8_t  mode;
+} __attribute__ ((packed));
+
 #define BT_HCI_CMD_ENABLE_DUT_MODE             0x1803
 
 #define BT_HCI_CMD_WRITE_SSP_DEBUG_MODE                0x1804
@@ -2382,6 +2508,14 @@ struct bt_hci_evt_amp_status_change {
        uint8_t  amp_status;
 } __attribute__ ((packed));
 
+#define BT_HCI_EVT_TRIGGERED_CLOCK_CAPTURE     0x4e
+struct bt_hci_evt_triggered_clock_capture {
+       uint16_t handle;
+       uint8_t  type;
+       uint32_t clock;
+       uint16_t clock_offset;
+} __attribute__ ((packed));
+
 #define BT_HCI_EVT_SYNC_TRAIN_COMPLETE         0x4f
 struct bt_hci_evt_sync_train_complete {
        uint8_t  status;
index 83aaee5..a32335a 100644 (file)
@@ -35,8 +35,8 @@
 #include <sys/stat.h>
 #include <arpa/inet.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
 
 #include "btsnoop.h"
 
index d9d6b44..44cc1da 100644 (file)
@@ -42,7 +42,8 @@
 
 #include "src/shared/util.h"
 #include "src/shared/btsnoop.h"
-#include "mainloop.h"
+#include "src/shared/mainloop.h"
+
 #include "display.h"
 #include "packet.h"
 #include "hcidump.h"
@@ -154,6 +155,7 @@ static const char *settings_str[] = {
        "powered", "connectable", "fast-connectable", "discoverable",
        "bondable", "link-security", "ssp", "br/edr", "hs", "le",
        "advertising", "secure-conn", "debug-keys", "privacy",
+       "configuration", "static-addr",
 };
 
 static void mgmt_new_settings(uint16_t len, const void *buf)
@@ -598,6 +600,7 @@ static void mgmt_new_irk(uint16_t len, const void *buf)
 static void mgmt_new_csrk(uint16_t len, const void *buf)
 {
        const struct mgmt_ev_new_csrk *ev = buf;
+       const char *type;
        char addr[18];
 
        if (len < sizeof(*ev)) {
@@ -607,8 +610,26 @@ static void mgmt_new_csrk(uint16_t len, const void *buf)
 
        ba2str(&ev->key.addr.bdaddr, addr);
 
-       printf("@ New CSRK: %s (%d) %s\n", addr, ev->key.addr.type,
-                                       ev->key.master ? "Master" : "Slave");
+       switch (ev->key.type) {
+       case 0x00:
+               type = "Local Unauthenticated";
+               break;
+       case 0x01:
+               type = "Remote Unauthenticated";
+               break;
+       case 0x02:
+               type = "Local Authenticated";
+               break;
+       case 0x03:
+               type = "Remote Authenticated";
+               break;
+       default:
+               type = "<unknown>";
+               break;
+       }
+
+       printf("@ New CSRK: %s (%d) %s (%u)\n", addr, ev->key.addr.type,
+                                                       type, ev->key.type);
 
        buf += sizeof(*ev);
        len -= sizeof(*ev);
index 1515f93..e910c5e 100644 (file)
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+
+#include "src/shared/mainloop.h"
 
-#include "mainloop.h"
 #include "packet.h"
 #include "hcidump.h"
 
index 0b6f752..5faa26f 100644 (file)
@@ -31,7 +31,7 @@
 #include <string.h>
 #include <inttypes.h>
 
-#include <bluetooth/bluetooth.h>
+#include "lib/bluetooth.h"
 
 #include "src/shared/util.h"
 #include "bt.h"
 #include "avctp.h"
 #include "rfcomm.h"
 
+/* L2CAP Control Field bit masks */
+#define L2CAP_CTRL_SAR_MASK            0xC000
+#define L2CAP_CTRL_REQSEQ_MASK         0x3F00
+#define L2CAP_CTRL_TXSEQ_MASK          0x007E
+#define L2CAP_CTRL_SUPERVISE_MASK      0x000C
+
+#define L2CAP_CTRL_RETRANS             0x0080
+#define L2CAP_CTRL_FINAL               0x0080
+#define L2CAP_CTRL_POLL                        0x0010
+#define L2CAP_CTRL_FRAME_TYPE          0x0001 /* I- or S-Frame */
+
+#define L2CAP_CTRL_TXSEQ_SHIFT         1
+#define L2CAP_CTRL_SUPER_SHIFT         2
+#define L2CAP_CTRL_REQSEQ_SHIFT                8
+#define L2CAP_CTRL_SAR_SHIFT           14
+
+#define L2CAP_EXT_CTRL_TXSEQ_MASK      0xFFFC0000
+#define L2CAP_EXT_CTRL_SAR_MASK                0x00030000
+#define L2CAP_EXT_CTRL_SUPERVISE_MASK  0x00030000
+#define L2CAP_EXT_CTRL_REQSEQ_MASK     0x0000FFFC
+
+#define L2CAP_EXT_CTRL_POLL            0x00040000
+#define L2CAP_EXT_CTRL_FINAL           0x00000002
+#define L2CAP_EXT_CTRL_FRAME_TYPE      0x00000001 /* I- or S-Frame */
+
+#define L2CAP_EXT_CTRL_REQSEQ_SHIFT    2
+#define L2CAP_EXT_CTRL_SAR_SHIFT       16
+#define L2CAP_EXT_CTRL_SUPER_SHIFT     16
+#define L2CAP_EXT_CTRL_TXSEQ_SHIFT     18
+
+/* L2CAP Supervisory Function */
+#define L2CAP_SUPER_RR         0x00
+#define L2CAP_SUPER_REJ                0x01
+#define L2CAP_SUPER_RNR                0x02
+#define L2CAP_SUPER_SREJ       0x03
+
+/* L2CAP Segmentation and Reassembly */
+#define L2CAP_SAR_UNSEGMENTED  0x00
+#define L2CAP_SAR_START                0x01
+#define L2CAP_SAR_END          0x02
+#define L2CAP_SAR_CONTINUE     0x03
+
 #define MAX_CHAN 64
 
 struct chan_data {
        uint16_t index;
        uint16_t handle;
+       uint8_t ident;
        uint16_t scid;
        uint16_t dcid;
        uint16_t psm;
        uint8_t  ctrlid;
        uint8_t  mode;
+       uint8_t  ext_ctrl;
 };
 
 static struct chan_data chan_list[MAX_CHAN];
@@ -92,6 +136,7 @@ static void assign_scid(const struct l2cap_frame *frame,
        memset(&chan_list[n], 0, sizeof(chan_list[n]));
        chan_list[n].index = frame->index;
        chan_list[n].handle = frame->handle;
+       chan_list[n].ident = frame->ident;
 
        if (frame->in)
                chan_list[n].dcid = scid;
@@ -128,8 +173,8 @@ static void release_scid(const struct l2cap_frame *frame, uint16_t scid)
        }
 }
 
-static void assign_dcid(const struct l2cap_frame *frame,
-                                       uint16_t dcid, uint16_t scid)
+static void assign_dcid(const struct l2cap_frame *frame, uint16_t dcid,
+                                                               uint16_t scid)
 {
        int i;
 
@@ -140,15 +185,32 @@ static void assign_dcid(const struct l2cap_frame *frame,
                if (chan_list[i].handle != frame->handle)
                        continue;
 
+               if (frame->ident != 0 && chan_list[i].ident != frame->ident)
+                       continue;
+
                if (frame->in) {
-                       if (chan_list[i].scid == scid) {
-                               chan_list[i].dcid = dcid;
-                               break;
+                       if (scid) {
+                               if (chan_list[i].scid == scid) {
+                                       chan_list[i].dcid = dcid;
+                                       break;
+                               }
+                       } else {
+                               if (chan_list[i].scid && !chan_list[i].dcid) {
+                                       chan_list[i].dcid = dcid;
+                                       break;
+                               }
                        }
                } else {
-                       if (chan_list[i].dcid == scid) {
-                               chan_list[i].scid = dcid;
-                               break;
+                       if (scid) {
+                               if (chan_list[i].dcid == scid) {
+                                       chan_list[i].scid = dcid;
+                                       break;
+                               }
+                       } else {
+                               if (chan_list[i].dcid && !chan_list[i].scid) {
+                                       chan_list[i].scid = dcid;
+                                       break;
+                               }
                        }
                }
        }
@@ -180,7 +242,7 @@ static void assign_mode(const struct l2cap_frame *frame,
        }
 }
 
-static uint16_t get_psm(const struct l2cap_frame *frame)
+static int get_chan_data_index(const struct l2cap_frame *frame)
 {
        int i;
 
@@ -189,70 +251,192 @@ static uint16_t get_psm(const struct l2cap_frame *frame)
                                        chan_list[i].ctrlid == 0)
                        continue;
 
-               if (chan_list[i].handle != frame->handle &&
+               if (chan_list[i].ctrlid != 0 &&
                                        chan_list[i].ctrlid != frame->index)
                        continue;
 
+               if (chan_list[i].handle != frame->handle)
+                       continue;
+
                if (frame->in) {
                        if (chan_list[i].scid == frame->cid)
-                               return chan_list[i].psm;
+                               return i;
                } else {
                        if (chan_list[i].dcid == frame->cid)
-                               return chan_list[i].psm;
+                               return i;
                }
        }
 
-       return 0;
+       return -1;
+}
+
+static uint16_t get_psm(const struct l2cap_frame *frame)
+{
+       int i = get_chan_data_index(frame);
+
+       if (i < 0)
+               return 0;
+
+       return chan_list[i].psm;
 }
 
 static uint8_t get_mode(const struct l2cap_frame *frame)
 {
+       int i = get_chan_data_index(frame);
+
+       if (i < 0)
+               return 0;
+
+       return chan_list[i].mode;
+}
+
+static uint16_t get_chan(const struct l2cap_frame *frame)
+{
+       int i = get_chan_data_index(frame);
+
+       if (i < 0)
+               return 0;
+
+       return i;
+}
+
+static void assign_ext_ctrl(const struct l2cap_frame *frame,
+                                       uint8_t ext_ctrl, uint16_t dcid)
+{
        int i;
 
        for (i = 0; i < MAX_CHAN; i++) {
-               if (chan_list[i].index != frame->index &&
-                                       chan_list[i].ctrlid == 0)
+               if (chan_list[i].index != frame->index)
                        continue;
 
-               if (chan_list[i].handle != frame->handle &&
-                                       chan_list[i].ctrlid != frame->index)
+               if (chan_list[i].handle != frame->handle)
                        continue;
 
                if (frame->in) {
-                       if (chan_list[i].scid == frame->cid)
-                               return chan_list[i].mode;
+                       if (chan_list[i].scid == dcid) {
+                               chan_list[i].ext_ctrl = ext_ctrl;
+                               break;
+                       }
                } else {
-                       if (chan_list[i].dcid == frame->cid)
-                               return chan_list[i].mode;
+                       if (chan_list[i].dcid == dcid) {
+                               chan_list[i].ext_ctrl = ext_ctrl;
+                               break;
+                       }
                }
        }
+}
+
+static uint8_t get_ext_ctrl(const struct l2cap_frame *frame)
+{
+       int i = get_chan_data_index(frame);
 
-       return 0;
+       if (i < 0)
+               return 0;
+
+       return chan_list[i].ext_ctrl;
 }
 
-static uint16_t get_chan(const struct l2cap_frame *frame)
+static char *sar2str(uint8_t sar)
 {
-       int i;
+       switch (sar) {
+       case L2CAP_SAR_UNSEGMENTED:
+               return "Unsegmented";
+       case L2CAP_SAR_START:
+               return "Start";
+       case L2CAP_SAR_END:
+               return "End";
+       case L2CAP_SAR_CONTINUE:
+               return "Continuation";
+       default:
+               return "Bad SAR";
+       }
+}
 
-       for (i = 0; i < MAX_CHAN; i++) {
-               if (chan_list[i].index != frame->index &&
-                                       chan_list[i].ctrlid == 0)
-                       continue;
+static char *supervisory2str(uint8_t supervisory)
+{
+       switch (supervisory) {
+       case L2CAP_SUPER_RR:
+               return "Receiver Ready (RR)";
+       case L2CAP_SUPER_REJ:
+               return "Reject (REJ)";
+       case L2CAP_SUPER_RNR:
+               return "Receiver Not Ready (RNR)";
+       case L2CAP_SUPER_SREJ:
+               return "Select Reject (SREJ)";
+       default:
+               return "Bad Supervisory";
+       }
+}
 
-               if (chan_list[i].handle != frame->handle &&
-                                       chan_list[i].ctrlid != frame->index)
-                       continue;
+static void l2cap_ctrl_ext_parse(struct l2cap_frame *frame, uint32_t ctrl)
+{
+       printf("      %s:",
+               ctrl & L2CAP_EXT_CTRL_FRAME_TYPE ? "S-frame" : "I-frame");
 
-               if (frame->in) {
-                       if (chan_list[i].scid == frame->cid)
-                               return i;
-               } else {
-                       if (chan_list[i].dcid == frame->cid)
-                               return i;
+       if (ctrl & L2CAP_EXT_CTRL_FRAME_TYPE) {
+               printf(" %s",
+               supervisory2str((ctrl & L2CAP_EXT_CTRL_SUPERVISE_MASK) >>
+                                               L2CAP_EXT_CTRL_SUPER_SHIFT));
+
+               if (ctrl & L2CAP_EXT_CTRL_POLL)
+                       printf(" P-bit");
+       } else {
+               uint8_t sar = (ctrl & L2CAP_EXT_CTRL_SAR_MASK) >>
+                                               L2CAP_EXT_CTRL_SAR_SHIFT;
+               printf(" %s", sar2str(sar));
+               if (sar == L2CAP_SAR_START) {
+                       uint16_t len;
+
+                       if (!l2cap_frame_get_le16(frame, &len))
+                               return;
+
+                       printf(" (len %d)", len);
                }
+               printf(" TxSeq %d", (ctrl & L2CAP_EXT_CTRL_TXSEQ_MASK) >>
+                                               L2CAP_EXT_CTRL_TXSEQ_SHIFT);
        }
 
-       return 0;
+       printf(" ReqSeq %d", (ctrl & L2CAP_EXT_CTRL_REQSEQ_MASK) >>
+                                               L2CAP_EXT_CTRL_REQSEQ_SHIFT);
+
+       if (ctrl & L2CAP_EXT_CTRL_FINAL)
+               printf(" F-bit");
+}
+
+static void l2cap_ctrl_parse(struct l2cap_frame *frame, uint32_t ctrl)
+{
+       printf("      %s:",
+                       ctrl & L2CAP_CTRL_FRAME_TYPE ? "S-frame" : "I-frame");
+
+       if (ctrl & 0x01) {
+               printf(" %s",
+                       supervisory2str((ctrl & L2CAP_CTRL_SUPERVISE_MASK) >>
+                                               L2CAP_CTRL_SUPER_SHIFT));
+
+               if (ctrl & L2CAP_CTRL_POLL)
+                       printf(" P-bit");
+       } else {
+               uint8_t sar;
+
+               sar = (ctrl & L2CAP_CTRL_SAR_MASK) >> L2CAP_CTRL_SAR_SHIFT;
+               printf(" %s", sar2str(sar));
+               if (sar == L2CAP_SAR_START) {
+                       uint16_t len;
+
+                       if (!l2cap_frame_get_le16(frame, &len))
+                               return;
+
+                       printf(" (len %d)", len);
+               }
+               printf(" TxSeq %d", (ctrl & L2CAP_CTRL_TXSEQ_MASK) >>
+                                               L2CAP_CTRL_TXSEQ_SHIFT);
+       }
+
+       printf(" ReqSeq %d", (ctrl & L2CAP_CTRL_REQSEQ_MASK) >>
+                                               L2CAP_CTRL_REQSEQ_SHIFT);
+
+       if (ctrl & L2CAP_CTRL_FINAL)
+               printf(" F-bit");
 }
 
 #define MAX_INDEX 16
@@ -421,7 +605,7 @@ static struct {
 };
 
 static void print_config_options(const struct l2cap_frame *frame,
-                               uint8_t offset, uint16_t dcid, bool response)
+                               uint8_t offset, uint16_t cid, bool response)
 {
        const uint8_t *data = frame->data + offset;
        uint16_t size = frame->size - offset;
@@ -496,7 +680,7 @@ static void print_config_options(const struct l2cap_frame *frame,
                         break;
                case 0x04:
                        if (response)
-                               assign_mode(frame, data[consumed + 2], dcid);
+                               assign_mode(frame, data[consumed + 2], cid);
 
                        switch (data[consumed + 2]) {
                        case 0x00:
@@ -573,8 +757,9 @@ static void print_config_options(const struct l2cap_frame *frame,
                                        get_le32(data + consumed + 14));
                        break;
                case 0x07:
-                       print_field("  Max window size: %d",
+                       print_field("  Extended window size: %d",
                                        get_le16(data + consumed + 2));
+                       assign_ext_ctrl(frame, 1, cid);
                        break;
                default:
                        packet_hexdump(data + consumed + 2, len);
@@ -1038,7 +1223,7 @@ static void sig_le_conn_rsp(const struct l2cap_frame *frame)
        print_field("Credits: %u", le16_to_cpu(pdu->credits));
        print_conn_result(pdu->result);
 
-       /*assign_dcid(frame, le16_to_cpu(pdu->dcid), le16_to_cpu(pdu->scid));*/
+       assign_dcid(frame, le16_to_cpu(pdu->dcid), 0);
 }
 
 static void sig_le_flowctl_creds(const struct l2cap_frame *frame)
@@ -1115,13 +1300,14 @@ static const struct sig_opcode_data le_sig_opcode_table[] = {
        { },
 };
 
-static void l2cap_frame_init(struct l2cap_frame *frame,
-                               uint16_t index, bool in, uint16_t handle,
+static void l2cap_frame_init(struct l2cap_frame *frame, uint16_t index, bool in,
+                               uint16_t handle, uint8_t ident,
                                uint16_t cid, const void *data, uint16_t size)
 {
        frame->index  = index;
        frame->in     = in;
        frame->handle = handle;
+       frame->ident  = ident;
        frame->cid    = cid;
        frame->data   = data;
        frame->size   = size;
@@ -1210,7 +1396,8 @@ static void bredr_sig_packet(uint16_t index, bool in, uint16_t handle,
                        }
                }
 
-               l2cap_frame_init(&frame, index, in, handle, cid, data, len);
+               l2cap_frame_init(&frame, index, in, handle, hdr->ident, cid,
+                                                               data, len);
                opcode_data->func(&frame);
 
                data += len;
@@ -1291,7 +1478,7 @@ static void le_sig_packet(uint16_t index, bool in, uint16_t handle,
                }
        }
 
-       l2cap_frame_init(&frame, index, in, handle, cid, data, len);
+       l2cap_frame_init(&frame, index, in, handle, hdr->ident, cid, data, len);
        opcode_data->func(&frame);
 }
 
@@ -1322,7 +1509,7 @@ static void connless_packet(uint16_t index, bool in, uint16_t handle,
                break;
        }
 
-       l2cap_frame_init(&frame, index, in, handle, cid, data, size);
+       l2cap_frame_init(&frame, index, in, handle, 0, cid, data, size);
 }
 
 static void print_controller_list(const uint8_t *data, uint16_t size)
@@ -1691,7 +1878,7 @@ static void amp_packet(uint16_t index, bool in, uint16_t handle,
                }
        }
 
-       l2cap_frame_init(&frame, index, in, handle, cid, data + 6, len);
+       l2cap_frame_init(&frame, index, in, handle, 0, cid, data + 6, len);
        opcode_data->func(&frame);
 }
 
@@ -2234,7 +2421,7 @@ static void att_packet(uint16_t index, bool in, uint16_t handle,
                }
        }
 
-       l2cap_frame_init(&frame, index, in, handle, cid, data + 1, size - 1);
+       l2cap_frame_init(&frame, index, in, handle, 0, cid, data + 1, size - 1);
        opcode_data->func(&frame);
 }
 
@@ -2685,7 +2872,7 @@ static void smp_packet(uint16_t index, bool in, uint16_t handle,
                }
        }
 
-       l2cap_frame_init(&frame, index, in, handle, cid, data + 1, size - 1);
+       l2cap_frame_init(&frame, index, in, handle, 0, cid, data + 1, size - 1);
        opcode_data->func(&frame);
 }
 
@@ -2693,6 +2880,9 @@ static void l2cap_frame(uint16_t index, bool in, uint16_t handle,
                        uint16_t cid, const void *data, uint16_t size)
 {
        struct l2cap_frame frame;
+       uint32_t ctrl32 = 0;
+       uint16_t ctrl16 = 0;
+       uint8_t ext_ctrl;
 
        switch (cid) {
        case 0x0001:
@@ -2715,12 +2905,44 @@ static void l2cap_frame(uint16_t index, bool in, uint16_t handle,
                smp_packet(index, in, handle, cid, data, size);
                break;
        default:
-               l2cap_frame_init(&frame, index, in, handle, cid, data, size);
+               l2cap_frame_init(&frame, index, in, handle, 0, cid, data, size);
+
+               if (frame.mode > 0) {
+                       ext_ctrl = get_ext_ctrl(&frame);
+
+                       if (ext_ctrl) {
+                               if (!l2cap_frame_get_le32(&frame, &ctrl32))
+                                       return;
+
+                               print_indent(6, COLOR_CYAN, "Channel:", "",
+                                               COLOR_OFF, " %d len %d"
+                                               " ext_ctrl 0x%8.8x"
+                                               " [PSM %d mode %d] {chan %d}",
+                                               cid, size, ctrl32, frame.psm,
+                                               frame.mode, frame.chan);
+
+                               l2cap_ctrl_ext_parse(&frame, ctrl32);
+                       } else {
+                               if (!l2cap_frame_get_le16(&frame, &ctrl16))
+                                       return;
 
-               print_indent(6, COLOR_CYAN, "Channel:", "", COLOR_OFF,
-                               " %d len %d [PSM %d mode %d] {chan %d}",
+                               print_indent(6, COLOR_CYAN, "Channel:", "",
+                                               COLOR_OFF, " %d len %d"
+                                               " ctrl 0x%4.4x"
+                                               " [PSM %d mode %d] {chan %d}",
+                                               cid, size, ctrl16, frame.psm,
+                                               frame.mode, frame.chan);
+
+                               l2cap_ctrl_parse(&frame, ctrl16);
+                       }
+
+                       printf("\n");
+               } else {
+                       print_indent(6, COLOR_CYAN, "Channel:", "", COLOR_OFF,
+                                       " %d len %d [PSM %d mode %d] {chan %d}",
                                                cid, size, frame.psm,
                                                frame.mode, frame.chan);
+               }
 
                switch (frame.psm) {
                case 0x0001:
index 975f78a..711bcb1 100644 (file)
@@ -29,6 +29,7 @@ struct l2cap_frame {
        uint16_t index;
        bool in;
        uint16_t handle;
+       uint8_t ident;
        uint16_t cid;
        uint16_t psm;
        uint16_t chan;
@@ -44,6 +45,7 @@ static inline void l2cap_frame_pull(struct l2cap_frame *frame,
                frame->index   = source->index;
                frame->in      = source->in;
                frame->handle  = source->handle;
+               frame->ident   = source->ident;
                frame->cid     = source->cid;
                frame->psm     = source->psm;
                frame->chan    = source->chan;
index f0922eb..de48db5 100644 (file)
@@ -32,7 +32,8 @@
 #include <string.h>
 #include <getopt.h>
 
-#include "mainloop.h"
+#include "src/shared/mainloop.h"
+
 #include "packet.h"
 #include "lmp.h"
 #include "keys.h"
index 06ecadd..8db485f 100644 (file)
@@ -37,9 +37,9 @@
 #include <time.h>
 #include <sys/time.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 #include "src/shared/util.h"
 #include "src/shared/btsnoop.h"
@@ -317,9 +317,10 @@ static const struct {
        { 0x1b, "SCO Offset Rejected"                                   },
        { 0x1c, "SCO Interval Rejected"                                 },
        { 0x1d, "SCO Air Mode Rejected"                                 },
-       { 0x1e, "Invalid LMP Parameters"                                },
+       { 0x1e, "Invalid LMP Parameters / Invalid LL Parameters"        },
        { 0x1f, "Unspecified Error"                                     },
-       { 0x20, "Unsupported LMP Parameter Value"                       },
+       { 0x20, "Unsupported LMP Parameter Value / "
+               "Unsupported LL Parameter Value"                        },
        { 0x21, "Role Change Not Allowed"                               },
        { 0x22, "LMP Response Timeout / LL Response Timeout"            },
        { 0x23, "LMP Error Transaction Collision"                       },
@@ -346,7 +347,7 @@ static const struct {
        { 0x38, "Host Busy - Pairing"                                   },
        { 0x39, "Connection Rejected due to No Suitable Channel Found"  },
        { 0x3a, "Controller Busy"                                       },
-       { 0x3b, "Unacceptable Connection Interval"                      },
+       { 0x3b, "Unacceptable Connection Parameters"                    },
        { 0x3c, "Directed Advertising Timeout"                          },
        { 0x3d, "Connection Terminated due to MIC Failure"              },
        { 0x3e, "Connection Failed to be Established"                   },
@@ -1036,9 +1037,10 @@ static void print_power_type(uint8_t type)
        print_field("Type: %s (0x%2.2x)", str, type);
 }
 
-static void print_power_level(int8_t level)
+static void print_power_level(int8_t level, const char *type)
 {
-       print_field("TX power: %d dBm", level);
+       print_field("TX power%s%s%s: %d dBm",
+               type ? " (" : "", type ? type : "", type ? ")" : "", level);
 }
 
 static void print_sync_flow_control(uint8_t enable)
@@ -1099,7 +1101,7 @@ static void print_voice_setting(uint16_t setting)
                str = "Linear";
                break;
        case 0x01:
-               str ="u-law";
+               str = "u-law";
                break;
        case 0x02:
                str = "A-law";
@@ -1143,7 +1145,7 @@ static void print_voice_setting(uint16_t setting)
                str = "CVSD";
                break;
        case 0x01:
-               str ="u-law";
+               str = "u-law";
                break;
        case 0x02:
                str = "A-law";
@@ -1368,6 +1370,47 @@ static void print_afh_mode(uint8_t mode)
        print_field("Mode: %s (0x%2.2x)", str, mode);
 }
 
+static void print_erroneous_reporting(uint8_t mode)
+{
+       const char *str;
+
+       switch (mode) {
+       case 0x00:
+               str = "Disabled";
+               break;
+       case 0x01:
+               str = "Enabled";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Mode: %s (0x%2.2x)", str, mode);
+}
+
+static void print_loopback_mode(uint8_t mode)
+{
+       const char *str;
+
+       switch (mode) {
+       case 0x00:
+               str = "No Loopback";
+               break;
+       case 0x01:
+               str = "Local Loopback";
+               break;
+       case 0x02:
+               str = "Remote Loopback";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Mode: %s (0x%2.2x)", str, mode);
+}
+
 static void print_simple_pairing_mode(uint8_t mode)
 {
        const char *str;
@@ -1866,6 +1909,25 @@ static void print_oob_data(uint8_t oob_data)
        print_field("OOB data: %s (0x%2.2x)", str, oob_data);
 }
 
+static void print_oob_data_response(uint8_t oob_data)
+{
+       const char *str;
+
+       switch (oob_data) {
+       case 0x00:
+               str = "Authentication data not present";
+               break;
+       case 0x01:
+               str = "Authentication data present";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("OOB data: %s (0x%2.2x)", str, oob_data);
+}
+
 static void print_authentication(uint8_t authentication)
 {
        const char *str;
@@ -2231,7 +2293,7 @@ static void print_channel_map(const uint8_t *map)
 
                        if (count > 1) {
                                print_field("  Channel %u-%u",
-                                               start, start + count - 1 );
+                                               start, start + count - 1);
                                count = 0;
                        } else if (count > 0) {
                                print_field("  Channel %u", start);
@@ -2337,6 +2399,71 @@ static void print_manufacturer(uint16_t manufacturer)
        packet_print_company("Manufacturer", le16_to_cpu(manufacturer));
 }
 
+static const struct {
+       uint16_t ver;
+       const char *str;
+} broadcom_uart_subversion_table[] = {
+       { 0x410e, "BCM43341B0"  },      /* 002.001.014 */
+       { }
+};
+
+static const struct {
+       uint16_t ver;
+       const char *str;
+} broadcom_usb_subversion_table[] = {
+       { 0x210b, "BCM43142A0"  },      /* 001.001.011 */
+       { 0x2112, "BCM4314A0"   },      /* 001.001.018 */
+       { 0x2118, "BCM20702A0"  },      /* 001.001.024 */
+       { 0x2126, "BCM4335A0"   },      /* 001.001.038 */
+       { 0x220e, "BCM20702A1"  },      /* 001.002.014 */
+       { 0x230f, "BCM4354A2"   },      /* 001.003.015 */
+       { 0x4106, "BCM4335B0"   },      /* 002.001.006 */
+       { 0x410e, "BCM20702B0"  },      /* 002.001.014 */
+       { 0x6109, "BCM4335C0"   },      /* 003.001.009 */
+       { 0x610c, "BCM4354"     },      /* 003.001.012 */
+       { }
+};
+
+static void print_manufacturer_broadcom(uint16_t subversion, uint16_t revision)
+{
+       uint16_t ver = le16_to_cpu(subversion);
+       uint16_t rev = le16_to_cpu(revision);
+       const char *str = NULL;
+       int i;
+
+       switch ((rev & 0xf000) >> 12) {
+       case 0:
+               for (i = 0; broadcom_uart_subversion_table[i].str; i++) {
+                       if (broadcom_uart_subversion_table[i].ver == ver) {
+                               str = broadcom_uart_subversion_table[i].str;
+                               break;
+                       }
+               }
+               break;
+       case 1:
+       case 2:
+               for (i = 0; broadcom_usb_subversion_table[i].str; i++) {
+                       if (broadcom_usb_subversion_table[i].ver == ver) {
+                               str = broadcom_usb_subversion_table[i].str;
+                               break;
+                       }
+               }
+               break;
+       }
+
+       if (str)
+               print_field("  Firmware: %3.3u.%3.3u.%3.3u (%s)",
+                               (ver & 0x7000) >> 13,
+                               (ver & 0x1f00) >> 8, ver & 0x00ff, str);
+       else
+               print_field("  Firmware: %3.3u.%3.3u.%3.3u",
+                               (ver & 0x7000) >> 13,
+                               (ver & 0x1f00) >> 8, ver & 0x00ff);
+
+       if (rev != 0xffff)
+               print_field("  Build: %4.4u", rev & 0x0fff);
+}
+
 static const char *get_supported_command(int bit);
 
 static void print_commands(const uint8_t *commands)
@@ -2622,7 +2749,7 @@ static const struct {
                                        LE_STATE_MASTER_SLAVE   },
        { 39, LE_STATE_CONN_SLAVE | LE_STATE_HIGH_DIRECT_ADV |
                                        LE_STATE_SLAVE_SLAVE    },
-       { 40, LE_STATE_CONN_SLAVE| LE_STATE_LOW_DIRECT_ADV |
+       { 40, LE_STATE_CONN_SLAVE | LE_STATE_LOW_DIRECT_ADV |
                                        LE_STATE_SLAVE_SLAVE    },
        { 41, LE_STATE_INITIATING | LE_STATE_CONN_SLAVE |
                                        LE_STATE_MASTER_SLAVE   },
@@ -2690,7 +2817,7 @@ static void print_le_channel_map(const uint8_t *map)
 
                        if (count > 1) {
                                print_field("  Channel %u-%u",
-                                               start, start + count - 1 );
+                                               start, start + count - 1);
                                count = 0;
                        } else if (count > 0) {
                                print_field("  Channel %u", start);
@@ -3947,7 +4074,7 @@ static void create_logic_link_cmd(const void *data, uint8_t size)
 
 static void accept_logic_link_cmd(const void *data, uint8_t size)
 {
-        const struct bt_hci_cmd_accept_logic_link *cmd = data;
+       const struct bt_hci_cmd_accept_logic_link *cmd = data;
 
        print_phy_handle(cmd->phy_handle);
        print_flow_spec("TX", cmd->tx_flow_spec);
@@ -3971,7 +4098,7 @@ static void logic_link_cancel_cmd(const void *data, uint8_t size)
 
 static void logic_link_cancel_rsp(const void *data, uint8_t size)
 {
-        const struct bt_hci_rsp_logic_link_cancel *rsp = data;
+       const struct bt_hci_rsp_logic_link_cancel *rsp = data;
 
        print_status(rsp->status);
        print_phy_handle(rsp->phy_handle);
@@ -3987,6 +4114,36 @@ static void flow_spec_modify_cmd(const void *data, uint8_t size)
        print_flow_spec("RX", cmd->rx_flow_spec);
 }
 
+static void enhanced_setup_sync_conn_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_enhanced_setup_sync_conn *cmd = data;
+
+       print_handle(cmd->handle);
+       print_field("Transmit bandwidth: %d", le32_to_cpu(cmd->tx_bandwidth));
+       print_field("Receive bandwidth: %d", le32_to_cpu(cmd->rx_bandwidth));
+
+       /* TODO */
+
+       print_field("Max latency: %d", le16_to_cpu(cmd->max_latency));
+       print_pkt_type_sco(cmd->pkt_type);
+       print_retransmission_effort(cmd->retrans_effort);
+}
+
+static void enhanced_accept_sync_conn_request_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_enhanced_accept_sync_conn_request *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+       print_field("Transmit bandwidth: %d", le32_to_cpu(cmd->tx_bandwidth));
+       print_field("Receive bandwidth: %d", le32_to_cpu(cmd->rx_bandwidth));
+
+       /* TODO */
+
+       print_field("Max latency: %d", le16_to_cpu(cmd->max_latency));
+       print_pkt_type_sco(cmd->pkt_type);
+       print_retransmission_effort(cmd->retrans_effort);
+}
+
 static void truncated_page_cmd(const void *data, uint8_t size)
 {
        const struct bt_hci_cmd_truncated_page *cmd = data;
@@ -4638,7 +4795,7 @@ static void read_tx_power_rsp(const void *data, uint8_t size)
 
        print_status(rsp->status);
        print_handle(rsp->handle);
-       print_power_level(rsp->level);
+       print_power_level(rsp->level, NULL);
 }
 
 static void read_sync_flow_control_rsp(const void *data, uint8_t size)
@@ -4675,6 +4832,18 @@ static void host_buffer_size_cmd(const void *data, uint8_t size)
                                        le16_to_cpu(cmd->sco_max_pkt));
 }
 
+static void host_num_completed_packets_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_host_num_completed_packets *cmd = data;
+
+       print_field("Num handles: %d", cmd->num_handles);
+       print_handle(cmd->handle);
+       print_field("Count: %d", le16_to_cpu(cmd->count));
+
+       if (size > sizeof(*cmd))
+               packet_hexdump(data + sizeof(*cmd), size - sizeof(*cmd));
+}
+
 static void read_link_supv_timeout_cmd(const void *data, uint8_t size)
 {
        const struct bt_hci_cmd_read_link_supv_timeout *cmd = data;
@@ -4888,14 +5057,29 @@ static void read_inquiry_resp_tx_power_rsp(const void *data, uint8_t size)
        const struct bt_hci_rsp_read_inquiry_resp_tx_power *rsp = data;
 
        print_status(rsp->status);
-       print_power_level(rsp->level);
+       print_power_level(rsp->level, NULL);
 }
 
 static void write_inquiry_tx_power_cmd(const void *data, uint8_t size)
 {
        const struct bt_hci_cmd_write_inquiry_tx_power *cmd = data;
 
-       print_power_level(cmd->level);
+       print_power_level(cmd->level, NULL);
+}
+
+static void read_erroneous_reporting_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_erroneous_reporting *rsp = data;
+
+       print_status(rsp->status);
+       print_erroneous_reporting(rsp->mode);
+}
+
+static void write_erroneous_reporting_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_erroneous_reporting *cmd = data;
+
+       print_erroneous_reporting(cmd->mode);
 }
 
 static void enhanced_flush_cmd(const void *data, uint8_t size)
@@ -4999,6 +5183,33 @@ static void write_flow_control_mode_cmd(const void *data, uint8_t size)
        print_flow_control_mode(cmd->mode);
 }
 
+static void read_enhanced_tx_power_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_enhanced_tx_power *cmd = data;
+
+       print_handle(cmd->handle);
+       print_power_type(cmd->type);
+}
+
+static void read_enhanced_tx_power_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_enhanced_tx_power *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+       print_power_level(rsp->level_gfsk, "GFSK");
+       print_power_level(rsp->level_dqpsk, "DQPSK");
+       print_power_level(rsp->level_8dpsk, "8DPSK");
+}
+
+static void short_range_mode_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_short_range_mode *cmd = data;
+
+       print_phy_handle(cmd->phy_handle);
+       print_short_range_mode(cmd->mode);
+}
+
 static void read_le_host_supported_rsp(const void *data, uint8_t size)
 {
        const struct bt_hci_rsp_read_le_host_supported *rsp = data;
@@ -5159,6 +5370,36 @@ static void read_local_oob_ext_data_rsp(const void *data, uint8_t size)
        print_randomizer_p256(rsp->randomizer256);
 }
 
+static void read_ext_page_timeout_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_ext_page_timeout *rsp = data;
+
+       print_status(rsp->status);
+       print_timeout(rsp->timeout);
+}
+
+static void write_ext_page_timeout_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_ext_page_timeout *cmd = data;
+
+       print_timeout(cmd->timeout);
+}
+
+static void read_ext_inquiry_length_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_ext_inquiry_length *rsp = data;
+
+       print_status(rsp->status);
+       print_interval(rsp->interval);
+}
+
+static void write_ext_inquiry_length_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_ext_inquiry_length *cmd = data;
+
+       print_interval(cmd->interval);
+}
+
 static void read_local_version_rsp(const void *data, uint8_t size)
 {
        const struct bt_hci_rsp_read_local_version *rsp = data;
@@ -5176,6 +5417,12 @@ static void read_local_version_rsp(const void *data, uint8_t size)
        }
 
        print_manufacturer(rsp->manufacturer);
+
+       switch (le16_to_cpu(rsp->manufacturer)) {
+       case 15:
+               print_manufacturer_broadcom(rsp->lmp_subver, rsp->hci_rev);
+               break;
+       }
 }
 
 static void read_local_commands_rsp(const void *data, uint8_t size)
@@ -5553,6 +5800,21 @@ static void set_triggered_clock_capture_cmd(const void *data, uint8_t size)
        print_field("Clock captures to filter: %u", cmd->num_filter);
 }
 
+static void read_loopback_mode_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_loopback_mode *rsp = data;
+
+       print_status(rsp->status);
+       print_loopback_mode(rsp->mode);
+}
+
+static void write_loopback_mode_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_loopback_mode *cmd = data;
+
+       print_loopback_mode(cmd->mode);
+}
+
 static void write_ssp_debug_mode_cmd(const void *data, uint8_t size)
 {
        const struct bt_hci_cmd_write_ssp_debug_mode *cmd = data;
@@ -5685,7 +5947,7 @@ static void le_read_adv_tx_power_rsp(const void *data, uint8_t size)
        const struct bt_hci_rsp_le_read_adv_tx_power *rsp = data;
 
        print_status(rsp->status);
-       print_power_level(rsp->level);
+       print_power_level(rsp->level, NULL);
 }
 
 static void le_set_adv_data_cmd(const void *data, uint8_t size)
@@ -6301,8 +6563,10 @@ static const struct opcode_data opcode_table[] = {
                                logic_link_cancel_rsp, 3, true },
        { 0x043c, 175, "Flow Specifcation Modify",
                                flow_spec_modify_cmd, 34, true },
-       { 0x043d, 235, "Enhanced Setup Synchronous Connection" },
-       { 0x043e, 236, "Enhanced Accept Synchronous Connection Request" },
+       { 0x043d, 235, "Enhanced Setup Synchronous Connection",
+                               enhanced_setup_sync_conn_cmd, 59, true },
+       { 0x043e, 236, "Enhanced Accept Synchronous Connection Request",
+                               enhanced_accept_sync_conn_request_cmd, 63, true },
        { 0x043f, 246, "Truncated Page",
                                truncated_page_cmd, 9, true },
        { 0x0440, 247, "Truncated Page Cancel",
@@ -6323,7 +6587,7 @@ static const struct opcode_data opcode_table[] = {
                                status_bdaddr_rsp, 7, true },
 
        /* OGF 2 - Link Policy */
-       { 0x0801,  33, "Holde Mode",
+       { 0x0801,  33, "Hold Mode",
                                hold_mode_cmd, 6, true },
        { 0x0803,  34, "Sniff Mode",
                                sniff_mode_cmd, 10, true },
@@ -6482,7 +6746,8 @@ static const struct opcode_data opcode_table[] = {
        { 0x0c33,  86, "Host Buffer Size",
                                host_buffer_size_cmd, 7, true,
                                status_rsp, 1, true },
-       { 0x0c35,  87, "Host Number of Completed Packets" },
+       { 0x0c35,  87, "Host Number of Completed Packets",
+                               host_num_completed_packets_cmd, 1, true },
        { 0x0c36,  88, "Read Link Supervision Timeout",
                                read_link_supv_timeout_cmd, 2, true,
                                read_link_supv_timeout_rsp, 5, true },
@@ -6560,8 +6825,12 @@ static const struct opcode_data opcode_table[] = {
        { 0x0c59, 145, "Write Inquiry Transmit Power Level",
                                write_inquiry_tx_power_cmd, 1, true,
                                status_rsp, 1, true },
-       { 0x0c5a, 146, "Read Default Erroneous Reporting" },
-       { 0x0c5b, 147, "Write Default Erroneous Reporting" },
+       { 0x0c5a, 146, "Read Default Erroneous Data Reporting",
+                               null_cmd, 0, true,
+                               read_erroneous_reporting_rsp, 2, true },
+       { 0x0c5b, 147, "Write Default Erroneous Data Reporting",
+                               write_erroneous_reporting_cmd, 1, true,
+                               status_rsp, 1, true },
        { 0x0c5f, 158, "Enhanced Flush",
                                enhanced_flush_cmd, 3, true },
        { 0x0c60, 162, "Send Keypress Notification",
@@ -6584,10 +6853,13 @@ static const struct opcode_data opcode_table[] = {
        { 0x0c67, 185, "Write Flow Control Mode",
                                write_flow_control_mode_cmd, 1, true,
                                status_rsp, 1, true },
-       { 0x0c68, 192, "Read Enhanced Transmit Power Level" },
+       { 0x0c68, 192, "Read Enhanced Transmit Power Level",
+                               read_enhanced_tx_power_cmd, 3, true,
+                               read_enhanced_tx_power_rsp, 6, true },
        { 0x0c69, 194, "Read Best Effort Flush Timeout" },
        { 0x0c6a, 195, "Write Best Effort Flush Timeout" },
-       { 0x0c6b, 196, "Short Range Mode" },
+       { 0x0c6b, 196, "Short Range Mode",
+                               short_range_mode_cmd, 2, true },
        { 0x0c6c, 197, "Read LE Host Supported",
                                null_cmd, 0, true,
                                read_le_host_supported_rsp, 3, true },
@@ -6630,10 +6902,18 @@ static const struct opcode_data opcode_table[] = {
        { 0x0c7d, 262, "Read Local OOB Extended Data",
                                null_cmd, 0, true,
                                read_local_oob_ext_data_rsp, 65, true },
-       { 0x0c7e, 264, "Read Extended Page Timeout" },
-       { 0x0c7f, 265, "Write Extended Page Timeout" },
-       { 0x0c80, 266, "Read Extended Inquiry Length" },
-       { 0x0c81, 267, "Write Extended Inquiry Length" },
+       { 0x0c7e, 264, "Read Extended Page Timeout",
+                               null_cmd, 0, true,
+                               read_ext_page_timeout_rsp, 3, true },
+       { 0x0c7f, 265, "Write Extended Page Timeout",
+                               write_ext_page_timeout_cmd, 2, true,
+                               status_rsp, 1, true },
+       { 0x0c80, 266, "Read Extended Inquiry Length",
+                               null_cmd, 0, true,
+                               read_ext_inquiry_length_rsp, 3, true },
+       { 0x0c81, 267, "Write Extended Inquiry Length",
+                               write_ext_inquiry_length_cmd, 2, true,
+                               status_rsp, 1, true },
 
        /* OGF 4 - Information Parameter */
        { 0x1001, 115, "Read Local Version Information",
@@ -6703,8 +6983,12 @@ static const struct opcode_data opcode_table[] = {
                                status_rsp, 1, true },
 
        /* OGF 6 - Testing */
-       { 0x1801, 128, "Read Loopback Mode" },
-       { 0x1802, 129, "Write Loopback Mode" },
+       { 0x1801, 128, "Read Loopback Mode",
+                               null_cmd, 0, true,
+                               read_loopback_mode_rsp, 2, true },
+       { 0x1802, 129, "Write Loopback Mode",
+                               write_loopback_mode_cmd, 1, true,
+                               status_rsp, 1, true },
        { 0x1803, 130, "Enable Device Under Test Mode",
                                null_cmd, 0, true,
                                status_rsp, 1, true },
@@ -6982,6 +7266,12 @@ static void remote_version_complete_evt(const void *data, uint8_t size)
        print_handle(evt->handle);
        print_lmp_version(evt->lmp_ver, evt->lmp_subver);
        print_manufacturer(evt->manufacturer);
+
+       switch (le16_to_cpu(evt->manufacturer)) {
+       case 15:
+               print_manufacturer_broadcom(evt->lmp_subver, 0xffff);
+               break;
+       }
 }
 
 static void qos_setup_complete_evt(const void *data, uint8_t size)
@@ -7362,7 +7652,7 @@ static void io_capability_response_evt(const void *data, uint8_t size)
 
        print_bdaddr(evt->bdaddr);
        print_io_capability(evt->capability);
-       print_oob_data(evt->oob_data);
+       print_oob_data_response(evt->oob_data);
        print_authentication(evt->authentication);
 }
 
@@ -7579,6 +7869,16 @@ static void amp_status_change_evt(const void *data, uint8_t size)
        print_amp_status(evt->amp_status);
 }
 
+static void triggered_clock_capture_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_triggered_clock_capture *evt = data;
+
+       print_handle(evt->handle);
+       print_clock_type(evt->type);
+       print_clock(evt->clock);
+       print_clock_offset(evt->clock_offset);
+}
+
 static void sync_train_complete_evt(const void *data, uint8_t size)
 {
        const struct bt_hci_evt_sync_train_complete *evt = data;
@@ -8047,7 +8347,8 @@ static const struct event_data event_table[] = {
                                short_range_mode_change_evt, 3, true },
        { 0x4d, "AMP Status Change",
                                amp_status_change_evt, 2, true },
-       { 0x4e, "Triggered Clock Capture" },
+       { 0x4e, "Triggered Clock Capture",
+                               triggered_clock_capture_evt, 9, true },
        { 0x4f, "Synchronization Train Complete",
                                sync_train_complete_evt, 1, true },
        { 0x50, "Synchronization Train Received",
@@ -8210,7 +8511,7 @@ void packet_hci_event(struct timeval *tv, uint16_t index,
        sprintf(extra_str, "(0x%2.2x) plen %d", hdr->evt, hdr->plen);
 
        print_packet(tv, index, '>', event_color, "HCI Event",
-                                                        event_str, extra_str);
+                                               event_str, extra_str);
 
        if (!event_data || !event_data->func) {
                packet_hexdump(data, size);
index be215a1..bdf4000 100644 (file)
@@ -32,7 +32,7 @@
 #include <ctype.h>
 #include <inttypes.h>
 
-#include <bluetooth/bluetooth.h>
+#include "lib/bluetooth.h"
 
 #include "src/shared/util.h"
 #include "bt.h"
index c171b9d..417a21c 100644 (file)
@@ -31,7 +31,7 @@
 #include <string.h>
 #include <inttypes.h>
 
-#include <bluetooth/bluetooth.h>
+#include "lib/bluetooth.h"
 
 #include "src/shared/util.h"
 
index 9670fb7..7fd7133 100644 (file)
 #include <inttypes.h>
 
 #include <glib.h>
-#include <gdbus/gdbus.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/rfcomm.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 
+#include "gdbus/gdbus.h"
 #include "btio/btio.h"
 
-#include "log.h"
+#include "obexd/src/log.h"
 #include "transport.h"
 #include "bluetooth.h"
 
index 243af59..bfe5c49 100644 (file)
 #endif
 
 #include <glib.h>
-#include <gdbus/gdbus.h>
 
-#include "log.h"
+#include "gdbus/gdbus.h"
+
+#include "obexd/src/log.h"
 #include "dbus.h"
 
 static void append_variant(DBusMessageIter *iter,
index a98dcf4..27857b5 100644 (file)
 #include <string.h>
 #include <errno.h>
 #include <glib.h>
-#include <gdbus/gdbus.h>
 
+#include "gdbus/gdbus.h"
+
+#include "obexd/src/log.h"
 #include "transfer.h"
 #include "session.h"
 #include "driver.h"
-#include "log.h"
 
 static GSList *drivers = NULL;
 
index fa85708..3628657 100644 (file)
 #include <errno.h>
 #include <string.h>
 
-#include <gdbus/gdbus.h>
+#include "gdbus/gdbus.h"
 
+#include "obexd/src/log.h"
 #include "dbus.h"
-#include "log.h"
-
 #include "transfer.h"
 #include "session.h"
 #include "driver.h"
index 9ca7cff..c54bed0 100644 (file)
 #include <syslog.h>
 
 #include <glib.h>
-#include <gdbus/gdbus.h>
 
-#include "log.h"
+#include "gdbus/gdbus.h"
+
+#include "obexd/src/log.h"
+#include "obexd/src/manager.h"
 #include "transfer.h"
 #include "session.h"
-#include "manager.h"
 #include "bluetooth.h"
 #include "opp.h"
 #include "ftp.h"
 #include "pbap.h"
 #include "sync.h"
 #include "map.h"
-#include "obexd/src/manager.h"
+#include "manager.h"
 #ifdef __TIZEN_PATCH__
 #include "mns-tizen.h"
 #endif
index 8c11576..e4068de 100644 (file)
@@ -23,6 +23,3 @@
 
 int client_manager_init(void);
 void client_manager_exit(void);
-#ifdef __TIZEN_PATCH__
-void release_session(struct obc_session *session);
-#endif
index d424924..e164e86 100644 (file)
 #include <stdbool.h>
 #include <inttypes.h>
 
-#include "log.h"
+#include "gdbus/gdbus.h"
+
+#include "obexd/src/log.h"
 #include "map-event.h"
 
-#include <gdbus/gdbus.h>
 #include "transfer.h"
 #include "session.h"
 
index e6c1073..4c6d676 100644 (file)
 #include <stdbool.h>
 #include <inttypes.h>
 #include <stdlib.h>
+
 #include <glib.h>
-#include <gdbus/gdbus.h>
-#include <gobex/gobex-apparam.h>
-#include <bluetooth/sdp.h>
 
+#include "lib/sdp.h"
+
+#include "gobex/gobex-apparam.h"
+#include "gdbus/gdbus.h"
+
+#include "obexd/src/log.h"
+#include "obexd/src/map_ap.h"
 #include "dbus.h"
-#include "log.h"
-#include "map_ap.h"
 #include "map-event.h"
 
 #include "map.h"
index 43b0502..14b1848 100644 (file)
 #include <stdbool.h>
 #include <stdlib.h>
 
-#include <gobex/gobex.h>
-#include <gobex/gobex-apparam.h>
-
-#include "obexd.h"
-#include "plugin.h"
-#include "log.h"
-#include "obex.h"
-#include "service.h"
-#include "mimetype.h"
-#include "map_ap.h"
+#include "gobex/gobex.h"
+#include "gobex/gobex-apparam.h"
+
+#include "obexd/src/obexd.h"
+#include "obexd/src/plugin.h"
+#include "obexd/src/log.h"
+#include "obexd/src/obex.h"
+#include "obexd/src/service.h"
+#include "obexd/src/mimetype.h"
+#include "obexd/src/map_ap.h"
 #include "map-event.h"
 
 #include "obexd/src/manager.h"
index 28c7846..846a969 100644 (file)
 #endif
 
 #include <errno.h>
-#include <gdbus/gdbus.h>
 
-#include "log.h"
+#include "gdbus/gdbus.h"
+
+#include "obexd/src/log.h"
 
 #include "transfer.h"
 #include "session.h"
index 0410fc7..4b868f0 100644 (file)
 #include <errno.h>
 #include <string.h>
 #include <stdio.h>
+
 #include <glib.h>
-#include <gdbus/gdbus.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <gobex/gobex-apparam.h>
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+
+#include "gobex/gobex-apparam.h"
+#include "gdbus/gdbus.h"
 
-#include "log.h"
+#include "obexd/src/log.h"
 
 #include "transfer.h"
 #include "session.h"
@@ -225,6 +227,11 @@ static char *build_phonebook_path(const char *location, const char *item)
        } else
                return NULL;
 
+#ifdef __TIZEN_PATCH__
+       if (!g_ascii_strcasecmp(item, "nil"))
+               return path;
+#endif
+
        if (!g_ascii_strcasecmp(item, "pb") ||
                !g_ascii_strcasecmp(item, "ich") ||
                !g_ascii_strcasecmp(item, "och") ||
@@ -747,9 +754,16 @@ static DBusMessage *pbap_select(DBusConnection *connection,
        }
 
        request = pending_request_new(pbap, message);
-
-       obc_session_setpath(pbap->session, path, pbap_setpath_cb, request,
-                                                                       &err);
+#ifdef __TIZEN_PATCH__
+       if (pbap->path == NULL || strlen(pbap->path) == 0)
+               obc_session_setpath(pbap->session, path + 1, pbap_setpath_cb, request,
+                                                                               &err);
+       else
+               obc_session_setpath(pbap->session, path, pbap_setpath_cb, request,
+                                                                               &err);
+#else
+       obc_session_setpath(pbap->session, path, pbap_setpath_cb, request, &err);
+#endif
        if (err != NULL) {
                DBusMessage *reply;
                reply =  g_dbus_create_error(message, ERROR_INTERFACE ".Failed",
@@ -880,6 +894,9 @@ static DBusMessage *pbap_list(DBusConnection *connection,
        struct pbap_data *pbap = user_data;
        GObexApparam *apparam;
        DBusMessageIter args;
+#ifdef __TIZEN_PATCH__
+       const char *pb_folder;
+#endif
 
        if (!pbap->path)
                return g_dbus_create_error(message,
@@ -888,6 +905,15 @@ static DBusMessage *pbap_list(DBusConnection *connection,
 
        dbus_message_iter_init(message, &args);
 
+#ifdef __TIZEN_PATCH__
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       dbus_message_iter_get_basic(&args, &pb_folder);
+       dbus_message_iter_next(&args);
+#endif
+
        apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
                                                        DEFAULT_COUNT);
        apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
@@ -899,7 +925,11 @@ static DBusMessage *pbap_list(DBusConnection *connection,
                                ERROR_INTERFACE ".InvalidArguments", NULL);
        }
 
+#ifdef __TIZEN_PATCH__
+       return pull_vcard_listing(pbap, message, pb_folder, apparam);
+#else
        return pull_vcard_listing(pbap, message, "", apparam);
+#endif
 }
 
 static GObexApparam *parse_attribute(GObexApparam *apparam, const char *field)
@@ -1059,7 +1089,11 @@ static const GDBusMethodTable pbap_methods[] = {
                                        { "properties", "a{sv}" }),
                        pbap_pull_vcard) },
        { GDBUS_ASYNC_METHOD("List",
-                       GDBUS_ARGS({ "filters", "a{sv}" }),
+#ifdef __TIZEN_PATCH__
+                        GDBUS_ARGS({ "folder", "s" }, {"filters", "a{sv}" }),
+#else
+                        GDBUS_ARGS({"filters", "a{sv}" }),
+#endif
                        GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
                        pbap_list) },
        { GDBUS_ASYNC_METHOD("Search",
index f605744..61b9357 100644 (file)
 #include <sys/stat.h>
 
 #include <glib.h>
-#include <gdbus/gdbus.h>
-#include <gobex/gobex.h>
 
+#include "gdbus/gdbus.h"
+#include "gobex/gobex.h"
+
+#include "obexd/src/log.h"
 #include "dbus.h"
-#include "log.h"
 #include "transfer.h"
 #include "session.h"
 #ifdef __TIZEN_PATCH__
@@ -1155,6 +1156,12 @@ guint obc_session_setpath(struct obc_session *session, const char *path,
        data->user_data = user_data;
        data->remaining = g_strsplit(strlen(path) ? path : "/", "/", 0);
 
+       if (!data->remaining || !data->remaining[0]) {
+               error("obc_session_setpath: invalid path %s", path);
+               g_set_error(err, OBEX_IO_ERROR, -EINVAL, "Invalid argument");
+               return 0;
+       }
+
        p = pending_request_new(session, session_process_setpath, NULL,
                                setpath_op_complete, data, setpath_data_free);
        session_queue(p);
index 35899bc..10d0272 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <stdint.h>
 #include <glib.h>
-#include <gdbus/gdbus.h>
 
 struct obc_session;
 
@@ -81,3 +80,6 @@ guint obc_session_delete(struct obc_session *session, const char *file,
                                GError **err);
 void obc_session_cancel(struct obc_session *session, guint id,
                                                        gboolean remove);
+#ifdef __TIZEN_PATCH__
+void release_session(struct obc_session *session);
+#endif
index 1a4b482..548c318 100644 (file)
 #include <string.h>
 
 #include <glib.h>
-#include <gdbus/gdbus.h>
 
-#include "log.h"
+#include "gdbus/gdbus.h"
+
+#include "obexd/src/log.h"
 
 #include "transfer.h"
 #include "session.h"
index 15edd47..521232e 100644 (file)
 #include <inttypes.h>
 
 #include <glib.h>
-#include <gdbus/gdbus.h>
-#include <gobex/gobex.h>
 
+#include "gdbus/gdbus.h"
+#include "gobex/gobex.h"
+
+#include "obexd/src/log.h"
 #include "dbus.h"
-#include "log.h"
 #include "transfer.h"
 
 #define TRANSFER_INTERFACE "org.bluez.obex.Transfer1"
index 77e52f7..aae6780 100644 (file)
@@ -30,8 +30,8 @@
 #include <glib.h>
 #include <inttypes.h>
 
+#include "obexd/src/log.h"
 #include "transport.h"
-#include "log.h"
 
 static GSList *transports = NULL;
 
diff --git a/obexd/plugins/.phonebook.h.swp b/obexd/plugins/.phonebook.h.swp
deleted file mode 100644 (file)
index fd9ab17..0000000
Binary files a/obexd/plugins/.phonebook.h.swp and /dev/null differ
index cf326cc..d8b872a 100644 (file)
 #include <sys/socket.h>
 
 #include <glib.h>
-#include <gdbus/gdbus.h>
 
-#include "btio/btio.h"
+#include "lib/bluetooth.h"
 #include "lib/uuid.h"
 
-#include "obexd.h"
-#include "plugin.h"
-#include "server.h"
-#include "obex.h"
-#include "transport.h"
-#include "service.h"
-#include "log.h"
+#include "gdbus/gdbus.h"
+
+#include "btio/btio.h"
+#include "obexd/src/obexd.h"
+#include "obexd/src/plugin.h"
+#include "obexd/src/server.h"
+#include "obexd/src/obex.h"
+#include "obexd/src/transport.h"
+#include "obexd/src/service.h"
+#include "obexd/src/log.h"
 
 #define BT_RX_MTU 32767
 #define BT_TX_MTU 32767
index 98281f2..0e6cd49 100644 (file)
 
 #include <glib.h>
 
-#include "obexd.h"
-#include "plugin.h"
-#include "log.h"
-#include "mimetype.h"
+#include "obexd/src/obexd.h"
+#include "obexd/src/plugin.h"
+#include "obexd/src/log.h"
+#include "obexd/src/mimetype.h"
 #include "filesystem.h"
 
 #define EOL_CHARS "\n"
index 99c7540..8d5aecd 100644 (file)
 
 #include <glib.h>
 
-#include "obexd.h"
-#include "plugin.h"
-#include "log.h"
-#include "obex.h"
-#include "manager.h"
-#include "mimetype.h"
-#include "service.h"
+#include "obexd/src/obexd.h"
+#include "obexd/src/plugin.h"
+#include "obexd/src/log.h"
+#include "obexd/src/obex.h"
+#include "obexd/src/manager.h"
+#include "obexd/src/mimetype.h"
+#include "obexd/src/service.h"
 #include "ftp.h"
 #include "filesystem.h"
 
index d343977..a3bbd60 100644 (file)
 #include <fcntl.h>
 #include <inttypes.h>
 
-#include "obexd.h"
-#include "plugin.h"
-#include "log.h"
-#include "obex.h"
-#include "service.h"
+#include "obexd/src/obexd.h"
+#include "obexd/src/plugin.h"
+#include "obexd/src/log.h"
+#include "obexd/src/obex.h"
+#include "obexd/src/service.h"
+#include "obexd/src/manager.h"
+#include "obexd/src/mimetype.h"
 #include "phonebook.h"
-#include "mimetype.h"
 #include "filesystem.h"
-#include "manager.h"
 
 struct aparam_header {
        uint8_t tag;
index 9fc747c..7036497 100644 (file)
 #include <inttypes.h>
 #include <sys/time.h>
 
-#include <gobex/gobex.h>
-#include <gobex/gobex-apparam.h>
-
-#include "obexd.h"
-#include "plugin.h"
-#include "log.h"
-#include "obex.h"
-#include "service.h"
-#include "mimetype.h"
+#include "gobex/gobex.h"
+#include "gobex/gobex-apparam.h"
+
+#include "obexd/src/obexd.h"
+#include "obexd/src/plugin.h"
+#include "obexd/src/log.h"
+#include "obexd/src/obex.h"
+#include "obexd/src/service.h"
+#include "obexd/src/mimetype.h"
+#include "obexd/src/manager.h"
+#include "obexd/src/map_ap.h"
 #include "filesystem.h"
-#include "manager.h"
-#include "map_ap.h"
-
 #include "messages.h"
 
 #define READ_STATUS_REQ 0
index bb0627f..765f08d 100644 (file)
@@ -31,7 +31,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "log.h"
+#include "obexd/src/log.h"
 
 #include "messages.h"
 
index ee0204c..5228ba8 100644 (file)
 
 #include <glib.h>
 
-#include "obexd.h"
-#include "plugin.h"
-#include "obex.h"
-#include "service.h"
-#include "log.h"
-#include "manager.h"
+#include "obexd/src/obexd.h"
+#include "obexd/src/plugin.h"
+#include "obexd/src/obex.h"
+#include "obexd/src/service.h"
+#include "obexd/src/log.h"
+#include "obexd/src/manager.h"
 #include "filesystem.h"
 
 #define VCARD_TYPE "text/x-vcard"
index d9e9643..68417a0 100644 (file)
 #include <fcntl.h>
 #include <inttypes.h>
 
-#include <gobex/gobex.h>
-#include <gobex-apparam.h>
-
-#include "obexd.h"
-#include "plugin.h"
-#include "log.h"
-#include "obex.h"
-#include "service.h"
+#include "gobex/gobex.h"
+#include "gobex/gobex-apparam.h"
+
+#include "obexd/src/obexd.h"
+#include "obexd/src/plugin.h"
+#include "obexd/src/log.h"
+#include "obexd/src/obex.h"
+#include "obexd/src/service.h"
+#include "obexd/src/manager.h"
+#include "obexd/src/mimetype.h"
 #include "phonebook.h"
-#include "mimetype.h"
 #include "filesystem.h"
-#include "manager.h"
 
 #define PHONEBOOK_TYPE         "x-bt/phonebook"
 #define VCARDLISTING_TYPE      "x-bt/vcard-listing"
@@ -460,7 +460,7 @@ static void cache_entry_done(void *user_data)
 {
        struct pbap_session *pbap = user_data;
        const char *id;
-       int ret = 0;
+       int ret;
 
        DBG("");
 
index 6460aa9..43ab409 100644 (file)
 #include <inttypes.h>
 
 #include <glib.h>
-#include <gdbus/gdbus.h>
-
-#include "obexd.h"
-#include "plugin.h"
-#include "log.h"
-#include "obex.h"
-#include "mimetype.h"
-#include "service.h"
+
+#include "gdbus/gdbus.h"
+
+#include "obexd/src/obexd.h"
+#include "obexd/src/plugin.h"
+#include "obexd/src/log.h"
+#include "obexd/src/obex.h"
+#include "obexd/src/mimetype.h"
+#include "obexd/src/service.h"
 #include "ftp.h"
 
 #define PCSUITE_CHANNEL 24
index 6b9d040..eeb078f 100644 (file)
@@ -41,7 +41,7 @@
 #include <libical/vobject.h>
 #include <libical/vcc.h>
 
-#include "log.h"
+#include "obexd/src/log.h"
 #include "phonebook.h"
 
 typedef void (*vcard_func_t) (const char *file, VObject *vo, void *user_data);
index 2e49576..c422585 100644 (file)
 
 #include <string.h>
 #include <errno.h>
-#include <glib.h>
-#include <bluetooth/bluetooth.h>
 
+#include <glib.h>
 #include <libebook/e-book.h>
 
-#include "log.h"
-#include "obex.h"
-#include "service.h"
+#include "lib/bluetooth.h"
+
+#include "obexd/src/log.h"
+#include "obexd/src/obex.h"
+#include "obexd/src/service.h"
 #include "phonebook.h"
 
 #define QUERY_FN "(contains \"family_name\" \"%s\")"
index 433f95a..0743629 100644 (file)
 #include <dbus/dbus.h>
 #include <libtracker-sparql/tracker-sparql.h>
 
-#include "log.h"
-#include "obex.h"
-#include "service.h"
-#include "mimetype.h"
+#include "obexd/src/log.h"
+#include "obexd/src/obex.h"
+#include "obexd/src/service.h"
+#include "obexd/src/mimetype.h"
 #include "phonebook.h"
 #include "vcard.h"
 
index fbeac1e..854505a 100644 (file)
 #include <glib.h>
 #include <dbus/dbus.h>
 
-#include <bluetooth/bluetooth.h>
+#include "lib/bluetooth.h"
 
-#include <gdbus/gdbus.h>
+#include "gdbus/gdbus.h"
 
 #include "btio/btio.h"
-#include "plugin.h"
-#include "obex.h"
-#include "service.h"
-#include "mimetype.h"
-#include "log.h"
-#include "manager.h"
-#include "obexd.h"
+#include "obexd/src/plugin.h"
+#include "obexd/src/obex.h"
+#include "obexd/src/service.h"
+#include "obexd/src/mimetype.h"
+#include "obexd/src/log.h"
+#include "obexd/src/manager.h"
+#include "obexd/src/obexd.h"
 #include "filesystem.h"
 
 #define SYNCML_TARGET_SIZE 11
index aaa126b..37f7c85 100644 (file)
@@ -31,7 +31,8 @@
 #include <errno.h>
 
 #include <glib.h>
-#include <gdbus/gdbus.h>
+
+#include "gdbus/gdbus.h"
 
 #include "vcard.h"
 
index c461c47..515405c 100644 (file)
 #include <syslog.h>
 #include <glib.h>
 
-#include <gdbus/gdbus.h>
-
-#include "../client/manager.h"
+#include "gdbus/gdbus.h"
 
 #include "log.h"
 #include "obexd.h"
 #include "server.h"
 
+#ifdef __TIZEN_PATCH__
+#include "../client/manager.h"
+#endif
+
 #define DEFAULT_CAP_FILE CONFIGDIR "/capability.xml"
 
 static GMainLoop *main_loop = NULL;
index fb8af06..ce20b01 100644 (file)
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
-#include <gdbus/gdbus.h>
 #include <sys/socket.h>
 #include <inttypes.h>
 
-#include <gobex/gobex.h>
+#include "gdbus/gdbus.h"
+#include "gobex/gobex.h"
 
 #include "btio/btio.h"
 #include "obexd.h"
index 25799d2..9083246 100644 (file)
@@ -40,7 +40,8 @@
 #include <inttypes.h>
 
 #include <glib.h>
-#include <gobex/gobex.h>
+
+#include "gobex/gobex.h"
 
 #include "btio/btio.h"
 #include "obexd.h"
index 007c27e..db85423 100644 (file)
@@ -35,7 +35,8 @@
 #include <inttypes.h>
 
 #include <glib.h>
-#include <gobex/gobex.h>
+
+#include "gobex/gobex.h"
 
 #include "log.h"
 #include "obex.h"
old mode 100755 (executable)
new mode 100644 (file)
index b905670..021631f
@@ -1,7 +1,7 @@
 #%define with_libcapng --enable-capng
 Name:          bluez
 Summary:       Bluetooth Stack for Linux
-Version:       5.27
+Version:       5.28
 Release:       0
 Group:         Network & Connectivity/Bluetooth
 License:       GPL-2.0+
@@ -46,8 +46,6 @@ BuildRequires:  pkgconfig(libnl-1)
 BuildRequires:  libical-devel
 BuildRequires:  pkgconfig(libtzplatform-config)
 
-%define cups_lib_dir %{_prefix}/lib/cups
-
 %description
 The Bluetooth stack for Linux.
 
@@ -69,24 +67,6 @@ Group:          Network & Connectivity/Bluetooth
 %description -n libbluetooth
 Bluetooth protocol stack libraries.
 
-%package -n libbluetooth-plugins-service
-Summary:        Bluetooth Plugins
-License:        GPL-2.0+
-Group:          Network & Connectivity/Bluetooth
-
-%description -n libbluetooth-plugins-service
-Bluetooth protocol stack plugins.
-
-%package cups
-Summary:        CUPS Driver for Bluetooth Printers
-License:        GPL-2.0+
-Group:          Network & Connectivity/Bluetooth
-Requires:       libbluetooth = %{version}
-
-%description cups
-Contains the files required by CUPS for printing to Bluetooth-connected
-printers.
-
 %package -n obexd
 Summary:        OBEX Server A basic OBEX server implementation
 Group:          Network & Connectivity/Bluetooth
@@ -114,60 +94,43 @@ cp %{SOURCE1001} .
 %build
 autoreconf -fiv
 
-export CFLAGS="${CFLAGS} -D__TIZEN_PATCH__ -D__BROADCOM_PATCH__"
+export CFLAGS="${CFLAGS} -D__TIZEN_PATCH__ -D__BROADCOM_PATCH__ -DBLUEZ5_27_GATT_CLIENT"
 
 export LDFLAGS=" -lncurses -Wl,--as-needed "
 export CFLAGS+=" -DPBAP_SIM_ENABLE"
-#%reconfigure --with-pic \
-%reconfigure --with-pic \
-               --libexecdir=/lib \
-               --disable-usb   \
-               --enable-test   \
-               --enable-library \
-               --enable-experimental   \
-               --enable-readline       \
-               --enable-service \
-               --with-systemdunitdir=%{_unitdir} \
-#                      --disable-static \
-#                      --sysconfdir=%{_sysconfdir} \
-#                      --localstatedir=%{_localstatedir} \
-#                      --disable-systemd \
-#                      --enable-debug \
-#                      --enable-pie \
-#%if "%{?tizen_profile_name}" == "mobile"
-#                      --enable-network \
-#%endif
-#                      --enable-serial \
-#                      --enable-input \
-#                      --disable-usb \
-#                      --enable-tools \
-#                      --disable-bccmd \
-#                      --disable-pcmcia \
-#                      --disable-hid2hci \
-#                      --disable-alsa \
-#                      --enable-gstreamer=no \
-#                      --disable-dfutool \
-#                      --disable-cups \
-#                      --enable-health \
-#                      --enable-dbusoob \
-#                      --enable-test \
-#                      --with-telephony=tizen \
-#                      --enable-obex \
-#                      --enable-library \
-#%if "%{?tizen_profile_name}" == "wearable"
-#                      --enable-gatt \
-#                      --enable-wearable \
-#%endif
-#%if "%{?tizen_profile_name}" == "common"
-#                      --enable-usbbt \
-#%endif
-#                      --enable-experimental \
-#                      --enable-readline       \
-#3                     --enable-service \
-#                      --with-systemdunitdir=%{_unitdir} \
-#                      %{?with_libcapng}
-#                      --disable-autopair \
-#                      --disable-tizenunusedplugin
+%reconfigure --disable-static \
+                       --sysconfdir=%{_sysconfdir} \
+                       --localstatedir=%{_localstatedir} \
+                       --with-systemdsystemunitdir=%{_libdir}/systemd/system \
+                       --with-systemduserunitdir=%{_libdir}/systemd/user \
+                       --libexecdir=%{_libdir} \
+                       --enable-debug \
+                       --enable-pie \
+                       --enable-serial \
+                       --enable-input \
+                       --enable-usb=no \
+                       --enable-tools \
+                       --disable-bccmd \
+                       --enable-pcmcia=no \
+                       --enable-hid2hci=no \
+                       --enable-alsa=no \
+                       --enable-gstreamer=no \
+                       --disable-dfutool \
+                       --disable-cups \
+                       --enable-health=yes \
+                       --enable-dbusoob \
+                       --enable-test \
+                       --with-telephony=tizen \
+                       --enable-obex \
+                       --enable-library \
+                       --enable-gatt \
+                       --enable-experimental \
+                       --enable-autopair=no \
+                       --enable-network \
+                       --enable-hid=yes \
+                       --enable-tizenunusedplugin=no
+
+
 make %{?_smp_mflags} all V=1
 
 %check
@@ -181,12 +144,7 @@ echo "%{_libdir}"
 rm -rvf $RPM_BUILD_ROOT/%{_libdir}/gstreamer-*
 install --mode=0755 -D %{S:4} $RPM_BUILD_ROOT/usr/lib/udev/bluetooth.sh
 install --mode=0644 -D %{S:7} $RPM_BUILD_ROOT/%{_sysconfdir}/modprobe.d/50-bluetooth.conf
-if ! test -e %{buildroot}%{cups_lib_dir}/backend/bluetooth
-then if test -e %{buildroot}%{_libdir}/cups/backend/bluetooth
-     then mkdir -p %{buildroot}%{cups_lib_dir}/backend
-          mv %{buildroot}%{_libdir}/cups/backend/bluetooth %{buildroot}%{cups_lib_dir}/backend/bluetooth
-     fi
-fi
+
 # no idea why this is suddenly necessary...
 install --mode 0755 -d $RPM_BUILD_ROOT/var/lib/bluetooth
 
@@ -204,7 +162,7 @@ install -D -m 0755 %SOURCE102 %{buildroot}%{_sysconfdir}/obex/root-setup.d/000_c
 install -D -m 0755 %SOURCE103 %{buildroot}%{_bindir}/obex.sh
 install -D -m 0755 tools/btiotest $RPM_BUILD_ROOT/%{_bindir}/
 install -D -m 0755 tools/bluetooth-player $RPM_BUILD_ROOT/%{_bindir}/
-install -D -m 0755 tools/mpris-player $RPM_BUILD_ROOT/%{_bindir}/
+#install -D -m 0755 tools/mpris-player $RPM_BUILD_ROOT/%{_bindir}/
 install -D -m 0755 tools/btmgmt $RPM_BUILD_ROOT/%{_bindir}/
 install -D -m 0755 tools/scotest $RPM_BUILD_ROOT/%{_bindir}/
 install -D -m 0755 tools/bluemoon $RPM_BUILD_ROOT/%{_bindir}/
@@ -220,10 +178,6 @@ ln -sf bluetooth.service %{buildroot}%{_unitdir}/dbus-org.bluez.service
 
 %postun -n libbluetooth -p /sbin/ldconfig
 
-%post -n libbluetooth-plugins-service -p /sbin/ldconfig
-
-%postun -n libbluetooth-plugins-service -p /sbin/ldconfig
-
 %files
 %manifest %{name}.manifest
 %defattr(-, root, root)
@@ -238,12 +192,13 @@ ln -sf bluetooth.service %{buildroot}%{_unitdir}/dbus-org.bluez.service
 %{_bindir}/l2ping
 %{_bindir}/obexctl
 %{_bindir}/rfcomm
+%{_bindir}/mpris-proxy
 %{_bindir}/sdptool
 %{_bindir}/ciptool
 #%{_bindir}/dfutool
 %{_bindir}/hciattach
 %{_bindir}/hciconfig
-/lib/bluetooth/bluetoothd
+%{_libdir}/bluetooth/bluetoothd
 %{_bindir}/bccmd
 #%{_sbindir}/hid2hci
 %dir /usr/lib/udev
@@ -258,7 +213,6 @@ ln -sf bluetooth.service %{buildroot}%{_unitdir}/dbus-org.bluez.service
 %dir /var/lib/bluetooth
 %dir %{_sysconfdir}/modprobe.d
 %config(noreplace) %{_sysconfdir}/modprobe.d/50-bluetooth.conf
-%{_unitdir}/bluetooth.service
 
 
 
@@ -274,25 +228,11 @@ ln -sf bluetooth.service %{buildroot}%{_unitdir}/dbus-org.bluez.service
 %manifest %{name}.manifest
 %defattr(-, root, root)
 %{_libdir}/libbluetooth.so.*
-%{_libdir}/bluetooth/plugins/*.so
-%license COPYING
-
-%files -n libbluetooth-plugins-service
-%manifest %{name}.manifest
-%defattr(-, root, root)
-%{_libdir}/bluetooth/plugins/*.so
 %license COPYING
 
-%files cups
-%manifest %{name}.manifest
-%defattr(-,root,root)
-%dir %{cups_lib_dir}
-%dir %{cups_lib_dir}/backend
-%{cups_lib_dir}/backend/bluetooth
-
 %files -n obexd
 %defattr(-,root,root,-)
-/lib/bluetooth/obexd
+%{_libdir}/bluetooth/obexd
 %{_unitdir_user}/obex.service
 %{_datadir}/dbus-1/services/org.bluez.obex.service
 %{_sysconfdir}/obex/root-setup.d/000_create-symlinks
@@ -308,7 +248,7 @@ ln -sf bluetooth.service %{buildroot}%{_unitdir}/dbus-org.bluez.service
 %{_bindir}/rctest
 %{_bindir}/bluetoothctl
 %{_bindir}/btiotest
-%{_bindir}/mpris-player
+#%{_bindir}/mpris-player
 %{_bindir}/bluetooth-player
 %{_bindir}/btmon
 %{_bindir}/hcidump
@@ -316,7 +256,8 @@ ln -sf bluetooth.service %{buildroot}%{_unitdir}/dbus-org.bluez.service
 %{_bindir}/scotest
 %{_bindir}/bluemoon
 %{_bindir}/gatttool
-
+%{_bindir}/hex2hcd
+%exclude /usr/lib/debug/*
 
 %docs_package
 
index 43b0e00..c201722 100644 (file)
 #include <unistd.h>
 #include <errno.h>
 
-#include <bluetooth/bluetooth.h>
 #include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+
 #include "src/plugin.h"
 #include "src/adapter.h"
 #include "src/device.h"
index 0e67280..2563dc5 100644 (file)
@@ -28,7 +28,7 @@
 #endif
 
 #include <errno.h>
-#include <gdbus.h>
+#include "gdbus/gdbus.h"
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
index 6e20b1f..5249751 100644 (file)
 #include <glib.h>
 #include <errno.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
 #include "src/plugin.h"
 #include "src/adapter.h"
 #include "src/shared/util.h"
index d4d72d3..4f9dfe6 100644 (file)
 #include <errno.h>
 #include <stdint.h>
 #include <stdlib.h>
-#include <gdbus/gdbus.h>
+#include <string.h>
+
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+
+#include "gdbus/gdbus.h"
 
 #include "src/dbus-common.h"
 #include "src/plugin.h"
index 137d601..cabcf34 100644 (file)
 
 #include <stdlib.h>
 #include <errno.h>
-#include <gdbus/gdbus.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/sdp.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/sdp.h"
+
+#include "gdbus/gdbus.h"
 
 #include "src/plugin.h"
 #include "src/log.h"
index 2d4baf3..bc9beba 100644 (file)
 
 #include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
 #include "lib/mgmt.h"
+
 #include "src/log.h"
 #include "src/plugin.h"
 #include "src/adapter.h"
@@ -44,6 +47,7 @@
 
 #ifdef __TIZEN_PATCH__
 #define CONTROL_CONNECT_TIMEOUT 4
+#define TARGET_CONNECT_TIMEOUT 1
 #else
 #define CONTROL_CONNECT_TIMEOUT 2
 #endif
@@ -218,6 +222,11 @@ static void sink_cb(struct btd_service *service, btd_service_state_t old_state,
 
        switch (new_state) {
        case BTD_SERVICE_STATE_UNAVAILABLE:
+               if (data->sink_timer > 0) {
+                       g_source_remove(data->sink_timer);
+                       data->sink_timer = 0;
+               }
+               break;
        case BTD_SERVICE_STATE_DISCONNECTED:
                if (old_state == BTD_SERVICE_STATE_CONNECTING) {
                        int err = btd_service_get_error(service);
@@ -290,9 +299,15 @@ static void policy_set_tg_timer(struct policy_data *data)
        if (data->tg_timer > 0)
                g_source_remove(data->tg_timer);
 
+#ifdef __TIZEN_PATCH__
+       data->tg_timer = g_timeout_add_seconds(TARGET_CONNECT_TIMEOUT,
+                                                       policy_connect_tg,
+                                                       data);
+#else
        data->tg_timer = g_timeout_add_seconds(CONTROL_CONNECT_TIMEOUT,
                                                        policy_connect_tg,
                                                        data);
+#endif
 }
 
 static gboolean policy_connect_source(gpointer user_data)
@@ -336,6 +351,11 @@ static void source_cb(struct btd_service *service,
 
        switch (new_state) {
        case BTD_SERVICE_STATE_UNAVAILABLE:
+               if (data->source_timer > 0) {
+                       g_source_remove(data->source_timer);
+                       data->source_timer = 0;
+               }
+               break;
        case BTD_SERVICE_STATE_DISCONNECTED:
                if (old_state == BTD_SERVICE_STATE_CONNECTING) {
                        int err = btd_service_get_error(service);
@@ -394,6 +414,11 @@ static void controller_cb(struct btd_service *service,
 
        switch (new_state) {
        case BTD_SERVICE_STATE_UNAVAILABLE:
+               if (data->ct_timer > 0) {
+                       g_source_remove(data->ct_timer);
+                       data->ct_timer = 0;
+               }
+               break;
        case BTD_SERVICE_STATE_DISCONNECTED:
                break;
        case BTD_SERVICE_STATE_CONNECTING:
@@ -422,6 +447,11 @@ static void target_cb(struct btd_service *service,
 
        switch (new_state) {
        case BTD_SERVICE_STATE_UNAVAILABLE:
+               if (data->tg_timer > 0) {
+                       g_source_remove(data->tg_timer);
+                       data->tg_timer = 0;
+               }
+               break;
        case BTD_SERVICE_STATE_DISCONNECTED:
                break;
        case BTD_SERVICE_STATE_CONNECTING:
diff --git a/plugins/service.c b/plugins/service.c
deleted file mode 100644 (file)
index 25111f6..0000000
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2014  Intel Corporation.
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include <glib.h>
-#include <gdbus/gdbus.h>
-
-#include "lib/uuid.h"
-#include "src/plugin.h"
-#include "src/log.h"
-#include "src/dbus-common.h"
-#include "src/error.h"
-#include "src/adapter.h"
-#include "src/device.h"
-#include "src/service.h"
-#include "src/profile.h"
-
-#define SERVICE_INTERFACE "org.bluez.Service1"
-
-static unsigned int service_id = 0;
-static GSList *services = NULL;
-
-struct service_data {
-       struct btd_service *service;
-       char *path;
-       DBusMessage *connect;
-       DBusMessage *disconnect;
-};
-
-static struct service_data *find_data(struct btd_service *service)
-{
-       GSList *l;
-
-       for (l = services; l; l = l->next) {
-               struct service_data *data = l->data;
-
-               if (data->service == service)
-                       return data;
-       }
-
-       return NULL;
-}
-
-static void data_free(void *user_data)
-{
-       struct service_data *data = user_data;
-
-       if (data->connect)
-               dbus_message_unref(data->connect);
-
-       if (data->disconnect)
-               dbus_message_unref(data->disconnect);
-
-       g_free(data->path);
-       g_free(data);
-}
-
-static void data_remove(struct service_data *data)
-{
-       services = g_slist_remove(services, data);
-       g_dbus_unregister_interface(btd_get_dbus_connection(), data->path,
-                                                       SERVICE_INTERFACE);
-}
-
-static DBusMessage *service_disconnect(DBusConnection *conn, DBusMessage *msg,
-                                                               void *user_data)
-{
-       struct service_data *data = user_data;
-       int err;
-
-       if (data->disconnect)
-               return btd_error_in_progress(msg);
-
-       data->disconnect = dbus_message_ref(msg);
-
-       err = btd_service_disconnect(data->service);
-       if (err == 0)
-               return NULL;
-
-       dbus_message_unref(data->disconnect);
-       data->disconnect = NULL;
-
-       return btd_error_failed(msg, strerror(-err));
-}
-
-static DBusMessage *service_connect(DBusConnection *conn, DBusMessage *msg,
-                                                               void *user_data)
-{
-       struct service_data *data = user_data;
-       int err;
-
-       if (data->connect)
-               return btd_error_in_progress(msg);
-
-       err = btd_service_connect(data->service);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
-
-       data->connect = dbus_message_ref(msg);
-
-       return NULL;
-}
-
-static const char *data_get_state(struct service_data *data)
-{
-       btd_service_state_t state = btd_service_get_state(data->service);
-       int err;
-
-       switch (state) {
-       case BTD_SERVICE_STATE_UNAVAILABLE:
-               return "unavailable";
-       case BTD_SERVICE_STATE_DISCONNECTED:
-               err = btd_service_get_error(data->service);
-               return err < 0 ? "error" : "disconnected";
-       case BTD_SERVICE_STATE_CONNECTING:
-               return "connecting";
-       case BTD_SERVICE_STATE_CONNECTED:
-               return "connected";
-       case BTD_SERVICE_STATE_DISCONNECTING:
-               return "disconnecting";
-       }
-
-       return "unknown";
-}
-
-static gboolean get_device(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *user_data)
-{
-       struct service_data *data = user_data;
-       struct btd_device *dev = btd_service_get_device(data->service);
-       const char *path = btd_device_get_path(dev);
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
-
-       return TRUE;
-}
-
-static gboolean get_state(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *user_data)
-{
-       struct service_data *data = user_data;
-       const char *state;
-
-       state = data_get_state(data);
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &state);
-
-       return TRUE;
-}
-
-static gboolean remote_uuid_exists(const GDBusPropertyTable *property,
-                                                               void *user_data)
-{
-       struct service_data *data = user_data;
-       struct btd_profile *p = btd_service_get_profile(data->service);
-
-       return p->remote_uuid != NULL;
-}
-
-static gboolean get_remote_uuid(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *user_data)
-{
-       struct service_data *data = user_data;
-       struct btd_profile *p = btd_service_get_profile(data->service);
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &p->remote_uuid);
-
-       return TRUE;
-}
-
-
-static gboolean local_uuid_exists(const GDBusPropertyTable *property,
-                                                               void *user_data)
-{
-       struct service_data *data = user_data;
-       struct btd_profile *p = btd_service_get_profile(data->service);
-
-       return p->local_uuid != NULL;
-}
-
-static gboolean get_local_uuid(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *user_data)
-{
-       struct service_data *data = user_data;
-       struct btd_profile *p = btd_service_get_profile(data->service);
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &p->local_uuid);
-
-       return TRUE;
-}
-
-static gboolean version_exists(const GDBusPropertyTable *property,
-                                                               void *user_data)
-{
-       struct service_data *data = user_data;
-       uint16_t version = btd_service_get_version(data->service);
-
-       return version != 0x0000;
-}
-
-static gboolean get_version(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *user_data)
-{
-       struct service_data *data = user_data;
-       uint16_t version = btd_service_get_version(data->service);
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &version);
-
-       return TRUE;
-}
-
-static gboolean get_auto_connect(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *user_data)
-{
-       struct service_data *data = user_data;
-       dbus_bool_t value = btd_service_get_auto_connect(data->service);
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
-
-       return TRUE;
-}
-
-static void set_auto_connect(const GDBusPropertyTable *property,
-                                               DBusMessageIter *value,
-                                               GDBusPendingPropertySet id,
-                                               void *user_data)
-{
-       struct service_data *data = user_data;
-       dbus_bool_t b;
-
-       if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN) {
-               g_dbus_pending_property_error(id,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "Invalid arguments in method call");
-               return;
-       }
-
-       dbus_message_iter_get_basic(value, &b);
-
-       btd_service_set_auto_connect(data->service, b);
-
-       g_dbus_pending_property_success(id);
-}
-
-static gboolean get_blocked(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *user_data)
-{
-       struct service_data *data = user_data;
-       dbus_bool_t value = btd_service_is_blocked(data->service);
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
-
-       return TRUE;
-}
-
-static void set_blocked(const GDBusPropertyTable *property,
-                                               DBusMessageIter *value,
-                                               GDBusPendingPropertySet id,
-                                               void *user_data)
-{
-       struct service_data *data = user_data;
-       dbus_bool_t b;
-
-       if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN) {
-               g_dbus_pending_property_error(id,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "Invalid arguments in method call");
-               return;
-       }
-
-       dbus_message_iter_get_basic(value, &b);
-
-       btd_service_set_blocked(data->service, b);
-
-       g_dbus_pending_property_success(id);
-}
-
-static const GDBusPropertyTable service_properties[] = {
-       { "Device", "o", get_device, NULL, NULL },
-       { "State", "s", get_state, NULL, NULL },
-       { "RemoteUUID", "s", get_remote_uuid, NULL, remote_uuid_exists },
-       { "LocalUUID", "s", get_local_uuid, NULL, local_uuid_exists },
-       { "Version", "q", get_version, NULL, version_exists },
-       { "AutoConnect", "b", get_auto_connect, set_auto_connect, NULL },
-       { "Blocked", "b", get_blocked, set_blocked, NULL },
-       { }
-};
-
-static const GDBusMethodTable service_methods[] = {
-       { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, service_disconnect) },
-       { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, service_connect) },
-       {}
-};
-
-static struct service_data *service_get_data(struct btd_service *service)
-{
-       struct btd_device *dev = btd_service_get_device(service);
-       struct btd_profile *p = btd_service_get_profile(service);
-       struct service_data *data;
-
-       data = find_data(service);
-       if (data != NULL)
-               return data;
-
-       data = g_new0(struct service_data, 1);
-       data->path = g_strdup_printf("%s/%s", btd_device_get_path(dev),
-                                                               p->remote_uuid);
-       data->path = g_strdelimit(data->path, "-", '_');
-       data->service = service;
-       if (g_dbus_register_interface(btd_get_dbus_connection(),
-                                       data->path, SERVICE_INTERFACE,
-                                       service_methods, NULL,
-                                       service_properties, data,
-                                       data_free) == FALSE) {
-               error("Unable to register service interface for %s",
-                                                               data->path);
-               data_free(data);
-               return NULL;
-       }
-
-       services = g_slist_prepend(services, data);
-
-       DBG("%s", data->path);
-
-       return data;
-}
-
-static void service_connected(struct service_data *data)
-{
-       DBusMessage *reply;
-
-       if (!data->connect)
-               return;
-
-       reply = dbus_message_new_method_return(data->connect);
-       g_dbus_send_message(btd_get_dbus_connection(), reply);
-       dbus_message_unref(data->connect);
-       data->connect = NULL;
-}
-
-static void service_disconnected(struct service_data *data)
-{
-       DBusMessage *reply;
-       int err;
-
-       if (data->disconnect) {
-               reply = dbus_message_new_method_return(data->disconnect);
-               g_dbus_send_message(btd_get_dbus_connection(), reply);
-               dbus_message_unref(data->disconnect);
-               data->connect = NULL;
-       }
-
-       if (!data->connect)
-               return;
-
-       err = btd_service_get_error(data->service);
-
-       reply = btd_error_failed(data->connect, strerror(-err));
-       g_dbus_send_message(btd_get_dbus_connection(), reply);
-       dbus_message_unref(data->connect);
-       data->connect = NULL;
-}
-
-static void service_cb(struct btd_service *service,
-                                               btd_service_state_t old_state,
-                                               btd_service_state_t new_state,
-                                               void *user_data)
-{
-       struct service_data *data;
-
-       data = service_get_data(service);
-       if (!data)
-               return;
-
-       switch (new_state) {
-       case BTD_SERVICE_STATE_UNAVAILABLE:
-               data_remove(data);
-               return;
-       case BTD_SERVICE_STATE_CONNECTED:
-               service_connected(data);
-               break;
-       case BTD_SERVICE_STATE_DISCONNECTED:
-               service_disconnected(data);
-               break;
-       default:
-               break;
-       }
-
-       g_dbus_emit_property_changed(btd_get_dbus_connection(), data->path,
-                                               SERVICE_INTERFACE, "State");
-}
-
-static int service_init(void)
-{
-       DBG("");
-
-       service_id = btd_service_add_state_cb(service_cb, NULL);
-
-       return 0;
-}
-
-static void service_exit(void)
-{
-       DBG("");
-
-       btd_service_remove_state_cb(service_id);
-
-       g_slist_free_full(services, data_free);
-}
-
-BLUETOOTH_PLUGIN_DEFINE(service, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
-                                       service_init, service_exit)
index ac53ba9..c93f5d4 100644 (file)
@@ -39,7 +39,9 @@
 #include <libudev.h>
 
 #include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
 #include "src/adapter.h"
 #include "src/device.h"
 #include "src/plugin.h"
index bd8820e..0ced275 100644 (file)
 
 #include <stdbool.h>
 
-#include <bluetooth/bluetooth.h>
 #include <glib.h>
 
+#include "bluetooth/bluetooth.h"
+#include "bluetooth/sdp.h"
+
 #include "src/plugin.h"
 #include "src/adapter.h"
 #include "src/device.h"
index aefcff8..2f6e3cd 100644 (file)
 
 #include <stdbool.h>
 #include <errno.h>
-#include <gdbus/gdbus.h>
-#include <glib.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
+
 #include "src/plugin.h"
 #include "src/dbus-common.h"
 #include "attrib/att.h"
index ffb482b..464faeb 100644 (file)
 #include <dbus/dbus.h>
 #include <glib.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 #include "lib/uuid.h"
+
 #include "src/plugin.h"
 #include "src/adapter.h"
 #include "src/device.h"
@@ -45,6 +45,9 @@
 #include "src/service.h"
 #include "src/log.h"
 #include "src/sdpd.h"
+#include "src/shared/queue.h"
+
+#include "btio/btio.h"
 
 #include "avdtp.h"
 #include "sink.h"
@@ -58,6 +61,8 @@
 #define SUSPEND_TIMEOUT 5
 #define RECONFIGURE_TIMEOUT 500
 
+#define AVDTP_PSM 25
+
 struct a2dp_sep {
        struct a2dp_server *server;
        struct a2dp_endpoint *endpoint;
@@ -108,6 +113,19 @@ struct a2dp_server {
        uint32_t sink_record_id;
        gboolean sink_enabled;
        gboolean source_enabled;
+       GIOChannel *io;
+       struct queue *seps;
+       struct queue *channels;
+};
+
+struct a2dp_channel {
+       struct a2dp_server *server;
+       struct btd_device *device;
+       GIOChannel *io;
+       guint io_id;
+       unsigned int state_id;
+       unsigned int auth_id;
+       struct avdtp *session;
 };
 
 static GSList *servers = NULL;
@@ -437,6 +455,41 @@ static void endpoint_setconf_cb(struct a2dp_setup *setup, gboolean ret)
        auto_config(setup);
 }
 
+static gboolean endpoint_match_codec_ind(struct avdtp *session,
+                               struct avdtp_media_codec_capability *codec,
+                               void *user_data)
+{
+       struct a2dp_sep *sep = user_data;
+       a2dp_vendor_codec_t *remote_codec;
+       a2dp_vendor_codec_t *local_codec;
+       uint8_t *capabilities;
+       size_t length;
+
+       if (codec->media_codec_type != A2DP_CODEC_VENDOR)
+               return TRUE;
+
+       if (sep->endpoint == NULL)
+               return FALSE;
+
+       length = sep->endpoint->get_capabilities(sep, &capabilities,
+                                                       sep->user_data);
+       if (length < sizeof(a2dp_vendor_codec_t))
+               return FALSE;
+
+       local_codec = (a2dp_vendor_codec_t *) capabilities;
+       remote_codec = (a2dp_vendor_codec_t *) codec->data;
+
+       if (remote_codec->vendor_id != local_codec->vendor_id)
+               return FALSE;
+
+       if (remote_codec->codec_id != local_codec->codec_id)
+               return FALSE;
+
+       DBG("vendor 0x%08x codec 0x%04x", btohl(remote_codec->vendor_id),
+                                               btohs(remote_codec->codec_id));
+       return TRUE;
+}
+
 static gboolean endpoint_setconf_ind(struct avdtp *session,
                                                struct avdtp_local_sep *sep,
                                                struct avdtp_stream *stream,
@@ -684,9 +737,11 @@ static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep,
        else
                DBG("Source %p: Open_Ind", sep);
 
-       setup = find_setup_by_session(session);
+       setup = a2dp_setup_get(session);
        if (!setup)
-               return TRUE;
+               return FALSE;
+
+       setup->stream = stream;
 
        if (setup->reconfigure)
                setup->reconfigure = FALSE;
@@ -1102,6 +1157,7 @@ static struct avdtp_sep_cfm cfm = {
 };
 
 static struct avdtp_sep_ind endpoint_ind = {
+       .match_codec            = endpoint_match_codec_ind,
        .get_capability         = endpoint_getcap_ind,
        .set_configuration      = endpoint_setconf_ind,
        .get_configuration      = getconf_ind,
@@ -1198,12 +1254,309 @@ static struct a2dp_server *find_server(GSList *list, struct btd_adapter *a)
        return NULL;
 }
 
+static void channel_free(void *data)
+{
+       struct a2dp_channel *chan = data;
+
+       if (chan->auth_id > 0)
+               btd_cancel_authorization(chan->auth_id);
+
+       if (chan->io_id > 0)
+               g_source_remove(chan->io_id);
+
+       if (chan->io) {
+               g_io_channel_shutdown(chan->io, TRUE, NULL);
+               g_io_channel_unref(chan->io);
+       }
+
+       avdtp_remove_state_cb(chan->state_id);
+
+       g_free(chan);
+}
+
+static void channel_remove(struct a2dp_channel *chan)
+{
+       struct a2dp_server *server = chan->server;
+
+       DBG("chan %p", chan);
+
+       queue_remove(server->channels, chan);
+
+       channel_free(chan);
+}
+
+static gboolean disconnect_cb(GIOChannel *io, GIOCondition cond, gpointer data)
+{
+       struct a2dp_channel *chan = data;
+
+       DBG("chan %p", chan);
+
+       chan->io_id = 0;
+
+       channel_remove(chan);
+
+       return FALSE;
+}
+
+static void avdtp_state_cb(struct btd_device *dev, struct avdtp *session,
+                                       avdtp_session_state_t old_state,
+                                       avdtp_session_state_t new_state,
+                                       void *user_data)
+{
+       struct a2dp_channel *chan = user_data;
+
+       switch (new_state) {
+       case AVDTP_SESSION_STATE_DISCONNECTED:
+               if (chan->session == session)
+                       channel_remove(chan);
+               break;
+       case AVDTP_SESSION_STATE_CONNECTING:
+               break;
+       case AVDTP_SESSION_STATE_CONNECTED:
+               break;
+       }
+}
+
+static struct a2dp_channel *channel_new(struct a2dp_server *server,
+                                       struct btd_device *device,
+                                       GIOChannel *io)
+{
+       struct a2dp_channel *chan;
+
+       chan = g_new0(struct a2dp_channel, 1);
+       chan->server = server;
+       chan->device = device;
+       chan->state_id = avdtp_add_state_cb(device, avdtp_state_cb, chan);
+
+       if (!queue_push_tail(server->channels, chan)) {
+               g_free(chan);
+               return NULL;
+       }
+
+       if (!io)
+               return chan;
+
+       chan->io = g_io_channel_ref(io);
+       chan->io_id = g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+                                       (GIOFunc) disconnect_cb, chan);
+
+       return chan;
+}
+
+static bool match_by_device(const void *data, const void *user_data)
+{
+       const struct a2dp_channel *chan = data;
+       const struct btd_device *device = user_data;
+
+       return chan->device == device;
+}
+
+struct avdtp *a2dp_avdtp_get(struct btd_device *device)
+{
+       struct a2dp_server *server;
+       struct a2dp_channel *chan;
+
+       server = find_server(servers, device_get_adapter(device));
+       if (server == NULL)
+               return NULL;
+
+       chan = queue_find(server->channels, match_by_device, device);
+       if (!chan) {
+               chan = channel_new(server, device, NULL);
+               if (!chan)
+                       return NULL;
+       }
+
+       if (chan->session)
+               return avdtp_ref(chan->session);
+
+       chan->session = avdtp_new(NULL, device, server->seps);
+       if (!chan->session) {
+               channel_remove(chan);
+               return NULL;
+       }
+
+       return avdtp_ref(chan->session);
+}
+
+static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
+{
+       struct a2dp_channel *chan = user_data;
+
+       if (err) {
+               error("%s", err->message);
+               goto fail;
+       }
+
+       chan->session = avdtp_new(chan->io, chan->device, chan->server->seps);
+       if (!chan->session) {
+               error("Unable to create AVDTP session");
+               goto fail;
+       }
+
+       g_io_channel_unref(chan->io);
+       chan->io = NULL;
+
+       g_source_remove(chan->io_id);
+       chan->io_id = 0;
+
+       return;
+
+fail:
+       channel_remove(chan);
+}
+
+static void auth_cb(DBusError *derr, void *user_data)
+{
+       struct a2dp_channel *chan = user_data;
+       GError *err = NULL;
+
+       chan->auth_id = 0;
+
+       if (derr && dbus_error_is_set(derr)) {
+               error("Access denied: %s", derr->message);
+               goto fail;
+       }
+
+       if (!bt_io_accept(chan->io, connect_cb, chan, NULL, &err)) {
+               error("bt_io_accept: %s", err->message);
+               g_error_free(err);
+               goto fail;
+       }
+
+       return;
+
+fail:
+       channel_remove(chan);
+}
+
+static void transport_cb(GIOChannel *io, GError *err, gpointer user_data)
+{
+       struct a2dp_setup *setup = user_data;
+       uint16_t omtu, imtu;
+
+       if (err) {
+               error("%s", err->message);
+               goto drop;
+       }
+
+       bt_io_get(io, &err, BT_IO_OPT_OMTU, &omtu, BT_IO_OPT_IMTU, &imtu,
+                                                       BT_IO_OPT_INVALID);
+       if (err) {
+               error("%s", err->message);
+               g_error_free(err);
+               goto drop;
+       }
+
+       if (!avdtp_stream_set_transport(setup->stream,
+                                       g_io_channel_unix_get_fd(io),
+                                       omtu, imtu))
+               goto drop;
+
+       g_io_channel_set_close_on_unref(io, FALSE);
+
+       setup_unref(setup);
+
+       return;
+
+drop:
+       setup_unref(setup);
+       g_io_channel_shutdown(io, TRUE, NULL);
+
+}
+static void confirm_cb(GIOChannel *io, gpointer data)
+{
+       struct a2dp_server *server = data;
+       struct a2dp_channel *chan;
+       char address[18];
+       bdaddr_t src, dst;
+       GError *err = NULL;
+       struct btd_device *device;
+
+       bt_io_get(io, &err,
+                       BT_IO_OPT_SOURCE_BDADDR, &src,
+                       BT_IO_OPT_DEST_BDADDR, &dst,
+                       BT_IO_OPT_DEST, address,
+                       BT_IO_OPT_INVALID);
+       if (err) {
+               error("%s", err->message);
+               g_error_free(err);
+               goto drop;
+       }
+
+       DBG("AVDTP: incoming connect from %s", address);
+
+       device = btd_adapter_find_device(adapter_find(&src), &dst,
+                                                               BDADDR_BREDR);
+       if (!device)
+               goto drop;
+
+       chan = queue_find(server->channels, match_by_device, device);
+       if (chan) {
+               struct a2dp_setup *setup;
+
+               setup = find_setup_by_session(chan->session);
+               if (!setup || !setup->stream)
+                       goto drop;
+
+               if (!bt_io_accept(io, transport_cb, setup, NULL, &err)) {
+                       error("bt_io_accept: %s", err->message);
+                       g_error_free(err);
+                       goto drop;
+               }
+
+               return;
+       }
+
+       chan = channel_new(server, device, io);
+       if (!chan)
+               goto drop;
+
+       chan->auth_id = btd_request_authorization(&src, &dst,
+                                                       ADVANCED_AUDIO_UUID,
+                                                       auth_cb, chan);
+       if (chan->auth_id == 0 && !chan->session)
+               channel_remove(chan);
+
+       return;
+
+drop:
+       g_io_channel_shutdown(io, TRUE, NULL);
+}
+
+static bool a2dp_server_listen(struct a2dp_server *server)
+{
+       GError *err = NULL;
+
+       if (server->io)
+               return true;
+
+       server->io = bt_io_listen(NULL, confirm_cb, server, NULL, &err,
+                               BT_IO_OPT_SOURCE_BDADDR,
+                               btd_adapter_get_address(server->adapter),
+                               BT_IO_OPT_PSM, AVDTP_PSM,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+                               BT_IO_OPT_MASTER, true,
+                               BT_IO_OPT_INVALID);
+       if (server->io)
+               return true;
+
+       error("%s", err->message);
+       g_error_free(err);
+
+       return false;
+}
+
 static struct a2dp_server *a2dp_server_register(struct btd_adapter *adapter)
 {
        struct a2dp_server *server;
 
        server = g_new0(struct a2dp_server, 1);
+
        server->adapter = btd_adapter_ref(adapter);
+       server->seps = queue_new();
+       server->channels = queue_new();
+
        servers = g_slist_append(servers, server);
 
        return server;
@@ -1211,18 +1564,38 @@ static struct a2dp_server *a2dp_server_register(struct btd_adapter *adapter)
 
 static void a2dp_unregister_sep(struct a2dp_sep *sep)
 {
+       struct a2dp_server *server = sep->server;
+
        if (sep->destroy) {
                sep->destroy(sep->user_data);
                sep->endpoint = NULL;
        }
 
-       avdtp_unregister_sep(sep->lsep);
+       avdtp_unregister_sep(server->seps, sep->lsep);
+
        g_free(sep);
+
+       if (!queue_isempty(server->seps))
+               return;
+
+       if (server->io) {
+               g_io_channel_shutdown(server->io, TRUE, NULL);
+               g_io_channel_unref(server->io);
+               server->io = NULL;
+       }
 }
 
 static void a2dp_server_unregister(struct a2dp_server *server)
 {
        servers = g_slist_remove(servers, server);
+       queue_destroy(server->channels, channel_free);
+       queue_destroy(server->seps, NULL);
+
+       if (server->io) {
+               g_io_channel_shutdown(server->io, TRUE, NULL);
+               g_io_channel_unref(server->io);
+       }
+
        btd_adapter_unref(server->adapter);
        g_free(server);
 }
@@ -1260,7 +1633,7 @@ struct a2dp_sep *a2dp_add_sep(struct btd_adapter *adapter, uint8_t type,
 
        sep = g_new0(struct a2dp_sep, 1);
 
-       sep->lsep = avdtp_register_sep(adapter, type,
+       sep->lsep = avdtp_register_sep(server->seps, type,
                                        AVDTP_MEDIA_TYPE_AUDIO, codec,
                                        delay_reporting, &endpoint_ind,
                                        &cfm, sep);
@@ -1294,8 +1667,7 @@ struct a2dp_sep *a2dp_add_sep(struct btd_adapter *adapter, uint8_t type,
        record = a2dp_record(type);
        if (!record) {
                error("Unable to allocate new service record");
-               avdtp_unregister_sep(sep->lsep);
-               g_free(sep);
+               a2dp_unregister_sep(sep);
                if (err)
                        *err = -EINVAL;
                return NULL;
@@ -1304,12 +1676,20 @@ struct a2dp_sep *a2dp_add_sep(struct btd_adapter *adapter, uint8_t type,
        if (adapter_service_add(server->adapter, record) < 0) {
                error("Unable to register A2DP service record");
                sdp_record_free(record);
-               avdtp_unregister_sep(sep->lsep);
-               g_free(sep);
+               a2dp_unregister_sep(sep);
+               if (err)
+                       *err = -EINVAL;
+               return NULL;
+       }
+
+       if (!a2dp_server_listen(server)) {
+               sdp_record_free(record);
+               a2dp_unregister_sep(sep);
                if (err)
                        *err = -EINVAL;
                return NULL;
        }
+
        *record_id = record->handle;
 
 add:
@@ -1380,42 +1760,6 @@ done:
        finalize_select(setup);
 }
 
-static gboolean check_vendor_codec(struct a2dp_sep *sep, uint8_t *cap,
-                                                               size_t len)
-{
-       uint8_t *capabilities;
-       size_t length;
-       a2dp_vendor_codec_t *local_codec;
-       a2dp_vendor_codec_t *remote_codec;
-
-       if (len < sizeof(a2dp_vendor_codec_t))
-               return FALSE;
-
-       remote_codec = (a2dp_vendor_codec_t *) cap;
-
-       if (sep->endpoint == NULL)
-               return FALSE;
-
-       length = sep->endpoint->get_capabilities(sep,
-                               &capabilities, sep->user_data);
-
-       if (length < sizeof(a2dp_vendor_codec_t))
-               return FALSE;
-
-       local_codec = (a2dp_vendor_codec_t *) capabilities;
-
-       if (btohl(remote_codec->vendor_id) != btohl(local_codec->vendor_id))
-               return FALSE;
-
-       if (btohs(remote_codec->codec_id) != btohs(local_codec->codec_id))
-               return FALSE;
-
-       DBG("vendor 0x%08x codec 0x%04x", btohl(remote_codec->vendor_id),
-                                               btohs(remote_codec->codec_id));
-
-       return TRUE;
-}
-
 static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
                                        const char *sender)
 {
@@ -1425,9 +1769,11 @@ static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
 
        for (; list; list = list->next) {
                struct a2dp_sep *sep = list->data;
+#ifdef __TIZEN_PATCH__
                struct avdtp_remote_sep *rsep;
                struct avdtp_media_codec_capability *cap;
                struct avdtp_service_capability *service;
+#endif
 
                /* Use sender's endpoint if available */
                if (sender) {
@@ -1440,7 +1786,7 @@ static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
                        if (g_strcmp0(sender, name) != 0)
                                continue;
                }
-
+#ifdef __TIZEN_PATCH__
                rsep = avdtp_find_remote_sep(session, sep->lsep);
                if (rsep == NULL)
                        continue;
@@ -1448,19 +1794,17 @@ static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
                service = avdtp_get_codec(rsep);
                cap = (struct avdtp_media_codec_capability *) service->data;
 
-#ifdef __TIZEN_PATCH__
                if (cap->media_codec_type != A2DP_CODEC_VENDOR) {
                        selected_sep = sep;
                        continue;
                }
 #else
-               if (cap->media_codec_type != A2DP_CODEC_VENDOR)
-                       return sep;
+               if (avdtp_find_remote_sep(session, sep->lsep) == NULL)
+                       continue;
+
 #endif
+               return sep;
 
-               if (check_vendor_codec(sep, cap->data,
-                                       service->length - sizeof(*cap)))
-                       return sep;
        }
 
 #ifdef __TIZEN_PATCH__
@@ -2071,12 +2415,8 @@ static void media_server_remove(struct btd_adapter *adapter)
 static struct btd_profile a2dp_source_profile = {
        .name           = "a2dp-source",
        .priority       = BTD_PROFILE_PRIORITY_MEDIUM,
-       .version        = 0x0103,
 
        .remote_uuid    = A2DP_SOURCE_UUID,
-       .local_uuid     = A2DP_SINK_UUID,
-       .auth_uuid      = ADVANCED_AUDIO_UUID,
-
        .device_probe   = a2dp_source_probe,
        .device_remove  = a2dp_source_remove,
 
@@ -2091,12 +2431,8 @@ static struct btd_profile a2dp_source_profile = {
 static struct btd_profile a2dp_sink_profile = {
        .name           = "a2dp-sink",
        .priority       = BTD_PROFILE_PRIORITY_MEDIUM,
-       .version        = 0x0103,
 
        .remote_uuid    = A2DP_SINK_UUID,
-       .local_uuid     = A2DP_SOURCE_UUID,
-       .auth_uuid      = ADVANCED_AUDIO_UUID,
-
        .device_probe   = a2dp_sink_probe,
        .device_remove  = a2dp_sink_remove,
 
index ef3be5c..544eea1 100644 (file)
@@ -87,3 +87,4 @@ gboolean a2dp_sep_lock(struct a2dp_sep *sep, struct avdtp *session);
 gboolean a2dp_sep_unlock(struct a2dp_sep *sep, struct avdtp *session);
 struct avdtp_stream *a2dp_sep_get_stream(struct a2dp_sep *sep);
 struct btd_device *a2dp_setup_get_device(struct a2dp_setup *setup);
+struct avdtp *a2dp_avdtp_get(struct btd_device *device);
index 4514d69..197373a 100644 (file)
 #include <fcntl.h>
 #include <netinet/in.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/l2cap.h>
-
 #include <glib.h>
 
-#include "btio/btio.h"
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/l2cap.h"
 #include "lib/uuid.h"
+
+#include "btio/btio.h"
 #include "src/adapter.h"
 #include "src/device.h"
-
 #include "src/log.h"
 #include "src/error.h"
 #include "src/uinput.h"
@@ -178,7 +177,7 @@ struct avctp_channel {
 };
 
 struct key_pressed {
-       uint8_t op;
+       uint16_t op;
        guint timer;
 };
 
@@ -331,6 +330,36 @@ static gboolean auto_release(gpointer user_data)
        return FALSE;
 }
 
+static void handle_press(struct avctp *session, uint16_t op)
+{
+       if (session->key.timer > 0) {
+               g_source_remove(session->key.timer);
+
+               /* Only auto release if keys are different */
+               if (session->key.op == op)
+                       goto done;
+
+               send_key(session->uinput, session->key.op, 0);
+       }
+
+       session->key.op = op;
+
+       send_key(session->uinput, op, 1);
+
+done:
+       session->key.timer = g_timeout_add_seconds(AVC_PRESS_TIMEOUT,
+                                                       auto_release, session);
+}
+
+static void handle_release(struct avctp *session, uint16_t op)
+{
+       if (session->key.timer > 0) {
+               g_source_remove(session->key.timer);
+               session->key.timer = 0;
+       }
+
+       send_key(session->uinput, op, 0);
+}
 #ifdef __TIZEN_PATCH__
 extern void avrcp_stop_position_timer(void);
 #endif
@@ -389,28 +418,14 @@ static size_t handle_panel_passthrough(struct avctp *session,
                }
 
                if (pressed) {
-                       if (session->key.timer > 0) {
-                               g_source_remove(session->key.timer);
-#ifndef __TIZEN_PATCH__
-                               send_key(session->uinput, session->key.op, 0);
-#endif
-                       }
-
-                       session->key.op = key_map[i].uinput;
-                       session->key.timer = g_timeout_add_seconds(
-                                                       AVC_PRESS_TIMEOUT,
-                                                       auto_release,
-                                                       session);
+                       handle_press(session, key_map[i].uinput);
 #ifdef __TIZEN_PATCH__
                        if (key_map[i].avc == AVC_REWIND)
                                avrcp_stop_position_timer();
 #endif
-               } else if (session->key.timer > 0) {
-                       g_source_remove(session->key.timer);
-                       session->key.timer = 0;
-               }
+               } else
+                       handle_release(session, key_map[i].uinput);
 
-               send_key(session->uinput, key_map[i].uinput, pressed);
                break;
        }
 
@@ -1084,6 +1099,8 @@ static int uinput_create(char *name)
                return err;
        }
 
+       send_event(fd, EV_REP, REP_DELAY, 300);
+
        return fd;
 }
 
@@ -1351,11 +1368,11 @@ static void avctp_control_confirm(struct avctp *session, GIOChannel *chan,
 #ifdef __TIZEN_PATCH__
        session->auth_id = btd_request_authorization(src, dst,
                                                        AVRCP_TARGET_UUID,
-                                                       auth_cb, session, 0);
+                                                       auth_cb, session);
 #else
        session->auth_id = btd_request_authorization(src, dst,
                                                        AVRCP_REMOTE_UUID,
-                                                       auth_cb, session, 0);
+                                                       auth_cb, session);
 #endif
        if (session->auth_id == 0)
                goto drop;
index ef6979e..b9db7f3 100644 (file)
@@ -37,6 +37,7 @@
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
+#include "lib/uuid.h"
 
 #ifdef __TIZEN_PATCH__
 #ifdef __BROADCOM_QOS_PATCH__
 
 #include <glib.h>
 
-#include "src/log.h"
 
 #include "btio/btio.h"
-#include "lib/uuid.h"
+#include "src/log.h"
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
 #include "src/adapter.h"
 #include "src/device.h"
 
+#ifdef __TIZEN_PATCH__
+#include "src/service.h"
+#endif
+
 #include "avdtp.h"
 #include "sink.h"
 #include "source.h"
@@ -61,6 +67,7 @@
 #define AVDTP_PSM 25
 
 #define MAX_SEID 0x3E
+static unsigned int seids;
 
 #ifndef MAX
 # define MAX(x, y) ((x) > (y) ? (x) : (y))
@@ -336,13 +343,6 @@ struct avdtp_remote_sep {
        struct avdtp_stream *stream;
 };
 
-struct avdtp_server {
-       struct btd_adapter *adapter;
-       GIOChannel *io;
-       GSList *seps;
-       GSList *sessions;
-};
-
 struct avdtp_local_sep {
        avdtp_state_t state;
        struct avdtp_stream *stream;
@@ -353,7 +353,6 @@ struct avdtp_local_sep {
        struct avdtp_sep_ind *ind;
        struct avdtp_sep_cfm *cfm;
        void *user_data;
-       struct avdtp_server *server;
 };
 
 struct stream_callback {
@@ -404,13 +403,11 @@ struct avdtp {
 
        uint16_t version;
 
-       struct avdtp_server *server;
+       struct queue *lseps;
        struct btd_device *device;
 
        avdtp_session_state_t state;
 
-       guint auth_id;
-
        GIOChannel *io;
        guint io_id;
 
@@ -439,8 +436,6 @@ struct avdtp {
        gboolean stream_setup;
 };
 
-static GSList *servers = NULL;
-
 static GSList *state_callbacks = NULL;
 
 static int send_request(struct avdtp *session, gboolean priority,
@@ -459,18 +454,6 @@ static void avdtp_sep_set_state(struct avdtp *session,
                                struct avdtp_local_sep *sep,
                                avdtp_state_t state);
 
-static struct avdtp_server *find_server(GSList *list, struct btd_adapter *a)
-{
-       for (; list; list = list->next) {
-               struct avdtp_server *server = list->data;
-
-               if (server->adapter == a)
-                       return server;
-       }
-
-       return NULL;
-}
-
 static const char *avdtp_statestr(avdtp_state_t state)
 {
        switch (state) {
@@ -724,9 +707,11 @@ static void avdtp_set_state(struct avdtp *session,
 
        session->state = new_state;
 
-       for (l = state_callbacks; l != NULL; l = l->next) {
+       for (l = state_callbacks; l != NULL;) {
                struct avdtp_state_callback *cb = l->data;
 
+               l = g_slist_next(l);
+
                if (session->device != cb->dev)
                        continue;
 
@@ -1221,25 +1206,6 @@ static void release_stream(struct avdtp_stream *stream, struct avdtp *session)
        avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE);
 }
 
-static int avdtp_cancel_authorization(struct avdtp *session)
-{
-       int err;
-
-       if (session->state != AVDTP_SESSION_STATE_CONNECTING)
-               return 0;
-
-       if (session->auth_id == 0)
-               return 0;
-
-       err = btd_cancel_authorization(session->auth_id);
-       if (err < 0)
-               return err;
-
-       session->auth_id = 0;
-
-       return 0;
-}
-
 static void sep_free(gpointer data)
 {
        struct avdtp_remote_sep *sep = data;
@@ -1291,7 +1257,6 @@ static void avdtp_free(void *data)
 
 static void connection_lost(struct avdtp *session, int err)
 {
-       struct avdtp_server *server = session->server;
        char address[18];
 #ifdef __TIZEN_PATCH__
        struct btd_service *service;
@@ -1300,15 +1265,11 @@ static void connection_lost(struct avdtp *session, int err)
        ba2str(device_get_address(session->device), address);
        DBG("Disconnected from %s", address);
 
-       if (err != EACCES)
-               avdtp_cancel_authorization(session);
-
 #ifdef __TIZEN_PATCH__
        service = btd_device_get_service(session->device, A2DP_SINK_UUID);
        if (service)
                btd_service_connecting_complete(service, -err);
 #endif
-
        g_slist_foreach(session->streams, (GFunc) release_stream, session);
        session->streams = NULL;
 
@@ -1325,7 +1286,6 @@ static void connection_lost(struct avdtp *session, int err)
                return;
 #endif
 
-       server->sessions = g_slist_remove(server->sessions, session);
        avdtp_free(session);
 }
 
@@ -1350,11 +1310,18 @@ static gboolean disconnect_timeout(gpointer user_data)
 #ifdef __TIZEN_PATCH__
        struct btd_device *device = NULL;
        struct btd_adapter *adapter = NULL;
-       struct bdaddr_t *bdaddr = NULL;
+       const bdaddr_t *bdaddr = NULL;
 #endif
 
        DBG("");
 
+/* Fix : REVERSE_INULL */
+#ifdef __TIZEN_PATCH__
+       if (session->device == NULL) {
+               error("session device NOT found");
+               return FALSE;
+       }
+#endif
        session->dc_timer = 0;
 
        stream_setup = session->stream_setup;
@@ -1373,14 +1340,12 @@ static gboolean disconnect_timeout(gpointer user_data)
        }
 
 #ifdef __TIZEN_PATCH__
-       if (session->device) {
-               adapter = device_get_adapter(session->device);
-               bdaddr = device_get_address(session->device);
-               if (adapter && bdaddr)
-                       device = btd_adapter_find_device(adapter, bdaddr, BDADDR_BREDR);
-               if (!device)
-                       error("device is NOT found");
-       }
+       adapter = device_get_adapter(session->device);
+       bdaddr = device_get_address(session->device);
+       if (adapter && bdaddr)
+               device = btd_adapter_find_device(adapter, bdaddr, BDADDR_BREDR);
+       if (!device)
+               error("device is NOT found");
 #endif
 
        connection_lost(session, ETIMEDOUT);
@@ -1440,19 +1405,18 @@ struct avdtp *avdtp_ref(struct avdtp *session)
        return session;
 }
 
-static struct avdtp_local_sep *find_local_sep_by_seid(struct avdtp_server *server,
-                                                       uint8_t seid)
+static bool match_by_seid(const void *data, const void *user_data)
 {
-       GSList *l;
-
-       for (l = server->seps; l != NULL; l = g_slist_next(l)) {
-               struct avdtp_local_sep *sep = l->data;
+       const struct avdtp_local_sep *sep = data;
+       uint8_t seid = PTR_TO_UINT(user_data);
 
-               if (sep->info.seid == seid)
-                       return sep;
-       }
+       return sep->info.seid == seid;
+}
 
-       return NULL;
+static struct avdtp_local_sep *find_local_sep_by_seid(struct avdtp *session,
+                                                               uint8_t seid)
+{
+       return queue_find(session->lseps, match_by_seid, INT_TO_PTR(seid));
 }
 
 struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
@@ -1484,6 +1448,11 @@ struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
                if (codec_data->media_codec_type != lsep->codec)
                        continue;
 
+               if (lsep->ind && lsep->ind->match_codec)
+                       if (!lsep->ind->match_codec(session, codec_data,
+                                                       lsep->user_data))
+                               continue;
+
                if (sep->stream == NULL)
                        return sep;
        }
@@ -1540,15 +1509,23 @@ static gboolean avdtp_unknown_cmd(struct avdtp *session, uint8_t transaction,
                                                        signal_id, NULL, 0);
 }
 
+static void copy_seps(void *data, void *user_data)
+{
+       struct avdtp_local_sep *sep = data;
+       struct seid_info **p = user_data;
+
+       memcpy(*p, &sep->info, sizeof(struct seid_info));
+       *p = *p + 1;
+}
+
 static gboolean avdtp_discover_cmd(struct avdtp *session, uint8_t transaction,
                                                        void *buf, int size)
 {
-       GSList *l;
-       unsigned int rsp_size, sep_count, i;
-       struct seid_info *seps;
+       unsigned int rsp_size, sep_count;
+       struct seid_info *seps, *p;
        gboolean ret;
 
-       sep_count = g_slist_length(session->server->seps);
+       sep_count = queue_length(session->lseps);
 
        if (sep_count == 0) {
                uint8_t err = AVDTP_NOT_SUPPORTED_COMMAND;
@@ -1559,12 +1536,9 @@ static gboolean avdtp_discover_cmd(struct avdtp *session, uint8_t transaction,
        rsp_size = sep_count * sizeof(struct seid_info);
 
        seps = g_new0(struct seid_info, sep_count);
+       p = seps;
 
-       for (l = session->server->seps, i = 0; l != NULL; l = l->next, i++) {
-               struct avdtp_local_sep *sep = l->data;
-
-               memcpy(&seps[i], &sep->info, sizeof(struct seid_info));
-       }
+       queue_foreach(session->lseps, copy_seps, &p);
 
        ret = avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
                                AVDTP_DISCOVER, seps, rsp_size);
@@ -1590,7 +1564,7 @@ static gboolean avdtp_getcap_cmd(struct avdtp *session, uint8_t transaction,
                goto failed;
        }
 
-       sep = find_local_sep_by_seid(session->server, req->acp_seid);
+       sep = find_local_sep_by_seid(session, req->acp_seid);
        if (!sep) {
                err = AVDTP_BAD_ACP_SEID;
                goto failed;
@@ -1667,7 +1641,7 @@ static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction,
                return FALSE;
        }
 
-       sep = find_local_sep_by_seid(session->server, req->acp_seid);
+       sep = find_local_sep_by_seid(session, req->acp_seid);
        if (!sep) {
                err = AVDTP_BAD_ACP_SEID;
                goto failed;
@@ -1782,7 +1756,7 @@ static gboolean avdtp_getconf_cmd(struct avdtp *session, uint8_t transaction,
 
        memset(buf, 0, sizeof(buf));
 
-       sep = find_local_sep_by_seid(session->server, req->acp_seid);
+       sep = find_local_sep_by_seid(session, req->acp_seid);
        if (!sep) {
                err = AVDTP_BAD_ACP_SEID;
                goto failed;
@@ -1898,7 +1872,7 @@ static gboolean avdtp_open_cmd(struct avdtp *session, uint8_t transaction,
                return FALSE;
        }
 
-       sep = find_local_sep_by_seid(session->server, req->acp_seid);
+       sep = find_local_sep_by_seid(session, req->acp_seid);
        if (!sep) {
                err = AVDTP_BAD_ACP_SEID;
                goto failed;
@@ -1958,7 +1932,7 @@ static gboolean avdtp_start_cmd(struct avdtp *session, uint8_t transaction,
        for (i = 0; i < seid_count; i++, seid++) {
                failed_seid = seid->seid;
 
-               sep = find_local_sep_by_seid(session->server,
+               sep = find_local_sep_by_seid(session,
                                        req->first_seid.seid);
                if (!sep || !sep->stream) {
                        err = AVDTP_BAD_ACP_SEID;
@@ -2009,7 +1983,7 @@ static gboolean avdtp_close_cmd(struct avdtp *session, uint8_t transaction,
                return FALSE;
        }
 
-       sep = find_local_sep_by_seid(session->server, req->acp_seid);
+       sep = find_local_sep_by_seid(session, req->acp_seid);
        if (!sep || !sep->stream) {
                err = AVDTP_BAD_ACP_SEID;
                goto failed;
@@ -2070,7 +2044,7 @@ static gboolean avdtp_suspend_cmd(struct avdtp *session, uint8_t transaction,
        for (i = 0; i < seid_count; i++, seid++) {
                failed_seid = seid->seid;
 
-               sep = find_local_sep_by_seid(session->server,
+               sep = find_local_sep_by_seid(session,
                                        req->first_seid.seid);
                if (!sep || !sep->stream) {
                        err = AVDTP_BAD_ACP_SEID;
@@ -2118,7 +2092,7 @@ static gboolean avdtp_abort_cmd(struct avdtp *session, uint8_t transaction,
                return FALSE;
        }
 
-       sep = find_local_sep_by_seid(session->server, req->acp_seid);
+       sep = find_local_sep_by_seid(session, req->acp_seid);
        if (!sep || !sep->stream)
                return TRUE;
 
@@ -2156,7 +2130,7 @@ static gboolean avdtp_delayreport_cmd(struct avdtp *session,
                return FALSE;
        }
 
-       sep = find_local_sep_by_seid(session->server, req->acp_seid);
+       sep = find_local_sep_by_seid(session, req->acp_seid);
        if (!sep || !sep->stream) {
                err = AVDTP_BAD_ACP_SEID;
                goto failed;
@@ -2479,18 +2453,6 @@ failed:
        return FALSE;
 }
 
-static struct avdtp *find_session(GSList *list, struct btd_device *device)
-{
-       for (; list != NULL; list = g_slist_next(list)) {
-               struct avdtp *s = list->data;
-
-               if (s->device == device)
-                       return s;
-       }
-
-       return NULL;
-}
-
 static uint16_t get_version(struct avdtp *session)
 {
        const sdp_record_t *rec;
@@ -2518,46 +2480,6 @@ static uint16_t get_version(struct avdtp *session)
        return ver;
 }
 
-static struct avdtp *avdtp_get_internal(struct btd_device *device)
-{
-       struct avdtp_server *server;
-       struct avdtp *session;
-
-       server = find_server(servers, device_get_adapter(device));
-       if (server == NULL)
-               return NULL;
-
-       session = find_session(server->sessions, device);
-       if (session)
-               return session;
-
-       session = g_new0(struct avdtp, 1);
-
-       session->server = server;
-       session->device = btd_device_ref(device);
-       /* We don't use avdtp_set_state() here since this isn't a state change
-        * but just setting of the initial state */
-       session->state = AVDTP_SESSION_STATE_DISCONNECTED;
-
-       session->version = get_version(session);
-
-       server->sessions = g_slist_append(server->sessions, session);
-
-       return session;
-}
-
-struct avdtp *avdtp_get(struct btd_device *device)
-{
-       struct avdtp *session;
-
-       session = avdtp_get_internal(device);
-
-       if (!session)
-               return NULL;
-
-       return avdtp_ref(session);
-}
-
 static void avdtp_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 {
        struct avdtp *session = user_data;
@@ -2636,102 +2558,39 @@ failed:
                connection_lost(session, err_no);
 }
 
-static void auth_cb(DBusError *derr, void *user_data)
-{
-       struct avdtp *session = user_data;
-       GError *err = NULL;
-
-       if (derr && dbus_error_is_set(derr)) {
-               error("Access denied: %s", derr->message);
-               connection_lost(session, EACCES);
-               return;
-       }
-
-       if (!bt_io_accept(session->io, avdtp_connect_cb, session, NULL,
-                                                               &err)) {
-               error("bt_io_accept: %s", err->message);
-               connection_lost(session, EACCES);
-               g_error_free(err);
-               return;
-       }
-
-       /* This is so that avdtp_connect_cb will know to do the right thing
-        * with respect to the disconnect timer */
-       session->stream_setup = TRUE;
-}
-
-static void avdtp_confirm_cb(GIOChannel *chan, gpointer data)
+struct avdtp *avdtp_new(GIOChannel *chan, struct btd_device *device,
+                                                       struct queue *lseps)
 {
        struct avdtp *session;
-       char address[18];
-       bdaddr_t src, dst;
-       GError *err = NULL;
-       struct btd_device *device;
-
-       bt_io_get(chan, &err,
-                       BT_IO_OPT_SOURCE_BDADDR, &src,
-                       BT_IO_OPT_DEST_BDADDR, &dst,
-                       BT_IO_OPT_DEST, address,
-                       BT_IO_OPT_INVALID);
-       if (err) {
-               error("%s", err->message);
-               g_error_free(err);
-               goto drop;
-       }
 
-       DBG("AVDTP: incoming connect from %s", address);
-
-       device = btd_adapter_find_device(adapter_find(&src), &dst,
-                                                               BDADDR_BREDR);
-       if (!device)
-               goto drop;
+       session = g_new0(struct avdtp, 1);
 
-       session = avdtp_get_internal(device);
-       if (!session)
-               goto drop;
+       session->device = btd_device_ref(device);
+       /* We don't use avdtp_set_state() here since this isn't a state change
+        * but just setting of the initial state */
+       session->state = AVDTP_SESSION_STATE_DISCONNECTED;
+       session->lseps = lseps;
 
-       /* This state (ie, session is already *connecting*) happens when the
-        * device initiates a connect (really a config'd L2CAP channel) even
-        * though there is a connect we initiated in progress. In sink.c &
-        * source.c, this state is referred to as XCASE connect:connect.
-        * Abort the device's channel in favor of our own.
-        */
-       if (session->state == AVDTP_SESSION_STATE_CONNECTING) {
-               DBG("connect already in progress (XCASE connect:connect)");
-               goto drop;
-       }
+       session->version = get_version(session);
 
-       if (session->pending_open && session->pending_open->open_acp) {
-               if (!bt_io_accept(chan, avdtp_connect_cb, session, NULL, NULL))
-                       goto drop;
-               return;
-       }
+       if (!chan)
+               return session;
 
-       if (session->io) {
-               error("Refusing unexpected connect from %s", address);
-               goto drop;
-       }
+       avdtp_set_state(session, AVDTP_SESSION_STATE_CONNECTING);
 
        btd_device_add_uuid(device, ADVANCED_AUDIO_UUID);
 
        session->io = g_io_channel_ref(chan);
-       avdtp_set_state(session, AVDTP_SESSION_STATE_CONNECTING);
-
        session->io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
                                        (GIOFunc) session_cb, session);
 
-       session->auth_id = btd_request_authorization(&src, &dst,
-                                                       ADVANCED_AUDIO_UUID,
-                                                       auth_cb, session, 0);
-       if (session->auth_id == 0) {
-               avdtp_set_state(session, AVDTP_SESSION_STATE_DISCONNECTED);
-               goto drop;
-       }
+       /* This is so that avdtp_connect_cb will know to do the right thing
+        * with respect to the disconnect timer */
+       session->stream_setup = TRUE;
 
-       return;
+       avdtp_connect_cb(chan, NULL, session);
 
-drop:
-       g_io_channel_shutdown(chan, TRUE, NULL);
+       return session;
 }
 
 static GIOChannel *l2cap_connect(struct avdtp *session)
@@ -2740,7 +2599,7 @@ static GIOChannel *l2cap_connect(struct avdtp *session)
        GIOChannel *io;
        const bdaddr_t *src;
 
-       src = btd_adapter_get_address(session->server->adapter);
+       src = btd_adapter_get_address(device_get_adapter(session->device));
 
        io = bt_io_connect(avdtp_connect_cb, session,
                                NULL, &err,
@@ -3446,6 +3305,23 @@ struct avdtp_remote_sep *avdtp_stream_get_remote_sep(
        return NULL;
 }
 
+gboolean avdtp_stream_set_transport(struct avdtp_stream *stream, int fd,
+                                               size_t imtu, size_t omtu)
+{
+       GIOChannel *io;
+
+       if (stream != stream->session->pending_open)
+               return FALSE;
+
+       io = g_io_channel_unix_new(fd);
+
+       handle_transport_connect(stream->session, io, imtu, omtu);
+
+       g_io_channel_unref(io);
+
+       return TRUE;
+}
+
 gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock,
                                        uint16_t *imtu, uint16_t *omtu,
                                        GSList **caps)
@@ -3872,48 +3748,7 @@ int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
                                                        &req, sizeof(req));
 }
 
-static GIOChannel *avdtp_server_socket(const bdaddr_t *src, gboolean master)
-{
-       GError *err = NULL;
-       GIOChannel *io;
-
-       io = bt_io_listen(NULL, avdtp_confirm_cb,
-                               NULL, NULL, &err,
-                               BT_IO_OPT_SOURCE_BDADDR, src,
-                               BT_IO_OPT_PSM, AVDTP_PSM,
-                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
-                               BT_IO_OPT_MASTER, master,
-                               BT_IO_OPT_INVALID);
-       if (!io) {
-               error("%s", err->message);
-               g_error_free(err);
-       }
-
-       return io;
-}
-
-static struct avdtp_server *avdtp_server_init(struct btd_adapter *adapter)
-{
-       struct avdtp_server *server;
-
-       server = g_new0(struct avdtp_server, 1);
-
-       server->io = avdtp_server_socket(btd_adapter_get_address(adapter),
-                                                                       TRUE);
-       if (!server->io) {
-               g_free(server);
-               return NULL;
-       }
-
-       server->adapter = btd_adapter_ref(adapter);
-
-       servers = g_slist_append(servers, server);
-
-       return server;
-}
-
-struct avdtp_local_sep *avdtp_register_sep(struct btd_adapter *adapter,
-                                               uint8_t type,
+struct avdtp_local_sep *avdtp_register_sep(struct queue *lseps, uint8_t type,
                                                uint8_t media_type,
                                                uint8_t codec_type,
                                                gboolean delay_reporting,
@@ -3921,74 +3756,50 @@ struct avdtp_local_sep *avdtp_register_sep(struct btd_adapter *adapter,
                                                struct avdtp_sep_cfm *cfm,
                                                void *user_data)
 {
-       struct avdtp_server *server;
        struct avdtp_local_sep *sep;
+       uint8_t seid = util_get_uid(&seids, MAX_SEID);
 
-       server = find_server(servers, adapter);
-       if (!server) {
-               server = avdtp_server_init(adapter);
-               if (!server)
-                       return NULL;
-       }
-
-       if (g_slist_length(server->seps) > MAX_SEID)
+       if (!seid)
                return NULL;
 
        sep = g_new0(struct avdtp_local_sep, 1);
 
        sep->state = AVDTP_STATE_IDLE;
-       sep->info.seid = g_slist_length(server->seps) + 1;
+       sep->info.seid = seid;
        sep->info.type = type;
        sep->info.media_type = media_type;
        sep->codec = codec_type;
        sep->ind = ind;
        sep->cfm = cfm;
        sep->user_data = user_data;
-       sep->server = server;
-       sep->delay_reporting = TRUE;
+       sep->delay_reporting = delay_reporting;
 
        DBG("SEP %p registered: type:%d codec:%d seid:%d", sep,
                        sep->info.type, sep->codec, sep->info.seid);
-       server->seps = g_slist_append(server->seps, sep);
 
-       return sep;
-}
-
-static void avdtp_server_destroy(struct avdtp_server *server)
-{
-       g_slist_free_full(server->sessions, avdtp_free);
-
-       servers = g_slist_remove(servers, server);
+       if (!queue_push_tail(lseps, sep)) {
+               g_free(sep);
+               return NULL;
+       }
 
-       g_io_channel_shutdown(server->io, TRUE, NULL);
-       g_io_channel_unref(server->io);
-       btd_adapter_unref(server->adapter);
-       g_free(server);
+       return sep;
 }
 
-int avdtp_unregister_sep(struct avdtp_local_sep *sep)
+int avdtp_unregister_sep(struct queue *lseps, struct avdtp_local_sep *sep)
 {
-       struct avdtp_server *server;
-
        if (!sep)
                return -EINVAL;
 
-       server = sep->server;
-       server->seps = g_slist_remove(server->seps, sep);
-
        if (sep->stream)
                release_stream(sep->stream, sep->stream->session);
 
        DBG("SEP %p unregistered: type:%d codec:%d seid:%d", sep,
                        sep->info.type, sep->codec, sep->info.seid);
 
+       util_clear_uid(&seids, sep->info.seid);
+       queue_remove(lseps, sep);
        g_free(sep);
 
-       if (server->seps)
-               return 0;
-
-       avdtp_server_destroy(server);
-
        return 0;
 }
 
@@ -4044,7 +3855,7 @@ avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep)
 
 struct btd_adapter *avdtp_get_adapter(struct avdtp *session)
 {
-       return session->server->adapter;
+       return device_get_adapter(session->device);
 }
 
 struct btd_device *avdtp_get_device(struct avdtp *session)
index fba5fe3..ec0b9f1 100644 (file)
@@ -29,6 +29,7 @@ typedef enum {
 } avdtp_session_state_t;
 
 struct avdtp;
+struct avdtp_server;
 struct avdtp_stream;
 struct avdtp_local_sep;
 struct avdtp_remote_sep;
@@ -171,6 +172,9 @@ struct avdtp_sep_cfm {
 /* Callbacks for indicating when we received a new command. The return value
  * indicates whether the command should be rejected or accepted */
 struct avdtp_sep_ind {
+       gboolean (*match_codec) (struct avdtp *session,
+                               struct avdtp_media_codec_capability *codec,
+                               void *user_data);
        gboolean (*get_capability) (struct avdtp *session,
                                        struct avdtp_local_sep *sep,
                                        gboolean get_all,
@@ -213,8 +217,6 @@ struct avdtp_sep_ind {
 typedef void (*avdtp_discover_cb_t) (struct avdtp *session, GSList *seps,
                                        struct avdtp_error *err, void *user_data);
 
-struct avdtp *avdtp_get(struct btd_device *device);
-
 void avdtp_unref(struct avdtp *session);
 struct avdtp *avdtp_ref(struct avdtp *session);
 
@@ -239,6 +241,8 @@ gboolean avdtp_stream_remove_cb(struct avdtp *session,
                                struct avdtp_stream *stream,
                                unsigned int id);
 
+gboolean avdtp_stream_set_transport(struct avdtp_stream *stream, int fd,
+                                               size_t imtu, size_t omtu);
 gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock,
                                        uint16_t *imtu, uint16_t *omtu,
                                        GSList **caps);
@@ -272,8 +276,7 @@ int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream);
 int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
                                                        uint16_t delay);
 
-struct avdtp_local_sep *avdtp_register_sep(struct btd_adapter *adapter,
-                                               uint8_t type,
+struct avdtp_local_sep *avdtp_register_sep(struct queue *lseps, uint8_t type,
                                                uint8_t media_type,
                                                uint8_t codec_type,
                                                gboolean delay_reporting,
@@ -285,7 +288,7 @@ struct avdtp_local_sep *avdtp_register_sep(struct btd_adapter *adapter,
 struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session,
                                                struct avdtp_local_sep *lsep);
 
-int avdtp_unregister_sep(struct avdtp_local_sep *sep);
+int avdtp_unregister_sep(struct queue *lseps, struct avdtp_local_sep *sep);
 
 avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep);
 
@@ -297,3 +300,7 @@ int avdtp_error_posix_errno(struct avdtp_error *err);
 
 struct btd_adapter *avdtp_get_adapter(struct avdtp *session);
 struct btd_device *avdtp_get_device(struct avdtp *session);
+struct avdtp_server *avdtp_get_server(struct avdtp_local_sep *lsep);
+
+struct avdtp *avdtp_new(GIOChannel *chan, struct btd_device *device,
+                                                       struct queue *lseps);
index 90fd5d5..891540c 100644 (file)
 #include <sys/stat.h>
 #include <fcntl.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
 
+#include "bluetooth/bluetooth.h"
+#include "bluetooth/sdp.h"
+#include "bluetooth/sdp_lib.h"
 #include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
+
 #include "src/plugin.h"
 #include "src/adapter.h"
 #include "src/device.h"
 #include "src/profile.h"
 #include "src/service.h"
-
 #include "src/log.h"
 #include "src/error.h"
 #include "src/sdpd.h"
@@ -257,7 +257,8 @@ struct control_pdu_handler {
 static GSList *servers = NULL;
 static unsigned int avctp_id = 0;
 #ifdef __TIZEN_PATCH__
-static uint16_t adapter_avrcp_ver = 0;
+static uint16_t adapter_avrcp_tg_ver = 0;
+static uint16_t adapter_avrcp_ct_ver = 0;
 #endif
 
 /* Company IDs supported by this device */
@@ -282,12 +283,23 @@ static sdp_record_t *avrcp_ct_record(void)
        sdp_record_t *record;
        sdp_data_t *psm[2], *version, *features;
        uint16_t lp = AVCTP_CONTROL_PSM, ap = AVCTP_BROWSING_PSM;
+#ifdef __TIZEN_PATCH__
+       uint16_t avrcp_ver = 0x0103, avctp_ver = 0x0104;
+       uint16_t feat = 0;
+#ifdef ENABLE_AVRCP_CATEGORY1
+       feat = AVRCP_FEATURE_CATEGORY_1;
+#endif
+#ifdef ENABLE_AVRCP_CATEGORY2
+       feat = feat | AVRCP_FEATURE_CATEGORY_2;
+#endif
+#else
        uint16_t avrcp_ver = 0x0105, avctp_ver = 0x0103;
        uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 |
                                                AVRCP_FEATURE_CATEGORY_2 |
                                                AVRCP_FEATURE_CATEGORY_3 |
                                                AVRCP_FEATURE_CATEGORY_4 |
                                                AVRCP_FEATURE_BROWSING);
+#endif
 
        record = sdp_record_alloc();
        if (!record)
@@ -338,6 +350,9 @@ static sdp_record_t *avrcp_ct_record(void)
        /* Bluetooth Profile Descriptor List */
        sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
        profile[0].version = avrcp_ver;
+#ifdef __TIZEN_PATCH__
+       adapter_avrcp_ct_ver = avrcp_ver;
+#endif
        pfseq = sdp_list_append(NULL, &profile[0]);
        sdp_set_profile_descs(record, pfseq);
 
@@ -372,13 +387,22 @@ static sdp_record_t *avrcp_tg_record(void)
        sdp_list_t *aproto_control, *proto_control[2];
        sdp_record_t *record;
        sdp_data_t *psm_control, *version, *features, *psm_browsing;
-       sdp_list_t *aproto_browsing, *proto_browsing[2] = {0};
+#ifndef __TIZEN_PATCH__
+       sdp_list_t *aproto_browsing;
+#endif
+       sdp_list_t *proto_browsing[2] = {0};
        uint16_t lp = AVCTP_CONTROL_PSM;
        uint16_t lp_browsing = AVCTP_BROWSING_PSM;
 #ifdef __TIZEN_PATCH__
        uint16_t avrcp_ver = 0x0103, avctp_ver = 0x0104;
-       uint16_t feat = AVRCP_FEATURE_CATEGORY_1 |
-                                       AVRCP_FEATURE_PLAYER_SETTINGS;
+       uint16_t feat = 0;
+#ifdef ENABLE_AVRCP_CATEGORY1
+       feat = AVRCP_FEATURE_CATEGORY_1 |
+               AVRCP_FEATURE_PLAYER_SETTINGS;
+#endif
+#ifdef ENABLE_AVRCP_CATEGORY2
+       feat = feat | AVRCP_FEATURE_CATEGORY_2;
+#endif
 #else
        uint16_t avrcp_ver = 0x0104, avctp_ver = 0x0103;
        uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 |
@@ -434,7 +458,7 @@ static sdp_record_t *avrcp_tg_record(void)
        sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
        profile[0].version = avrcp_ver;
 #ifdef __TIZEN_PATCH__
-       adapter_avrcp_ver = avrcp_ver;
+       adapter_avrcp_tg_ver = avrcp_ver;
 #endif
        pfseq = sdp_list_append(NULL, &profile[0]);
        sdp_set_profile_descs(record, pfseq);
@@ -448,7 +472,9 @@ static sdp_record_t *avrcp_tg_record(void)
        sdp_list_free(proto_browsing[0], NULL);
        sdp_list_free(proto_browsing[1], NULL);
        sdp_list_free(apseq_browsing, NULL);
+#ifndef __TIZEN_PATCH__
        sdp_list_free(aproto_browsing, NULL);
+#endif
 
        free(psm_control);
        free(version);
@@ -3409,10 +3435,12 @@ static gboolean avrcp_get_capabilities_resp(struct avctp *conn,
                case AVRCP_EVENT_STATUS_CHANGED:
                case AVRCP_EVENT_TRACK_CHANGED:
                case AVRCP_EVENT_SETTINGS_CHANGED:
+#ifndef __TIZEN_PATCH__
                case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
                case AVRCP_EVENT_UIDS_CHANGED:
                case AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED:
                case AVRCP_EVENT_VOLUME_CHANGED:
+#endif
                        avrcp_register_notification(session, event);
                        break;
                }
@@ -3578,7 +3606,7 @@ static void target_init(struct avrcp *session)
                return;
 
 #ifdef __TIZEN_PATCH__
-       if (adapter_avrcp_ver < 0x0104)
+       if (adapter_avrcp_tg_ver < 0x0104)
                return;
 #endif
 
@@ -3602,12 +3630,24 @@ static void controller_init(struct avrcp *session)
                return;
 
        controller = data_init(session, AVRCP_TARGET_UUID);
+#ifdef __TIZEN_PATCH__
+       /* Fix : NULL_RETURNS */
+       if (controller == NULL) {
+               error("controller is NULL");
+               return;
+       }
+#endif
        session->controller = controller;
 
        DBG("%p version 0x%04x", controller, controller->version);
 
+#ifdef __TIZEN_PATCH__
+       if ((controller->version >= 0x0104) && (adapter_avrcp_ct_ver >= 0x0104))
+               session->supported_events |= (1 << AVRCP_EVENT_VOLUME_CHANGED);
+#else
        if (controller->version >= 0x0104)
                session->supported_events |= (1 << AVRCP_EVENT_VOLUME_CHANGED);
+#endif
 
        service = btd_device_get_service(session->dev, AVRCP_TARGET_UUID);
        if (service != NULL)
@@ -3629,6 +3669,11 @@ static void controller_init(struct avrcp *session)
        if (controller->version < 0x0104)
                return;
 
+#ifdef __TIZEN_PATCH__
+       if (adapter_avrcp_ct_ver < 0x0104)
+               return;
+#endif
+
        if (!(controller->features & AVRCP_FEATURE_BROWSING))
                return;
 
@@ -4031,12 +4076,8 @@ done:
 
 static struct btd_profile avrcp_target_profile = {
        .name           = "audio-avrcp-target",
-       .version        = 0x0105,
 
        .remote_uuid    = AVRCP_TARGET_UUID,
-       .local_uuid     = AVRCP_REMOTE_UUID,
-       .auth_uuid      = AVRCP_REMOTE_UUID,
-
        .device_probe   = avrcp_target_probe,
        .device_remove  = avrcp_target_remove,
 
@@ -4118,12 +4159,8 @@ done:
 
 static struct btd_profile avrcp_controller_profile = {
        .name           = "avrcp-controller",
-       .version        = 0x0104,
 
        .remote_uuid    = AVRCP_REMOTE_UUID,
-       .local_uuid     = AVRCP_TARGET_UUID,
-       .auth_uuid      = AVRCP_REMOTE_UUID,
-
        .device_probe   = avrcp_controller_probe,
        .device_remove  = avrcp_controller_remove,
 
@@ -4135,16 +4172,31 @@ static struct btd_profile avrcp_controller_profile = {
 
 static int avrcp_init(void)
 {
+#ifdef __TIZEN_PATCH__
+#ifdef SUPPORT_AVRCP_CONTROL
        btd_profile_register(&avrcp_controller_profile);
+#else
        btd_profile_register(&avrcp_target_profile);
-
+#endif
+#else
+       btd_profile_register(&avrcp_controller_profile);
+       btd_profile_register(&avrcp_target_profile);
+#endif
        return 0;
 }
 
 static void avrcp_exit(void)
 {
+#ifdef __TIZEN_PATCH__
+#ifdef SUPPORT_AVRCP_CONTROL
+       btd_profile_unregister(&avrcp_controller_profile);
+#else
+       btd_profile_unregister(&avrcp_target_profile);
+#endif
+#else
        btd_profile_unregister(&avrcp_controller_profile);
        btd_profile_unregister(&avrcp_target_profile);
+#endif
 }
 
 BLUETOOTH_PLUGIN_DEFINE(avrcp, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
index 3985362..9110b0f 100644 (file)
 #include <sys/stat.h>
 #include <fcntl.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 #include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
+
 #include "src/adapter.h"
 #include "src/device.h"
 #include "src/profile.h"
 #include "src/service.h"
-
 #include "src/log.h"
 #include "src/error.h"
 #include "src/sdpd.h"
index d13e76d..e9e4da9 100644 (file)
 #include <inttypes.h>
 
 #include <glib.h>
-#include <gdbus/gdbus.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
+
 #include "src/plugin.h"
 #include "src/adapter.h"
 #include "src/device.h"
 #include "src/dbus-common.h"
 #include "src/profile.h"
 
+#ifdef __TIZEN_PATCH__
+#include "src/service.h"
+#endif
+
 #include "src/uuid-helper.h"
 #include "src/log.h"
 #include "src/error.h"
+#include "src/shared/queue.h"
 
 #include "avdtp.h"
 #include "media.h"
@@ -270,7 +279,7 @@ static void clear_configuration(struct media_endpoint *endpoint,
 done:
        endpoint->transports = g_slist_remove(endpoint->transports, transport);
 #ifdef __TIZEN_PATCH__
-       if (mp = media_adapter_get_player(endpoint->adapter))
+       if ((mp = media_adapter_get_player(endpoint->adapter)))
                if (mp->sink_watch) {
                        sink_remove_state_cb(mp->sink_watch);
                        mp->sink_watch = 0;
@@ -309,9 +318,6 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data)
 
                /* Clear endpoint configuration in case of NO_REPLY error */
                if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
-                       if (request->cb)
-                               request->cb(endpoint, NULL, size,
-                                                       request->user_data);
                        clear_endpoint(endpoint);
                        dbus_message_unref(reply);
                        dbus_error_free(&err);
@@ -604,7 +610,7 @@ static gboolean set_configuration(struct media_endpoint *endpoint,
 #ifdef __TIZEN_PATCH__
        set_avrcp_status = FALSE;
        adapter = find_adapter(device);
-       if (mp = media_adapter_get_player(adapter))
+       if ((mp = media_adapter_get_player(adapter)))
                media_set_sink_callback(device, mp);
 #endif
 
@@ -1286,6 +1292,11 @@ static uint64_t get_uid(void *user_data)
        if (mp->track == NULL)
                return UINT64_MAX;
 
+#ifdef __TIZEN_PATCH__
+       if (!g_hash_table_lookup(mp->track, "Title"))
+               return UINT64_MAX;
+#endif
+
        return 0;
 }
 
index 168e677..94eb2eb 100644 (file)
@@ -36,7 +36,8 @@
 
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
+
+#include "gdbus/gdbus.h"
 
 #include "src/log.h"
 #include "src/dbus-common.h"
index 994d4fe..78a6887 100644 (file)
 #include <stdbool.h>
 #include <errno.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
 
-#include "src/log.h"
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 
+#include "gdbus/gdbus.h"
+
+#include "src/log.h"
 #include "src/adapter.h"
 #include "src/device.h"
 #include "src/service.h"
 #include "src/error.h"
 #include "src/dbus-common.h"
+#include "src/shared/queue.h"
 
 #include "avdtp.h"
 #include "media.h"
@@ -298,7 +299,7 @@ int sink_connect(struct btd_service *service)
 
 #ifndef __TIZEN_PATCH__
        if (!sink->session)
-               sink->session = avdtp_get(btd_service_get_device(service));
+               sink->session = a2dp_avdtp_get(btd_service_get_device(service));
 
        if (!sink->session) {
                DBG("Unable to get a session");
@@ -317,7 +318,7 @@ int sink_connect(struct btd_service *service)
 
 #ifdef __TIZEN_PATCH__
        if (!sink->session)
-               sink->session = avdtp_get(btd_service_get_device(service));
+               sink->session = a2dp_avdtp_get(btd_service_get_device(service));
 
        if (!sink->session) {
                DBG("Unable to get a session");
index aca2fcb..b235a7d 100644 (file)
 #include <stdbool.h>
 #include <errno.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
 
-#include "src/log.h"
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 
+#include "gdbus/gdbus.h"
+
+#include "src/log.h"
 #include "src/adapter.h"
 #include "src/device.h"
 #include "src/service.h"
 #include "src/error.h"
 #include "src/dbus-common.h"
+#include "src/shared/queue.h"
 
 #include "avdtp.h"
 #include "media.h"
@@ -283,7 +284,7 @@ int source_connect(struct btd_service *service)
        struct source *source = btd_service_get_user_data(service);
 
        if (!source->session)
-               source->session = avdtp_get(btd_service_get_device(service));
+               source->session = a2dp_avdtp_get(btd_service_get_device(service));
 
        if (!source->session) {
                DBG("Unable to get a session");
index c82fbb5..112ec17 100644 (file)
 #include <errno.h>
 
 #include <glib.h>
-#include <gdbus/gdbus.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
+
 #include "src/adapter.h"
 #include "src/device.h"
 #include "src/dbus-common.h"
 
 #include "src/log.h"
 #include "src/error.h"
+#include "src/shared/queue.h"
 
 #include "avdtp.h"
 #include "media.h"
@@ -332,7 +337,7 @@ static guint resume_a2dp(struct media_transport *transport,
        guint id;
 
        if (a2dp->session == NULL) {
-               a2dp->session = avdtp_get(transport->device);
+               a2dp->session = a2dp_avdtp_get(transport->device);
                if (a2dp->session == NULL)
                        return 0;
        }
index a93dda0..edaa2cd 100644 (file)
 #include <string.h>
 #include <signal.h>
 #include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
 #include <netinet/in.h>
 
+#include "lib/bluetooth.h"
+#include "lib/l2cap.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+
 #include "cups.h"
 
 #define HCRP_PDU_CREDIT_GRANT          0x0001
index 11ce72f..d46f35e 100644 (file)
 #include <assert.h>
 #include <signal.h>
 #include <sys/socket.h>
+
 #include <glib.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 
-#include <gdbus/gdbus.h>
+#include "gdbus/gdbus.h"
 
 #include "cups.h"
 
index c7f17a4..de9cd4e 100644 (file)
@@ -31,9 +31,9 @@
 #include <signal.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 
 #include "cups.h"
 
index d906ed2..2f1e270 100644 (file)
 #include <signal.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/rfcomm.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 
 #include "cups.h"
 
index 6b00da7..e447725 100644 (file)
 
 #include <errno.h>
 #include <stdbool.h>
+
 #include <glib.h>
-#include <gdbus/gdbus.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
+
 #include "src/plugin.h"
 #include "src/adapter.h"
 #include "src/device.h"
index 208598a..a0e9951 100644 (file)
 
 #include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
 #include "src/plugin.h"
 #include "src/adapter.h"
 #include "src/device.h"
index 01b6ec2..819a967 100644 (file)
 
 #include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
 #include "src/shared/util.h"
 #include "src/shared/att.h"
 #include "src/shared/queue.h"
 #include "src/service.h"
 #include "src/log.h"
 
+#define GAP_UUID16 0x1800
+
 /* Generic Attribute/Access Service */
 struct gas {
        struct btd_device *device;
        struct gatt_db *db;
+       unsigned int db_id;
        struct bt_gatt_client *client;
-       uint16_t start_handle, end_handle;
+       struct gatt_db_attribute *attr;
 };
 
 static GSList *devices;
 
 static void gas_free(struct gas *gas)
 {
-       btd_device_unref(gas->device);
+       gatt_db_unregister(gas->db, gas->db_id);
        gatt_db_unref(gas->db);
        bt_gatt_client_unref(gas->client);
+       btd_device_unref(gas->device);
        g_free(gas);
 }
 
@@ -69,7 +77,7 @@ static int cmp_device(gconstpointer a, gconstpointer b)
        return gas->device == device ? 0 : -1;
 }
 
-static char *name2utf8(const uint8_t *name, uint8_t len)
+static char *name2utf8(const uint8_t *name, uint16_t len)
 {
        char utf8_name[HCI_MAX_NAME_LENGTH + 2];
        int i;
@@ -77,6 +85,8 @@ static char *name2utf8(const uint8_t *name, uint8_t len)
        if (g_utf8_validate((const char *) name, len, NULL))
                return g_strndup((char *) name, len);
 
+       len = MIN(len, sizeof(utf8_name) - 1);
+
        memset(utf8_name, 0, sizeof(utf8_name));
        strncpy(utf8_name, (char *) name, len);
 
@@ -97,7 +107,18 @@ static void read_device_name_cb(bool success, uint8_t att_ecode,
                                        void *user_data)
 {
        struct gas *gas = user_data;
-       char *name = name2utf8(value, length);
+       char *name;
+
+       if (!success) {
+               DBG("Reading device name failed with ATT errror: %u",
+                                                               att_ecode);
+               return;
+       }
+
+       if (!length)
+               return;
+
+       name = name2utf8(value, length);
 
        DBG("GAP Device Name: %s", name);
 
@@ -183,48 +204,31 @@ static void handle_characteristic(struct gatt_db_attribute *attr,
 
 static void handle_gap_service(struct gas *gas)
 {
-       struct gatt_db_attribute *attr;
-
-       attr = gatt_db_get_attribute(gas->db, gas->start_handle);
-       if (!attr) {
-               error("Service with handle 0x%04x not found in db",
-                                                       gas->start_handle);
-               return;
-       }
-
-       gatt_db_service_foreach_char(attr, handle_characteristic, gas);
+       gatt_db_service_foreach_char(gas->attr, handle_characteristic, gas);
 }
 
 static int gap_driver_probe(struct btd_service *service)
 {
        struct btd_device *device = btd_service_get_device(service);
        struct gas *gas;
-       uint16_t start_handle, end_handle;
        GSList *l;
        char addr[18];
 
-       if (!btd_service_get_gatt_handles(service, &start_handle, &end_handle))
-               return -1;
-
        ba2str(device_get_address(device), addr);
-       DBG("GAP profile probe (%s): start: 0x%04x, end 0x%04x", addr,
-                                               start_handle, end_handle);
+       DBG("GAP profile probe (%s)", addr);
 
-       /*
-        * There can't be more than one instance of the GAP service on the same
-        * device.
-        */
+       /* Ignore, if we were probed for this device already */
        l = g_slist_find_custom(devices, device, cmp_device);
        if (l) {
-               error("More than one GAP service exists on device");
+               error("Profile probed twice for the same device!");
                return -1;
        }
 
        gas = g_new0(struct gas, 1);
+       if (!gas)
+               return -1;
 
        gas->device = btd_device_ref(device);
-       gas->start_handle = start_handle;
-       gas->end_handle = end_handle;
        devices = g_slist_append(devices, gas);
 
        return 0;
@@ -234,19 +238,11 @@ static void gap_driver_remove(struct btd_service *service)
 {
        struct btd_device *device = btd_service_get_device(service);
        struct gas *gas;
-       uint16_t start_handle, end_handle;
        GSList *l;
        char addr[18];
 
-       if (!btd_service_get_gatt_handles(service, &start_handle,
-                                                               &end_handle)) {
-               error("Removed service is not a GATT service");
-               return;
-       }
-
        ba2str(device_get_address(device), addr);
-       DBG("GAP profile remove (%s): start: 0x%04x, end 0x%04x", addr,
-                                               start_handle, end_handle);
+       DBG("GAP profile remove (%s)", addr);
 
        l = g_slist_find_custom(devices, device, cmp_device);
        if (!l) {
@@ -256,14 +252,58 @@ static void gap_driver_remove(struct btd_service *service)
 
        gas = l->data;
 
-       if (gas->start_handle != start_handle ||
-                                               gas->end_handle != end_handle) {
-               error("Removed unknown GAP service");
+       devices = g_slist_remove(devices, gas);
+       gas_free(gas);
+}
+
+static void foreach_gap_service(struct gatt_db_attribute *attr, void *user_data)
+{
+       struct gas *gas = user_data;
+
+       if (gas->attr) {
+               error("More than one GAP service exists for this device");
                return;
        }
 
-       devices = g_slist_remove(devices, gas);
-       gas_free(gas);
+       gas->attr = attr;
+       handle_gap_service(gas);
+}
+
+static void service_added(struct gatt_db_attribute *attr, void *user_data)
+{
+       struct gas *gas = user_data;
+       bt_uuid_t uuid, gap_uuid;
+
+       if (!bt_gatt_client_is_ready(gas->client))
+               return;
+
+       gatt_db_attribute_get_service_uuid(attr, &uuid);
+       bt_uuid16_create(&gap_uuid, GAP_UUID16);
+
+       if (bt_uuid_cmp(&uuid, &gap_uuid))
+               return;
+
+       if (gas->attr) {
+               error("More than one GAP service added to device");
+               return;
+       }
+
+       DBG("GAP service added");
+
+       gas->attr = attr;
+       handle_gap_service(gas);
+}
+
+static void service_removed(struct gatt_db_attribute *attr, void *user_data)
+{
+       struct gas *gas = user_data;
+
+       if (gas->attr != attr)
+               return;
+
+       DBG("GAP service removed");
+
+       gas->attr = NULL;
 }
 
 static int gap_driver_accept(struct btd_service *service)
@@ -272,19 +312,12 @@ static int gap_driver_accept(struct btd_service *service)
        struct gatt_db *db = btd_device_get_gatt_db(device);
        struct bt_gatt_client *client = btd_device_get_gatt_client(device);
        struct gas *gas;
-       uint16_t start_handle, end_handle;
        GSList *l;
        char addr[18];
-
-       if (!btd_service_get_gatt_handles(service, &start_handle,
-                                                               &end_handle)) {
-               error("Service is not a GATT service");
-               return -1;
-       }
+       bt_uuid_t gap_uuid;
 
        ba2str(device_get_address(device), addr);
-       DBG("GAP profile accept (%s): start: 0x%04x, end 0x%04x", addr,
-                                               start_handle, end_handle);
+       DBG("GAP profile accept (%s)", addr);
 
        l = g_slist_find_custom(devices, device, cmp_device);
        if (!l) {
@@ -294,21 +327,20 @@ static int gap_driver_accept(struct btd_service *service)
 
        gas = l->data;
 
-       if (gas->start_handle != start_handle ||
-                                               gas->end_handle != end_handle) {
-               error("Accepting unknown GAP service");
-               return -1;
-       }
-
        /* Clean-up any old client/db and acquire the new ones */
+       gas->attr = NULL;
+       gatt_db_unregister(gas->db, gas->db_id);
        gatt_db_unref(gas->db);
        bt_gatt_client_unref(gas->client);
 
        gas->db = gatt_db_ref(db);
        gas->client = bt_gatt_client_ref(client);
+       gas->db_id = gatt_db_register(db, service_added, service_removed, gas,
+                                                                       NULL);
 
-       /* Handle the service */
-       handle_gap_service(gas);
+       /* Handle the GAP services */
+       bt_uuid16_create(&gap_uuid, GAP_UUID16);
+       gatt_db_foreach_service(db, &gap_uuid, foreach_gap_service, gas);
 
        return 0;
 }
index c1ce1b8..bc3b38a 100644 (file)
 
 #include <glib.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/l2cap.h>
-#include <gdbus/gdbus.h>
+#include "lib/bluetooth.h"
+#include "lib/l2cap.h"
+#include "lib/sdp.h"
+
+#include "gdbus/gdbus.h"
+
 #include "src/dbus-common.h"
 #include "src/log.h"
 #include "src/error.h"
index 6dc9acf..2c4bbe2 100644 (file)
 #endif
 
 #include <errno.h>
-#include <gdbus/gdbus.h>
 
-#include "src/plugin.h"
+#include "gdbus/gdbus.h"
 
+#include "src/plugin.h"
 #include "hdp_manager.h"
 
 static int hdp_init(void)
index 95ee7ac..401adf6 100644 (file)
 
 #include <stdbool.h>
 
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+#include "lib/uuid.h"
 
 #include "btio/btio.h"
-#include "lib/uuid.h"
 #include "src/adapter.h"
 #include "src/device.h"
 #include "src/profile.h"
@@ -70,10 +70,7 @@ static void hdp_driver_remove(struct btd_service *service)
 
 static struct btd_profile hdp_source_profile = {
        .name           = "hdp-source",
-       .version        = 0x0100,
-
        .remote_uuid    = HDP_SOURCE_UUID,
-       .local_uuid     = HDP_SINK_UUID,
 
        .device_probe   = hdp_driver_probe,
        .device_remove  = hdp_driver_remove,
@@ -84,10 +81,7 @@ static struct btd_profile hdp_source_profile = {
 
 static struct btd_profile hdp_sink_profile = {
        .name           = "hdp-sink",
-       .version        = 0x0100,
-
        .remote_uuid    = HDP_SINK_UUID,
-       .local_uuid     = HDP_SOURCE_UUID,
 
        .device_probe   = hdp_driver_probe,
        .device_remove  = hdp_driver_remove,
index af50b01..b459eaa 100644 (file)
 
 #include <glib.h>
 
-#include <gdbus/gdbus.h>
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+#include "lib/uuid.h"
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include "gdbus/gdbus.h"
 
+#include "btio/btio.h"
 #include "src/adapter.h"
 #include "src/device.h"
-
 #include "src/sdpd.h"
 #include "src/sdp-client.h"
 #include "src/uuid-helper.h"
-
-#include "lib/uuid.h"
-#include "btio/btio.h"
-
 #include "src/log.h"
 #include "src/dbus-common.h"
 
index 287ea72..9e8c499 100644 (file)
 #include <errno.h>
 #include <stdbool.h>
 #include <glib.h>
-#include <gdbus/gdbus.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
+
 #include "src/plugin.h"
 #include "src/adapter.h"
 #include "src/dbus-common.h"
index 0e8f43f..53dd9fb 100644 (file)
@@ -35,7 +35,8 @@
 #include <sys/signalfd.h>
 
 #include <glib.h>
-#include <gdbus.h>
+
+#include "gdbus/gdbus.h"
 
 #define IAP_PATH "/org/bluez/iap"
 
index 277f8a5..a494ea2 100644 (file)
 #include <unistd.h>
 #include <sys/ioctl.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hidp.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <gdbus/gdbus.h>
+#include "lib/bluetooth.h"
+#include "lib/hidp.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+#include "lib/uuid.h"
 
-#include "src/log.h"
+#include "gdbus/gdbus.h"
 
 #include "btio/btio.h"
-#include "lib/uuid.h"
+#include "src/log.h"
 #include "src/adapter.h"
 #include "src/device.h"
 #include "src/profile.h"
@@ -1341,29 +1340,8 @@ static gboolean property_get_reconnect_mode(
        return TRUE;
 }
 
-static gboolean property_get_connected(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *data)
-{
-       struct input_device *idev = data;
-       dbus_bool_t connected;
-
-       if (idev->service == NULL)
-               return FALSE;
-
-       if (btd_service_get_state(idev->service)
-                               == BTD_SERVICE_STATE_CONNECTED) {
-               connected = true;
-       } else
-               connected = false;
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &connected);
-
-       return TRUE;
-}
-
 static const GDBusPropertyTable input_properties[] = {
        { "ReconnectMode", "s", property_get_reconnect_mode },
-       { "Connected", "b", property_get_connected },
        { }
 };
 
index fb51663..3d23d5b 100644 (file)
 #include <sys/stat.h>
 #include <fcntl.h>
 
-#include <bluetooth/bluetooth.h>
-
 #include <glib.h>
 
-#include "src/log.h"
-
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
+#include "src/log.h"
 #include "src/adapter.h"
 #include "src/device.h"
 #include "src/profile.h"
 #include "src/service.h"
 #include "src/shared/util.h"
 #include "src/shared/uhid.h"
-
 #include "src/plugin.h"
 
 #include "suspend.h"
@@ -221,7 +220,6 @@ static void discover_descriptor_cb(uint8_t status, GSList *descs,
                switch (desc->uuid16) {
                case GATT_CLIENT_CHARAC_CFG_UUID:
                        report = user_data;
-                       attrib = report->hogdev->attrib;
                        write_ccc(desc->handle, report);
                        break;
                case GATT_REPORT_REFERENCE:
index cfc9f6a..1d31b06 100644 (file)
 #include <errno.h>
 #include <stdbool.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+#include "lib/uuid.h"
 
 #include "src/log.h"
 #include "src/plugin.h"
-
-#include "lib/uuid.h"
 #include "src/adapter.h"
 #include "src/device.h"
 #include "src/profile.h"
@@ -57,8 +56,6 @@ static void hid_server_remove(struct btd_profile *p,
 
 static struct btd_profile input_profile = {
        .name           = "input-hid",
-       .version        = 0x0101,
-
        .local_uuid     = HID_UUID,
        .remote_uuid    = HID_UUID,
 
index 95f7eeb..eb3fcf8 100644 (file)
 #include <stdbool.h>
 #include <errno.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-
 #include <glib.h>
 #include <dbus/dbus.h>
 
-#include "src/log.h"
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/uuid.h"
 
+#include "src/log.h"
 #include "src/uuid-helper.h"
 #include "btio/btio.h"
-#include "lib/uuid.h"
 #include "src/adapter.h"
 #include "src/device.h"
 #include "src/profile.h"
@@ -270,7 +269,7 @@ static void confirm_event_cb(GIOChannel *chan, gpointer user_data)
        bacpy(&server->confirm->dst, &dst);
 
        ret = btd_request_authorization(&src, &dst, HID_UUID,
-                                       auth_callback, server, 0);
+                                       auth_callback, server);
        if (ret != 0)
                return;
 
index 8ea6e53..0350f92 100644 (file)
 #include <net/if.h>
 #include <linux/sockios.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/bnep.h>
-
 #include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/l2cap.h"
+#include "lib/bnep.h"
+#include "lib/uuid.h"
+
 #include "src/log.h"
 #include "src/shared/util.h"
-#include "lib/uuid.h"
 #include "btio/btio.h"
 
 #include "bnep.h"
@@ -98,31 +98,6 @@ struct bnep {
        void    *disconn_data;
 };
 
-uint16_t bnep_service_id(const char *svc)
-{
-       int i;
-       uint16_t id;
-
-       /* Friendly service name */
-       for (i = 0; __svc[i].name; i++) {
-               if (!strcasecmp(svc, __svc[i].name))
-                       return __svc[i].id;
-       }
-
-       /* UUID 128 string */
-       for (i = 0; __svc[i].uuid128; i++) {
-               if (!strcasecmp(svc, __svc[i].uuid128))
-                       return __svc[i].id;
-       }
-
-       /* Try convert to HEX */
-       id = strtol(svc, NULL, 16);
-       if ((id < BNEP_SVC_PANU) || (id > BNEP_SVC_GN))
-               return 0;
-
-       return id;
-}
-
 const char *bnep_uuid(uint16_t id)
 {
        int i;
@@ -559,8 +534,9 @@ static int bnep_add_to_bridge(const char *devname, const char *bridge)
                err = -errno;
                error("bnep: Can't add %s to the bridge %s: %s(%d)",
                                        devname, bridge, strerror(-err), -err);
-       } else
-               info("bridge %s: interface %s added", bridge, devname);
+       } else {
+               info("bnep: bridge %s: interface %s added", bridge, devname);
+       }
 
        close(sk);
 
@@ -591,8 +567,9 @@ static int bnep_del_from_bridge(const char *devname, const char *bridge)
                err = -errno;
                error("bnep: Can't delete %s from the bridge %s: %s(%d)",
                                        devname, bridge, strerror(-err), -err);
-       } else
-               info("bridge %s: interface %s removed", bridge, devname);
+       } else {
+               info("bnep: bridge %s: interface %s removed", bridge, devname);
+       }
 
        close(sk);
 
@@ -643,26 +620,6 @@ ssize_t bnep_send_ctrl_rsp(int sk, uint8_t type, uint8_t ctrl, uint16_t resp)
        return send(sk, &rsp, sizeof(rsp), 0);
 }
 
-uint16_t bnep_setup_chk(uint16_t dst, uint16_t src)
-{
-       /* Allowed PAN Profile scenarios */
-       switch (dst) {
-       case BNEP_SVC_NAP:
-       case BNEP_SVC_GN:
-               if (src == BNEP_SVC_PANU)
-                       return 0;
-               return BNEP_CONN_INVALID_SRC;
-       case BNEP_SVC_PANU:
-               if (src == BNEP_SVC_PANU ||  src == BNEP_SVC_GN ||
-                                                       src == BNEP_SVC_NAP)
-                       return 0;
-
-               return BNEP_CONN_INVALID_SRC;
-       }
-
-       return BNEP_CONN_INVALID_DST;
-}
-
 uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req, uint16_t *dst,
                                                                uint16_t *src)
 {
@@ -707,7 +664,22 @@ uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req, uint16_t *dst,
                return BNEP_CONN_INVALID_SVC;
        }
 
-       return BNEP_SUCCESS;
+       /* Allowed PAN Profile scenarios */
+       switch (*dst) {
+       case BNEP_SVC_NAP:
+       case BNEP_SVC_GN:
+               if (*src == BNEP_SVC_PANU)
+                       return BNEP_SUCCESS;
+               return BNEP_CONN_INVALID_SRC;
+       case BNEP_SVC_PANU:
+               if (*src == BNEP_SVC_PANU || *src == BNEP_SVC_GN ||
+                                                       *src == BNEP_SVC_NAP)
+                       return BNEP_SUCCESS;
+
+               return BNEP_CONN_INVALID_SRC;
+       }
+
+       return BNEP_CONN_INVALID_DST;
 }
 
 #ifdef  __TIZEN_PATCH__
index 02c54c1..7255f82 100644 (file)
@@ -26,7 +26,6 @@ struct bnep;
 int bnep_init(void);
 int bnep_cleanup(void);
 
-uint16_t bnep_service_id(const char *svc);
 const char *bnep_uuid(uint16_t id);
 const char *bnep_name(uint16_t id);
 
@@ -46,7 +45,6 @@ int bnep_server_add(int sk, uint16_t dst, char *bridge, char *iface,
 void bnep_server_delete(char *bridge, char *iface, const bdaddr_t *addr);
 
 ssize_t bnep_send_ctrl_rsp(int sk, uint8_t type, uint8_t ctrl, uint16_t resp);
-uint16_t bnep_setup_chk(uint16_t dst_role, uint16_t src_role);
 uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req, uint16_t *dst,
                                                                uint16_t *src);
 #ifdef  __TIZEN_PATCH__
index 43ac3b0..bb8e34c 100644 (file)
 #include <unistd.h>
 #include <netinet/in.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/bnep.h>
-#include <bluetooth/sdp.h>
-
 #include <glib.h>
-#include <gdbus/gdbus.h>
+
+#include "lib/bluetooth.h"
+#include "lib/bnep.h"
+#include "lib/sdp.h"
+
+#include "gdbus/gdbus.h"
 
 #include "btio/btio.h"
 #include "src/log.h"
@@ -46,6 +47,7 @@
 #include "src/profile.h"
 #include "src/service.h"
 #include "src/error.h"
+#include "lib/uuid.h"
 
 #include "bnep.h"
 #include "connection.h"
@@ -78,9 +80,16 @@ struct network_conn {
 
 static GSList *peers = NULL;
 
-static uint16_t get_service_id(struct btd_service *service)
+static uint16_t get_pan_srv_id(const char *svc)
 {
-       return bnep_service_id(btd_service_get_profile(service)->remote_uuid);
+       if (!strcasecmp(svc, "panu") || !strcasecmp(svc, PANU_UUID))
+               return BNEP_SVC_PANU;
+       if (!strcasecmp(svc, "nap") || !strcasecmp(svc, NAP_UUID))
+               return BNEP_SVC_NAP;
+       if (!strcasecmp(svc, "gn") || !strcasecmp(svc, GN_UUID))
+               return BNEP_SVC_GN;
+
+       return 0;
 }
 
 static struct network_peer *find_peer(GSList *list, struct btd_device *device)
@@ -299,7 +308,7 @@ static DBusMessage *local_connect(DBusConnection *conn,
                                                DBUS_TYPE_INVALID) == FALSE)
                return btd_error_invalid_args(msg);
 
-       id = bnep_service_id(svc);
+       id = get_pan_srv_id(svc);
        uuid = bnep_uuid(id);
 
        if (uuid == NULL)
@@ -324,11 +333,11 @@ static DBusMessage *local_connect(DBusConnection *conn,
 }
 
 /* Connect and initiate BNEP session */
-int connection_connect(struct btd_service *service)
+int connection_connect(struct btd_service *svc)
 {
-       struct network_conn *nc = btd_service_get_user_data(service);
+       struct network_conn *nc = btd_service_get_user_data(svc);
        struct network_peer *peer = nc->peer;
-       uint16_t id = get_service_id(service);
+       uint16_t id = get_pan_srv_id(btd_service_get_profile(svc)->remote_uuid);
        GError *err = NULL;
        const bdaddr_t *src;
        const bdaddr_t *dst;
@@ -358,9 +367,9 @@ int connection_connect(struct btd_service *service)
        return 0;
 }
 
-int connection_disconnect(struct btd_service *service)
+int connection_disconnect(struct btd_service *svc)
 {
-       struct network_conn *nc = btd_service_get_user_data(service);
+       struct network_conn *nc = btd_service_get_user_data(svc);
 
        if (nc->state == DISCONNECTED)
                return 0;
@@ -512,12 +521,12 @@ static const GDBusPropertyTable connection_properties[] = {
        { }
 };
 
-void connection_unregister(struct btd_service *service)
+void connection_unregister(struct btd_service *svc)
 {
-       struct btd_device *device = btd_service_get_device(service);
-       struct network_conn *conn = btd_service_get_user_data(service);
+       struct btd_device *device = btd_service_get_device(svc);
+       struct network_conn *conn = btd_service_get_user_data(svc);
        struct network_peer *peer = conn->peer;
-       uint16_t id = get_service_id(service);
+       uint16_t id = get_pan_srv_id(btd_service_get_profile(svc)->remote_uuid);
 
        DBG("%s id %u", device_get_path(device), id);
 
@@ -559,12 +568,12 @@ static struct network_peer *create_peer(struct btd_device *device)
        return peer;
 }
 
-int connection_register(struct btd_service *service)
+int connection_register(struct btd_service *svc)
 {
-       struct btd_device *device = btd_service_get_device(service);
+       struct btd_device *device = btd_service_get_device(svc);
        struct network_peer *peer;
        struct network_conn *nc;
-       uint16_t id = get_service_id(service);
+       uint16_t id = get_pan_srv_id(btd_service_get_profile(svc)->remote_uuid);
 
        DBG("%s id %u", device_get_path(device), id);
 
@@ -578,11 +587,11 @@ int connection_register(struct btd_service *service)
 
        nc = g_new0(struct network_conn, 1);
        nc->id = id;
-       nc->service = btd_service_ref(service);
+       nc->service = btd_service_ref(svc);
        nc->state = DISCONNECTED;
        nc->peer = peer;
 
-       btd_service_set_user_data(service, nc);
+       btd_service_set_user_data(svc, nc);
 
        DBG("id %u registered", id);
 
index 81b0ce0..41377fb 100644 (file)
 #include <errno.h>
 #include <stdbool.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/bnep.h>
-#include <bluetooth/sdp.h>
-
 #include <glib.h>
-#include <gdbus/gdbus.h>
+
+#include "lib/bluetooth.h"
+#include "lib/bnep.h"
+#include "lib/sdp.h"
+#include "lib/uuid.h"
 
 #include "src/log.h"
 #include "src/plugin.h"
-
-#include "lib/uuid.h"
 #include "src/adapter.h"
 #include "src/device.h"
 #include "src/profile.h"
@@ -135,10 +133,8 @@ static void nap_server_remove(struct btd_profile *p,
 
 static struct btd_profile panu_profile = {
        .name           = "network-panu",
-       .version        = 0x0100,
        .local_uuid     = NAP_UUID,
        .remote_uuid    = PANU_UUID,
-       .auth_uuid      = BNEP_SVC_UUID,
        .device_probe   = connection_register,
        .device_remove  = connection_unregister,
        .connect        = connection_connect,
@@ -149,10 +145,8 @@ static struct btd_profile panu_profile = {
 
 static struct btd_profile gn_profile = {
        .name           = "network-gn",
-       .version        = 0x0100,
        .local_uuid     = PANU_UUID,
        .remote_uuid    = GN_UUID,
-       .auth_uuid      = BNEP_SVC_UUID,
        .device_probe   = connection_register,
        .device_remove  = connection_unregister,
        .connect        = connection_connect,
@@ -163,10 +157,8 @@ static struct btd_profile gn_profile = {
 
 static struct btd_profile nap_profile = {
        .name           = "network-nap",
-       .version        = 0x0100,
        .local_uuid     = PANU_UUID,
        .remote_uuid    = NAP_UUID,
-       .auth_uuid      = BNEP_SVC_UUID,
        .device_probe   = connection_register,
        .device_remove  = connection_unregister,
        .connect        = connection_connect,
index a1b4126..4f13902 100644 (file)
 #include <unistd.h>
 #include <stdlib.h>
 #include <errno.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/bnep.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
 #include <netinet/in.h>
 
 #include <glib.h>
-#include <gdbus/gdbus.h>
 
-#include "btio/btio.h"
+#include "lib/bluetooth.h"
+#include "lib/bnep.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 #include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
+
+#include "btio/btio.h"
 #include "src/dbus-common.h"
 #include "src/adapter.h"
 #include "src/log.h"
@@ -325,7 +326,7 @@ static gboolean server_disconnected_cb(GIOChannel *chan,
 {
        struct network_server *ns = NULL;
        struct network_session *session = NULL;
-       char address[24] = {0};
+       char address[20] = {0};
        const char* paddr = address;
        char *name_str = NULL;
 
@@ -373,7 +374,7 @@ static gboolean bnep_setup(GIOChannel *chan,
                        GIOCondition cond, gpointer user_data)
 {
        struct network_adapter *na = user_data;
-       struct network_server *ns = NULL;
+       struct network_server *ns;
        uint8_t packet[BNEP_MTU];
        struct bnep_setup_conn_req *req = (void *) packet;
        uint16_t src_role, dst_role, rsp = BNEP_CONN_NOT_ALLOWED;
@@ -415,11 +416,7 @@ static gboolean bnep_setup(GIOChannel *chan,
                return FALSE;
 
        rsp = bnep_setup_decode(req, &dst_role, &src_role);
-       if (rsp)
-               goto reply;
-
-       rsp = bnep_setup_chk(dst_role, src_role);
-       if (rsp)
+       if (rsp != BNEP_SUCCESS)
                goto reply;
 
        rsp = BNEP_CONN_NOT_ALLOWED;
@@ -550,13 +547,7 @@ static void confirm_event(GIOChannel *chan, gpointer user_data)
        }
 
        ns = find_server(na->servers, BNEP_SVC_NAP);
-       if (!ns)
-               goto drop;
-
-       if (!ns->record_id)
-               goto drop;
-
-       if (!ns->bridge)
+       if (!ns || !ns->record_id || !ns->bridge)
                goto drop;
 
        na->setup = g_new0(struct network_session, 1);
@@ -564,7 +555,7 @@ static void confirm_event(GIOChannel *chan, gpointer user_data)
        na->setup->io = g_io_channel_ref(chan);
 
        ret = btd_request_authorization(&src, &dst, BNEP_SVC_UUID,
-                                       auth_cb, na, 0);
+                                       auth_cb, na);
        if (ret == 0) {
                error("Refusing connect from %s", address);
                setup_destroy(na);
@@ -611,26 +602,11 @@ static void server_remove_sessions(struct network_server *ns)
 
        for (list = ns->sessions; list; list = list->next) {
                struct network_session *session = list->data;
-               char address[24] = {0};
-               char *paddr = address;
-               const char *name_str = NULL;
 
                if (*session->dev == '\0')
                        continue;
 
                bnep_server_delete(ns->bridge, session->dev, &session->dst);
-
-               name_str = session->dev;
-               ba2str(&session->dst, paddr);
-
-               DBG("send peerdisconnected signal");
-
-               g_dbus_emit_signal(btd_get_dbus_connection(),
-                       adapter_get_path(ns->na->adapter),
-                       NETWORK_SERVER_INTERFACE, "PeerDisconnected",
-                       DBUS_TYPE_STRING, &name_str,
-                       DBUS_TYPE_STRING, &paddr,
-                       DBUS_TYPE_INVALID);
        }
 
 #ifndef __TIZEN_PATCH__
@@ -885,8 +861,7 @@ static struct network_adapter *create_adapter(struct btd_adapter *adapter)
        na = g_new0(struct network_adapter, 1);
        na->adapter = btd_adapter_ref(adapter);
 
-       na->io = bt_io_listen(NULL, confirm_event, na,
-                               NULL, &err,
+       na->io = bt_io_listen(NULL, confirm_event, na, NULL, &err,
                                BT_IO_OPT_SOURCE_BDADDR,
                                btd_adapter_get_address(adapter),
                                BT_IO_OPT_PSM, BNEP_PSM,
index 3d50b8d..26a0ac9 100644 (file)
 #include <glib.h>
 
 #include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
+
 #include "src/log.h"
 #include "src/adapter.h"
 #include "attrib/gattrib.h"
index 476803a..2f1ab13 100644 (file)
 #include <glib.h>
 
 #include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
+
 #include "src/log.h"
 #include "src/adapter.h"
 #include "src/device.h"
index 8a350d4..38a51f1 100644 (file)
@@ -29,7 +29,8 @@
 #include <errno.h>
 #include <stdint.h>
 #include <glib.h>
-#include <gdbus/gdbus.h>
+
+#include "gdbus/gdbus.h"
 
 #include "src/log.h"
 #include "src/plugin.h"
index 3f0f63c..dbb3bda 100644 (file)
 #include <stdbool.h>
 
 #include <glib.h>
-#include <gdbus/gdbus.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
+
 #include "src/adapter.h"
 #include "src/device.h"
 #include "src/profile.h"
index b05cdd7..a583eb7 100644 (file)
 
 #include <errno.h>
 #include <fcntl.h>
-#include <gdbus/gdbus.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/stat.h>
-#include <glib.h>
 
-#include <bluetooth/bluetooth.h>
+#include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
+
 #include "src/dbus-common.h"
 #include "src/adapter.h"
 #include "src/device.h"
index fb91bc1..366d96b 100644 (file)
 #include <glib.h>
 
 #include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
-
-#include "src/log.h"
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
+
+#include "src/log.h"
 #include "src/dbus-common.h"
 #include "src/adapter.h"
 #include "src/device.h"
index ad55cd2..cd707ff 100644 (file)
@@ -23,7 +23,9 @@
 #endif
 
 #include <errno.h>
-#include <gdbus/gdbus.h>
+
+#include "gdbus/gdbus.h"
+
 #include "src/plugin.h"
 #include "manager.h"
 
index 5c2a0f1..b622397 100644 (file)
@@ -24,6 +24,9 @@
 
 #include <stdbool.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+
 #include "src/log.h"
 #include "src/adapter.h"
 #include "src/device.h"
index 854105e..53463ca 100644 (file)
 #endif
 
 #include <glib.h>
-#include <gdbus/gdbus.h>
 #include <stdint.h>
 
+#include "gdbus/gdbus.h"
+
 #include "src/dbus-common.h"
 #include "src/error.h"
 #include "src/log.h"
+
 #include "sap.h"
 
 #define SAP_DUMMY_IFACE "org.bluez.SimAccessTest1"
index 683d6f2..ce423a1 100644 (file)
 
 #include <errno.h>
 #include <glib.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
 
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 #include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
+
 #include "btio/btio.h"
 #include "src/adapter.h"
 #include "src/sdpd.h"
@@ -41,6 +44,7 @@
 #include "src/error.h"
 #include "src/dbus-common.h"
 #include "src/shared/util.h"
+
 #include "sap.h"
 #include "server.h"
 
@@ -1253,7 +1257,7 @@ static void connect_confirm_cb(GIOChannel *io, gpointer data)
        ba2str(&dst, dstaddr);
 
        ret = btd_request_authorization(&src, &dst, SAP_UUID, connect_auth_cb,
-                                                               server, 0);
+                                                               server);
        if (ret == 0) {
                error("Authorization failure");
                sap_server_remove_conn(server);
index d7e674a..4bf9296 100644 (file)
@@ -18,7 +18,5 @@
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <gdbus/gdbus.h>
-
 int sap_server_register(struct btd_adapter *adapter);
 void sap_server_unregister(const char *path);
index 3eece9d..fbda8a8 100644 (file)
 #include <stdbool.h>
 #include <errno.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
 #include "src/log.h"
 #include "src/plugin.h"
 #include "src/adapter.h"
index e3ab923..b0fc3e0 100644 (file)
 #include <stdbool.h>
 #include <errno.h>
 
-#include <gdbus/gdbus.h>
-
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
 #include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
+
 #include "src/plugin.h"
 #include "src/dbus-common.h"
 #include "src/adapter.h"
index 1716a5e..2289c6a 100644 (file)
 #include <config.h>
 #endif
 
-#include <glib.h>
 #include <time.h>
 #include <errno.h>
+#include <string.h>
 #include <stdbool.h>
 
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/uuid.h"
+
 #include "src/adapter.h"
 #include "src/device.h"
 #include "src/profile.h"
 #include "src/plugin.h"
-
-#include "lib/uuid.h"
 #include "attrib/gattrib.h"
 #include "attrib/att.h"
 #include "attrib/gatt.h"
index 0066c76..8eab02e 100644 (file)
 #include <sys/stat.h>
 #include <dirent.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
+
+#include "bluetooth/bluetooth.h"
+#include "bluetooth/hci.h"
+#include "bluetooth/hci_lib.h"
+#include "bluetooth/sdp.h"
+#include "bluetooth/sdp_lib.h"
+#include "lib/uuid.h"
+#include "lib/mgmt.h"
+
+#include "gdbus/gdbus.h"
 
 #include "log.h"
 #include "textfile.h"
 
-#include "lib/uuid.h"
-#include "lib/mgmt.h"
 #include "src/shared/mgmt.h"
 #include "src/shared/util.h"
+#include "src/shared/queue.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
 
 #include "hcid.h"
 #include "sdpd.h"
 #include "attrib/att.h"
 #include "attrib/gatt.h"
 #include "attrib-server.h"
+#include "gatt-database.h"
 #include "eir.h"
-#ifdef BLUEZ5_GATT_CLIENT
-#include "src/shared/gatt-client.h"
-#include "src/shared/att-types.h"
-#include <bluetooth/l2cap.h>
+
+#ifdef __TIZEN_PATCH__
+#include "adapter_le_vsc_features.h"
 #endif
 
 #define ADAPTER_INTERFACE      "org.bluez.Adapter1"
@@ -88,7 +93,7 @@
 #define BONDING_TIMEOUT (2 * 60)
 #ifdef __TIZEN_PATCH__
 #define check_address(address) bachk(address)
-#define ADV_DATA_LENGTH_MAX 28
+#define ADV_DATA_MAX_LENGTH 31
 #define SCAN_RESPONSE_DATA_LENGTH_MAX 31
 #define MANUFACTURER_DATA_LENGTH_MAX 28
 #define PRIVATE_ADDR_TIMEOUT (15 * 60)
@@ -116,10 +121,13 @@ static struct mgmt *mgmt_master = NULL;
 static uint8_t mgmt_version = 0;
 static uint8_t mgmt_revision = 0;
 
+#if 0 // Not used
 #ifdef __TIZEN_PATCH__
 static DBusMessage *write_sec_conn_host_support(DBusConnection *conn,
                                        DBusMessage *msg, void *user_data);
 #endif /* __TIZEN_PATCH__ */
+#endif
+
 static GSList *adapter_drivers = NULL;
 
 static GSList *disconnect_list = NULL;
@@ -173,7 +181,6 @@ struct service_auth {
        struct btd_device *device;
        struct btd_adapter *adapter;
        struct agent *agent;            /* NULL for queued auths */
-       int fd;
 };
 
 struct btd_adapter_pin_cb_iter {
@@ -182,6 +189,13 @@ struct btd_adapter_pin_cb_iter {
        /* When the iterator reaches the end, it is NULL and attempt is 0 */
 };
 
+#ifdef __TIZEN_PATCH__
+struct adv_info {
+       int slot_id;    /* Reservied slot id is 0 (Single adv) */
+       bool status;            /* Advertising status */
+};
+#endif
+
 struct btd_adapter {
        int ref_count;
 
@@ -191,9 +205,6 @@ struct btd_adapter {
        bdaddr_t bdaddr;                /* controller Bluetooth address */
 #ifdef __TIZEN_PATCH__
        bdaddr_t rpaddr;                /* controller RPA */
-#ifdef BLUEZ5_GATT_CLIENT
-       struct client *gatt_client;
-#endif
 #endif
        uint32_t dev_class;             /* controller class of device */
        char *name;                     /* controller device name */
@@ -216,6 +227,7 @@ struct btd_adapter {
        bool le_privacy_enabled;        /* whether LE Privacy feature enabled */
        char local_irk[MGMT_IRK_SIZE];  /* adapter local IRK */
        uint8_t disc_type;
+       bool ipsp_intialized;           /* Ipsp Initialization state */
 #endif
 
        bool discovering;               /* discovering property state */
@@ -238,14 +250,22 @@ struct btd_adapter {
        struct btd_device *connect_le;  /* LE device waiting to be connected */
        sdp_list_t *services;           /* Services associated to adapter */
 
+       struct btd_gatt_database *database;
+
        gboolean initialized;
 #ifdef __TIZEN_PATCH__
+       GSList *adv_list;       /* List of advertising instance */
        bool advertising;               /* Advertising active */
        gchar *version;                 /* Bluetooth Version */
+#if 0 // Not used
        bool secure_connection;         /* Secure Connection active*/
        uint16_t auth_payload_timeout; /* Authenticated payload timeout value*/
+
        bool set_new_rpa;               /* RPA to be set */
        bool rpa_is_set;                /* RPA is set */
+#endif
+
+       uint8_t adv_tx_power;
 
        gboolean le_discovering;                /* LE Discovery active */
        GSList *le_discovery_list;              /* list of LE discovery clients */
@@ -268,18 +288,13 @@ struct btd_adapter {
 
        unsigned int pair_device_id;
        guint pair_device_timeout;
+       unsigned int db_id;             /* Service event handler for GATT db */
 #ifdef __TIZEN_PATCH__
        guint private_addr_timeout;
 #endif
        bool is_default;                /* true if adapter is default one */
 };
 
-#ifdef BLUEZ5_GATT_CLIENT
-struct client {
-       int fd;
-       struct bt_gatt_client *gatt;
-};
-#endif
 
 #ifdef __TIZEN_PATCH__
 enum {
@@ -287,6 +302,11 @@ enum {
        ENABLE_PRIVACY,
        GEN_IRK_THEN_ENABLE_PRIVACY
 };
+
+enum {
+       DEINIT_6LOWPAN,
+       INIT_6LOWPAN
+};
 #endif
 
 static struct btd_adapter *btd_adapter_lookup(uint16_t index)
@@ -342,7 +362,6 @@ static void dev_class_changed_callback(uint16_t index, uint16_t length,
 {
        struct btd_adapter *adapter = user_data;
        const struct mgmt_cod *rp = param;
-       uint8_t appearance[3];
        uint32_t dev_class;
 
        if (length < sizeof(*rp)) {
@@ -361,12 +380,6 @@ static void dev_class_changed_callback(uint16_t index, uint16_t length,
 
        g_dbus_emit_property_changed(dbus_conn, adapter->path,
                                                ADAPTER_INTERFACE, "Class");
-
-       appearance[0] = rp->val[0];
-       appearance[1] = rp->val[1] & 0x1f;      /* removes service class */
-       appearance[2] = rp->val[2];
-
-       attrib_gap_set(adapter, GATT_CHARAC_APPEARANCE, appearance, 2);
 }
 
 static void set_dev_class_complete(uint8_t status, uint16_t length,
@@ -524,6 +537,120 @@ static bool set_mode(struct btd_adapter *adapter, uint16_t opcode,
 static bool set_privacy(struct btd_adapter *adapter, bool privacy);
 #endif
 
+#ifdef __TIZEN_PATCH__
+static int compare_slot(gconstpointer a, gconstpointer b)
+{
+       const struct adv_info *adv = a;
+       const int id = *(int*)b;
+
+       return (adv->slot_id == id ? 0 : -1);
+}
+
+static struct adv_info *find_advertiser(struct btd_adapter *adapter,
+                               int slot_id)
+{
+       GSList *list;
+
+       list = g_slist_find_custom(adapter->adv_list, &slot_id,
+                                                       compare_slot);
+       if (list)
+               return list->data;
+
+       return NULL;
+}
+
+static void create_advertiser(struct btd_adapter *adapter,
+                                       int slot_id)
+{
+       struct adv_info *adv;
+
+       if (!adapter)
+               return;
+
+       if (find_advertiser(adapter, slot_id) != NULL) {
+               error("Aleady existed [%d]", slot_id);
+               return;
+       }
+
+       DBG("Create adv slot id : %d", slot_id);
+
+       adv = g_new0(struct adv_info, 1);
+       if (adv == NULL)
+               return;
+
+       adv->slot_id = slot_id;
+
+       adapter->adv_list= g_slist_append(adapter->adv_list, adv);
+       return;
+}
+
+#ifndef __TIZEN_PATCH__
+/* There is no caller of this function */
+static void destroy_advertiser(struct btd_adapter *adapter,
+                               int slot_id)
+{
+       struct adv_info *adv;
+
+       if (!adapter)
+               return;
+
+       adv = find_advertiser(adapter, slot_id);
+       if (!adv) {
+               DBG("Unable to find advertiser [%d]", slot_id);
+               return;
+       }
+
+       adapter->adv_list = g_slist_remove(adapter->adv_list,
+                                                               adv);
+}
+#endif
+
+static void advertising_state_changed(struct btd_adapter *adapter,
+                                       int slot_id, bool enabled)
+{
+       struct adv_info *adv;
+       int id = slot_id;
+       int state = enabled;
+
+       if (!adapter)
+               return;
+
+       adv = find_advertiser(adapter, slot_id);
+       if (!adv) {
+               DBG("Unable to find advertiser [%d]", slot_id);
+               return;
+       }
+
+       adv->status = enabled;
+       DBG("slot_id %d, status %d", adv->slot_id, adv->status);
+
+       g_dbus_emit_signal(dbus_conn, adapter->path,
+                       ADAPTER_INTERFACE, "AdvertisingEnabled",
+                       DBUS_TYPE_INT32, &id,
+                       DBUS_TYPE_BOOLEAN, &state,
+                       DBUS_TYPE_INVALID);
+}
+
+static void clear_advertiser_cb(gpointer data, gpointer user_data)
+{
+       struct adv_info *adv = data;
+       struct btd_adapter *adapter = user_data;
+
+       if (adv->status)
+               advertising_state_changed(adapter, adv->slot_id, 0);
+}
+
+static void advertiser_cleanup(struct btd_adapter *adapter)
+{
+       if (!adapter->adv_list)
+               return;
+
+       g_slist_foreach(adapter->adv_list, clear_advertiser_cb, adapter);
+       g_slist_free(adapter->adv_list);
+       adapter->adv_list = NULL;
+}
+#endif
+
 static void settings_changed(struct btd_adapter *adapter, uint32_t settings)
 {
        uint32_t changed_mask;
@@ -581,9 +708,9 @@ static void settings_changed(struct btd_adapter *adapter, uint32_t settings)
                        (adapter->advertising)) {
                        return;
                }
+
                adapter->advertising = adapter->current_settings & MGMT_SETTING_ADVERTISING;
-               g_dbus_emit_property_changed(dbus_conn, adapter->path,
-                                       ADAPTER_INTERFACE, "Advertising");
+               advertising_state_changed(adapter, 0, adapter->advertising);
        }
 #endif
 }
@@ -1237,14 +1364,14 @@ gboolean adapter_clear_le_white_list(struct btd_adapter *adapter)
        if (mgmt_send(adapter->mgmt, MGMT_OP_CLEAR_DEV_WHITE_LIST,
                                   adapter->dev_id, 0, NULL,
                                   NULL, NULL, NULL) > 0)
-
-       return TRUE;
+               return TRUE;
+       else
+               return FALSE;
 }
 
 gboolean adapter_add_le_white_list(struct btd_adapter *adapter, struct btd_device *device)
 {
        struct mgmt_cp_add_dev_white_list cp;
-       uint8_t bdaddr_type;
        const bdaddr_t *dst;
        char device_addr[18];
 
@@ -2135,6 +2262,7 @@ static void discovery_cleanup(struct btd_adapter *adapter)
        adapter->discovery_found = NULL;
 }
 
+#ifndef __TIZEN_PATCH__
 static gboolean remove_temp_devices(gpointer user_data)
 {
        struct btd_adapter *adapter = user_data;
@@ -2155,6 +2283,7 @@ static gboolean remove_temp_devices(gpointer user_data)
 
        return FALSE;
 }
+#endif
 
 static void discovery_destroy(void *user_data)
 {
@@ -2389,6 +2518,125 @@ static DBusMessage *start_discovery(DBusConnection *conn,
 }
 
 #ifdef __TIZEN_PATCH__
+static int set_adv_data_flag(uint8_t *adv_data, uint8_t *data, int data_len)
+{
+       adv_data[0] = 2;
+       adv_data[1] = EIR_FLAGS;
+       adv_data[2] = EIR_GEN_DISC;
+
+       memcpy(adv_data + 3, data, data_len);
+       return data_len + 3;
+}
+
+static int set_adv_data_device_name(uint8_t *adv_data, int adv_len, char *name)
+{
+       int ad_type;
+       int ad_len;
+       int i, j;
+       int name_len;
+       uint8_t *data = NULL;
+
+       data = g_memdup(adv_data, adv_len);
+
+       if (!data || !name)
+               return adv_len;
+
+       name_len = strlen(name);
+
+       for (i = 0; i <adv_len ; i++) {
+               ad_len = data[i];
+               ad_type = data[i + 1];
+
+               if (ad_type == EIR_NAME_COMPLETE) {
+                       /* Move to last position and update local name */
+                       for (j = i; j < adv_len - 2; j++)
+                               adv_data[j] = data[j + 2];
+
+                       adv_data[j] = name_len + 1;
+                       if (name_len > ADV_DATA_MAX_LENGTH - adv_len) {
+                               adv_data[j + 1] = EIR_NAME_SHORT;
+                               memcpy(adv_data + j + 2, name, ADV_DATA_MAX_LENGTH - adv_len);
+                       } else {
+                               adv_data[j + 1] = EIR_NAME_COMPLETE;
+                               memcpy(adv_data + j + 2, name, name_len);
+                       }
+
+                       g_free(data);
+                       return adv_len + name_len;
+               } else {
+                       memcpy(adv_data + i, &data[i], ad_len + 1);
+                       i = i + data[i];
+               }
+       }
+
+       g_free(data);
+       return adv_len;
+}
+
+static int set_adv_data_tx_power(uint8_t *adv_data, int adv_len, int8_t tx_power)
+{
+       int ad_type;
+       int ad_len;
+       int i, j;
+       uint8_t *data = NULL;
+
+       data = g_memdup(adv_data, adv_len);
+       if (!data)
+               return adv_len;
+
+       for (i = 0; i <adv_len ; i++) {
+               ad_len = data[i];
+               ad_type = data[i + 1];
+
+               if (ad_type == EIR_TX_POWER) {
+                       adv_data[i] = 2;
+                       adv_data[i + 1] = EIR_TX_POWER;
+                       adv_data[i + 2] = tx_power;
+
+                       for(j = i + 2; j < adv_len; j++)
+                               adv_data[j + 1] = data[j];
+
+                       g_free(data);
+                       return adv_len + 1;
+               } else {
+                       memcpy(adv_data + i, &data[i], ad_len + 1);
+                       i = i + data[i];
+               }
+       }
+
+       g_free(data);
+       return adv_len;
+}
+
+static gboolean adapter_le_set_missed_adv_data(uint8_t *p_data, uint8_t data_len,
+               gboolean is_scan_rsp, char *adapter_name, int8_t tx_power, uint8_t **adv_data, int *adv_len)
+{
+       uint8_t *data;
+       int len;
+
+       data = g_malloc0(ADV_DATA_MAX_LENGTH);
+       /* Fix : NULL_RETURNS */
+       if (data == NULL) {
+               return FALSE;
+       }
+       memcpy(data, p_data, data_len);
+       len = data_len;
+
+       /* In case multi advertising, need to update the below AD type
+               since it handled into kernel */
+       if (!is_scan_rsp) {
+               len = set_adv_data_flag(data, p_data, data_len);
+       }
+
+       len = set_adv_data_tx_power(data, len, tx_power);
+
+       len = set_adv_data_device_name(data, len, adapter_name);
+
+       *adv_data = data;
+       *adv_len = len;
+       return TRUE;
+}
+
 static DBusMessage *adapter_start_custom_discovery(DBusConnection *conn,
                                        DBusMessage *msg, void *user_data)
 {
@@ -2572,6 +2820,7 @@ static DBusMessage *adapter_set_advertising(DBusConnection *conn,
        struct btd_adapter *adapter = data;
        dbus_bool_t err;
        dbus_bool_t enable = FALSE;
+       dbus_int32_t slot_id;
 
        DBG("adapter_set_advertising");
 
@@ -2579,13 +2828,24 @@ static DBusMessage *adapter_set_advertising(DBusConnection *conn,
                return btd_error_not_ready(msg);
 
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &enable,
+                                               DBUS_TYPE_INT32, &slot_id,
                                                DBUS_TYPE_INVALID))
                return btd_error_invalid_args(msg);
 
-       err = set_mode(adapter, MGMT_OP_SET_ADVERTISING, enable);
+       if (adapter_le_is_supported_multi_advertising() && slot_id > 0)
+               err = adapter_le_enable_multi_adv(enable, slot_id);
+       else
+               err = set_mode(adapter, MGMT_OP_SET_ADVERTISING, enable);
+
        if (!err)
                return btd_error_failed(msg, "Set Advertising failed");
 
+       if (enable)
+               create_advertiser(adapter, slot_id);
+
+       if (err && slot_id > 0)
+               advertising_state_changed(adapter, slot_id, enable);
+
        return dbus_message_new_method_return(msg);
 }
 
@@ -2598,6 +2858,8 @@ static DBusMessage *adapter_set_advertising_params(DBusConnection *conn,
        dbus_uint32_t interval_max;
        dbus_uint32_t filter_policy;
        dbus_uint32_t type;
+       dbus_int32_t slot_id;
+       gboolean ret;
 
        DBG("Set customised advertising parameters");
 
@@ -2609,6 +2871,7 @@ static DBusMessage *adapter_set_advertising_params(DBusConnection *conn,
                                DBUS_TYPE_UINT32, &interval_max,
                                DBUS_TYPE_UINT32, &filter_policy,
                                DBUS_TYPE_UINT32, &type,
+                               DBUS_TYPE_INT32, &slot_id,
                                DBUS_TYPE_INVALID))
                return btd_error_invalid_args(msg);
 
@@ -2623,17 +2886,46 @@ static DBusMessage *adapter_set_advertising_params(DBusConnection *conn,
        if (type > 0x04)
                return btd_error_invalid_args(msg);
 
-       cp.interval_max = interval_max;
-       cp.interval_min = interval_min;
-       cp.filter_policy = filter_policy;
-       cp.type = type;
+       if (adapter_le_is_supported_multi_advertising() && slot_id > 0) {
+               adapter_le_adv_inst_info_t *p_inst;
+               adapter_le_adv_param_t *p_params;
+
+               p_inst = malloc(sizeof(adapter_le_adv_inst_info_t));
+               p_params = malloc(sizeof(adapter_le_adv_param_t));
+               memset(p_inst, 0, sizeof(adapter_le_adv_inst_info_t));
+               memset(p_params, 0, sizeof(adapter_le_adv_param_t));
+               p_inst->inst_id = slot_id;
+               p_params->adv_int_min = interval_min;
+               p_params->adv_int_max = interval_max;
+               p_params->adv_type = type;
+               p_params->channel_map = 0x07;   /* fixed channel :: will be used all */
+               p_params->adv_filter_policy = filter_policy;
+               p_params->tx_power = BLE_ADV_TX_POWER_MID;      /* TODO:need to optimize */
+               p_inst->bdaddr_type = 0x00;
+               bacpy(&p_inst->bdaddr, &adapter->bdaddr);
+
+               ret = adapter_le_set_multi_adv_params(p_inst, p_params);
+
+               free(p_inst);
+               free(p_params);
+
+               if (ret)
+                       return dbus_message_new_method_return(msg);
+               else
+                       return btd_error_failed(msg, "set advertising param failed");
+       } else {
+               cp.interval_max = interval_max;
+               cp.interval_min = interval_min;
+               cp.filter_policy = filter_policy;
+               cp.type = type;
 
-       if (mgmt_send(adapter->mgmt, MGMT_OP_SET_ADVERTISING_PARAMS,
-                               adapter->dev_id, sizeof(cp), &cp,
-                               NULL, NULL, NULL) > 0)
-               return dbus_message_new_method_return(msg);
+               if (mgmt_send(adapter->mgmt, MGMT_OP_SET_ADVERTISING_PARAMS,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       NULL, NULL, NULL) > 0)
+                       return dbus_message_new_method_return(msg);
 
-       return btd_error_failed(msg, "set advertising param failed");
+               return btd_error_failed(msg, "set advertising param failed");
+       }
 }
 
 static DBusMessage *adapter_set_advertising_data(DBusConnection *conn,
@@ -2643,6 +2935,9 @@ static DBusMessage *adapter_set_advertising_data(DBusConnection *conn,
        struct mgmt_cp_set_advertising_data cp;
        uint8_t *value;
        int32_t len = 0;
+       dbus_int32_t slot_id;
+       uint8_t *adv_data = NULL;
+       int adv_len = 0;
 
        DBG("Set advertising data");
 
@@ -2651,20 +2946,202 @@ static DBusMessage *adapter_set_advertising_data(DBusConnection *conn,
 
        if (!dbus_message_get_args(msg, NULL,
                        DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &value, &len,
+                       DBUS_TYPE_INT32, &slot_id,
                        DBUS_TYPE_INVALID))
                return btd_error_invalid_args(msg);
 
-       if (len > ADV_DATA_LENGTH_MAX)
+       if (len > ADV_DATA_MAX_LENGTH - 3)
                return btd_error_invalid_args(msg);
 
-       memcpy(&cp, value, len);
+       if (adapter_le_set_missed_adv_data(value, len, FALSE,
+                       adapter->name, adapter->adv_tx_power, &adv_data, &adv_len) != TRUE)
+                       return btd_error_failed(msg, "set advertising data failed");
 
-       if (mgmt_send(adapter->mgmt, MGMT_OP_SET_ADVERTISING_DATA,
-                                       adapter->dev_id, len,
-                                       &cp, NULL, NULL, NULL) > 0)
-               return dbus_message_new_method_return(msg);
+       if (adapter_le_is_supported_multi_advertising() && slot_id > 0) {
+               if (adapter_le_set_multi_adv_data(slot_id, FALSE, adv_len, adv_data)) {
+                       g_free(adv_data);
+                       return dbus_message_new_method_return(msg);
+               } else {
+                       g_free(adv_data);
+                       return btd_error_failed(msg, "set advertising data failed");
+               }
+       } else {
+               memcpy(&cp, adv_data, adv_len);
+
+               if (mgmt_send(adapter->mgmt, MGMT_OP_SET_ADVERTISING_DATA,
+                                               adapter->dev_id, adv_len,
+                                               &cp, NULL, NULL, NULL) > 0) {
+                       g_free(adv_data);
+                       return dbus_message_new_method_return(msg);
+               }
+
+               g_free(adv_data);
+               return btd_error_failed(msg, "set advertising data failed");
+       }
+}
+
+static DBusMessage *adapter_le_scan_filter_param_setup(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       dbus_bool_t err;
+       dbus_int32_t client_if, action, filt_index;
+       dbus_int32_t feat_seln, list_logic_type, filt_logic_type;
+       dbus_int32_t rssi_high_thres, rssi_low_thres, dely_mode;
+       dbus_int32_t found_timeout, lost_timeout, found_timeout_cnt;
+       adapter_le_scan_filter_param_t params;
+
+       DBG("adapter_le_scan_filter_param_setup");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (adapter_le_get_scan_filter_size() == 0)
+               return btd_error_not_supported(msg);
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &client_if,
+                                               DBUS_TYPE_INT32, &action,
+                                               DBUS_TYPE_INT32, &filt_index,
+                                               DBUS_TYPE_INT32, &feat_seln,
+                                               DBUS_TYPE_INT32, &list_logic_type,
+                                               DBUS_TYPE_INT32, &filt_logic_type,
+                                               DBUS_TYPE_INT32, &rssi_high_thres,
+                                               DBUS_TYPE_INT32, &rssi_low_thres,
+                                               DBUS_TYPE_INT32, &dely_mode,
+                                               DBUS_TYPE_INT32, &found_timeout,
+                                               DBUS_TYPE_INT32, &lost_timeout,
+                                               DBUS_TYPE_INT32, &found_timeout_cnt,
+                                               DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       memset(&params, 0, sizeof(params));
+
+       params.action = action;
+       params.index = filt_index;
+       params.feature = feat_seln;
+       params.filter_logic_type = filt_logic_type;
+       params.list_logic_type = list_logic_type;
+       params.delivery_mode = dely_mode;
+       params.rssi_high_threshold = rssi_high_thres;
+
+       if (params.delivery_mode == ON_FOUND) {
+               params.rssi_low_threshold = rssi_low_thres;
+               params.onfound_timeout = found_timeout;
+               params.onfound_timeout_cnt = found_timeout_cnt;
+               params.onlost_timeout = lost_timeout;
+       }
+
+       err = adapter_le_set_scan_filter_params(&params);
+
+       if (!err)
+               return btd_error_failed(msg, "Failed to scan filter param setup");
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_le_scan_filter_add_remove(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       dbus_bool_t err;
+       dbus_int32_t client_if, action, filt_type, filt_index;
+       dbus_int32_t company_id, company_id_mask;
+       gchar *string;
+       dbus_uint32_t address_type;
+       uint8_t *p_uuid, *p_uuid_mask, *p_data, *p_mask;
+       int32_t uuid_len = 0, uuid_mask_len = 0, data_len = 0, mask_len = 0;
+
+       DBG("adapter_le_scan_filter_add_remove");
 
-       return btd_error_failed(msg, "set advertising data failed");
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (adapter_le_get_scan_filter_size() == 0)
+               return btd_error_not_supported(msg);
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &client_if,
+                                               DBUS_TYPE_INT32, &action,
+                                               DBUS_TYPE_INT32, &filt_type,
+                                               DBUS_TYPE_INT32, &filt_index,
+                                               DBUS_TYPE_INT32, &company_id,
+                                               DBUS_TYPE_INT32, &company_id_mask,
+                                               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &p_uuid, &uuid_len,
+                                               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &p_uuid_mask, &uuid_mask_len,
+                                               DBUS_TYPE_STRING, &string,
+                                               DBUS_TYPE_UINT32, &address_type,
+                                               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &p_data, &data_len,
+                                               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &p_mask, &mask_len,
+                                               DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       err = adapter_le_set_scan_filter_data(client_if, action, filt_type,
+                       filt_index, company_id, company_id_mask,
+                       uuid_len, p_uuid, uuid_mask_len, p_uuid_mask,
+                       string, address_type, data_len, p_data, mask_len, p_mask);
+
+       if (!err)
+               return btd_error_failed(msg, "Failed to add/remove filter");
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_le_scan_filter_clear(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       dbus_bool_t err;
+       dbus_int32_t client_if;
+       dbus_int32_t filt_index;
+
+       DBG("adapter_le_scan_filter_clear");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (adapter_le_get_scan_filter_size() == 0)
+               return btd_error_not_supported(msg);
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &client_if,
+                                               DBUS_TYPE_INT32, &filt_index,
+                                               DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       err = adapter_le_clear_scan_filter_data(client_if, filt_index);
+
+       if (!err)
+               return btd_error_failed(msg, "Failed to clear filter");
+
+       return dbus_message_new_method_return(msg);
+}
+
+
+static DBusMessage *adapter_le_scan_filter_enable(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       dbus_bool_t err;
+       dbus_bool_t enable = FALSE;
+       dbus_int32_t client_if;
+
+       DBG("adapter_le_scan_filter_enable");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (adapter_le_get_scan_filter_size() == 0)
+               return btd_error_not_supported(msg);
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &client_if,
+                                               DBUS_TYPE_BOOLEAN, &enable,
+                                               DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       err = adapter_le_enable_scan_filtering(enable);
+
+       if (!err)
+               return btd_error_failed(msg, "Failed to enable scan filtering");
+
+       return dbus_message_new_method_return(msg);
 }
 
 static DBusMessage *adapter_le_set_scan_params(DBusConnection *conn,
@@ -2711,6 +3188,9 @@ static DBusMessage *adapter_set_scan_rsp_data(DBusConnection *conn,
        struct mgmt_cp_set_scan_rsp_data cp;
        uint8_t *value;
        int32_t len = 0;
+       dbus_int32_t slot_id;
+       uint8_t *adv_data = NULL;
+       int adv_len = 0;
 
        DBG("Set scan response data");
 
@@ -2719,20 +3199,38 @@ static DBusMessage *adapter_set_scan_rsp_data(DBusConnection *conn,
 
        if (!dbus_message_get_args(msg, NULL,
                        DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &value, &len,
+                       DBUS_TYPE_INT32, &slot_id,
                        DBUS_TYPE_INVALID))
                return btd_error_invalid_args(msg);
 
        if (len > SCAN_RESPONSE_DATA_LENGTH_MAX)
                return btd_error_invalid_args(msg);
 
-       memcpy(&cp, value, len);
+       if (adapter_le_set_missed_adv_data(value, len, TRUE,
+                       adapter->name, adapter->adv_tx_power, &adv_data, &adv_len) != TRUE)
+                       return btd_error_failed(msg, "set advertising data failed");
 
-       if (mgmt_send(adapter->mgmt, MGMT_OP_SET_SCAN_RSP_DATA,
-                                       adapter->dev_id, len, &cp,
-                                       NULL, NULL, NULL) > 0)
-               return dbus_message_new_method_return(msg);
+       if (adapter_le_is_supported_multi_advertising() && slot_id > 0) {
+               if (adapter_le_set_multi_adv_data(slot_id, TRUE, adv_len, (uint8_t *)adv_data)) {
+                       g_free(adv_data);
+                       return dbus_message_new_method_return(msg);
+               } else {
+                       g_free(adv_data);
+                       return btd_error_failed(msg, "set advertising data failed");
+               }
+       } else {
+               memcpy(&cp, adv_data, adv_len);
+
+               if (mgmt_send(adapter->mgmt, MGMT_OP_SET_SCAN_RSP_DATA,
+                                               adapter->dev_id, adv_len, &cp,
+                                               NULL, NULL, NULL) > 0) {
+                       g_free(adv_data);
+                       return dbus_message_new_method_return(msg);
+               }
 
-       return btd_error_failed(msg, "set scan reponse data failed");
+               g_free(adv_data);
+               return btd_error_failed(msg, "set scan reponse data failed");
+       }
 }
 
 static DBusMessage *adapter_add_device_white_list(DBusConnection *conn,
@@ -2860,6 +3358,7 @@ static DBusMessage *adapter_set_le_privacy(DBusConnection *conn,
        return dbus_message_new_method_return(msg);
 }
 
+#if 0 // Not used
 static void read_sec_conn_host_support_complete(uint8_t status, uint16_t length,
                                        const void *param, void *user_data)
 {
@@ -2936,6 +3435,7 @@ static DBusMessage *write_sec_conn_host_support(DBusConnection *conn,
                        NULL, NULL);
        return dbus_message_new_method_return(msg);
 }
+#endif
 
 static DBusMessage *adapter_enable_rssi(DBusConnection *conn,
                                                DBusMessage *msg, void *data)
@@ -3047,6 +3547,37 @@ static DBusMessage *adapter_get_rssi(DBusConnection *conn,
        return btd_error_failed(msg, "Get Raw RSSI Failed");
 }
 
+static void get_adv_tx_power_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const struct mgmt_rp_get_adv_tx_power *rp = param;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to get adv tx power: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
+
+       if (length < sizeof(*rp)) {
+               error("Wrong size of get adv tx power");
+               return;
+       }
+
+       adapter->adv_tx_power = rp->adv_tx_power;
+       return;
+}
+
+static  void adapter_get_adv_tx_power(void *data)
+{
+       struct btd_adapter *adapter = data;
+
+       mgmt_send(adapter->mgmt, MGMT_OP_GET_ADV_TX_POWER,
+                                       adapter->dev_id, 0, NULL,
+                                       get_adv_tx_power_complete, adapter, NULL);
+       return;
+}
+
 #ifdef __BROADCOM_PATCH__
 static DBusMessage *set_wbs_parameters(DBusConnection *conn,
                                DBusMessage *msg, void *data)
@@ -3506,6 +4037,14 @@ static void property_set_powered(const GDBusPropertyTable *property,
                return;
        }
 
+#ifdef __TIZEN_PATCH__
+       if (adapter_le_read_ble_feature_info())
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                       ADAPTER_INTERFACE, "SupportedLEFeatures");
+
+       adapter_get_adv_tx_power(adapter);
+#endif
+
        property_set_mode(adapter, MGMT_SETTING_POWERED, iter, id);
 }
 
@@ -3630,197 +4169,33 @@ static gboolean property_get_discovering(const GDBusPropertyTable *property,
        return TRUE;
 }
 
-#ifdef __TIZEN_PATCH__
-#ifdef BLUEZ5_GATT_CLIENT
-static void print_services(struct client *cli)
+static void add_gatt_uuid(struct gatt_db_attribute *attrib, void *user_data)
 {
-       DBG("+");
-       struct bt_gatt_service_iter iter_srv;
-       const bt_gatt_service_t *service;
-       struct bt_gatt_characteristic_iter iter_chr;
-       const bt_gatt_characteristic_t *chrc;
+       GHashTable *uuids = user_data;
+       bt_uuid_t uuid, u128;
+       char uuidstr[MAX_LEN_UUID_STR + 1];
 
-       if (!bt_gatt_service_iter_init(&iter_srv, cli->gatt)) {
-               DBG("Failed to initialize service iterator");
+       if (!gatt_db_service_get_active(attrib))
                return;
-       }
 
-       while (bt_gatt_service_iter_next(&iter_srv, &service)) {
-               if (!bt_gatt_characteristic_iter_init(&iter_chr, service)) {
-                       DBG("Failed to initialize characteristic iterator");
-                       return;
-               }
-               DBG("service - start: 0x%04x, end: 0x%04x",
-                                       service->start_handle, service->end_handle);
-
-               while (bt_gatt_characteristic_iter_next(&iter_chr, &chrc)) {
-                       DBG("characterustuc - start: 0x%04x, end: 0x%04x, value: 0x%04x, props: 0x%02x",
-                                       chrc->start_handle, chrc->end_handle, chrc->value_handle, chrc->properties);
-               }
-       }
-}
-
-static void gatt_discover_services_cb(bool success, uint8_t att_ecode, void *user_data)
-{
-       struct btd_adapter *adapter = user_data;
-       struct client *cli = adapter->gatt_client;
-
-       DBG("LE Discover services\n");
-
-       print_services(cli);
-}
-
-static void gatt_connected_cb(bool success, uint8_t att_ecode, void *user_data)
-{
-       struct btd_device *device = user_data;
-       struct client *cli;
-       struct btd_adapter *adapter;
-
-       if (!device) {
-               DBG("Unable to get device object");
-               return;
-       }
-       adapter = device_get_adapter(device);
-       cli = adapter->gatt_client;
-
-       if (!success) {
-               DBG("GATT discovery procedures failed - error code: 0x%02x\n",
-                                                               att_ecode);
+       if (!gatt_db_attribute_get_service_uuid(attrib, &uuid))
                return;
-       }
-
-       device_set_gatt_connected(device, TRUE);
-       DBG("LE Device connected\n");
 
-       print_services(cli);
+       bt_uuid_to_uuid128(&uuid, &u128);
+       bt_uuid_to_string(&u128, uuidstr, sizeof(uuidstr));
 
-       fflush(stdout);
+       g_hash_table_add(uuids, strdup(uuidstr));
 }
 
-static void gatt_disconnected_cb(void *user_data)
+static void iter_append_uuid(gpointer key, gpointer value, gpointer user_data)
 {
-       struct btd_device *device = user_data;
-
-       if (!device) {
-               DBG("Unable to get device object");
-               return;
-       }
-
-       device_set_gatt_connected(device, FALSE);
-       DBG("LE Device disconnected\n");
-}
-
-static int le_att_connect(bdaddr_t *src, bdaddr_t *dst, uint8_t dst_type,
-                                                                       int sec)
-{
-       DBG("+");
-       int sock;
-       struct sockaddr_l2 srcaddr, dstaddr;
-       struct bt_security btsec;
-
-       sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
-       if (sock < 0) {
-               error("Failed to create L2CAP socket");
-               return -1;
-       }
-
-       /* Set up source address */
-       memset(&srcaddr, 0, sizeof(srcaddr));
-       srcaddr.l2_family = AF_BLUETOOTH;
-       srcaddr.l2_cid = htobs(ATT_CID);
-       srcaddr.l2_bdaddr_type = 0;
-       bacpy(&srcaddr.l2_bdaddr, src);
-
-       if (bind(sock, (struct sockaddr *)&srcaddr, sizeof(srcaddr)) < 0) {
-               error("Failed to bind L2CAP socket");
-               close(sock);
-               return -1;
-       }
-
-       /* Set the security level */
-       memset(&btsec, 0, sizeof(btsec));
-       btsec.level = sec;
-       if (setsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &btsec,
-                                                       sizeof(btsec)) != 0) {
-               error("Failed to set L2CAP security level\n");
-               close(sock);
-               return -1;
-       }
-
-       /* Set up destination address */
-       memset(&dstaddr, 0, sizeof(dstaddr));
-       dstaddr.l2_family = AF_BLUETOOTH;
-       dstaddr.l2_cid = htobs(ATT_CID);
-       dstaddr.l2_bdaddr_type = dst_type;
-       bacpy(&dstaddr.l2_bdaddr, dst);
+       DBusMessageIter *iter = user_data;
+       const char *uuid = key;
 
-       DBG("Connecting to device...");
-       fflush(stdout);
-
-       if (connect(sock, (struct sockaddr *) &dstaddr, sizeof(dstaddr)) < 0) {
-               error("Failed to connect");
-               close(sock);
-               return -1;
-       }
-
-       DBG(" Done\n");
-
-       return sock;
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
 }
 
-static struct client *create_client(int fd, struct btd_device *device)
-{
-       DBG("+");
-       struct client *cli;
-       struct bt_att *att;
-       struct btd_adapter *adapter;
-
-       cli = g_new0(struct client, 1);
-       if (!cli) {
-               error("Failed to allocate memory for client\n");
-               return NULL;
-       }
-
-       att = bt_att_new(fd);
-       if (!att) {
-               error("Failed to initialze ATT transport layer\n");
-               bt_att_unref(att);
-               free(cli);
-               return NULL;
-       }
-       if (!bt_att_set_close_on_unref(att, true)) {
-               error("Failed to set up ATT transport layer\n");
-               bt_att_unref(att);
-               free(cli);
-               return NULL;
-       }
-       if (!bt_att_register_disconnect(att, gatt_disconnected_cb, device, NULL)) {
-               error("Failed to set ATT disconnect handler\n");
-               bt_att_unref(att);
-               free(cli);
-               return NULL;
-       }
-
-       cli->fd = fd;
-       cli->gatt = bt_gatt_client_new(att, BT_ATT_DEFAULT_LE_MTU); /* mtu value can be adjustable */
-
-       if (!cli->gatt) {
-               error("Failed to create GATT client\n");
-               bt_att_unref(att);
-               free(cli);
-               return NULL;
-       }
-
-       adapter = device_get_adapter(device);
-       adapter->gatt_client = cli;
-
-       bt_gatt_client_set_ready_handler(cli->gatt, gatt_connected_cb, device, NULL);
-
-       /* bt_gatt_client already holds a reference */
-       bt_att_unref(att);
-       return cli;
-}
-#endif /* BLUEZ5_GATT_CLIENT */
+#ifdef __TIZEN_PATCH__
 
 static gboolean property_get_le_discovering(const GDBusPropertyTable *property,
                                        DBusMessageIter *iter, void *user_data)
@@ -3833,17 +4208,7 @@ static gboolean property_get_le_discovering(const GDBusPropertyTable *property,
        return TRUE;
 }
 
-static gboolean property_get_advertising(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *user_data)
-{
-       struct btd_adapter *adapter = user_data;
-       dbus_bool_t advertising = (dbus_bool_t)adapter->advertising;
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &advertising);
-
-       return TRUE;
-}
-
+#if 0 // Not used
 static gboolean property_get_secure_connection(const GDBusPropertyTable
                          *property, DBusMessageIter *iter, void *user_data)
 {
@@ -3855,6 +4220,7 @@ static gboolean property_get_secure_connection(const GDBusPropertyTable
 
        return TRUE;
 }
+#endif
 
 static gboolean property_get_connectable(const GDBusPropertyTable *property,
                                        DBusMessageIter *iter, void *user_data)
@@ -3873,17 +4239,87 @@ static void property_set_connectable(const GDBusPropertyTable *property,
        property_set_mode(adapter, MGMT_SETTING_CONNECTABLE, iter, id);
 }
 
-static gboolean property_get_version(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *user_data)
+static gboolean property_get_version(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const char *str = adapter->version ? : "";
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
+
+       return TRUE;
+}
+
+static gboolean property_get_supported_le_features(
+                                       const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       const char *str, *val;
+       int value;
+       DBusMessageIter entry;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_TYPE_STRING_AS_STRING, &entry);
+
+       value = adapter_le_get_max_adv_instance();
+       if (value > 0) {
+               str = g_strdup("adv_inst_max");
+               dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &str);
+
+               val = g_strdup_printf("%d", value);
+               dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &val);
+
+               free((void *)str);
+               free((void *)val);
+       }
+
+       value = adapter_le_is_supported_offloading();
+       if (value > 0) {
+               str = g_strdup("rpa_offloading");
+               dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &str);
+
+               val = g_strdup_printf("%d", value);
+               dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &val);
+
+               free((void *)str);
+               free((void *)val);
+       }
+
+       value = adapter_le_get_scan_filter_size();
+       if (value > 0) {
+               str = g_strdup("max_filter");
+               dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &str);
+
+               val = g_strdup_printf("%d", value);
+               dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &val);
+
+               free((void *)str);
+               free((void *)val);
+       }
+
+       dbus_message_iter_close_container(iter, &entry);
+
+       return TRUE;
+}
+
+static gboolean property_get_ipsp_init_state(
+                                       const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
 {
-       struct btd_adapter *adapter = user_data;
-       const char *str = adapter->version ? : "";
+       struct btd_adapter *adapter = data;
+       dbus_bool_t ipsp_initialized;
 
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
+       DBG("property_get_ipsp_init_state called");
+       if (adapter->ipsp_intialized)
+               ipsp_initialized = TRUE;
+       else
+               ipsp_initialized = FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN,
+                                       &ipsp_initialized);
 
        return TRUE;
 }
-
 #endif
 
 static gboolean property_get_uuids(const GDBusPropertyTable *property,
@@ -3892,10 +4328,14 @@ static gboolean property_get_uuids(const GDBusPropertyTable *property,
        struct btd_adapter *adapter = user_data;
        DBusMessageIter entry;
        sdp_list_t *l;
+       struct gatt_db *db;
+       GHashTable *uuids;
 
-       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
-                                       DBUS_TYPE_STRING_AS_STRING, &entry);
+       uuids = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
+       if (!uuids)
+               return FALSE;
 
+       /* SDP records */
        for (l = adapter->services; l != NULL; l = l->next) {
                sdp_record_t *rec = l->data;
                char *uuid;
@@ -3904,13 +4344,21 @@ static gboolean property_get_uuids(const GDBusPropertyTable *property,
                if (uuid == NULL)
                        continue;
 
-               dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
-                                                               &uuid);
-               free(uuid);
+               g_hash_table_add(uuids, uuid);
        }
 
+       /* GATT services */
+       db = btd_gatt_database_get_db(adapter->database);
+       if (db)
+               gatt_db_foreach_service(db, NULL, add_gatt_uuid, uuids);
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_TYPE_STRING_AS_STRING, &entry);
+       g_hash_table_foreach(uuids, iter_append_uuid, &entry);
        dbus_message_iter_close_container(iter, &entry);
 
+       g_hash_table_destroy(uuids);
+
        return TRUE;
 }
 
@@ -4036,148 +4484,142 @@ static DBusMessage *find_device(DBusConnection *conn, DBusMessage *msg,
        return reply;
 }
 
-#ifdef BLUEZ5_GATT_CLIENT
-static DBusMessage *connect_le(DBusConnection *conn, DBusMessage *msg,
-                                                       void *user_data)
+static void adapter_set_ipsp_init_state(struct btd_adapter *adapter, gboolean initialized)
 {
-       struct btd_adapter *adapter = user_data;
-       struct btd_device *device;
-       struct client *cli;
-       int fd;
-       int sec_level = BT_SECURITY_LOW;
-       const gchar *address;
-       bdaddr_t addr;
+       if (adapter->ipsp_intialized == initialized)
+               return;
 
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               return btd_error_invalid_args(msg);
+       adapter->ipsp_intialized = initialized;
 
-       if (check_address(address) < 0)
-               return btd_error_invalid_args(msg);
+       DBG("Set Ipsp init state for adapter %s", adapter->path);
 
-       DBG("%s", address);
-       str2ba(address, &addr);
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "IpspInitStateChanged");
+}
 
-       cli = g_new0(struct client, 1);
+static void deinitialize_6lowpan_complete(uint8_t status, uint16_t length,
+       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       bool initialized = FALSE;
 
-       device = btd_adapter_get_device(adapter, &addr,
-                       BDADDR_LE_PUBLIC);
+       if (status != MGMT_STATUS_SUCCESS)
+               error("De-Initialize BT 6lowpan failed for hci%u: %s (0x%02x)",
+                       adapter->dev_id, mgmt_errstr(status), status);
+       else {
+               adapter_set_ipsp_init_state(adapter, initialized);
+               DBG("De-Initialize BT 6lowpan successfully for hci%u",
+                       adapter->dev_id);
+       }
+}
 
-       if (!device) {
-               DBG("Unable to get device object");
-               return btd_error_not_available(msg);
-       } else {
-               if (device_get_gatt_connected(device))
-                       return btd_error_already_connected(msg);
+static bool deinitialize_6lowpan(struct btd_adapter *adapter)
+{
+       struct mgmt_cp_enable_6lowpan cp;
 
-               if (device_is_paired(device, BDADDR_LE_PUBLIC))
-                       sec_level = BT_SECURITY_MEDIUM;
-       }
+       memset(&cp, 0, sizeof(cp));
 
-       fd = le_att_connect(btd_adapter_get_address(adapter),
-                       &addr, BDADDR_LE_PUBLIC, sec_level);
+       cp.enable_6lowpan = DEINIT_6LOWPAN;
+       if (mgmt_send(adapter->mgmt, MGMT_OP_ENABLE_6LOWPAN,
+                       adapter->dev_id, sizeof(cp), &cp,
+                       deinitialize_6lowpan_complete, adapter, NULL) > 0)
+               return true;
 
-       if (fd < 0)
-               return btd_error_not_available(msg);
+       error("Failed to de-initialize BT 6Lowpan for index %u",
+               adapter->dev_id);
+       return false;
+}
 
-       cli = create_client(fd, device);
+static void initialize_6lowpan_complete(uint8_t status, uint16_t length,
+       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       bool initialized = TRUE;
 
-       if (!cli) {
-               close(fd);
-               return btd_error_not_available(msg);
+       if (status != MGMT_STATUS_SUCCESS)
+               error("Initialize BT 6lowpan failed for hci%u: %s (0x%02x)",
+                       adapter->dev_id, mgmt_errstr(status), status);
+       else {
+               adapter_set_ipsp_init_state(adapter, initialized);
+               DBG("Initialize BT 6lowpan successfully for hci%u",
+                       adapter->dev_id);
        }
-       adapter->gatt_client = cli;
+}
 
-       return dbus_message_new_method_return(msg);
+static bool initialize_6lowpan(struct btd_adapter *adapter)
+{
+       struct mgmt_cp_enable_6lowpan cp;
+
+       memset(&cp, 0, sizeof(cp));
+
+       cp.enable_6lowpan = INIT_6LOWPAN;
+       if (mgmt_send(adapter->mgmt, MGMT_OP_ENABLE_6LOWPAN,
+                       adapter->dev_id, sizeof(cp), &cp,
+                       initialize_6lowpan_complete, adapter, NULL) > 0)
+               return true;
+
+       error("Failed to initialize BT 6Lowpan for index %u",
+               adapter->dev_id);
+       return false;
 }
 
-static DBusMessage *disconnect_le(DBusConnection *conn,
-               DBusMessage *msg, void *user_data)
+static DBusMessage *adapter_initialize_ipsp(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
 {
-       struct btd_adapter *adapter = user_data;
-       struct btd_device *device;
-       const gchar *address;
-       bdaddr_t addr;
+       struct btd_adapter *adapter = data;
+       dbus_bool_t err;
 
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               return btd_error_invalid_args(msg);
+       DBG("Initialize IPSP");
 
-       if (check_address(address) < 0)
-               return btd_error_invalid_args(msg);
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
 
-       DBG("%s", address);
-       str2ba(address, &addr);
+       if (adapter->ipsp_intialized)
+               return btd_error_already_exists(msg);
 
-       device = btd_adapter_find_device(adapter, &addr, BDADDR_LE_PUBLIC);
+       /* Register IPSP service as GATT primary service */
+       err = gatt_register_internet_protocol_service(adapter);
 
-       if (!device) {
-               DBG("Unable to get device object");
-               return btd_error_not_available(msg);
-       } else {
-               if (!device_get_gatt_connected(device))
-                       return btd_error_not_connected(msg);
+       if (!err)
+               return btd_error_failed(msg, "Failed to register IPSP service");
 
-               if (btd_device_get_bdaddr_type(device) == BDADDR_BREDR)
-                       return btd_error_not_supported(msg);
-       }
+       /* Enable BT 6lowpan in kernel */
+       err = initialize_6lowpan(adapter);
 
-       DBG("Disconnect LE device");
-       if (!disconnect_le_device(device))
-               return btd_error_failed(msg, "to disconnect LE device");
+       if (!err)
+               return btd_error_failed(msg, "Failed to initialize BT 6lowpan");
 
        return dbus_message_new_method_return(msg);
 }
 
-static DBusMessage *discover_le_services(DBusConnection *conn,
-               DBusMessage *msg, void *user_data)
+static DBusMessage *adapter_deinitialize_ipsp(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
 {
-       DBusMessage *reply;
-       dbus_bool_t val;
-       struct btd_adapter *adapter = user_data;
-       struct btd_device *device;
-       const gchar *address;
-       bdaddr_t addr;
-
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               return btd_error_invalid_args(msg);
-
-       if (check_address(address) < 0)
-               return btd_error_invalid_args(msg);
-
-       DBG("%s", address);
-       str2ba(address, &addr);
+       struct btd_adapter *adapter = data;
+       dbus_bool_t err;
 
-       device = btd_adapter_find_device(adapter, &addr, BDADDR_LE_PUBLIC);
+       DBG("De-initialize IPSP");
 
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return btd_error_invalid_args(msg);
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
 
-       if (!device) {
-               DBG("Unable to get device object");
-               return btd_error_not_available(msg);
-       } else {
-               if (!device_get_gatt_connected(device))
-                       return btd_error_not_connected(msg);
+       if (!adapter->ipsp_intialized)
+               return btd_error_not_permitted(msg, "IPSP not initialized");
 
-               if (btd_device_get_bdaddr_type(device) == BDADDR_BREDR)
-                       return btd_error_not_supported(msg);
-       }
+       /* Un-register IPSP service as GATT primary service */
+       err = gatt_unregister_internet_protocol_service(adapter);
 
-       val = bt_gatt_discover_services(adapter->gatt_client->gatt);
+       if (!err)
+               return btd_error_failed(msg, "Failed to un-register IPSP service");
 
-       if(val == TRUE)
-               bt_gatt_client_set_ready_handler(adapter->gatt_client->gatt,
-                               gatt_discover_services_cb, adapter, NULL);
+       /* Disable BT 6lowpan in kernel */
+       err = deinitialize_6lowpan(adapter);
 
-       dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &val,
-                                                               DBUS_TYPE_INVALID);
+       if (!err)
+               return btd_error_failed(msg, "Failed to deinitialize BT 6lowpan");
 
-       return reply;
+       return dbus_message_new_method_return(msg);
 }
-#endif /* BLUEZ5_GATT_CLIENT */
 #endif
 
 static DBusMessage *remove_device(DBusConnection *conn,
@@ -4224,32 +4666,67 @@ static const GDBusMethodTable adapter_methods[] = {
                        adapter_start_le_discovery) },
        { GDBUS_ASYNC_METHOD("StopLEDiscovery", NULL, NULL,
                        adapter_stop_le_discovery) },
+#if 0 // Not used
        { GDBUS_METHOD("EnableSecureConnection",
                        GDBUS_ARGS({"enable", "b"}), NULL,
                        write_sec_conn_host_support)},
+
        { GDBUS_METHOD("ReadSecureConnection", NULL,
                                        NULL, read_sec_conn_host_support)},
+#endif
+
        { GDBUS_METHOD("SetAdvertising",
-                       GDBUS_ARGS({ "enable", "b" }), NULL,
+                       GDBUS_ARGS({ "enable", "b" },
+                               { "slot_id", "i" }), NULL,
                        adapter_set_advertising) },
        { GDBUS_METHOD("SetAdvertisingParameters",
                        GDBUS_ARGS({ "interval_min", "u" },
                                { "interval_max", "u" },
                                { "filter_policy", "u" },
-                               { "type", "u" }), NULL,
+                               { "type", "u" },
+                               { "slot_id", "i" }), NULL,
                        adapter_set_advertising_params) },
        { GDBUS_METHOD("SetAdvertisingData",
                        GDBUS_ARGS({ "value", "ay" },
-                               { "length", "i" }), NULL,
+                               { "slot_id", "i" }), NULL,
                        adapter_set_advertising_data) },
        { GDBUS_METHOD("SetScanParameters",
                        GDBUS_ARGS({ "type", "u" },
                                { "interval", "u" },
                                { "window", "u" }), NULL,
                        adapter_le_set_scan_params) },
+       { GDBUS_ASYNC_METHOD("scan_filter_param_setup",
+                       GDBUS_ARGS({ "client_if", "i" }, { "action", "i" },
+                               { "filt_index", "i" }, { "feat_seln", "i"},
+                               { "list_logic_type", "i" }, { "filt_logic_type", "i"},
+                               { "rssi_high_thres", "i" }, { "rssi_low_thres", "i"},
+                               { "dely_mode", "i" }, { "found_timeout", "i"},
+                               { "lost_timeout", "i" }, { "found_timeout_cnt", "i"}), NULL,
+                       adapter_le_scan_filter_param_setup) },
+       { GDBUS_ASYNC_METHOD("scan_filter_add_remove",
+                       GDBUS_ARGS({ "client_if", "i" }, { "action", "i" },
+                               { "filt_type", "i" }, { "filt_index", "i"},
+                               { "company_id", "i" }, { "company_id_mask", "i"},
+                               { "p_uuid", "ay" }, { "p_uuid_mask", "ay" },
+                               { "string", "s" }, { "address_type", "u" },
+                               /*{ "data_len", "i" },*/ { "p_data", "ay" },
+                               /*{ "mask_len", "i" },*/ { "p_mask", "ay" }), NULL,
+                       adapter_le_scan_filter_add_remove) },
+       { GDBUS_ASYNC_METHOD("scan_filter_clear",
+                       GDBUS_ARGS({ "client_if", "i" }, { "filt_index", "i" }), NULL,
+                       adapter_le_scan_filter_clear) },
+       { GDBUS_ASYNC_METHOD("scan_filter_enable",
+                       GDBUS_ARGS({ "client_if", "i" }, { "enable", "b" }), NULL,
+                       adapter_le_scan_filter_enable) },
+       { GDBUS_ASYNC_METHOD("InitializeIpsp",
+                       NULL, NULL,
+                       adapter_initialize_ipsp) },
+       { GDBUS_ASYNC_METHOD("DeinitializeIpsp",
+                       NULL, NULL,
+                       adapter_deinitialize_ipsp) },
        { GDBUS_METHOD("SetScanRespData",
                        GDBUS_ARGS({ "value", "ay" },
-                               { "length", "i" }), NULL,
+                               { "slot_id", "i" }), NULL,
                        adapter_set_scan_rsp_data) },
        { GDBUS_METHOD("AddDeviceWhiteList",
                        GDBUS_ARGS({ "address", "s" },
@@ -4299,18 +4776,6 @@ static const GDBusMethodTable adapter_methods[] = {
        { GDBUS_ASYNC_METHOD("CreateDevice",
                        GDBUS_ARGS({ "address", "s" }), NULL,
                        create_device) },
-#ifdef BLUEZ5_GATT_CLIENT
-       { GDBUS_METHOD("ConnectLE",
-                       GDBUS_ARGS({ "address", "s"}),
-                       NULL, connect_le) },
-       { GDBUS_METHOD("DisconnectLE",
-                       GDBUS_ARGS({ "address", "s"}),
-                       NULL, disconnect_le) },
-       { GDBUS_METHOD("DiscoverLEServices",
-                       GDBUS_ARGS({ "address", "s"}),
-                       GDBUS_ARGS({ "result", "b"}),
-                       discover_le_services) },
-#endif
 #endif
        { GDBUS_ASYNC_METHOD("RemoveDevice",
                        GDBUS_ARGS({ "device", "o" }), NULL, remove_device) },
@@ -4319,6 +4784,9 @@ static const GDBusMethodTable adapter_methods[] = {
 
 #ifdef __TIZEN_PATCH__
 static const GDBusSignalTable adapter_signals[] = {
+       { GDBUS_SIGNAL("AdvertisingEnabled",
+                       GDBUS_ARGS({ "slot_id", "i" },
+                                       { "enabled", "b"})) },
        { GDBUS_SIGNAL("RssiEnabled",
                        GDBUS_ARGS({"address","s"},
                                        { "link_type", "i" },
@@ -4359,11 +4827,14 @@ static const GDBusPropertyTable adapter_properties[] = {
        { "Modalias", "s", property_get_modalias, NULL,
                                        property_exists_modalias },
 #ifdef __TIZEN_PATCH__
-       { "Advertising", "b", property_get_advertising },
+#if 0 // Not used
        { "SecureConnection", "b", property_get_secure_connection },
+#endif
        { "Connectable", "b", property_get_connectable,
                                        property_set_connectable },
        { "Version", "s", property_get_version },
+       { "SupportedLEFeatures", "as", property_get_supported_le_features},
+       { "IpspInitStateChanged", "b", property_get_ipsp_init_state},
 #endif
 
        { }
@@ -5219,6 +5690,14 @@ bool btd_adapter_get_connectable(struct btd_adapter *adapter)
        return false;
 }
 
+struct btd_gatt_database *btd_adapter_get_database(struct btd_adapter *adapter)
+{
+       if (!adapter)
+               return NULL;
+
+       return adapter->database;
+}
+
 uint32_t btd_adapter_get_class(struct btd_adapter *adapter)
 {
        return adapter->dev_class;
@@ -6079,6 +6558,7 @@ static void convert_sdp_entry(char *key, char *value, void *user_data)
        if (record_has_uuid(rec, att_uuid))
                goto failed;
 
+       /* TODO: Do this through btd_gatt_database */
        if (!gatt_parse_record(rec, &uuid, &psm, &start, &end))
                goto failed;
 
@@ -6615,6 +7095,9 @@ static struct btd_adapter *btd_adapter_new(uint16_t index)
 static void adapter_remove(struct btd_adapter *adapter)
 {
        GSList *l;
+#ifndef __TIZEN_PATCH__
+       struct gatt_db *db;
+#endif
 
        DBG("Removing adapter %s", adapter->path);
 
@@ -6640,7 +7123,17 @@ static void adapter_remove(struct btd_adapter *adapter)
        adapter->devices = NULL;
 
        unload_drivers(adapter);
+
+#ifndef __TIZEN_PATCH__
+       db = btd_gatt_database_get_db(adapter->database);
+       gatt_db_unregister(db, adapter->db_id);
+       adapter->db_id = 0;
+
+       btd_gatt_database_destroy(adapter->database);
+       adapter->database = NULL;
+#else
        btd_adapter_gatt_server_stop(adapter);
+#endif
 
        g_slist_free(adapter->pin_callbacks);
        adapter->pin_callbacks = NULL;
@@ -6857,6 +7350,7 @@ static void update_found_devices(struct btd_adapter *adapter,
        }
 
        device_set_last_addr_type(dev, bdaddr_type);
+       device_set_ipsp_connected(dev, FALSE);
 #else
        if (device_is_temporary(dev) && !adapter->discovery_list) {
                eir_data_free(&eir_data);
@@ -7176,11 +7670,7 @@ static void adapter_stop(struct btd_adapter *adapter)
        }
 
 #ifdef __TIZEN_PATCH__
-       if (adapter->advertising) {
-               adapter->advertising = FALSE;
-               g_dbus_emit_property_changed(dbus_conn, adapter->path,
-                                       ADAPTER_INTERFACE, "Advertising");
-       }
+       advertiser_cleanup(adapter);
 #endif
        g_dbus_emit_property_changed(dbus_conn, adapter->path,
                                                ADAPTER_INTERFACE, "Powered");
@@ -7267,11 +7757,6 @@ static gboolean process_auth_queue(gpointer user_data)
                if (auth->svc_id > 0)
                        return FALSE;
 
-               if (device_is_service_blocked(device, auth->uuid)) {
-                       auth->cb(&err, auth->user_data);
-                       goto next;
-               }
-
 /* The below patch should be removed after we provide the API
  * to control autorization for the specific UUID.
  */
@@ -7294,7 +7779,7 @@ static gboolean process_auth_queue(gpointer user_data)
                dev_path = device_get_path(device);
 
                if (agent_authorize_service(auth->agent, dev_path, auth->uuid,
-                                       agent_auth_cb, adapter, NULL, auth->fd) < 0) {
+                                       agent_auth_cb, adapter, NULL) < 0) {
                        auth->cb(&err, auth->user_data);
                        goto next;
                }
@@ -7330,7 +7815,7 @@ static void svc_complete(struct btd_device *dev, int err, void *user_data)
 
 static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
                                        const char *uuid, service_auth_cb cb,
-                                       void *user_data, int fd)
+                                       void *user_data)
 {
        struct service_auth *auth;
        struct btd_device *device;
@@ -7354,7 +7839,6 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
        auth->device = device;
        auth->adapter = adapter;
        auth->id = ++id;
-       auth->fd = fd;
        auth->svc_id = device_wait_for_svc_complete(device, svc_complete, auth);
 
        g_queue_push_tail(adapter->auths, auth);
@@ -7364,7 +7848,7 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
 
 guint btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
                                        const char *uuid, service_auth_cb cb,
-                                       void *user_data, int fd)
+                                       void *user_data)
 {
        struct btd_adapter *adapter;
        GSList *l;
@@ -7374,7 +7858,7 @@ guint btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
                if (!adapter)
                        return 0;
 
-               return adapter_authorize(adapter, dst, uuid, cb, user_data, fd);
+               return adapter_authorize(adapter, dst, uuid, cb, user_data);
        }
 
        for (l = adapters; l != NULL; l = g_slist_next(l)) {
@@ -7382,7 +7866,7 @@ guint btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
 
                adapter = l->data;
 
-               id = adapter_authorize(adapter, dst, uuid, cb, user_data, fd);
+               id = adapter_authorize(adapter, dst, uuid, cb, user_data);
                if (id != 0)
                        return id;
        }
@@ -7896,6 +8380,7 @@ void adapter_check_version(struct btd_adapter *adapter, uint8_t hci_ver)
        adapter->version = g_strdup(ver);
 }
 
+#if 0 // Not used
 static void new_local_irk_callback(uint16_t index, uint16_t length,
                                        const void *param, void *user_data)
 {
@@ -7913,6 +8398,7 @@ static void new_local_irk_callback(uint16_t index, uint16_t length,
        memcpy(adapter->local_irk, (char *)ev->irk, sizeof(adapter->local_irk));
        store_adapter_info(adapter);
 }
+#endif
 
 static void hardware_error_callback(uint16_t index, uint16_t length,
                const void *param, void *user_data)
@@ -7949,7 +8435,7 @@ static void device_name_update_callback(uint16_t index, uint16_t length,
        struct btd_adapter *adapter = user_data;
        struct btd_device *device;
        char addr[18];
-       const char *eir_name;
+       const uint8_t *eir_name;
        struct eir_data eir_data;
 
        if (length < sizeof(*ev)) {
@@ -7980,6 +8466,57 @@ static void device_name_update_callback(uint16_t index, uint16_t length,
 
        eir_data_free(&eir_data);
 }
+
+static void multi_adv_state_change_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_vendor_specific_multi_adv_state_changed *ev = param;
+
+       if (length < sizeof(*ev)) {
+               error("Too small adv state change event");
+               return;
+       }
+
+       DBG("adv id %d, state change reason %d, connection_handle %x",
+               ev->adv_instance, ev->state_change_reason, ev->connection_handle);
+
+       if ((ev->adv_instance > 0 && ev->adv_instance < adapter_le_get_max_adv_instance()) &&
+                       ev->state_change_reason == 0)
+               adapter_le_enable_multi_adv(TRUE, ev->adv_instance);
+}
+
+static void bt_6lowpan_conn_state_change_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_6lowpan_conn_state_changed *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       char addr[18];
+       gboolean connected = 0;
+
+       if (length < sizeof(*ev)) {
+               error("Too small device connected event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, addr);
+
+       DBG("hci%u device %s", index, addr);
+
+       device = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
+                                                               ev->addr.type);
+       if (!device) {
+               error("Unable to get device object for %s", addr);
+               return;
+       }
+
+       if (ev->connected)
+               connected = TRUE;
+       else
+               connected = FALSE;
+
+       device_set_ipsp_connected(device, connected);
+}
 #endif
 
 struct btd_adapter_pin_cb_iter *btd_adapter_pin_cb_iter_new(
@@ -8634,7 +9171,7 @@ static void new_long_term_key_callback(uint16_t index, uint16_t length,
 
 static void store_csrk(const bdaddr_t *local, const bdaddr_t *peer,
                                uint8_t bdaddr_type, const unsigned char *key,
-                               uint8_t master)
+                               uint32_t counter, uint8_t type)
 {
        const char *group;
        char adapter_addr[18];
@@ -8643,15 +9180,29 @@ static void store_csrk(const bdaddr_t *local, const bdaddr_t *peer,
        GKeyFile *key_file;
        char key_str[33];
        gsize length = 0;
+       gboolean auth;
        char *str;
        int i;
 
-       if (master == 0x00)
+       switch (type) {
+       case 0x00:
                group = "LocalSignatureKey";
-       else if (master == 0x01)
+               auth = FALSE;
+               break;
+       case 0x01:
                group = "RemoteSignatureKey";
-       else {
-               warn("Unsupported CSRK type %u", master);
+               auth = FALSE;
+               break;
+       case 0x02:
+               group = "LocalSignatureKey";
+               auth = TRUE;
+               break;
+       case 0x03:
+               group = "RemoteSignatureKey";
+               auth = TRUE;
+               break;
+       default:
+               warn("Unsupported CSRK type %u", type);
                return;
        }
 
@@ -8668,6 +9219,8 @@ static void store_csrk(const bdaddr_t *local, const bdaddr_t *peer,
                sprintf(key_str + (i * 2), "%2.2X", key[i]);
 
        g_key_file_set_string(key_file, group, "Key", key_str);
+       g_key_file_set_integer(key_file, group, "Counter", counter);
+       g_key_file_set_boolean(key_file, group, "Authenticated", auth);
 
        create_file(filename, S_IRUSR | S_IWUSR);
 
@@ -8696,8 +9249,8 @@ static void new_csrk_callback(uint16_t index, uint16_t length,
 
        ba2str(&addr->bdaddr, dst);
 
-       DBG("hci%u new CSRK for %s master %u", adapter->dev_id, dst,
-                                                               ev->key.master);
+       DBG("hci%u new CSRK for %s type %u", adapter->dev_id, dst,
+                                                               ev->key.type);
 
        device = btd_adapter_get_device(adapter, &addr->bdaddr, addr->type);
        if (!device) {
@@ -8708,8 +9261,8 @@ static void new_csrk_callback(uint16_t index, uint16_t length,
        if (!ev->store_hint)
                return;
 
-       store_csrk(bdaddr, &key->addr.bdaddr, key->addr.type, key->val,
-                                                               key->master);
+       store_csrk(bdaddr, &key->addr.bdaddr, key->addr.type, key->val, 0,
+                                                               key->type);
 
        if (device_is_temporary(device))
                btd_device_set_temporary(device, FALSE);
@@ -9077,9 +9630,22 @@ static int set_did(struct btd_adapter *adapter, uint16_t vendor,
        return -EIO;
 }
 
+#ifndef __TIZEN_PATCH__
+static void services_modified(struct gatt_db_attribute *attrib, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "UUIDs");
+}
+#endif
+
 static int adapter_register(struct btd_adapter *adapter)
 {
        struct agent *agent;
+#ifndef __TIZEN_PATCH__
+       struct gatt_db *db;
+#endif
 
        if (powering_down)
                return -EBUSY;
@@ -9114,7 +9680,21 @@ static int adapter_register(struct btd_adapter *adapter)
                agent_unref(agent);
        }
 
+#ifndef __TIZEN_PATCH__
+       adapter->database = btd_gatt_database_new(adapter);
+       if (!adapter->database) {
+               error("Failed to create GATT database for adapter");
+               adapters = g_slist_remove(adapters, adapter);
+               return -EINVAL;
+       }
+
+       db = btd_gatt_database_get_db(adapter->database);
+       adapter->db_id = gatt_db_register(db, services_modified,
+                                                       services_modified,
+                                                       adapter, NULL);
+#else
        btd_adapter_gatt_server_start(adapter);
+#endif
 
        load_config(adapter);
        fix_storage(adapter);
@@ -9204,6 +9784,7 @@ static void connected_callback(uint16_t index, uint16_t length,
        struct eir_data eir_data;
        uint16_t eir_len;
        char addr[18];
+       bool name_known;
 
        if (length < sizeof(*ev)) {
                error("Too small device connected event");
@@ -9236,7 +9817,9 @@ static void connected_callback(uint16_t index, uint16_t length,
 
        adapter_add_connection(adapter, device, ev->addr.type);
 
-       if (eir_data.name != NULL) {
+       name_known = device_name_known(device);
+
+       if (eir_data.name && (eir_data.name_complete || !name_known)) {
                device_store_cached_name(device, eir_data.name);
                btd_device_device_set_name(device, eir_data.name);
        }
@@ -9467,6 +10050,44 @@ static bool set_privacy(struct btd_adapter *adapter, bool privacy)
 
        return false;
 }
+
+int btd_adapter_connect_ipsp(struct btd_adapter *adapter,
+                                               const bdaddr_t *bdaddr,
+                                               uint8_t bdaddr_type)
+
+{
+       struct mgmt_cp_connect_6lowpan cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_CONNECT_6LOWPAN,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
+
+int btd_adapter_disconnect_ipsp(struct btd_adapter *adapter,
+                                               const bdaddr_t *bdaddr,
+                                               uint8_t bdaddr_type)
+
+{
+       struct mgmt_cp_disconnect_6lowpan cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_DISCONNECT_6LOWPAN,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
 #endif
 
 static void clear_devices_complete(uint8_t status, uint16_t length,
@@ -9588,8 +10209,10 @@ static void read_info_complete(uint8_t status, uint16_t length,
                break;
        }
 
+#if 0
        if (missing_settings & MGMT_SETTING_SECURE_CONN)
                set_mode(adapter, MGMT_OP_SET_SECURE_CONN, 0x01);
+#endif
 
        err = adapter_register(adapter);
        if (err < 0) {
@@ -9733,10 +10356,12 @@ static void read_info_complete(uint8_t status, uint16_t length,
                                                        rssi_disabled_callback,
                                                        adapter, NULL);
 
+#if 0 // Not used
        mgmt_register(adapter->mgmt, MGMT_EV_NEW_LOCAL_IRK,
                                                adapter->dev_id,
                                                new_local_irk_callback,
                                                adapter, NULL);
+#endif
 
        mgmt_register(adapter->mgmt, MGMT_EV_HARDWARE_ERROR,
                                                adapter->dev_id,
@@ -9752,6 +10377,16 @@ static void read_info_complete(uint8_t status, uint16_t length,
                                        adapter->dev_id,
                                        device_name_update_callback,
                                        adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_MULTI_ADV_STATE_CHANGED,
+                               adapter->dev_id,
+                               multi_adv_state_change_callback,
+                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_6LOWPAN_CONN_STATE_CHANGED,
+                                               adapter->dev_id,
+                                               bt_6lowpan_conn_state_change_callback,
+                                               adapter, NULL);
 #endif
 
        set_dev_class(adapter);
@@ -10104,6 +10739,7 @@ bool btd_le_connect_before_pairing(void)
 }
 
 #ifdef __TIZEN_PATCH__
+#if 0 // Not used
 static void read_rssi_complete(uint8_t status, uint16_t length,
                                        const void *param, void *user_data)
 {
@@ -10240,6 +10876,7 @@ int btd_adapter_read_auth_payload_timeout(struct btd_adapter *adapter,
                        return 0;
        return -EIO;
 }
+#endif
 
 int btd_adapter_le_conn_update(struct btd_adapter *adapter, bdaddr_t *bdaddr,
                                uint16_t interval_min, uint16_t interval_max,
index 0069c4b..d402dbf 100644 (file)
  *
  */
 
+#include <stdbool.h>
+#include <dbus/dbus.h>
+#include <glib.h>
+#ifdef __TIZEN_PATCH__
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/hci.h>
 #include <bluetooth/hci_lib.h>
-#include <dbus/dbus.h>
-#include <glib.h>
-#include <stdbool.h>
+#endif
 
 #define MAX_NAME_LENGTH                248
 
@@ -86,6 +88,8 @@ bool btd_adapter_get_pairable(struct btd_adapter *adapter);
 bool btd_adapter_get_powered(struct btd_adapter *adapter);
 bool btd_adapter_get_connectable(struct btd_adapter *adapter);
 
+struct btd_gatt_database *btd_adapter_get_database(struct btd_adapter *adapter);
+
 uint32_t btd_adapter_get_class(struct btd_adapter *adapter);
 const char *btd_adapter_get_name(struct btd_adapter *adapter);
 void btd_adapter_remove_device(struct btd_adapter *adapter,
@@ -127,7 +131,7 @@ void adapter_remove_profile(struct btd_adapter *adapter, gpointer p);
 int btd_register_adapter_driver(struct btd_adapter_driver *driver);
 void btd_unregister_adapter_driver(struct btd_adapter_driver *driver);
 guint btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
-               const char *uuid, service_auth_cb cb, void *user_data, int fd);
+               const char *uuid, service_auth_cb cb, void *user_data);
 int btd_cancel_authorization(guint id);
 
 int btd_adapter_restore_powered(struct btd_adapter *adapter);
@@ -236,17 +240,22 @@ void btd_adapter_for_each_device(struct btd_adapter *adapter,
 bool btd_le_connect_before_pairing(void);
 
 #ifdef __TIZEN_PATCH__
+#if 0 // Not used
 int btd_adapter_read_rssi(struct btd_adapter *adapter, bdaddr_t *bdaddr,
                        struct btd_device *device);
+
 int btd_adapter_l2cap_conn_param_update(struct btd_adapter *adapter,
                        bdaddr_t *bdaddr, uint16_t interval_min,
                        uint16_t interval_max, uint16_t latency,
                        uint16_t supervision_time_out);
+
 int btd_adapter_write_auth_payload_timeout(struct btd_adapter *adapter,
                                bdaddr_t *bdaddr, uint32_t payload_timeout,
                                struct btd_device *device);
 int btd_adapter_read_auth_payload_timeout(struct btd_adapter *adapter,
                                bdaddr_t *bdaddr, struct btd_device *device);
+#endif
+
 int btd_adapter_le_conn_update(struct btd_adapter *adapter, bdaddr_t *bdaddr,
                        uint16_t interval_min, uint16_t interval_max,
                        uint16_t latency, uint16_t supervision_time_out);
@@ -258,4 +267,11 @@ void btd_adapter_set_le_auto_connect(struct btd_adapter *adapter, gboolean auto_
 gboolean btd_adapter_disable_le_auto_connect(struct btd_adapter *adapter);
 void adapter_check_version(struct btd_adapter *adapter, uint8_t hci_ver);
 GSList *btd_adapter_get_connections(struct btd_adapter *adapter);
-#endif
\ No newline at end of file
+int btd_adapter_connect_ipsp(struct btd_adapter *adapter,
+                                               const bdaddr_t *bdaddr,
+                                               uint8_t bdaddr_type);
+int btd_adapter_disconnect_ipsp(struct btd_adapter *adapter,
+                                               const bdaddr_t *bdaddr,
+                                               uint8_t bdaddr_type);
+
+#endif
diff --git a/src/adapter_le_vsc_features.c b/src/adapter_le_vsc_features.c
new file mode 100644 (file)
index 0000000..440938c
--- /dev/null
@@ -0,0 +1,652 @@
+#ifdef __TIZEN_PATCH__
+#ifdef __BROADCOM_PATCH__
+
+#include <errno.h>
+
+#include "log.h"
+#include "adapter.h"
+#include "eir.h"
+
+#include "adapter_le_vsc_features.h"
+
+
+static apater_le_vsc_rp_get_vendor_cap ble_vsc_cb = { -1, };
+
+void add_data_to_stream(uint8_t *stream, uint8_t *data, uint8_t len)
+{
+       int i;
+
+       for (i=0; i<len; i++) {
+               *(stream)++ = (uint8_t) data[len-1-i];
+               DBG("[%d]>> 0x%X", i, data[len-1-i] );
+               }
+}
+
+static int send_vsc_command(uint16_t ocf, uint8_t *cp, uint8_t cp_len,
+                                               uint8_t *rp, uint8_t rp_len)
+{
+       int dd;
+       struct hci_request rq;
+
+       dd = hci_open_dev(0);
+       if (dd < 0) {
+               error("hci_open_dev is failed");
+               return -1;
+       }
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf    = OGF_VENDOR_CMD;
+       rq.ocf    = ocf;
+       rq.cparam = cp;
+       rq.clen   = cp_len;
+       rq.rparam = rp;
+       rq.rlen   = rp_len;
+
+       if (hci_send_req(dd, &rq, 5000) < 0) {
+               error("Fail to send VSC");
+               hci_close_dev(dd);
+               return -1;
+       }
+
+       hci_close_dev(dd);
+       return 0;
+}
+
+gboolean adapter_le_read_ble_feature_info(void)
+{
+       int ret;
+
+       DBG("");
+
+       ret = send_vsc_command(OCF_BCM_LE_GET_VENDOR_CAP, (uint8_t *) NULL, 0,
+                                               (uint8_t *) &ble_vsc_cb, sizeof(ble_vsc_cb));
+       if (ret < 0)
+               return FALSE;
+
+       if (HCI_SUCCESS != ble_vsc_cb.status) {
+               error("Fail to read ble feature info");
+               return FALSE;
+       }
+
+       DBG("======== BLE support info ========");
+       DBG("adv_inst_max [%d]", ble_vsc_cb.adv_inst_max);
+       DBG("rpa_offloading [%d]", ble_vsc_cb.rpa_offloading);
+       DBG("tot_scan_results_strg [%d]", ble_vsc_cb.tot_scan_results_strg);
+       DBG("max_irk_list_sz [%d]", ble_vsc_cb.max_irk_list_sz);
+       DBG("filter_support [%d]", ble_vsc_cb.filter_support);
+       DBG("max_filter [%d]", ble_vsc_cb.max_filter);
+       DBG("energy_support [%d]", ble_vsc_cb.energy_support);
+       DBG("onlost_follow [%d]", ble_vsc_cb.onlost_follow);
+       DBG("=================================");
+
+       return TRUE;
+}
+
+int adapter_le_get_max_adv_instance(void)
+{
+       if (HCI_SUCCESS != ble_vsc_cb.status) {
+               error("not yet acquired chipset info");
+               return 0;
+       }
+
+       /* GearS does not support multi advertising.
+       but its official firmware returns adv_inst_max vaule to 5.
+       So here check rpa_offloading support and filter_support */
+       if (!ble_vsc_cb.rpa_offloading || !ble_vsc_cb.max_filter)
+               return 0;
+
+       return ble_vsc_cb.adv_inst_max;
+}
+
+gboolean adapter_le_is_supported_multi_advertising(void)
+{
+       if (HCI_SUCCESS != ble_vsc_cb.status) {
+               error("not yet acquired chipset info");
+               return FALSE;
+       }
+
+       /* GearS does not support multi advertising.
+       but its official firmware returns adv_inst_max vaule to 5.
+       So here check rpa_offloading support and filter_support */
+       if (!ble_vsc_cb.rpa_offloading || !ble_vsc_cb.max_filter)
+               return FALSE;
+
+       if (ble_vsc_cb.adv_inst_max >= 5)
+               return TRUE;
+       else
+               return FALSE;
+}
+
+gboolean adapter_le_is_supported_offloading(void)
+{
+       if (HCI_SUCCESS != ble_vsc_cb.status) {
+               error("not yet acquired chipset info");
+               return FALSE;
+       }
+
+       return ble_vsc_cb.rpa_offloading ? TRUE : FALSE;
+}
+
+int adapter_le_get_scan_filter_size(void)
+{
+       if (HCI_SUCCESS != ble_vsc_cb.status) {
+               error("not yet acquired chipset info");
+               return 0;
+       }
+#if 0
+       if (!ble_vsc_cb.filter_support) {
+               error("filter_support is not supported");
+               return 0;
+       }
+#endif
+       return ble_vsc_cb.max_filter;
+}
+
+gboolean adapter_le_set_multi_adv_params (adapter_le_adv_inst_info_t *p_inst,
+                                       adapter_le_adv_param_t *p_params)
+{
+       int ret;
+       adapter_le_vsc_cp_set_multi_adv_params cp;
+       apater_le_vsc_rp_multi_adv rp;
+
+       DBG("");
+
+       memset(&cp, 0, sizeof(cp));
+       cp.subcode = SUB_CMD_LE_MULTI_ADV_SET_PARAM;
+       cp.adv_int_min = p_params->adv_int_min;
+       cp.adv_int_max = p_params->adv_int_max;
+       cp.adv_type = p_params->adv_type;
+       cp.bdaddr_type = p_inst->bdaddr_type;
+       bacpy(&cp.bdaddr, &p_inst->bdaddr);
+       cp.direct_bdaddr_type = 0;
+       bacpy(&cp.direct_bdaddr, BDADDR_ANY);
+
+       cp.channel_map = p_params->channel_map;
+       cp.adv_filter_policy = p_params->adv_filter_policy;
+       cp.inst_id = p_inst->inst_id;
+       cp.tx_power = p_params->tx_power;
+
+       ret = send_vsc_command(OCF_BCM_LE_MULTI_ADV, (uint8_t *) &cp, sizeof(cp),
+                                       (uint8_t *) &rp, sizeof(rp));
+
+       if (ret < 0)
+               return FALSE;
+
+       if (HCI_SUCCESS != rp.status) {
+               DBG("Fail to send VSC :: sub[%x] - status [0x%02x]", rp.subcode, rp.status);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+gboolean adapter_le_set_multi_adv_data(uint8_t inst_id, gboolean is_scan_rsp,
+                                       uint8_t data_len, uint8_t *p_data)
+{
+       int ret;
+       adapter_le_vsc_cp_set_multi_adv_data cp;
+       apater_le_vsc_rp_multi_adv rp;
+
+       DBG("");
+
+       memset(&cp, 0, sizeof(cp));
+       cp.subcode = (is_scan_rsp) ?
+                           SUB_CMD_LE_MULTI_ADV_WRITE_SCAN_RSP_DATA :
+                           SUB_CMD_LE_MULTI_ADV_WRITE_ADV_DATA;
+       cp.data_len = data_len;
+       memcpy(&cp.data, p_data, data_len);
+       cp.inst_id = inst_id;
+
+       ret = send_vsc_command(OCF_BCM_LE_MULTI_ADV, (uint8_t *) &cp, sizeof(cp),
+                                       (uint8_t *) &rp, sizeof(rp));
+
+       if (ret < 0)
+               return FALSE;
+
+       if (HCI_SUCCESS != rp.status) {
+               DBG("Fail to send VSC :: sub[%x] - status [0x%02x]", rp.subcode, rp.status);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+gboolean adapter_le_enable_multi_adv (gboolean enable, uint8_t inst_id)
+{
+       int ret;
+       adapter_le_vsc_cp_enable_multi_adv cp;
+       apater_le_vsc_rp_multi_adv rp;
+
+       DBG("");
+
+       memset(&cp, 0, sizeof(cp));
+       cp.subcode = SUB_CMD_LE_MULTI_ADV_ENB;
+       cp.enable = enable;
+       cp.inst_id = inst_id;
+
+       ret = send_vsc_command(OCF_BCM_LE_MULTI_ADV, (uint8_t *) &cp, sizeof(cp),
+                                       (uint8_t *) &rp, sizeof(rp));
+
+       if (ret < 0)
+               return FALSE;
+
+       if (HCI_SUCCESS != rp.status) {
+               DBG("Fail to send VSC :: sub[%x] - status [0x%02x]", rp.subcode, rp.status);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+gboolean adapter_le_enable_scan_filtering (gboolean enable)
+{
+       int ret;
+       adapter_le_vsc_cp_enable_scan_filter cp;
+       apater_le_vsc_rp_enable_scan_filter rp;
+
+       DBG(" enable[%d]", enable);
+
+       memset(&cp, 0, sizeof(cp));
+       cp.subcode = SUB_CMD_LE_META_PF_ENABLE;
+       cp.enable = enable;
+
+       ret = send_vsc_command(OCF_BCM_LE_SCAN_FILTER, (uint8_t *) &cp, sizeof(cp),
+                                               (uint8_t *) &rp, sizeof(rp));
+
+       if (ret < 0)
+               return FALSE;
+
+       if (HCI_SUCCESS != rp.status) {
+               DBG("Fail to send VSC :: sub[%x] - status [%x]", rp.subcode, rp.status);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+gboolean adapter_le_set_scan_filter_params(adapter_le_scan_filter_param_t *params)
+{
+       int ret;
+       adapter_le_vsc_cp_apcf_set_filter_params cp;
+       adapter_le_vsc_rp_apcf_set_scan_filter rp;
+
+       DBG("filter_index [%d]", params->index);
+
+       memset(&cp, 0, sizeof(cp));
+       cp.subcode = SUB_CMD_LE_META_PF_FEAT_SEL;
+       cp.action = params->action;
+       cp.filter_index= params->index;
+       cp.feature= params->feature;
+       cp.feature_list_logic = params->filter_logic_type;
+       cp.filter_logic = params->filter_logic_type;
+       cp.rssi_high_threshold = params->rssi_high_threshold;
+       cp.rssi_low_thresh = params->rssi_low_threshold;
+       cp.delivery_mode = params->delivery_mode;
+       cp.onfound_timeout = params->onfound_timeout;
+       cp.onfound_timeout_cnt = params->onfound_timeout_cnt;
+       cp.onlost_timeout = params->onlost_timeout;
+
+       ret = send_vsc_command(OCF_BCM_LE_SCAN_FILTER, (uint8_t *) &cp, sizeof(cp),
+                                               (uint8_t *) &rp, sizeof(rp));
+
+       if (ret < 0)
+               return FALSE;
+
+       if (HCI_SUCCESS != rp.status) {
+               DBG("Fail to send VSC :: sub[%x] - status [%x] Available space [%x]",
+                                       rp.subcode, rp.status, rp.available_space);
+               return FALSE;
+       }
+
+       DBG("Scan Filter VSC :: sub[%x] - status [%x] Action [%x] Available space [%x]",
+                                       rp.subcode, rp.status, rp.action, rp.available_space);
+       return TRUE;
+}
+
+gboolean adapter_le_service_address_scan_filtering(adapter_le_address_filter_params_t *params)
+{
+       int ret;
+       adapter_le_vsc_cp_address_scan_filter cp;
+       adapter_le_vsc_rp_apcf_set_scan_filter rp;
+
+       DBG("");
+
+       memset(&cp, 0, sizeof(cp));
+       cp.subcode = SUB_CMD_LE_META_PF_ADDR;
+       cp.action= params ->action;
+       cp.filter_index = params->filter_index;
+
+       bacpy(&cp.bdaddr, &params->broadcaster_addr);
+       cp.bdaddr_type = params->bdaddr_type;
+
+       ret = send_vsc_command(OCF_BCM_LE_SCAN_FILTER, (uint8_t *) &cp, sizeof(cp),
+                                               (uint8_t *) &rp, sizeof(rp));
+
+       if (ret < 0)
+               return FALSE;
+
+       if (HCI_SUCCESS != rp.status) {
+               DBG("Fail to send VSC :: sub[%x] - status [%x]", rp.subcode, rp.status);
+               return FALSE;
+       }
+
+       DBG("Scan Filter VSC :: sub[%x] - status [%x] Action [%x] Available space [%x]",
+                                       rp.subcode, rp.status, rp.action, rp.available_space);
+
+       return TRUE;
+}
+
+gboolean adapter_le_service_uuid_scan_filtering(gboolean is_solicited,
+                                       adapter_le_uuid_params_t *params)
+{
+       int ret;
+       adapter_le_vsc_cp_service_uuid_scan_filter cp;
+       adapter_le_vsc_rp_apcf_set_scan_filter rp;
+       uint8_t *p = cp.data;
+       int cp_len = UUID_SCAN_FILTER_HEADER_SIZE;
+
+       DBG("");
+
+       memset(&cp, 0, sizeof(cp));
+       cp.subcode = (is_solicited) ? SUB_CMD_LE_META_PF_SOL_UUID :
+                                       SUB_CMD_LE_META_PF_UUID;
+
+       cp.action= params ->action;
+       cp.filter_index = params->filter_index;
+
+       add_data_to_stream((uint8_t *)&cp.data, params->uuid, params->uuid_len);
+       cp_len += params->uuid_len;
+
+       add_data_to_stream(p+params->uuid_len, params->uuid_mask, params->uuid_len);
+       cp_len += params->uuid_len;
+
+       ret = send_vsc_command(OCF_BCM_LE_SCAN_FILTER, (uint8_t *) &cp, cp_len,
+                                               (uint8_t *) &rp, sizeof(rp));
+
+       if (ret < 0)
+               return FALSE;
+
+       if (HCI_SUCCESS != rp.status) {
+               DBG("Fail to send VSC :: sub[%x] - status [%x]", rp.subcode, rp.status);
+               return FALSE;
+       }
+
+       DBG("Scan Filter VSC :: sub[%x] - status [%x] Action [%x] Available space [%x]",
+                                       rp.subcode, rp.status, rp.action, rp.available_space);
+
+       return TRUE;
+}
+
+gboolean adapter_le_local_name_scan_filtering(adapter_le_local_name_params_t *params)
+{
+       int ret;
+       adapter_le_vsc_cp_local_name_scan_filter cp;
+       adapter_le_vsc_rp_apcf_set_scan_filter rp;
+       int cp_len = NAME_SCAN_FILTER_HEADER_SIZE;
+       int name_len;
+
+       DBG("");
+
+       memset(&cp, 0, sizeof(cp));
+       cp.subcode = SUB_CMD_LE_META_PF_LOCAL_NAME;
+       cp.action= params->action;
+       cp.filter_index = params->filter_index;
+
+       name_len = params->name_len;
+       DBG("name [%s], len [%d]",params->local_name, name_len);
+
+       if (name_len > SCAN_FILTER_DATA_MAX_LEN)
+               name_len = SCAN_FILTER_DATA_MAX_LEN;
+
+       if (name_len > 0) {
+               memcpy(&cp.name, params->local_name, name_len);
+               cp_len += name_len;
+       }
+
+       ret = send_vsc_command(OCF_BCM_LE_SCAN_FILTER, (uint8_t *) &cp, cp_len,
+                                               (uint8_t *) &rp, sizeof(rp));
+
+       if (ret < 0)
+               return FALSE;
+
+       if (HCI_SUCCESS != rp.status) {
+               DBG("Fail to send VSC :: sub[%x] - status [%x]", rp.subcode, rp.status);
+               return FALSE;
+       }
+
+       DBG("Scan Filter VSC :: sub[%x] - status [%x] Action [%x] Available space [%x]",
+                                       rp.subcode, rp.status, rp.action, rp.available_space);
+
+       return TRUE;
+}
+
+gboolean adapter_le_manf_data_scan_filtering (adapter_le_manf_data_params_t *params)
+{
+       int ret;
+       adapter_le_vsc_cp_manf_data_scan_filter cp;
+       adapter_le_vsc_rp_apcf_set_scan_filter rp;
+       uint8_t *p = cp.data;
+       int data_len = 0;
+       DBG("");
+
+       memset(&cp, 0, sizeof(cp));
+       cp.subcode = SUB_CMD_LE_META_PF_MANU_DATA;
+       cp.action= params->action;
+       cp.filter_index = params->filter_index;
+
+       /* add company_id and data */
+       cp.data[data_len++] = (uint8_t) (params->company_id >> 8);
+       cp.data[data_len++] = (uint8_t) params->company_id;
+       DBG("");
+       memcpy(p + data_len, params->man_data, params->man_data_len);
+       data_len += params->man_data_len;
+
+       /* add company_id mask and data mask */
+       cp.data[data_len++] = (uint8_t) (params->company_id_mask >> 8);
+       cp.data[data_len++] = (uint8_t) params->company_id_mask;
+       memcpy(p + data_len, params->man_data_mask, params->man_data_len);
+       data_len += params->man_data_len;
+
+       ret = send_vsc_command(OCF_BCM_LE_SCAN_FILTER, (uint8_t *) &cp,
+                                               MANF_DATA_SCAN_FILTER_HEADER_SIZE + data_len,
+                                               (uint8_t *) &rp, sizeof(rp));
+
+       if (ret < 0)
+               return FALSE;
+
+       if (HCI_SUCCESS != rp.status) {
+               DBG("Fail to send VSC :: sub[%x] - status [%x]", rp.subcode, rp.status);
+               return FALSE;
+       }
+
+       DBG("Scan Filter VSC :: sub[%x] - status [%x] Action [%x] Available space [%x]",
+                                       rp.subcode, rp.status, rp.action, rp.available_space);
+
+       return TRUE;
+}
+
+gboolean adapter_le_service_data_scan_filtering (adapter_le_service_data_params_t *params)
+{
+       int ret;
+       adapter_le_vsc_cp_service_data_scan_filter cp;
+       adapter_le_vsc_rp_apcf_set_scan_filter rp;
+       uint8_t *p = cp.data;
+       int cp_len = SERVICE_DATA_SCAN_FILTER_HEADER_SIZE;
+
+       DBG("");
+
+       memset(&cp, 0, sizeof(cp));
+       cp.subcode = SUB_CMD_LE_META_PF_SRVC_DATA;
+       cp.action= params->action;
+       cp.filter_index = params->filter_index;
+
+       memcpy(&cp.data, params->service_data, params->service_data_len);
+       cp_len += params->service_data_len;
+
+       memcpy(p+params->service_data_len, params->service_data_mask,
+                                               params->service_data_len);
+       cp_len += params->service_data_len;
+
+       ret = send_vsc_command(OCF_BCM_LE_SCAN_FILTER, (uint8_t *) &cp, cp_len,
+                                               (uint8_t *) &rp, sizeof(rp));
+
+       if (ret < 0)
+               return FALSE;
+
+       if (HCI_SUCCESS != rp.status) {
+               DBG("Fail to send VSC :: sub[%x] - status [%x]", rp.subcode, rp.status);
+               return FALSE;
+       }
+
+       DBG("Scan Filter VSC :: sub[%x] - status [%x] Action [%x] Available space [%x]",
+                                       rp.subcode, rp.status, rp.action, rp.available_space);
+
+       return TRUE;
+}
+
+gboolean adapter_le_set_scan_filter_data(int client_if, int action,
+                                                       int filt_type, int filter_index,
+                                                       int company_id,
+                                                       int company_id_mask,
+                                                       int uuid_len, uint8_t *p_uuid,
+                                                       int uuid_mask_len, uint8_t *p_uuid_mask,
+                                                       gchar *string, int addr_type,
+                                                       int data_len, uint8_t *p_data,
+                                                       int mask_len, uint8_t *p_mask)
+{
+       gboolean ret;
+
+       DBG("");
+
+       switch (filt_type) {
+       case TYPE_DEVICE_ADDRESS: {
+               /* TYPE_DEVICE_ADDRESS */
+               adapter_le_address_filter_params_t params;
+               bdaddr_t bd_addr;
+
+               str2ba(string, &bd_addr);
+
+               params.action = action;
+               params.filter_index = filter_index;
+               bacpy(&params.broadcaster_addr, &bd_addr);
+               params.bdaddr_type = addr_type;
+
+               ret = adapter_le_service_address_scan_filtering(&params);
+               break;
+       }
+
+       case TYPE_SERVICE_UUID:
+       case TYPE_SOLICIT_UUID: {
+               adapter_le_uuid_params_t params;
+               gboolean is_solicited = (filt_type == TYPE_SOLICIT_UUID) ? TRUE : FALSE;
+
+               if (uuid_len != UUID_16_LEN && uuid_len != UUID_32_LEN
+                       && uuid_len != UUID_128_LEN) {
+                       DBG("UUID length error");
+                       return FALSE;
+               }
+
+               if (uuid_len != uuid_mask_len) {
+                       DBG("Both UUID and UUID_MASK length shoule be samed");
+                       return FALSE;
+               }
+
+               params.action = action;
+               params.filter_index = filter_index;
+               params.uuid =  p_uuid;
+               params.uuid_mask =  p_uuid_mask;
+               params.uuid_len = uuid_len;
+
+               ret = adapter_le_service_uuid_scan_filtering(is_solicited, &params);
+               break;
+       }
+
+       case TYPE_LOCAL_NAME: {
+               adapter_le_local_name_params_t params;
+
+               params.action = action;
+               params.filter_index = filter_index;
+               params.local_name = string;
+               params.name_len = strlen(string);
+               ret = adapter_le_local_name_scan_filtering(&params);
+               break;
+       }
+
+       case TYPE_MANUFACTURER_DATA: {
+               adapter_le_manf_data_params_t params;
+
+               if (data_len == 0 || (data_len != mask_len)) {
+                       DBG("parameter length error");
+                       return FALSE;
+               }
+
+               params.action = action;
+               params.filter_index = filter_index;
+               params.company_id = company_id;
+               params.company_id_mask = company_id_mask;
+               params.man_data = p_data;
+               params.man_data_mask = p_mask;
+               params.man_data_len = data_len;
+
+               ret = adapter_le_manf_data_scan_filtering(&params);
+               break;
+       }
+
+       case TYPE_SERVICE_DATA: {
+               adapter_le_service_data_params_t params;
+
+               if (data_len == 0 || (data_len != mask_len)) {
+                       DBG("parameter length error");
+                       return FALSE;
+               }
+
+               params.action = action;
+               params.filter_index = filter_index;
+               params.service_data = p_data;
+               params.service_data_mask = p_mask;
+               params.service_data_len = data_len;
+
+               ret = adapter_le_service_data_scan_filtering(&params);
+               break;
+       }
+
+       default:
+               DBG("filter_type error");
+               ret = FALSE;
+       }
+
+       return ret;
+}
+
+gboolean adapter_le_clear_scan_filter_data(int client_if, int filter_index)
+{
+       int ret;
+       adapter_le_vsc_cp_service_data_scan_filter cp;
+       adapter_le_vsc_rp_apcf_set_scan_filter rp;
+
+       DBG("");
+
+       memset(&cp, 0, sizeof(cp));
+       cp.subcode = SUB_CMD_LE_META_PF_FEAT_SEL;
+       cp.action= 0x02; // (Add - 0x00, Delete - 0x01, Clear - 0x02)
+       cp.filter_index = filter_index;
+
+       ret = send_vsc_command(OCF_BCM_LE_SCAN_FILTER, (uint8_t *) &cp, sizeof(cp),
+                                               (uint8_t *) &rp, sizeof(rp));
+
+       if (ret < 0)
+               return FALSE;
+
+       if (HCI_SUCCESS != rp.status) {
+               DBG("Fail to send VSC :: sub[%x] - status [%x] Available space [%x]",
+                                       rp.subcode, rp.status, rp.available_space);
+               return FALSE;
+       }
+
+       DBG("Scan Filter VSC :: sub[%x] - status [%x] Action [%x] Available space [%x]",
+                                       rp.subcode, rp.status, rp.action, rp.available_space);
+       return TRUE;
+}
+
+#endif /* __BROADCOM_PATCH__ */
+#endif /* __TIZEN_PATCH__ */
diff --git a/src/adapter_le_vsc_features.h b/src/adapter_le_vsc_features.h
new file mode 100644 (file)
index 0000000..6850e01
--- /dev/null
@@ -0,0 +1,461 @@
+#ifdef __TIZEN_PATCH__
+
+typedef enum {
+       BLE_ADV_TX_POWER_MIN = 0x00,
+       BLE_ADV_TX_POWER_LOW = 0x01,
+       BLE_ADV_TX_POWER_MID = 0x02,
+       BLE_ADV_TX_POWER_UPPER = 0x03,
+       BLE_ADV_TX_POWER_MAX = 0x04,
+} adapter_le_tx_power_t;
+
+typedef struct {
+       uint8_t inst_id;
+       uint8_t bdaddr_type;
+       bdaddr_t bdaddr;
+} adapter_le_adv_inst_info_t;
+
+typedef struct {
+       uint16_t adv_int_min;         /* minimum adv interval */
+       uint16_t adv_int_max;         /* maximum adv interval */
+       uint8_t adv_type;             /* adv event type (0x00 ~ 0x04) */
+       uint8_t channel_map;          /* adv channel map (all channel = 0x07)  */
+       uint8_t adv_filter_policy;    /* advertising filter policy (0x00 ~ 0x04) */
+       adapter_le_tx_power_t tx_power;    /* adv tx power */
+} adapter_le_adv_param_t;
+
+typedef enum {
+       ADD,
+       DELETE,
+       CLEAR,
+} adapter_le_scan_filter_action_type;
+
+typedef enum {
+       ADDR_LE_PUBLIC,
+       ADDR_LE_RANDOM,
+} adapter_vsc_le_addr_type;
+
+typedef enum {
+       TYPE_DEVICE_ADDRESS = 0x01,
+       TYPE_SERVICE_DATA_CHANGED = 0x02,
+       TYPE_SERVICE_UUID = 0x04,
+       TYPE_SOLICIT_UUID = 0x08,
+       TYPE_LOCAL_NAME = 0x10,
+       TYPE_MANUFACTURER_DATA = 0x20,
+       TYPE_SERVICE_DATA = 0x40,
+} adapter_le_scan_filter_type;
+
+#define BDADDR_BREDR           0x00
+#define BDADDR_LE_PUBLIC       0x01
+
+#define BROADCAST_ADDR_FILTER  0x01
+#define SERVICE_DATA_CHANGE_FILTER     0x02
+#define SERVICE_UUID_CHECK             0x04
+#define SERVICE_SOLICITATION_UUID_CHECK        0x08
+#define LOCAL_NAME_CHECK                       0x10
+#define MANUFACTURE_DATA_CHECK         0x20
+#define SERVICE_DATA_CHECK                     0x40
+
+typedef uint16_t adapter_le_scan_filter_feature_t;
+
+typedef enum {
+       OR,
+       AND,
+} adapter_le_scan_filter_logic_type;
+
+typedef enum {
+       IMMEDIATE,
+       ON_FOUND,
+       BATCHED,
+} adapter_le_scan_filter_delivery_mode;
+
+typedef enum {
+       UUID_16_LEN=2,
+       UUID_32_LEN=4,
+       UUID_128_LEN =16,
+} adapter_le_uuid_len;
+
+typedef struct {
+       adapter_le_scan_filter_action_type action;
+       uint8_t index;
+       adapter_le_scan_filter_feature_t feature;
+       adapter_le_scan_filter_logic_type list_logic_type;
+       adapter_le_scan_filter_logic_type filter_logic_type;
+       uint8_t rssi_high_threshold;
+       adapter_le_scan_filter_delivery_mode delivery_mode;
+       uint16_t onfound_timeout;
+       uint8_t onfound_timeout_cnt;
+       uint8_t rssi_low_threshold;
+       uint16_t onlost_timeout;
+}adapter_le_scan_filter_param_t;
+
+typedef struct {
+       adapter_le_scan_filter_action_type action;
+       uint8_t filter_index;
+       bdaddr_t broadcaster_addr;
+       adapter_vsc_le_addr_type bdaddr_type;
+} adapter_le_address_filter_params_t;
+
+typedef struct {
+       adapter_le_scan_filter_action_type action;
+       uint8_t filter_index;
+       uint8_t *uuid;
+       uint8_t *uuid_mask;
+       adapter_le_uuid_len     uuid_len;
+}adapter_le_uuid_params_t;
+
+typedef struct {
+       adapter_le_scan_filter_action_type action;
+       uint8_t filter_index;
+       const char *local_name;
+       uint8_t name_len;
+}adapter_le_local_name_params_t;
+
+typedef struct {
+       adapter_le_scan_filter_action_type action;
+       uint8_t filter_index;
+       uint16_t company_id;
+       uint16_t company_id_mask;
+       uint8_t *man_data;
+       uint8_t *man_data_mask;
+       uint8_t man_data_len;
+}adapter_le_manf_data_params_t;
+
+typedef struct {
+       adapter_le_scan_filter_action_type action;
+       uint8_t filter_index;
+       uint8_t *service_data;
+       uint8_t *service_data_mask;
+       uint8_t service_data_len;
+}adapter_le_service_data_params_t;
+
+#ifdef __BROADCOM_PATCH__
+
+/*****************************************************************************
+**  Defentions for HCI Error Codes that are past in the events
+*/
+#define HCI_SUCCESS                                     0x00
+
+
+
+/*****************************************************************************
+**                          Vendor Specific Commands
+**
+*/
+
+#define OCF_BCM_LE_GET_VENDOR_CAP    0x0153     /* LE Get Vendor Capabilities */
+
+#define OCF_BCM_LE_MULTI_ADV     0x0154     /* Multi adv OCF */
+
+/* subcode for multi adv feature */
+#define SUB_CMD_LE_MULTI_ADV_SET_PARAM                     0x01
+#define SUB_CMD_LE_MULTI_ADV_WRITE_ADV_DATA                0x02
+#define SUB_CMD_LE_MULTI_ADV_WRITE_SCAN_RSP_DATA           0x03
+#define SUB_CMD_LE_MULTI_ADV_SET_RANDOM_ADDR               0x04
+#define SUB_CMD_LE_MULTI_ADV_ENB                           0x05
+
+/* APCF : Advertising Packet Content Filter feature */
+#define OCF_BCM_LE_SCAN_FILTER     0x0157     /* Advertising filter OCF */
+
+/* Sub codes for APCF */
+#define SUB_CMD_LE_META_PF_ENABLE          0x00
+#define SUB_CMD_LE_META_PF_FEAT_SEL        0x01
+#define SUB_CMD_LE_META_PF_ADDR            0x02
+#define SUB_CMD_LE_META_PF_UUID            0x03
+#define SUB_CMD_LE_META_PF_SOL_UUID        0x04
+#define SUB_CMD_LE_META_PF_LOCAL_NAME      0x05
+#define SUB_CMD_LE_META_PF_MANU_DATA       0x06
+#define SUB_CMD_LE_META_PF_SRVC_DATA       0x07
+#define SUB_CMD_LE_META_PF_ALL             0x08
+
+
+
+/*****************************************************************************
+**                          CP & RP for OCF_BCM_LE_GET_VENDOR_CAP
+**
+*/
+
+/**
+*
+* RP
+*
+* (1 octet) status        : Command complete status
+* (1 octet) adv_inst_max  : Num of advertisement instances supported
+* (1 octet) rpa_offloading: BT chip capability of RPA
+*                           (value 0 not capable, value 1 capable)
+*                           If supported by chip, it needs enablement by host
+* (2 octet) tot_scan_results_strg : Storage for scan results in bytes
+* (1 octet) max_irk_list_sz : Num of IRK entries supported in f/w
+* (1 octet) filter_support  : Support Filtering in controller.
+*                             0 = Not supported / 1 = supported
+* (1 octet) max_filter      : Number of filters supported
+* (1 octet) energy_support  : Supports reporting of activity and energy info
+*                             0 = not capable, 1 = capable
+* (1 octet) onlost_follow   : Number of advertisers that can be analysed
+*                             for onlost per filter
+*/
+typedef struct {
+       uint8_t status;
+       uint8_t adv_inst_max;
+       uint8_t rpa_offloading;
+       uint16_t tot_scan_results_strg;
+       uint8_t max_irk_list_sz;
+       uint8_t filter_support;
+       uint8_t max_filter;
+       uint8_t energy_support;
+       uint8_t onlost_follow;
+} __attribute__ ((packed)) apater_le_vsc_rp_get_vendor_cap;
+
+
+
+/*****************************************************************************
+**                          CP & RP for OCF_BCM_LE_MULTI_ADV
+**
+*/
+
+/**
+*
+* CP for  OCF_BCM_LE_MULTI_ADV & SUB_CMD_LE_MULTI_ADV_SET_PARAM
+*
+* (1 octet) subcode            : SUB_CMD_LE_MULTI_ADV_SET_PARAM
+* (2 octet) adv_int_min        : per spec
+* (2 octet) adv_int_max        : per spec
+* (1 octet) adv_type           : per spec
+* (1 octet) bdaddr_type        : per spec
+* (6 octet) bdaddr             : per spec
+* (1 octet) direct_bdaddr_type : per spec
+* (6 octet) direct_bdaddr      : per spec
+* (1 octet) channel_map        : per spec
+* (1 octet) adv_filter_policy  : per spec
+* (1 octet) inst_id            : Specifies the applicability of the above parameters to an instance
+* (1 octet) tx_power           : Transmit_Power Unit - in dBm (signed integer) Range (70 to +20)
+*/
+typedef struct {
+       uint8_t subcode;
+       uint16_t adv_int_min;
+       uint16_t adv_int_max;
+       uint8_t adv_type;
+       uint8_t bdaddr_type;
+       bdaddr_t bdaddr;
+       uint8_t direct_bdaddr_type;
+       bdaddr_t direct_bdaddr;
+       uint8_t channel_map;
+       uint8_t adv_filter_policy;
+       uint8_t inst_id;
+       uint8_t tx_power;
+} __attribute__ ((packed)) adapter_le_vsc_cp_set_multi_adv_params;
+
+/**
+*
+* CP for SUB_CMD_LE_MULTI_ADV_WRITE_ADV_DATA
+* CP for SUB_CMD_LE_MULTI_ADV_WRITE_SCAN_RSP_DATA
+*
+* ( 1 octet) subcode     : SUB_CMD_LE_MULTI_ADV_WRITE_ADV_DATA
+*                          or SUB_CMD_LE_MULTI_ADV_WRITE_SCAN_RSP_DATA
+* ( 1 octet) data_len    : per spec
+* (31 octet) data        : per spec
+* ( 1 octet) inst_id     : Specifies the applicability of the above parameters to an instance.
+*/
+typedef struct {
+       uint8_t subcode;
+       uint8_t data_len;
+       uint8_t data[31];
+       uint8_t inst_id;
+} __attribute__ ((packed)) adapter_le_vsc_cp_set_multi_adv_data;
+
+/**
+*
+* CP for SUB_CMD_LE_MULTI_ADV_ENB
+*
+* (1 octet) subcode     : SUB_CMD_LE_MULTI_ADV_ENB
+* (1 octet) enable      : When set to 1, it means enable, otherwise disable.
+* (1 octet) inst_id     : Specifies the applicability of the above parameters
+*                         to an instance. Instance 0 has special meaning this
+*                         refers to std HCI instance.
+*/
+typedef struct {
+       uint8_t subcode;
+       uint8_t enable;
+       uint8_t inst_id;
+} __attribute__ ((packed)) adapter_le_vsc_cp_enable_multi_adv;
+
+/**
+*
+* RP
+*
+* (1 octet) status      : Command complete status
+* (1 octet) subcode     : subcode of OCF_BCM_LE_MULTI_ADV
+*/
+typedef struct {
+       uint8_t status;
+       uint8_t subcode;
+} __attribute__ ((packed)) apater_le_vsc_rp_multi_adv;
+
+
+
+/*****************************************************************************
+**                          CP & RP for OCF_BCM_LE_SCAN_FILTER
+**
+*/
+
+
+/* CP for SUB_CMD_LE_META_PF_ENABLE */
+typedef struct {
+       uint8_t subcode;
+       uint8_t enable;
+} __attribute__ ((packed)) adapter_le_vsc_cp_enable_scan_filter;
+
+/* RP for SUB_CMD_LE_META_PF_ENABLE */
+typedef struct {
+       uint8_t status;
+       uint8_t subcode;
+       uint8_t enable;
+} __attribute__ ((packed)) apater_le_vsc_rp_enable_scan_filter;
+
+/* CP for SUB_CMD_LE_META_PF_FEAT_SEL */
+typedef struct {
+       uint8_t  subcode;
+       uint8_t  action;
+       uint8_t  filter_index;
+       uint16_t feature;
+       uint16_t feature_list_logic;
+       uint8_t  filter_logic;
+       int8_t   rssi_high_threshold;
+       uint8_t  delivery_mode;
+       uint16_t onfound_timeout;
+       uint8_t  onfound_timeout_cnt;
+       uint8_t  rssi_low_thresh;
+       uint16_t onlost_timeout;
+} __attribute__ ((packed)) adapter_le_vsc_cp_apcf_set_filter_params;
+
+/* CP for SUB_CMD_LE_META_PF_ADDR */
+typedef struct {
+       uint8_t subcode;
+       uint8_t action;
+       uint8_t filter_index;
+       bdaddr_t bdaddr;
+       uint8_t bdaddr_type;
+} __attribute__ ((packed))adapter_le_vsc_cp_address_scan_filter;
+
+/* CP for SUB_CMD_LE_META_PF_UUID & SUB_CMD_LE_META_PF_SOL_UUID */
+typedef struct {
+       uint8_t subcode;
+       uint8_t action;
+       uint8_t filter_index;
+       uint8_t data[40];               /* UUID + UUID_MASK */
+} __attribute__ ((packed))adapter_le_vsc_cp_service_uuid_scan_filter;
+#define UUID_SCAN_FILTER_HEADER_SIZE 3
+
+#define SCAN_FILTER_DATA_MAX_LEN 29
+
+/* CP for SUB_CMD_LE_META_PF_LOCAL_NAME*/
+typedef struct {
+       uint8_t subcode;
+       uint8_t action;
+       uint8_t filter_index;
+       uint8_t name[SCAN_FILTER_DATA_MAX_LEN];
+} __attribute__ ((packed)) adapter_le_vsc_cp_local_name_scan_filter;
+#define NAME_SCAN_FILTER_HEADER_SIZE 3
+
+/* CP for SUB_CMD_LE_META_PF_MANU_DATA*/
+typedef struct {
+       uint8_t subcode;
+       uint8_t action;
+       uint8_t filter_index;
+       uint8_t data[SCAN_FILTER_DATA_MAX_LEN * 2];     /* data + mask filed */
+} __attribute__ ((packed)) adapter_le_vsc_cp_manf_data_scan_filter;
+#define MANF_DATA_SCAN_FILTER_HEADER_SIZE 3
+
+/* CP for SUB_CMD_LE_META_PF_SRVC_DATA*/
+typedef struct {
+       uint8_t subcode;
+       uint8_t action;
+       uint8_t filter_index;
+       uint8_t data[SCAN_FILTER_DATA_MAX_LEN * 2];     /* data + mask filed */
+} __attribute__ ((packed)) adapter_le_vsc_cp_service_data_scan_filter;
+#define SERVICE_DATA_SCAN_FILTER_HEADER_SIZE 3
+
+/* RP for SUB_CMD_LE_META_PF_ADDR & SUB_CMD_LE_META_PF_FEAT_SEL &
+               SUB_CMD_LE_META_PF_UUID & SUB_CMD_LE_META_PF_SOL_UUID &
+               SUB_CMD_LE_META_PF_LOCAL_NAME & SUB_CMD_LE_META_PF_MANU_DATA &
+               SUB_CMD_LE_META_PF_SRVC_DATA */
+typedef struct {
+       uint8_t status;
+       uint8_t subcode;
+       uint8_t         action;
+       uint8_t         available_space;
+} __attribute__ ((packed)) adapter_le_vsc_rp_apcf_set_scan_filter;
+
+
+
+
+/*****************************************************************************
+**                          Functions
+**
+*/
+
+/* Read supported BLE feature info from chipset */
+gboolean adapter_le_read_ble_feature_info(void);
+
+gboolean adapter_le_is_supported_multi_advertising(void);
+
+gboolean adapter_le_is_supported_offloading(void);
+
+int adapter_le_get_max_adv_instance(void);
+
+int adapter_le_get_scan_filter_size(void);
+
+gboolean adapter_le_set_multi_adv_params (adapter_le_adv_inst_info_t *p_inst,
+                                       adapter_le_adv_param_t *p_params);
+
+gboolean adapter_le_set_multi_adv_data(uint8_t inst_id, gboolean is_scan_rsp,
+                                       uint8_t data_len, uint8_t *p_data);
+
+gboolean adapter_le_enable_multi_adv (gboolean enable, uint8_t inst_id);
+
+
+gboolean adapter_le_enable_scan_filtering (gboolean enable);
+
+gboolean adapter_le_set_scan_filter_params(adapter_le_scan_filter_param_t *params);
+
+gboolean adapter_le_set_scan_filter_data(int client_if, int action,
+                                                       int filt_type, int filter_index,
+                                                       int company_id,
+                                                       int company_id_mask,
+                                                       int uuid_len, uint8_t *p_uuid,
+                                                       int uuid_mask_len, uint8_t *p_uuid_mask,
+                                                       gchar *string, int addr_type,
+                                                       int data_len, uint8_t *p_data,
+                                                       int mask_len, uint8_t *p_mask);
+gboolean adapter_le_clear_scan_filter_data(int client_if, int filter_index);
+#else /* __BROADCOM_PATCH__ */
+
+gboolean adapter_le_read_ble_feature_info(void) { return FALSE; }
+gboolean adapter_le_is_supported_multi_advertising(void)  { return FALSE; }
+gboolean adapter_le_is_supported_offloading(void) { return FALSE; }
+int adapter_le_get_max_adv_instance(void) { return 0; }
+int adapter_le_get_scan_filter_size(void) { return 0; }
+
+gboolean adapter_le_set_multi_adv_params (adapter_le_adv_inst_info_t *p_inst,
+                                       adapter_le_adv_param_t *p_params) { return FALSE; }
+gboolean adapter_le_set_multi_adv_data(uint8_t inst_id, gboolean is_scan_rsp,
+                                       uint8_t data_len, uint8_t *p_data) { return FALSE; }
+gboolean adapter_le_enable_multi_adv (gboolean enable, uint8_t inst_id)
+                                       { return FALSE; }
+
+gboolean adapter_le_enable_scan_filtering (gboolean enable) { return FALSE; }
+gboolean adapter_le_set_scan_filter_params(adapter_le_scan_filter_param_t *params)
+                                       { return FALSE; }
+gboolean adapter_le_set_scan_filter_data(int client_if, int action,
+                                                       int filt_type, int filter_index,
+                                                       int company_id,
+                                                       int company_id_mask,
+                                                       int uuid_len, uint8_t *p_uuid,
+                                                       int uuid_mask_len, uint8_t *p_uuid_mask,
+                                                       gchar *string, int addr_type,
+                                                       int data_len, uint8_t *p_data,
+                                                       int mask_len, uint8_t *p_mask)
+                                       { return FALSE; }
+gboolean adapter_le_clear_scan_filter_data(int client_if, int filter_index)
+                                       { return FALSE; }
+#endif /* __BROADCOM_PATCH__ */
+#endif /* __TIZEN_PATCH__ */
index bd88eb9..12e369a 100644 (file)
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
+
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+
+#include "gdbus/gdbus.h"
 
 #include "log.h"
 #include "error.h"
@@ -383,9 +384,8 @@ done:
 
 static int agent_call_authorize_service(struct agent_request *req,
                                                const char *device_path,
-                                               const char *uuid, const int fd)
+                                               const char *uuid)
 {
-       DBusMessageIter iter, dict;
        struct agent *agent = req->agent;
 
        req->msg = dbus_message_new_method_call(agent->owner, agent->path,
@@ -395,14 +395,10 @@ static int agent_call_authorize_service(struct agent_request *req,
                return -ENOMEM;
        }
 
-       dbus_message_iter_init_append(req->msg, &iter);
-
-       dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-                                               &device_path);
-
-       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uuid);
-
-       dbus_message_iter_append_basic(&iter, DBUS_TYPE_UNIX_FD, &fd);
+       dbus_message_append_args(req->msg,
+                               DBUS_TYPE_OBJECT_PATH, &device_path,
+                               DBUS_TYPE_STRING, &uuid,
+                               DBUS_TYPE_INVALID);
 
        if (g_dbus_send_message_with_reply(btd_get_dbus_connection(),
                                                req->msg, &req->call,
@@ -417,7 +413,7 @@ static int agent_call_authorize_service(struct agent_request *req,
 
 int agent_authorize_service(struct agent *agent, const char *path,
                                const char *uuid, agent_cb cb,
-                               void *user_data, GDestroyNotify destroy, int fd)
+                               void *user_data, GDestroyNotify destroy)
 {
        struct agent_request *req;
        int err;
@@ -428,7 +424,7 @@ int agent_authorize_service(struct agent *agent, const char *path,
        req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZE_SERVICE, cb,
                                                        user_data, destroy);
 
-       err = agent_call_authorize_service(req, path, uuid, fd);
+       err = agent_call_authorize_service(req, path, uuid);
        if (err < 0) {
                agent_request_free(req, FALSE);
                return -ENOMEM;
index dafee9c..1e46920 100644 (file)
@@ -40,7 +40,7 @@ struct agent *agent_get(const char *owner);
 
 int agent_authorize_service(struct agent *agent, const char *path,
                                const char *uuid, agent_cb cb,
-                               void *user_data, GDestroyNotify destroy, int fd);
+                               void *user_data, GDestroyNotify destroy);
 
 int agent_request_pincode(struct agent *agent, struct btd_device *device,
                                agent_pincode_cb cb, gboolean secure,
index d863146..7602ac4 100644 (file)
 #include <glib.h>
 #include <sys/stat.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 #include "lib/uuid.h"
+
 #include "btio/btio.h"
 #include "log.h"
 #include "adapter.h"
@@ -264,17 +264,25 @@ static int attribute_cmp(gconstpointer a1, gconstpointer a2)
 }
 
 #ifdef __TIZEN_PATCH__
-static int attribute_uuid_cmp(gconstpointer a, gconstpointer b)
+ static int attribute_uuid_cmp(gconstpointer a, gconstpointer b)
 {
        const struct attribute *attrib1 = a;
        const bt_uuid_t *uuid = b;
 
-       return bt_uuid_cmp(&attrib1->uuid, uuid);
+       if (attrib1->uuid.value.u16 != GATT_PRIM_SVC_UUID) {
+               return bt_uuid_cmp(&attrib1->uuid, uuid);
+       } else {
+               bt_uuid_t prim_uuid;
+               prim_uuid = att_get_uuid(attrib1->data, attrib1->len);
+
+               return bt_uuid_cmp(&prim_uuid, uuid);
+       }
 }
 
-struct attribute *attribute_find(struct btd_adapter *adapter, bt_uuid_t *uuid)
+struct attribute *attribute_find(struct btd_adapter *adapter, const bt_uuid_t *uuid)
 {
-       GList *l;
+       GSList *l;
+       GList *ldata;
        struct gatt_server *server;
 
        /* Find the attrib server database for the given adapter */
@@ -284,12 +292,12 @@ struct attribute *attribute_find(struct btd_adapter *adapter, bt_uuid_t *uuid)
 
        server = l->data;
 
-       l = g_list_find_custom(server->database, GUINT_TO_POINTER(uuid),
+       ldata = g_list_find_custom(server->database, GUINT_TO_POINTER(uuid),
                                                        attribute_uuid_cmp);
-       if (!l)
+       if (!ldata)
                return NULL;
 
-       return l->data;
+       return ldata->data;
 }
 #endif
 
@@ -895,7 +903,7 @@ static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle,
 
        a = l->data;
 
-       if (a->len <= offset)
+       if (a->len < offset)
                return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle,
                                        ATT_ECODE_INVALID_OFFSET, pdu, len);
 
@@ -1269,10 +1277,6 @@ guint attrib_channel_attach(GAttrib *attrib)
                return 0;
        }
 
-#ifdef __TIZEN_PATCH__
-       device_set_gatt_connected(device, TRUE);
-#endif
-
        if (!device_is_bonded(device, bdaddr_type)) {
                char *filename;
 
@@ -1307,43 +1311,32 @@ guint attrib_channel_attach(GAttrib *attrib)
        return channel->id;
 }
 
-static int channel_id_cmp(gconstpointer data, gconstpointer user_data)
-{
-       const struct gatt_channel *channel = data;
-       guint id = GPOINTER_TO_UINT(user_data);
-
-       return channel->id - id;
-}
-
-gboolean attrib_channel_detach(GAttrib *attrib, guint id)
+static struct gatt_channel *find_channel(guint id)
 {
-       struct gatt_server *server;
-       struct gatt_channel *channel;
-       GError *gerr = NULL;
-       GIOChannel *io;
-       bdaddr_t src;
        GSList *l;
 
-       io = g_attrib_get_channel(attrib);
+       for (l = servers; l; l = g_slist_next(l)) {
+               struct gatt_server *server = l->data;
+               GSList *c;
 
-       bt_io_get(io, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_INVALID);
+               for (c = server->clients; c; c = g_slist_next(c)) {
+                       struct gatt_channel *channel = c->data;
 
-       if (gerr != NULL) {
-               error("bt_io_get: %s", gerr->message);
-               g_error_free(gerr);
-               return FALSE;
+                       if (channel->id == id)
+                               return channel;
+               }
        }
 
-       server = find_gatt_server(&src);
-       if (server == NULL)
-               return FALSE;
+       return NULL;
+}
 
-       l = g_slist_find_custom(server->clients, GUINT_TO_POINTER(id),
-                                                               channel_id_cmp);
-       if (!l)
-               return FALSE;
+gboolean attrib_channel_detach(GAttrib *attrib, guint id)
+{
+       struct gatt_channel *channel;
 
-       channel = l->data;
+       channel = find_channel(id);
+       if (channel == NULL)
+               return FALSE;
 
        g_attrib_unregister(channel->attrib, channel->id);
        channel_remove(channel);
@@ -1403,12 +1396,12 @@ static gboolean register_core_services(struct gatt_server *server)
                                                                atval, 2);
 
        /* GAP service: device name characteristic */
-       server->name_handle = 0x0006;
+       server->name_handle = 0x0003;
        bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
        atval[0] = GATT_CHR_PROP_READ;
        put_le16(server->name_handle, &atval[1]);
        put_le16(GATT_CHARAC_DEVICE_NAME, &atval[3]);
-       attrib_db_add_new(server, 0x0004, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+       attrib_db_add_new(server, 0x0002, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
                                                                atval, 5);
 
        /* GAP service: device name attribute */
@@ -1417,12 +1410,12 @@ static gboolean register_core_services(struct gatt_server *server)
                                                ATT_NOT_PERMITTED, NULL, 0);
 
        /* GAP service: device appearance characteristic */
-       server->appearance_handle = 0x0008;
+       server->appearance_handle = 0x0005;
        bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
        atval[0] = GATT_CHR_PROP_READ;
        put_le16(server->appearance_handle, &atval[1]);
        put_le16(GATT_CHARAC_APPEARANCE, &atval[3]);
-       attrib_db_add_new(server, 0x0007, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+       attrib_db_add_new(server, 0x0004, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
                                                                atval, 5);
 
        /* GAP service: device appearance attribute */
@@ -1430,6 +1423,7 @@ static gboolean register_core_services(struct gatt_server *server)
        put_le16(appearance, &atval[0]);
        attrib_db_add_new(server, server->appearance_handle, &uuid, ATT_NONE,
                                                ATT_NOT_PERMITTED, atval, 2);
+
        server->gap_sdp_handle = attrib_create_sdp_new(server, 0x0001,
                                                "Generic Access Profile");
        if (server->gap_sdp_handle == 0) {
@@ -1440,28 +1434,33 @@ static gboolean register_core_services(struct gatt_server *server)
        /* GATT service: primary service definition */
        bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
        put_le16(GENERIC_ATTRIB_PROFILE_ID, &atval[0]);
-       attrib_db_add_new(server, 0x0010, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+       attrib_db_add_new(server, 0x0006, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
                                                                atval, 2);
 
 #ifdef __TIZEN_PATCH__
        /* GATT service: service changed characteristic */
-       service_changed_handle = 0x0012;
-       bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
+       service_changed_handle = 0x0008;
+       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
 
-       atval[0] = GATT_CHR_PROP_READ;
+       atval[0] = GATT_CHR_PROP_INDICATE;
        put_le16(service_changed_handle, &atval[1]);
        put_le16(GATT_CHARAC_SERVICE_CHANGED, &atval[3]);
-       put_le16(GATT_CLIENT_CHARAC_CFG_IND_BIT, atval);
-       attrib_db_add_new(server, 0x0011, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
-                                                               atval, 4);
+
+       attrib_db_add_new(server, 0x0007, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                       atval, 5);
 
        /* GATT service: service changed attribute */
        bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
-       attrib_db_add_new(server, service_changed_handle, &uuid, ATT_NONE,
+       attrib_db_add_new(server, service_changed_handle, &uuid, ATT_NOT_PERMITTED,
                                                ATT_NOT_PERMITTED, NULL, 0);
+
+       bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
+       atval[0] = GATT_CHR_PROP_READ | GATT_CHR_PROP_WRITE;
+       atval[1] = 0;
+       attrib_db_add_new(server, 0x0009, &uuid, ATT_NONE, ATT_NONE, atval, 2);
 #endif
 
-       server->gatt_sdp_handle = attrib_create_sdp_new(server, 0x0010,
+       server->gatt_sdp_handle = attrib_create_sdp_new(server, 0x0006,
                                                "Generic Attribute Profile");
        if (server->gatt_sdp_handle == 0) {
                error("Failed to register GATT service record");
@@ -1768,8 +1767,12 @@ static uint8_t attrib_get_ccc_info(struct btd_device *device, uint16_t handle)
 
        /* Get the CCC value */
        value = g_key_file_get_string(key_file, group, "Value", NULL);
-       if (!value)
+       if (!value) {
+               /* Fix : RESOURCE_LEAK */
+               g_free(filename);
+               g_key_file_free(key_file);
                return 0;
+       }
 
        sscanf(value, "%hX", &cccval);
 
index feb9fc2..44031e4 100644 (file)
@@ -41,11 +41,14 @@ GAttrib *attrib_from_device(struct btd_device *device);
 guint attrib_channel_attach(GAttrib *attrib);
 gboolean attrib_channel_detach(GAttrib *attrib, guint id);
 #ifdef __TIZEN_PATCH__
-struct attribute *attribute_find(struct btd_adapter *adapter, bt_uuid_t *uuid);
+struct attribute *attribute_find(struct btd_adapter *adapter, const bt_uuid_t *uuid);
 void attrib_send_noty_ind(struct btd_device *device, GAttrib *attrib,
                                uint16_t handle, uint16_t desc_handle,
                                uint8_t *value, size_t vlen);
 uint16_t send_sc_indication(uint16_t handle, uint16_t end_handle, size_t vlen,
                         uint8_t *pdu, size_t len);
 
+void attrib_send_sc_ind(struct btd_device *device, GAttrib *attrib,
+                               uint16_t start_handle, uint16_t end_handle,
+                               size_t vlen);
 #endif
old mode 100755 (executable)
new mode 100644 (file)
index 3caebdc..bb6b835
     <allow own="org.bluez.Profile1"/>
     <allow send_interface="org.bluez.Profile1"/>
     <allow send_destination="org.bluez.Profile1"/>
+    <allow send_interface="org.bluez.HeartRateWatcher1"/>
+    <allow send_interface="org.bluez.CyclingSpeedWatcher1"/>
+    <allow send_interface="org.bluez.GattCharacteristic1"/>
+    <allow send_interface="org.bluez.GattDescriptor1"/>
     <allow send_interface="org.freedesktop.DBus.ObjectManager"/>
+    <allow send_interface="org.freedesktop.DBus.Properties"/>
   </policy>
 
   <policy at_console="true">
old mode 100755 (executable)
new mode 100644 (file)
index b8afaa0..35e9457
@@ -5,13 +5,12 @@ Documentation=man:bluetoothd(8)
 [Service]
 Type=dbus
 BusName=org.bluez
-ExecStart=@libexecdir@/bluetoothd -E
+ExecStart=@libexecdir@/bluetoothd
 NotifyAccess=main
 #WatchdogSec=10
 #Restart=on-failure
 CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
 LimitNPROC=1
-SmackProcessLabel=User
 
 [Install]
 WantedBy=bluetooth.target
index d466a8f..936616b 100644 (file)
@@ -32,7 +32,8 @@
 
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
+
+#include "gdbus/gdbus.h"
 
 #include "log.h"
 
index 9a4f5f2..8e7cd52 100644 (file)
 #include <dirent.h>
 #include <time.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
-
-#include "log.h"
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 #include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
+
+#include "log.h"
 #include "src/shared/util.h"
 #include "src/shared/att.h"
 #include "src/shared/queue.h"
 #include "src/shared/gatt-db.h"
 #include "src/shared/gatt-client.h"
+#include "src/shared/gatt-server.h"
 #include "btio/btio.h"
 #include "lib/mgmt.h"
 #include "attrib/att.h"
 #include "hcid.h"
 #include "adapter.h"
+#include "gatt-database.h"
 #include "attrib/gattrib.h"
 #include "attio.h"
 #ifdef __TIZEN_PATCH__
 #include "eir.h"
-#include "attrib/client.h"
 #endif
 #include "device.h"
 #include "gatt-client.h"
@@ -77,7 +78,6 @@
 #include "attrib-server.h"
 #ifdef __TIZEN_PATCH__
 #include "sdp-xml.h"
-#include "gatt.h"
 #endif
 
 #define IO_CAPABILITY_NOINPUTNOOUTPUT  0x03
 #endif
 
 static DBusConnection *dbus_conn = NULL;
-unsigned service_state_cb_id;
+static unsigned service_state_cb_id;
 
 struct btd_disconnect_data {
        guint id;
@@ -198,6 +198,11 @@ struct bearer_state {
        bool svc_resolved;
 };
 
+struct csrk_info {
+       uint8_t key[16];
+       uint32_t counter;
+};
+
 #ifdef __TIZEN_PATCH__
 typedef enum {
        DEV_PAIRED_NONE = 0,
@@ -239,9 +244,6 @@ struct btd_device {
        GSList          *uuids;
        GSList          *primaries;             /* List of primary services */
        GSList          *services;              /* List of btd_service */
-#ifdef __TIZEN_PATCH__
-       GSList          *gatt_services; /* List of GATT Services */
-#endif
        GSList          *pending;               /* Pending services */
        GSList          *watches;               /* List of disconnect_data */
        gboolean        temporary;
@@ -256,7 +258,6 @@ struct btd_device {
        GAttrib         *attrib;
        GSList          *attios;
        GSList          *attios_offline;
-       guint           attachid;               /* Attrib server attach */
 
        struct bt_att *att;                     /* The new ATT transport */
        uint16_t att_mtu;                       /* The ATT MTU */
@@ -269,12 +270,16 @@ struct btd_device {
         */
        struct gatt_db *db;                     /* GATT db cache */
        struct bt_gatt_client *client;          /* GATT client instance */
+       struct bt_gatt_server *server;          /* GATT server instance */
 
        struct btd_gatt_client *client_dbus;
 
        struct bearer_state bredr_state;
        struct bearer_state le_state;
 
+       struct csrk_info *local_csrk;
+       struct csrk_info *remote_csrk;
+
        sdp_list_t      *tmp_records;
 
        time_t          bredr_seen;
@@ -292,6 +297,7 @@ struct btd_device {
        GIOChannel      *att_io;
        guint           store_id;
 #ifdef __TIZEN_PATCH__
+       guint           attachid;               /* Attrib server attach */
        bool    legacy_pairing;
        char            *manufacturer_data;
        int             manufacturer_data_len;
@@ -304,6 +310,7 @@ struct btd_device {
        uint8_t         last_bdaddr_type;
        gboolean                le_auto_connect;
        guint           auto_id;
+       gboolean        ipsp_connected; /* IPSP Connection state */
 #endif
 };
 
@@ -360,21 +367,15 @@ static GSList *find_service_with_state(GSList *list,
        return NULL;
 }
 
-static GSList *find_service_with_gatt_handles(GSList *list,
-                                                       uint16_t start_handle,
-                                                       uint16_t end_handle)
+static GSList *find_service_with_uuid(GSList *list, char *uuid)
 {
        GSList *l;
-       uint16_t svc_start, svc_end;
 
        for (l = list; l != NULL; l = g_slist_next(l)) {
                struct btd_service *service = l->data;
+               struct btd_profile *profile = btd_service_get_profile(service);
 
-               if (!btd_service_get_gatt_handles(service, &svc_start,
-                                                               &svc_end))
-                       continue;
-
-               if (svc_start == start_handle && svc_end == end_handle)
+               if (bt_uuid_strcmp(profile->remote_uuid, uuid) == 0)
                        return l;
        }
 
@@ -383,7 +384,7 @@ static GSList *find_service_with_gatt_handles(GSList *list,
 
 static void update_technologies(GKeyFile *file, struct btd_device *dev)
 {
-       const char *list[2] = {NULL, NULL};
+       const char *list[2];
        size_t len = 0;
 
        if (dev->bredr)
@@ -406,6 +407,19 @@ static void update_technologies(GKeyFile *file, struct btd_device *dev)
                                                                list, len);
 }
 
+static void store_csrk(struct csrk_info *csrk, GKeyFile *key_file,
+                                                       const char *group)
+{
+       char key[33];
+       int i;
+
+       for (i = 0; i < 16; i++)
+               sprintf(key + (i * 2), "%2.2X", csrk->key[i]);
+
+       g_key_file_set_string(key_file, group, "Key", key);
+       g_key_file_set_integer(key_file, group, "Counter", csrk->counter);
+}
+
 #ifdef __TIZEN_PATCH__
 static char *manufacturer_data2str(char *data, int size)
 {
@@ -546,6 +560,12 @@ static gboolean store_device_info_cb(gpointer user_data)
                g_key_file_remove_group(key_file, "DeviceID", NULL);
        }
 
+       if (device->local_csrk)
+               store_csrk(device->local_csrk, key_file, "LocalSignatureKey");
+
+       if (device->remote_csrk)
+               store_csrk(device->remote_csrk, key_file, "RemoteSignatureKey");
+
        create_file(filename, S_IRUSR | S_IWUSR);
 
        str = g_key_file_to_data(key_file, &length, NULL);
@@ -639,16 +659,32 @@ static void gatt_client_cleanup(struct btd_device *device)
        bt_gatt_client_unref(device->client);
        device->client = NULL;
 
+       /*
+        * TODO: Once GATT over BR/EDR is properly supported, we should check
+        * the bonding state for the correct bearer based on the transport over
+        * which GATT is being done.
+        */
        if (!device->le_state.bonded)
                gatt_db_clear(device->db);
 }
+#ifndef __TIZEN_PATCH__
+static void gatt_server_cleanup(struct btd_device *device)
+{
+       if (!device->server)
+               return;
 
+       bt_gatt_server_unref(device->server);
+       device->server = NULL;
+}
+#endif
 static void attio_cleanup(struct btd_device *device)
 {
+#ifdef __TIZEN_PATCH__
        if (device->attachid) {
                attrib_channel_detach(device->attrib, device->attachid);
                device->attachid = 0;
        }
+#endif
 
        if (device->att_disconn_id)
                bt_att_unregister_disconnect(device->att,
@@ -661,6 +697,9 @@ static void attio_cleanup(struct btd_device *device)
        }
 
        gatt_client_cleanup(device);
+#ifndef __TIZEN_PATCH__
+       gatt_server_cleanup(device);
+#endif
 
        if (device->att) {
                bt_att_unref(device->att);
@@ -669,6 +708,7 @@ static void attio_cleanup(struct btd_device *device)
 
        if (device->attrib) {
                GAttrib *attrib = device->attrib;
+
                device->attrib = NULL;
                g_attrib_cancel_all(attrib);
                g_attrib_unref(attrib);
@@ -680,6 +720,8 @@ static void browse_request_cancel(struct browse_req *req)
        struct btd_device *device = req->device;
        struct btd_adapter *adapter = device->adapter;
 
+       DBG("");
+
        bt_cancel_discovery(btd_adapter_get_address(adapter), &device->bdaddr);
 
        attio_cleanup(device);
@@ -712,9 +754,6 @@ static void device_free(gpointer user_data)
        g_slist_free_full(device->attios, g_free);
        g_slist_free_full(device->attios_offline, g_free);
        g_slist_free_full(device->svc_callbacks, svc_dev_remove);
-#ifdef __TIZEN_PATCH__
-       g_slist_free_full(device->gatt_services, g_free);
-#endif
 
        attio_cleanup(device);
 
@@ -756,6 +795,8 @@ static void device_free(gpointer user_data)
        if (device->eir_uuids)
                g_slist_free_full(device->eir_uuids, g_free);
 
+       g_free(device->local_csrk);
+       g_free(device->remote_csrk);
        g_free(device->path);
        g_free(device->alias);
        free(device->modalias);
@@ -810,34 +851,6 @@ gboolean device_is_trusted(struct btd_device *device)
        return device->trusted;
 }
 
-bool device_is_service_blocked(struct btd_device *device, const char *uuid)
-{
-       GSList *l;
-       bool block = false;
-
-       for (l = device->services; l; l = g_slist_next(l)) {
-               struct btd_service *service = l->data;
-               struct btd_profile *p = btd_service_get_profile(service);
-               const char *p_uuid;
-
-               p_uuid = p->auth_uuid ? p->auth_uuid : p->local_uuid;
-               if (!p_uuid)
-                       continue;
-
-               if (strcasecmp(uuid, p_uuid))
-                       continue;
-
-               if (!btd_service_is_blocked(service))
-                       return false;
-
-               block = true;
-       }
-
-       /* Every service matching is blocked
-        */
-       return block;
-}
-
 static gboolean dev_property_get_address(const GDBusPropertyTable *property,
                                        DBusMessageIter *iter, void *data)
 {
@@ -1179,7 +1192,6 @@ static void dev_property_set_blocked(const GDBusPropertyTable *property,
 }
 
 #ifdef __TIZEN_PATCH__
-#if 0 /* caller of below function exists but currently commented */
 static uint8_t device_get_connected_state(struct btd_device *device)
 {
        if (device->bredr_state.connected && device->le_state.connected)
@@ -1191,7 +1203,6 @@ static uint8_t device_get_connected_state(struct btd_device *device)
        else
                return DEV_CONNECTED_NONE;
 }
-#endif
 
 static gboolean dev_property_get_payload(const GDBusPropertyTable *property,
                                        DBusMessageIter *iter, void *data)
@@ -1217,6 +1228,22 @@ static gboolean dev_property_get_last_addr_type(const GDBusPropertyTable *proper
        return TRUE;
 }
 
+static gboolean dev_property_get_ipsp_conn_state(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct btd_device *dev = data;
+       dbus_bool_t ipsp_connected;
+
+       if (dev->ipsp_connected)
+               ipsp_connected = TRUE;
+       else
+               ipsp_connected = FALSE;
+
+       dbus_message_iter_append_basic(iter,
+                       DBUS_TYPE_BOOLEAN, &ipsp_connected);
+
+       return TRUE;
+}
 #endif
 
 static gboolean dev_property_get_connected(const GDBusPropertyTable *property,
@@ -1224,12 +1251,10 @@ static gboolean dev_property_get_connected(const GDBusPropertyTable *property,
 {
        struct btd_device *dev = data;
 
-#if 0 /* Need to discuss with SLP team */
-/* #ifdef __TIZEN_PATCH__ */
+#ifdef __TIZEN_PATCH__
        uint8_t connected = device_get_connected_state(dev);
 
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE,
-                                               &connected);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, &connected);
 #else
        dbus_bool_t connected;
 
@@ -1323,44 +1348,6 @@ static gboolean dev_property_get_adapter(const GDBusPropertyTable *property,
 }
 
 #ifdef __TIZEN_PATCH__
-static gboolean dev_property_get_prim_services(const GDBusPropertyTable *property,
-                    DBusMessageIter *iter, void *data)
-{
-       struct btd_device *device = data;
-       gchar *attrib_data;
-       DBusMessageIter array;
-       GSList *l;
-       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
-                               DBUS_TYPE_STRING_AS_STRING,
-                               &array);
-
-       for (l = device->primaries; l != NULL; l = l->next) {
-               struct gatt_primary *primary = l->data;
-
-               DBG("start handle = 0x%04x, end grp handle = 0x%04x "
-                       "uuid: %s\n", primary->range.start, primary->range.end,
-                       primary->uuid);
-
-               /*
-                * attrib_data contains the start_handle followed by '#', end
-                * handle followed by '#' and 128 bit UUID as string. Attribute
-                * data represents one service.
-                */
-
-               attrib_data = g_strdup_printf("%04x""#""%04x""#""%s",
-                       primary->range.start,primary->range.end,primary->uuid);
-
-               DBG("attrib_data string: %s",attrib_data);
-
-               dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
-                                       &attrib_data);
-
-       }
-
-       dbus_message_iter_close_container(iter, &array);
-
-       return TRUE;
-}
 
 static gboolean property_get_flag(const GDBusPropertyTable *property,
                                        DBusMessageIter *iter, void *user_data)
@@ -1431,22 +1418,6 @@ static gboolean disconnect_all(gpointer user_data)
        return FALSE;
 }
 
-#ifdef BLUEZ5_GATT_CLIENT
-gboolean disconnect_le_device(gpointer user_data)
-{
-       struct btd_device *device = user_data;
-       device->disconn_timer = 0;
-
-       if (device->le_state.connected) {
-               if (!btd_adapter_disconnect_device(device->adapter,
-                               &device->bdaddr, BDADDR_LE_PUBLIC))
-                       return TRUE;
-       }
-
-       return FALSE;
-}
-#endif
-
 int device_block(struct btd_device *device, gboolean update_only)
 {
        int err = 0;
@@ -1524,11 +1495,11 @@ int device_unblock(struct btd_device *device, gboolean silent,
        return 0;
 }
 
-static void discover_services_req_exit(DBusConnection *conn, void *user_data)
+static void browse_request_exit(DBusConnection *conn, void *user_data)
 {
        struct browse_req *req = user_data;
 
-       DBG("DiscoverServices requestor exited");
+       DBG("Requestor exited");
 
        browse_request_cancel(req);
 }
@@ -1839,10 +1810,6 @@ static GSList *create_pending_list(struct btd_device *dev, const char *uuid)
 
        for (l = dev->services; l != NULL; l = g_slist_next(l)) {
                service = l->data;
-               
-               if (!btd_service_get_auto_connect(service))
-                       continue;
-               
                p = btd_service_get_profile(service);
 
 #ifdef __TIZEN_PATCH__
@@ -1986,6 +1953,9 @@ static uint8_t select_conn_bearer(struct btd_device *dev)
                        le_last = NVAL_TIME;
        }
 
+       if (le_last == NVAL_TIME && bredr_last == NVAL_TIME)
+               return dev->bdaddr_type;
+
        if (dev->bredr && (!dev->le || le_last == NVAL_TIME))
                return BDADDR_BREDR;
 
@@ -2120,17 +2090,134 @@ static DBusMessage *disconnect_profile(DBusConnection *conn, DBusMessage *msg,
        return btd_error_failed(msg, strerror(-err));
 }
 
+static void store_services(struct btd_device *device)
+{
+       struct btd_adapter *adapter = device->adapter;
+       char filename[PATH_MAX];
+       char src_addr[18], dst_addr[18];
+       uuid_t uuid;
+       char *prim_uuid;
+       GKeyFile *key_file;
+       GSList *l;
+       char *data;
+       gsize length = 0;
+
+       if (device_address_is_private(device)) {
+               warn("Can't store services for private addressed device %s",
+                                                               device->path);
+               return;
+       }
+
+       sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+       prim_uuid = bt_uuid2string(&uuid);
+       if (prim_uuid == NULL)
+               return;
+
+       ba2str(btd_adapter_get_address(adapter), src_addr);
+       ba2str(&device->bdaddr, dst_addr);
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/attributes", src_addr,
+                                                               dst_addr);
+       key_file = g_key_file_new();
+
+       for (l = device->primaries; l; l = l->next) {
+               struct gatt_primary *primary = l->data;
+               char handle[6], uuid_str[33];
+               int i;
+
+               sprintf(handle, "%hu", primary->range.start);
+
+               bt_string2uuid(&uuid, primary->uuid);
+               sdp_uuid128_to_uuid(&uuid);
+
+               switch (uuid.type) {
+               case SDP_UUID16:
+                       sprintf(uuid_str, "%4.4X", uuid.value.uuid16);
+                       break;
+               case SDP_UUID32:
+                       sprintf(uuid_str, "%8.8X", uuid.value.uuid32);
+                       break;
+               case SDP_UUID128:
+                       for (i = 0; i < 16; i++)
+                               sprintf(uuid_str + (i * 2), "%2.2X",
+                                               uuid.value.uuid128.data[i]);
+                       break;
+               default:
+                       uuid_str[0] = '\0';
+               }
+
+               g_key_file_set_string(key_file, handle, "UUID", prim_uuid);
+               g_key_file_set_string(key_file, handle, "Value", uuid_str);
+               g_key_file_set_integer(key_file, handle, "EndGroupHandle",
+                                       primary->range.end);
+       }
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
+
+       free(prim_uuid);
+       g_free(data);
+       g_key_file_free(key_file);
+}
+
+static void browse_request_complete(struct browse_req *req, uint8_t bdaddr_type,
+                                                                       int err)
+{
+       struct btd_device *dev = req->device;
+       DBusMessage *reply = NULL;
+
+       if (!req->msg)
+               goto done;
+
+       if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE, "Pair")) {
+               if (!device_is_paired(dev, bdaddr_type)) {
+                       reply = btd_error_failed(req->msg, "Not paired");
+                       goto done;
+               }
+
+               if (dev->pending_paired) {
+                       g_dbus_emit_property_changed(dbus_conn, dev->path,
+                                               DEVICE_INTERFACE, "Paired");
+                       dev->pending_paired = false;
+               }
+
+               /* Disregard browse errors in case of Pair */
+               reply = g_dbus_create_reply(req->msg, DBUS_TYPE_INVALID);
+               goto done;
+       }
+
+       if (err) {
+               reply = btd_error_failed(req->msg, strerror(-err));
+               goto done;
+       }
+
+       if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE, "Connect"))
+               reply = dev_connect(dbus_conn, req->msg, dev);
+       else if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE,
+                                                       "ConnectProfile"))
+               reply = connect_profile(dbus_conn, req->msg, dev);
+       else
+               reply = g_dbus_create_reply(req->msg, DBUS_TYPE_INVALID);
+
+done:
+       if (reply)
+               g_dbus_send_message(dbus_conn, reply);
+
+       browse_request_free(req);
+}
+
 static void device_svc_resolved(struct btd_device *dev, uint8_t bdaddr_type,
                                                                int err)
 {
        struct bearer_state *state = get_state(dev, bdaddr_type);
-       DBusMessage *reply;
        struct browse_req *req = dev->browse;
 
        DBG("%s err %d", dev->path, err);
 
        state->svc_resolved = true;
-       dev->browse = NULL;
 
        /* Disconnection notification can happen before this function
         * gets called, so don't set svc_refreshed for a disconnected
@@ -2164,34 +2251,14 @@ static void device_svc_resolved(struct btd_device *dev, uint8_t bdaddr_type,
        if (!dev->temporary)
                store_device_info(dev);
 
-       if (!req || !req->msg)
-               return;
-
-       if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE,
-                                                               "Pair")) {
-               g_dbus_send_reply(dbus_conn, req->msg, DBUS_TYPE_INVALID);
-               return;
-       }
-
-       if (err) {
-               reply = btd_error_failed(req->msg, strerror(-err));
-               g_dbus_send_message(dbus_conn, reply);
-               return;
-       }
+       if (bdaddr_type != BDADDR_BREDR && err == 0)
+               store_services(dev);
 
-       if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE, "Connect"))
-               reply = dev_connect(dbus_conn, req->msg, dev);
-       else if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE,
-                                                       "ConnectProfile"))
-               reply = connect_profile(dbus_conn, req->msg, dev);
-       else
+       if (!req)
                return;
 
-       dbus_message_unref(req->msg);
-       req->msg = NULL;
-
-       if (reply)
-               g_dbus_send_message(dbus_conn, reply);
+       dev->browse = NULL;
+       browse_request_complete(req, bdaddr_type, err);
 }
 
 static struct bonding_req *bonding_request_new(DBusMessage *msg,
@@ -2355,7 +2422,7 @@ static DBusMessage *pair_device(DBusConnection *conn, DBusMessage *msg,
 
 #ifdef __TIZEN_PATCH__
        if (((conn_type == DEV_CONN_DEFAULT  && bdaddr_type != BDADDR_BREDR) ||
-               (connect_le)) && !device->le_state.connected)
+               (connect_le)))
                bonding = bonding_request_new(msg, device, bdaddr_type, agent);
        else
                bonding = bonding_request_new(msg, device, BDADDR_BREDR, agent);
@@ -2381,9 +2448,13 @@ static DBusMessage *pair_device(DBusConnection *conn, DBusMessage *msg,
 #ifdef __TIZEN_PATCH__
        if (((conn_type == DEV_CONN_DEFAULT  && bdaddr_type != BDADDR_BREDR) ||
                (connect_le)) && !device->le_state.connected)
-                       err = device_connect_le(device);
-               else
-                       err = adapter_create_bonding(adapter, &device->bdaddr,
+               err = device_connect_le(device);
+       else if (connect_le) /* Send bonding request if LE is already connected*/
+               err = adapter_create_bonding(adapter, &device->bdaddr,
+                                                       bdaddr_type,
+                                                       IO_CAPABILITY_NOINPUTNOOUTPUT);
+       else
+               err = adapter_create_bonding(adapter, &device->bdaddr,
                                                        BDADDR_BREDR, io_cap);
 #else
        if (bdaddr_type != BDADDR_BREDR) {
@@ -2505,6 +2576,7 @@ static DBusMessage *cancel_pairing(DBusConnection *conn, DBusMessage *msg,
 }
 
 #ifdef __TIZEN_PATCH__
+#if 0 // Not used
 static DBusMessage *read_rssi(DBusConnection *conn, DBusMessage *msg,
                                                        void *user_data)
 {
@@ -2555,48 +2627,7 @@ static DBusMessage *read_auth_payload_timeout(DBusConnection *conn,
        else
                return dbus_message_new_method_return(msg);
 }
-
-static DBusMessage *get_prim_services(DBusConnection *conn,
-                                       DBusMessage *msg, void *user_data)
-{
-       struct btd_device *device = user_data;
-       DBusMessage *reply;
-       const char *device_path;
-       DBusMessageIter iter, array_iter;
-       GSList *l;
-
-       reply = dbus_message_new_method_return(msg);
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                               DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
-       device_path = device_get_path(device);
-
-       for (l = device->primaries; l != NULL; l = l->next) {
-               struct gatt_primary *primary = l->data;
-               gchar* attrib_data;
-
-               /*
-                * attrib_data contains the start_handle followed by '#', end
-                * handle followed by '#' and 128 bit UUID as string. Attribute
-                * data represents one service.
-                */
-
-               attrib_data = g_strdup_printf("%s/service%04x", device_path,
-                                                               primary->range.start);
-
-               DBG("attrib_data string: %s", attrib_data);
-
-               dbus_message_iter_append_basic(&array_iter,
-                                       DBUS_TYPE_OBJECT_PATH, &attrib_data);
-
-       }
-
-       dbus_message_iter_close_container(&iter, &array_iter);
-
-       return reply;
-}
+#endif
 
 static DBusMessage *discover_services(DBusConnection *conn,
                                        DBusMessage *msg, void *user_data)
@@ -2744,7 +2775,8 @@ static DBusMessage *cancel_discover(DBusConnection *conn,
 
        return dbus_message_new_method_return(msg);
 }
-
+#ifndef __TIZEN_PATCH__
+/* Its not used */
 static DBusMessage *write_auth_payload_timeout(DBusConnection *conn,
                                DBusMessage *msg, void *user_data)
 {
@@ -2766,7 +2798,7 @@ static DBusMessage *write_auth_payload_timeout(DBusConnection *conn,
        else
                return dbus_message_new_method_return(msg);
 }
-
+#endif
 void device_set_attrib(struct btd_device *device, guint attachid, GAttrib *attrib)
 {
        if (device == NULL) {
@@ -2838,8 +2870,13 @@ static DBusMessage *connect_le(DBusConnection *conn, DBusMessage *msg,
         * simultaneously. And bdaddr_type is not supporting both BREDR and LE
         * type. So, device for LE is created when connect_le() called.
         */
-       if (device->bdaddr_type == BDADDR_BREDR)
-               device = btd_adapter_get_device(device->adapter, &device->bdaddr, BDADDR_LE_PUBLIC);
+       if (device->bdaddr_type == BDADDR_BREDR) {
+               if(device->le)
+                       device->bdaddr_type = BDADDR_LE_PUBLIC;
+               else
+                       device = btd_adapter_get_device(device->adapter,
+                                               &device->bdaddr, BDADDR_LE_PUBLIC);
+       }
 
        if (device->gatt_connected)
                return btd_error_already_connected(msg);
@@ -2889,25 +2926,85 @@ static DBusMessage *disconnect_le(DBusConnection *conn, DBusMessage *msg,
        if (device->bdaddr_type == BDADDR_BREDR)
                return btd_error_not_supported(msg);
 
-       if (device->le_auto_connect && !device->gatt_connected) {
-               DBG("le_auto_connect : %d, gatt_connected : %d, attrib : %p",
-                                               device->le_auto_connect, device->gatt_connected, device->attrib);
+       if (device->le_auto_connect && !device->le_state.connected) {
+               DBG("le_auto_connect : %d, le_connected : %d, attrib : %p",
+                               device->le_auto_connect,
+                               device->le_state.connected,
+                               device->attrib);
 
                DBG("Cancel LE auto connection");
 
                btd_adapter_disable_le_auto_connect(device->adapter);
                device->le_auto_connect = FALSE;
+
                return dbus_message_new_method_return(msg);
        }
 
-       if(!device->gatt_connected || !device->attrib)
+       if (!device->le_state.connected)
                return btd_error_not_connected(msg);
 
        disconnect_all(device);
 
+       /*
+        * Current bt_adapter_start_device_discovery() cannot scan BREDR and LE
+        * simultaneously. And bdaddr_type is not supporting both BREDR and LE
+        * type. So, bdaddr_type is returned to bredr after disconnect le.
+        */
+       if(device->bredr)
+               device->bdaddr_type = BDADDR_BREDR;
+
        return dbus_message_new_method_return(msg);
 }
 
+static DBusMessage *connect_ipsp(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
+{
+       struct btd_device *device = user_data;
+
+       DBG("bdaddr_type  %d", device->bdaddr_type);
+
+       if (device->bdaddr_type == BDADDR_BREDR) {
+               if(device->le)
+                       device->bdaddr_type = BDADDR_LE_PUBLIC;
+               else
+                       device = btd_adapter_get_device(device->adapter,
+                                       &device->bdaddr, BDADDR_LE_PUBLIC);
+       }
+
+       if (device->ipsp_connected)
+               return btd_error_already_connected(msg);
+
+       /* Initiate Connection for 6Lowan*/
+       if (btd_adapter_connect_ipsp(device->adapter, &device->bdaddr,
+                                       device->bdaddr_type) != 0)
+               return btd_error_failed(msg, "ConnectFailed");
+
+       return dbus_message_new_method_return(msg);;
+}
+
+static DBusMessage *disconnect_ipsp(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
+{
+       struct btd_device *device = user_data;
+       DBG("bdaddr_type  %d", device->bdaddr_type);
+
+       if (device->bdaddr_type == BDADDR_BREDR)
+               return btd_error_not_supported(msg);
+
+       if (!device->ipsp_connected)
+               return btd_error_not_connected(msg);
+
+       /* Disconnect the 6Lowpan connection */
+       if (btd_adapter_disconnect_ipsp(device->adapter, &device->bdaddr,
+                                       device->bdaddr_type) != 0)
+               return btd_error_failed(msg, "DisconnectFailed");
+
+       /* TODO: Handle disconnection of GATT connection, If the connection
+        * is established as part of IPSP connection. */
+
+       return dbus_message_new_method_return(msg);;
+}
+
 static DBusMessage *is_connected_profile(DBusConnection *conn, DBusMessage *msg,
                                                                        void *user_data)
 {
@@ -3008,21 +3105,23 @@ static const GDBusMethodTable device_methods[] = {
 #endif
        { GDBUS_METHOD("CancelPairing", NULL, NULL, cancel_pairing) },
 #ifdef __TIZEN_PATCH__
+#if 0 // Not used
        { GDBUS_METHOD("ReadRSSI", NULL, NULL, read_rssi) },
        { GDBUS_METHOD("L2capConnParamUpdate",
                        GDBUS_ARGS({ "interval_min", "u" },
                                { "interval_max", "u" }, { "latency", "u" },
                                { "time_out", "u" }), NULL,
                                l2cap_conn_param_update) },
-       { GDBUS_METHOD("ConnectLE",
-                       GDBUS_ARGS({ "auto_connect", "b"}),
-                       NULL, connect_le) },
-       { GDBUS_METHOD("DisconnectLE", NULL, NULL, disconnect_le) },
        { GDBUS_METHOD("WritePayloadTimeout",
                        GDBUS_ARGS({"auth_payload_timeout", "u"}),
                        NULL, write_auth_payload_timeout)},
        { GDBUS_METHOD("ReadPayloadTimeout", NULL,
                        NULL, read_auth_payload_timeout)},
+#endif
+       { GDBUS_METHOD("ConnectLE",
+                       GDBUS_ARGS({ "auto_connect", "b"}),
+                       NULL, connect_le) },
+       { GDBUS_METHOD("DisconnectLE", NULL, NULL, disconnect_le) },
        { GDBUS_METHOD("IsConnectedProfile", GDBUS_ARGS({ "UUID", "s" }),
                GDBUS_ARGS({ "IsConnected", "b" }), is_connected_profile)},
        { GDBUS_METHOD("LeConnUpdate",
@@ -3030,13 +3129,12 @@ static const GDBusMethodTable device_methods[] = {
                                { "interval_max", "u" }, { "latency", "u" },
                                { "time_out", "u" }), NULL,
                                le_conn_update) },
-       { GDBUS_METHOD("GetPrimServices",
-                               NULL, GDBUS_ARGS({ "Services", "ao" }),
-                               get_prim_services) },
        { GDBUS_ASYNC_METHOD("DiscoverServices",
                        GDBUS_ARGS({ "pattern", "s" }), NULL,
                                discover_services) },
        { GDBUS_METHOD("CancelDiscovery", NULL, NULL, cancel_discover) },
+       { GDBUS_ASYNC_METHOD("ConnectIpsp", NULL, NULL, connect_ipsp) },
+       { GDBUS_ASYNC_METHOD("DisconnectIpsp", NULL, NULL, disconnect_ipsp) },
 #endif
        { }
 };
@@ -3061,8 +3159,7 @@ static const GDBusPropertyTable device_properties[] = {
        { "Blocked", "b", dev_property_get_blocked, dev_property_set_blocked },
        { "LegacyPairing", "b", dev_property_get_legacy },
        { "RSSI", "n", dev_property_get_rssi, NULL, dev_property_exists_rssi },
-#if 0 /* Need to discuss with SLP team */
-/* #ifdef __TIZEN_PATCH__ */
+#ifdef __TIZEN_PATCH__
        { "Connected", "y", dev_property_get_connected },
 #else
        { "Connected", "b", dev_property_get_connected },
@@ -3074,14 +3171,13 @@ static const GDBusPropertyTable device_properties[] = {
 #ifdef __TIZEN_PATCH__
         /* To handle Failed Legacy Pairing when initiated from Remote device*/
        { "LegacyPaired", "b", dev_property_get_paired },
-       { "Services", "as", dev_property_get_prim_services },
        { "Flag", "q", property_get_flag },
        { "ManufacturerDataLen", "q", property_get_manufacturer_data_len },
        { "ManufacturerData", "ay", property_get_manufacturer_data },
        { "GattConnected", "b", dev_property_get_gatt_connected },
        { "PayloadTimeout", "q", dev_property_get_payload},
        { "LastAddrType", "y", dev_property_get_last_addr_type},
-
+       { "IpspConnected", "b", dev_property_get_ipsp_conn_state },
 #endif
        { }
 };
@@ -3135,10 +3231,10 @@ void device_add_connection(struct btd_device *dev, uint8_t bdaddr_type)
 
        state->connected = true;
 
+#ifndef __TIZEN_PATCH__
        if (dev->le_state.connected && dev->bredr_state.connected)
                return;
 
-#ifndef __TIZEN_PATCH__
        g_dbus_emit_property_changed(dbus_conn, dev->path, DEVICE_INTERFACE,
                                                                "Connected");
 #else
@@ -3184,10 +3280,10 @@ void device_remove_connection(struct btd_device *device, uint8_t bdaddr_type)
                btd_adapter_remove_bonding(device->adapter, &device->bdaddr,
                                                                bdaddr_type);
 
+#ifndef __TIZEN_PATCH__
        if (device->bredr_state.connected || device->le_state.connected)
                return;
 
-#ifndef __TIZEN_PATCH__
        g_dbus_emit_property_changed(dbus_conn, device->path,
                                                DEVICE_INTERFACE, "Connected");
 #else
@@ -3263,6 +3359,40 @@ failed:
        return str;
 }
 
+static struct csrk_info *load_csrk(GKeyFile *key_file, const char *group)
+{
+       struct csrk_info *csrk;
+       char *str;
+       int i;
+
+       str = g_key_file_get_string(key_file, group, "Key", NULL);
+       if (!str)
+               return NULL;
+
+       csrk = g_new0(struct csrk_info, 1);
+
+       for (i = 0; i < 16; i++) {
+               if (sscanf(str + (i * 2), "%2hhx", &csrk->key[i]) != 1)
+                       goto fail;
+       }
+
+       /*
+        * In case of older storage this will return 0 which is fine since it
+        * didn't support signing at that point the counter should never have
+        * been used.
+        */
+       csrk->counter = g_key_file_get_integer(key_file, group, "Counter",
+                                                                       NULL);
+       g_free(str);
+
+       return csrk;
+
+fail:
+       g_free(str);
+       g_free(csrk);
+       return NULL;
+}
+
 static void load_info(struct btd_device *device, const char *local,
                        const char *peer, GKeyFile *key_file)
 {
@@ -3357,6 +3487,9 @@ static void load_info(struct btd_device *device, const char *local,
                        error("Unknown LE device technology");
 
                g_free(str);
+
+               device->local_csrk = load_csrk(key_file, "LocalSignatureKey");
+               device->remote_csrk = load_csrk(key_file, "RemoteSignatureKey");
        }
 
        g_strfreev(techno);
@@ -3506,10 +3639,6 @@ static void device_register_primaries(struct btd_device *device,
                                                GSList *prim_list, int psm)
 {
        device->primaries = g_slist_concat(device->primaries, prim_list);
-#ifdef __TIZEN_PATCH__
-       device->gatt_services = attrib_client_register(dbus_conn, device, psm, NULL,
-                                                               prim_list);
-#endif
 }
 
 static void add_primary(struct gatt_db_attribute *attr, void *user_data)
@@ -3535,6 +3664,7 @@ static void add_primary(struct gatt_db_attribute *attr, void *user_data)
 static void device_add_uuids(struct btd_device *device, GSList *uuids)
 {
        GSList *l;
+       bool changed = false;
 
        for (l = uuids; l != NULL; l = g_slist_next(l)) {
                GSList *match = g_slist_find_custom(device->uuids, l->data,
@@ -3542,25 +3672,23 @@ static void device_add_uuids(struct btd_device *device, GSList *uuids)
                if (match)
                        continue;
 
+               changed = true;
                device->uuids = g_slist_insert_sorted(device->uuids,
                                                g_strdup(l->data),
                                                bt_uuid_strcmp);
        }
 
-       g_dbus_emit_property_changed(dbus_conn, device->path,
+       if (changed)
+               g_dbus_emit_property_changed(dbus_conn, device->path,
                                                DEVICE_INTERFACE, "UUIDs");
 }
 
-static void store_services(struct btd_device *device);
-
 struct gatt_probe_data {
        struct btd_device *dev;
        bool all_services;
        GSList *uuids;
        struct gatt_db_attribute *cur_attr;
        char cur_uuid[MAX_LEN_UUID_STR];
-       uint16_t start_handle, end_handle;
-       GSList *valid_services;
 };
 
 static bool device_match_profile(struct btd_device *device,
@@ -3588,8 +3716,7 @@ static void dev_probe_gatt(struct btd_profile *p, void *user_data)
        if (!p->remote_uuid || bt_uuid_strcmp(p->remote_uuid, data->cur_uuid))
                return;
 
-       service = service_create_gatt(data->dev, p, data->start_handle,
-                                                       data->end_handle);
+       service = service_create(data->dev, p);
        if (!service)
                return;
 
@@ -3598,73 +3725,10 @@ static void dev_probe_gatt(struct btd_profile *p, void *user_data)
                return;
        }
 
-       data->dev->services = g_slist_append(data->dev->services, service);
-
-       if (data->all_services)
-               data->valid_services = g_slist_append(data->valid_services,
-                                                               service);
-}
-
-static bool match_existing_service(struct gatt_probe_data *data)
-{
-       struct btd_device *dev = data->dev;
-       struct btd_service *service;
-       struct btd_profile *profile;
-       uint16_t start, end;
-       GSList *l, *tmp;
-
-       /*
-        * Check if the profiles should be probed for the service in the
-        * database.
-        */
-       for (l = dev->services; l != NULL;) {
-               service = l->data;
-               profile = btd_service_get_profile(service);
-
-               /* If this is local or non-GATT based service, then skip. */
-               if (!profile->remote_uuid ||
-                       !btd_service_get_gatt_handles(service, &start, &end)) {
-                       l = g_slist_next(l);
-                       continue;
-               }
-
-               /* Skip this service if the handle ranges don't overlap. */
-               if (start > data->end_handle || end < data->start_handle) {
-                       l = g_slist_next(l);
-                       continue;
-               }
-
-               /*
-                * If there is an exact match, then there's no need to probe the
-                * profiles. An exact match is when the service handles AND the
-                * service UUID match.
-                */
-               if (start == data->start_handle && end == data->end_handle &&
-                       !bt_uuid_strcmp(profile->remote_uuid, data->cur_uuid)) {
-                       if (data->all_services)
-                               data->valid_services = g_slist_append(
-                                               data->valid_services, service);
-                       return true;
-               }
-
-               /*
-                * The handles overlap but there is no exact match. This means
-                * that the service is no longer valid. Remove it.
-                *
-                * TODO: The following code is fairly inefficient, especially
-                * when we consider all the extra searches that we're already
-                * doing. Consider changing the services list to a GList.
-                */
-               tmp = l->next;
-               dev->services = g_slist_delete_link(dev->services, l);
-               dev->pending = g_slist_remove(dev->pending, service);
-               service_remove(service);
-
-               l = tmp;
-       }
+       /* Mark service as claimed */
+       gatt_db_service_set_claimed(data->cur_attr, true);
 
-       /* No match found */
-       return false;
+       data->dev->services = g_slist_append(data->dev->services, service);
 }
 
 static void dev_probe_gatt_profile(struct gatt_db_attribute *attr,
@@ -3674,23 +3738,31 @@ static void dev_probe_gatt_profile(struct gatt_db_attribute *attr,
        bt_uuid_t uuid;
        GSList *l = NULL;
 
-       gatt_db_attribute_get_service_data(attr, &data->start_handle,
-                                                       &data->end_handle, NULL,
-                                                       &uuid);
+       gatt_db_attribute_get_service_uuid(attr, &uuid);
        bt_uuid_to_string(&uuid, data->cur_uuid, sizeof(data->cur_uuid));
 
        data->cur_attr = attr;
 
-       /* Don't probe the profiles if a matching service already exists. */
-       if (!match_existing_service(data))
-               btd_profile_foreach(dev_probe_gatt, data);
-
-       if (data->all_services) {
+       /*
+        * If we're probing for all services, store the UUID since device->uuids
+        * was cleared.
+        */
+       if (data->all_services)
                data->uuids = g_slist_append(data->uuids,
                                                g_strdup(data->cur_uuid));
+
+       /* Don't probe the profiles if a matching service already exists. */
+       if (find_service_with_uuid(data->dev->services, data->cur_uuid)) {
+               /* Mark the service as claimed by the existing profile. */
+               gatt_db_service_set_claimed(data->cur_attr, true);
                return;
        }
 
+       btd_profile_foreach(dev_probe_gatt, data);
+
+       if (data->all_services)
+               return;
+
        l = g_slist_append(l, g_strdup(data->cur_uuid));
        device_add_uuids(data->dev, l);
 }
@@ -3708,30 +3780,6 @@ static void device_probe_gatt_profile(struct btd_device *device,
        g_slist_free_full(data.uuids, g_free);
 }
 
-static void remove_invalid_services(struct gatt_probe_data *data)
-{
-       struct btd_device *dev = data->dev;
-       struct btd_service *service;
-       GSList *l, *tmp;
-
-       for (l = dev->services; l != NULL;) {
-               service = l->data;
-
-               if (g_slist_find(data->valid_services, service)) {
-                       l = g_slist_next(l);
-                       continue;
-               }
-
-               /* Service no longer valid, so remove it */
-               tmp = l->next;
-               dev->services = g_slist_delete_link(dev->services, l);
-               dev->pending = g_slist_remove(dev->pending, service);
-               service_remove(service);
-
-               l = tmp;
-       }
-}
-
 static void device_probe_gatt_profiles(struct btd_device *device)
 {
        struct gatt_probe_data data;
@@ -3751,11 +3799,9 @@ static void device_probe_gatt_profiles(struct btd_device *device)
 
        gatt_db_foreach_service(device->db, NULL, dev_probe_gatt_profile,
                                                                        &data);
+
        device_add_uuids(device, data.uuids);
        g_slist_free_full(data.uuids, g_free);
-
-       remove_invalid_services(&data);
-       g_slist_free(data.valid_services);
 }
 
 static void device_accept_gatt_profiles(struct btd_device *device)
@@ -3769,13 +3815,15 @@ static void device_accept_gatt_profiles(struct btd_device *device)
 static void device_remove_gatt_profile(struct btd_device *device,
                                                struct gatt_db_attribute *attr)
 {
-       uint16_t start, end;
        struct btd_service *service;
+       bt_uuid_t uuid;
+       char uuid_str[MAX_LEN_UUID_STR];
        GSList *l;
 
-       gatt_db_attribute_get_service_handles(attr, &start, &end);
+       gatt_db_attribute_get_service_uuid(attr, &uuid);
+       bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
 
-       l = find_service_with_gatt_handles(device->services, start, end);
+       l = find_service_with_uuid(device->services, uuid_str);
        if (!l)
                return;
 
@@ -3789,13 +3837,16 @@ static void gatt_service_added(struct gatt_db_attribute *attr, void *user_data)
 {
        struct btd_device *device = user_data;
        GSList *new_service = NULL;
+       bt_uuid_t uuid;
+       char uuid_str[MAX_LEN_UUID_STR];
        uint16_t start, end;
        GSList *l;
 
        if (!bt_gatt_client_is_ready(device->client))
                return;
 
-       gatt_db_attribute_get_service_handles(attr, &start, &end);
+       gatt_db_attribute_get_service_data(attr, &start, &end, NULL, &uuid);
+       bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
 
        DBG("start: 0x%04x, end: 0x%04x", start, end);
 
@@ -3807,15 +3858,23 @@ static void gatt_service_added(struct gatt_db_attribute *attr, void *user_data)
        if (!new_service)
                return;
 
+       l = find_service_with_uuid(device->services, uuid_str);
+
        device_register_primaries(device, new_service, -1);
 
-       device_probe_gatt_profile(device, attr);
+       /*
+        * If the profile was probed for the first time then call accept on
+        * the service.
+        */
+       if (!l) {
+               l = find_service_with_uuid(device->services, uuid_str);
+               if (l)
+                       service_accept(l->data);
+       }
 
-       l = find_service_with_gatt_handles(device->services, start, end);
-       if (l)
-               service_accept(l->data);
+       device_probe_gatt_profile(device, attr);
 
-       store_services(device);
+       store_device_info(device);
 
        btd_gatt_client_service_added(device->client_dbus, attr);
 }
@@ -3847,8 +3906,21 @@ static void gatt_service_removed(struct gatt_db_attribute *attr,
        struct gatt_primary *prim;
        uint16_t start, end;
 
-       if (!bt_gatt_client_is_ready(device->client))
-               return;
+       /*
+        * NOTE: shared/gatt-client clears the database in case of failure. This
+        * triggers the service_removed callback for all affected services.
+        * Hence, this function will be called in the following cases:
+        *
+        *    1. When a GATT service gets removed due to "Service Changed".
+        *
+        *    2. When a GATT service gets removed when the database get cleared
+        *       upon disconnection with a non-bonded device.
+        *
+        *    3. When a GATT service gets removed when the database get cleared
+        *       by shared/gatt-client when its initialization procedure fails,
+        *       e.g. due to an ATT protocol error or an unexpected disconnect.
+        *       In this case the gatt-client will not be ready.
+        */
 
        gatt_db_attribute_get_service_handles(attr, &start, &end);
 
@@ -3859,27 +3931,29 @@ static void gatt_service_removed(struct gatt_db_attribute *attr,
        if (!l)
                return;
 
-       prim = l->data;
-       device->primaries = g_slist_delete_link(device->primaries, l);
-
-       /*
-        * If this happend since the db was cleared for a non-bonded device,
-        * then don't remove the btd_service just yet. We do this so that we can
-        * avoid re-probing the profile if the same GATT service is found on the
-        * device on re-connection. However, if the device is marked as
-        * temporary, then we remove it anyway.
-        */
-       if (device->client || device->temporary == TRUE)
-               device_remove_gatt_profile(device, attr);
+       prim = l->data;
+       device->primaries = g_slist_delete_link(device->primaries, l);
 
        /*
-        * Remove the corresponding UUIDs entry, only if this is the last
-        * service with this UUID.
+        * Remove the corresponding UUIDs entry and profile, only if this is
+        * the last service with this UUID.
         */
        l = g_slist_find_custom(device->uuids, prim->uuid, bt_uuid_strcmp);
 
-       if (!g_slist_find_custom(device->primaries, prim->uuid,
+       if (l && !g_slist_find_custom(device->primaries, prim->uuid,
                                                        prim_uuid_cmp)) {
+               /*
+                * If this happend since the db was cleared for a non-bonded
+                * device, then don't remove the btd_service just yet. We do
+                * this so that we can avoid re-probing the profile if the same
+                * GATT service is found on the device on re-connection.
+                * However, if the device is marked as temporary, then we
+                * remove it anyway.
+                */
+               if (device->client || device->temporary == TRUE)
+                       device_remove_gatt_profile(device, attr);
+
+               g_free(l->data);
                device->uuids = g_slist_delete_link(device->uuids, l);
                g_dbus_emit_property_changed(dbus_conn, device->path,
                                                DEVICE_INTERFACE, "UUIDs");
@@ -3887,7 +3961,7 @@ static void gatt_service_removed(struct gatt_db_attribute *attr,
 
        g_free(prim);
 
-       store_services(device);
+       store_device_info(device);
 
        btd_gatt_client_service_removed(device->client_dbus, attr);
 }
@@ -4289,7 +4363,6 @@ void device_unpair(struct btd_device *device, gboolean remove_stored)
        if (device->browse)
                browse_request_cancel(device->browse);
 
-       attrib_client_unregister(device->gatt_services);
 
 //     while (device->services != NULL) {
 //             struct btd_service *service = device->services->data;
@@ -4355,9 +4428,6 @@ void device_remove(struct btd_device *device, gboolean remove_stored)
        if (device->browse)
                browse_request_cancel(device->browse);
 
-#ifdef __TIZEN_PATCH__
-       attrib_client_unregister(device->gatt_services);
-#endif
 
        while (device->services != NULL) {
                struct btd_service *service = device->services->data;
@@ -4912,7 +4982,6 @@ done:
 #endif
 
        device_svc_resolved(device, BDADDR_BREDR, err);
-       browse_request_free(req);
 }
 
 static void browse_cb(sdp_list_t *recs, int err, gpointer user_data)
@@ -4948,79 +5017,6 @@ done:
        search_cb(recs, err, user_data);
 }
 
-static void store_services(struct btd_device *device)
-{
-       struct btd_adapter *adapter = device->adapter;
-       char filename[PATH_MAX];
-       char src_addr[18], dst_addr[18];
-       uuid_t uuid;
-       char *prim_uuid;
-       GKeyFile *key_file;
-       GSList *l;
-       char *data;
-       gsize length = 0;
-
-       if (device_address_is_private(device)) {
-               warn("Can't store services for private addressed device %s",
-                                                               device->path);
-               return;
-       }
-
-       sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
-       prim_uuid = bt_uuid2string(&uuid);
-       if (prim_uuid == NULL)
-               return;
-
-       ba2str(btd_adapter_get_address(adapter), src_addr);
-       ba2str(&device->bdaddr, dst_addr);
-
-       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/attributes", src_addr,
-                                                               dst_addr);
-       key_file = g_key_file_new();
-
-       for (l = device->primaries; l; l = l->next) {
-               struct gatt_primary *primary = l->data;
-               char handle[6], uuid_str[33];
-               int i;
-
-               sprintf(handle, "%hu", primary->range.start);
-
-               bt_string2uuid(&uuid, primary->uuid);
-               sdp_uuid128_to_uuid(&uuid);
-
-               switch (uuid.type) {
-               case SDP_UUID16:
-                       sprintf(uuid_str, "%4.4X", uuid.value.uuid16);
-                       break;
-               case SDP_UUID32:
-                       sprintf(uuid_str, "%8.8X", uuid.value.uuid32);
-                       break;
-               case SDP_UUID128:
-                       for (i = 0; i < 16; i++)
-                               sprintf(uuid_str + (i * 2), "%2.2X",
-                                               uuid.value.uuid128.data[i]);
-                       break;
-               default:
-                       uuid_str[0] = '\0';
-               }
-
-               g_key_file_set_string(key_file, handle, "UUID", prim_uuid);
-               g_key_file_set_string(key_file, handle, "Value", uuid_str);
-               g_key_file_set_integer(key_file, handle, "EndGroupHandle",
-                                       primary->range.end);
-       }
-
-       data = g_key_file_to_data(key_file, &length, NULL);
-       if (length > 0) {
-               create_file(filename, S_IRUSR | S_IWUSR);
-               g_file_set_contents(filename, data, length, NULL);
-       }
-
-       free(prim_uuid);
-       g_free(data);
-       g_key_file_free(key_file);
-}
-
 static bool device_get_auto_connect(struct btd_device *device)
 {
        if (device->disable_auto_connect)
@@ -5082,39 +5078,9 @@ done:
        attio_cleanup(device);
 }
 
-static void send_le_browse_response(struct browse_req *req)
-{
-       struct btd_device *dev = req->device;
-       struct bearer_state *state = &dev->le_state;
-       DBusMessage *reply, *msg = req->msg;
-
-       if (!msg)
-               return;
-
-       if (!dbus_message_is_method_call(msg, DEVICE_INTERFACE, "Pair")) {
-               reply = btd_error_failed(msg, "Service discovery failed");
-               g_dbus_send_message(dbus_conn, reply);
-               return;
-       }
-
-       if (!state->paired) {
-               reply = btd_error_failed(msg, "Not paired");
-               g_dbus_send_message(dbus_conn, reply);
-               return;
-       }
-
-       if (!dev->bredr_state.paired && dev->pending_paired) {
-               g_dbus_emit_property_changed(dbus_conn, dev->path,
-                                               DEVICE_INTERFACE, "Paired");
-               dev->pending_paired = false;
-       }
-
-       g_dbus_send_reply(dbus_conn, msg, DBUS_TYPE_INVALID);
-}
-
-static void register_gatt_services(struct browse_req *req)
+static void register_gatt_services(struct btd_device *device)
 {
-       struct btd_device *device = req->device;
+       struct browse_req *req = device->browse;
        GSList *services = NULL;
 
        if (!bt_gatt_client_is_ready(device->client))
@@ -5128,7 +5094,9 @@ static void register_gatt_services(struct browse_req *req)
 
        btd_device_set_temporary(device, FALSE);
 
-       update_gatt_uuids(req, device->primaries, services);
+       if (req)
+               update_gatt_uuids(req, device->primaries, services);
+
        g_slist_free_full(device->primaries, g_free);
        device->primaries = NULL;
 
@@ -5137,11 +5105,14 @@ static void register_gatt_services(struct browse_req *req)
        device_probe_gatt_profiles(device);
 
        device_svc_resolved(device, device->bdaddr_type, 0);
+}
 
-       store_services(device);
-
-       browse_request_free(req);
+#ifdef __TIZEN_PATCH__
+static void gatt_client_debug_func(const char *str, void *user_data)
+{
+       DBG("%s", str);
 }
+#endif
 
 static void gatt_client_ready_cb(bool success, uint8_t att_ecode,
                                                                void *user_data)
@@ -5154,11 +5125,22 @@ static void gatt_client_ready_cb(bool success, uint8_t att_ecode,
                if (device->browse) {
                        struct browse_req *req = device->browse;
 
-                       send_le_browse_response(req);
                        device->browse = NULL;
-                       browse_request_free(req);
+                       browse_request_complete(req, device->bdaddr_type, -EIO);
                }
 
+#ifdef __TIZEN_PATCH__
+               if (device->attachid == 0) {
+                       error("GATT client / server both are not connected");
+                       return;
+               }
+
+               error("Even though GATT client's connection is failed, "
+                               "because GATT server's connection is made, "
+                               "update GATT connection state.");
+               device_set_gatt_connected(device, TRUE);
+#endif
+
                return;
        }
 
@@ -5167,8 +5149,7 @@ static void gatt_client_ready_cb(bool success, uint8_t att_ecode,
 
        DBG("MTU: %u", device->att_mtu);
 
-       if (device->browse)
-               register_gatt_services(device->browse);
+       register_gatt_services(device);
 
        device_accept_gatt_profiles(device);
 
@@ -5195,6 +5176,13 @@ static void gatt_client_init(struct btd_device *device)
                return;
        }
 
+#ifdef __TIZEN_PATCH__
+       if (!bt_gatt_client_set_debug(device->client, gatt_client_debug_func,
+                               NULL, NULL)) {
+               error("Failed to set debug function");
+       }
+#endif
+
        if (!bt_gatt_client_set_ready_handler(device->client,
                                                        gatt_client_ready_cb,
                                                        device, NULL)) {
@@ -5212,6 +5200,50 @@ static void gatt_client_init(struct btd_device *device)
        }
 }
 
+#ifndef __TIZEN_PATCH__
+static void gatt_server_init(struct btd_device *device, struct gatt_db *db)
+{
+       if (!db) {
+               error("No local GATT database exists for this adapter");
+               return;
+       }
+
+       gatt_server_cleanup(device);
+
+       device->server = bt_gatt_server_new(db, device->att, device->att_mtu);
+       if (!device->server)
+               error("Failed to initialize bt_gatt_server");
+}
+#endif
+
+static bool local_counter(uint32_t *sign_cnt, void *user_data)
+{
+       struct btd_device *dev = user_data;
+
+       if (!dev->local_csrk)
+               return false;
+
+       *sign_cnt = dev->local_csrk->counter++;
+
+       store_device_info(dev);
+
+       return true;
+}
+
+static bool remote_counter(uint32_t *sign_cnt, void *user_data)
+{
+       struct btd_device *dev = user_data;
+
+       if (!dev->remote_csrk || *sign_cnt < dev->remote_csrk->counter)
+               return false;
+
+       dev->remote_csrk->counter = *sign_cnt;
+
+       store_device_info(dev);
+
+       return true;
+}
+
 bool device_attach_att(struct btd_device *dev, GIOChannel *io)
 {
        GError *gerr = NULL;
@@ -5219,6 +5251,9 @@ bool device_attach_att(struct btd_device *dev, GIOChannel *io)
        BtIOSecLevel sec_level;
        uint16_t mtu;
        uint16_t cid;
+#ifndef __TIZEN_PATCH__
+       struct btd_gatt_database *database;
+#endif
 
        bt_io_get(io, &gerr, BT_IO_OPT_SEC_LEVEL, &sec_level,
                                                BT_IO_OPT_IMTU, &mtu,
@@ -5231,6 +5266,7 @@ bool device_attach_att(struct btd_device *dev, GIOChannel *io)
                return false;
        }
 
+#if 0
        if (sec_level == BT_IO_SEC_LOW && dev->le_state.paired) {
                DBG("Elevating security level since LTK is available");
 
@@ -5243,6 +5279,7 @@ bool device_attach_att(struct btd_device *dev, GIOChannel *io)
                        return false;
                }
        }
+#endif
 
        dev->att_mtu = MIN(mtu, BT_ATT_MAX_LE_MTU);
        attrib = g_attrib_new(io, dev->att_mtu);
@@ -5251,12 +5288,14 @@ bool device_attach_att(struct btd_device *dev, GIOChannel *io)
                return false;
        }
 
+#ifdef __TIZEN_PATCH__
        dev->attachid = attrib_channel_attach(attrib);
        if (dev->attachid == 0) {
                g_attrib_unref(attrib);
                error("Attribute server attach failure!");
                return false;
        }
+#endif
 
        dev->attrib = attrib;
        dev->att = g_attrib_get_att(attrib);
@@ -5267,7 +5306,22 @@ bool device_attach_att(struct btd_device *dev, GIOChannel *io)
                                                att_disconnected_cb, dev, NULL);
        bt_att_set_close_on_unref(dev->att, true);
 
+       if (dev->local_csrk)
+               bt_att_set_local_key(dev->att, dev->local_csrk->key,
+                                                       local_counter, dev);
+
+       if (dev->remote_csrk)
+               bt_att_set_remote_key(dev->att, dev->remote_csrk->key,
+                                                       remote_counter, dev);
+
+#ifndef __TIZEN_PATCH__
+       database = btd_adapter_get_database(dev->adapter);
+#endif
+
        gatt_client_init(dev);
+#ifndef __TIZEN_PATCH__
+       gatt_server_init(dev, btd_gatt_database_get_db(database));
+#endif
 
        /*
         * Remove the device from the connect_list and give the passive
@@ -5462,34 +5516,43 @@ static void att_browse_error_cb(const GError *gerr, gpointer user_data)
        struct btd_device *device = attcb->user_data;
        struct browse_req *req = device->browse;
 
-       send_le_browse_response(req);
        device->browse = NULL;
-       browse_request_free(req);
+       browse_request_complete(req, device->bdaddr_type, -ECONNABORTED);
 }
 
-static void browse_gatt_client(struct browse_req *req)
+static void att_browse_cb(gpointer user_data)
 {
-       struct btd_device *device = req->device;
+       DBG("ATT connection successful");
+}
 
-       if (!device->client) {
-               DBG("No instance currently attached");
-               return;
-       }
+static struct browse_req *browse_request_new(struct btd_device *device,
+                                                       DBusMessage *msg)
+{
+       struct browse_req *req;
+
+       if (device->browse)
+               return NULL;
+
+       req = g_new0(struct browse_req, 1);
+       req->device = device;
+
+       device->browse = req;
+
+       if (!msg)
+               return req;
+
+       req->msg = dbus_message_ref(msg);
 
        /*
-        * If gatt-client is ready, then register all services. Otherwise, this
-        * will be deferred until client becomes ready.
+        * Track the request owner to cancel it automatically if the owner
+        * exits
         */
-       if (bt_gatt_client_is_ready(device->client))
-               register_gatt_services(req);
-}
-
-static void att_browse_cb(gpointer user_data)
-{
-       struct att_callbacks *attcb = user_data;
-       struct btd_device *device = attcb->user_data;
+       req->listener_id = g_dbus_add_disconnect_watch(dbus_conn,
+                                               dbus_message_get_sender(msg),
+                                               browse_request_exit,
+                                               req, NULL);
 
-       browse_gatt_client(device->browse);
+       return req;
 }
 
 static int device_browse_gatt(struct btd_device *device, DBusMessage *msg)
@@ -5498,17 +5561,24 @@ static int device_browse_gatt(struct btd_device *device, DBusMessage *msg)
        struct att_callbacks *attcb;
        struct browse_req *req;
 
-       if (device->browse)
+       req = browse_request_new(device, msg);
+       if (!req)
                return -EBUSY;
 
-       req = g_new0(struct browse_req, 1);
-       req->device = device;
-
-       device->browse = req;
-
        if (device->attrib) {
-               browse_gatt_client(device->browse);
-               goto done;
+               /*
+                * If discovery has not yet completed, then wait for gatt-client
+                * to become ready.
+                */
+               if (!device->le_state.svc_resolved)
+                       return 0;
+
+               /*
+                * Services have already been discovered, so signal this browse
+                * request as resolved.
+                */
+               device_svc_resolved(device, device->bdaddr_type, 0);
+               return 0;
        }
 
        attcb = g_new0(struct att_callbacks, 1);
@@ -5534,20 +5604,6 @@ static int device_browse_gatt(struct btd_device *device, DBusMessage *msg)
                return -EIO;
        }
 
-done:
-
-       if (msg) {
-               const char *sender = dbus_message_get_sender(msg);
-
-               req->msg = dbus_message_ref(msg);
-               /* Track the request owner to cancel it
-                * automatically if the owner exits */
-               req->listener_id = g_dbus_add_disconnect_watch(dbus_conn,
-                                               sender,
-                                               discover_services_req_exit,
-                                               req, NULL);
-       }
-
        return 0;
 }
 
@@ -5583,11 +5639,10 @@ static int device_browse_sdp(struct btd_device *device, DBusMessage *msg)
        uuid_t uuid;
        int err;
 
-       if (device->browse)
+       req = browse_request_new(device, msg);
+       if (!req)
                return -EBUSY;
 
-       req = g_new0(struct browse_req, 1);
-       req->device = device;
        sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]);
 
        req->sdp_flags = get_sdp_flags(device);
@@ -5600,20 +5655,6 @@ static int device_browse_sdp(struct btd_device *device, DBusMessage *msg)
                return err;
        }
 
-       device->browse = req;
-
-       if (msg) {
-               const char *sender = dbus_message_get_sender(msg);
-
-               req->msg = dbus_message_ref(msg);
-               /* Track the request owner to cancel it
-                * automatically if the owner exits */
-               req->listener_id = g_dbus_add_disconnect_watch(dbus_conn,
-                                               sender,
-                                               discover_services_req_exit,
-                                               req, NULL);
-       }
-
        return err;
 }
 
@@ -5657,7 +5698,7 @@ static int device_custom_browse_sdp(struct btd_device *device,
                 * automatically if the owner exits */
                req->listener_id = g_dbus_add_disconnect_watch(dbus_conn,
                                                sender,
-                                               discover_services_req_exit,
+                                               browse_request_exit,
                                                req, NULL);
        }
        return err;
@@ -5672,6 +5713,24 @@ void device_set_last_addr_type(struct btd_device *device, uint8_t type)
 
        device->last_bdaddr_type = type;
 }
+
+void device_set_ipsp_connected(struct btd_device *device, gboolean connected)
+{
+       if (device == NULL) {
+               error("device is NULL");
+               return;
+       }
+
+       if (device->ipsp_connected == connected)
+               return;
+
+       device->ipsp_connected = connected;
+
+       DBG("ipsp_connected %d", connected);
+
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                       DEVICE_INTERFACE, "IpspConnected");
+}
 #endif
 
 int device_discover_services(struct btd_device *device)
@@ -6485,6 +6544,14 @@ struct bt_gatt_client *btd_device_get_gatt_client(struct btd_device *device)
        return device->client;
 }
 
+struct bt_gatt_server *btd_device_get_gatt_server(struct btd_device *device)
+{
+       if (!device)
+               return NULL;
+
+       return device->server;
+}
+
 void btd_device_gatt_set_service_changed(struct btd_device *device,
                                                uint16_t start, uint16_t end)
 {
index 383f268..af9b931 100644 (file)
@@ -80,6 +80,7 @@ struct gatt_primary *btd_device_get_primary(struct btd_device *device,
 GSList *btd_device_get_primaries(struct btd_device *device);
 struct gatt_db *btd_device_get_gatt_db(struct btd_device *device);
 struct bt_gatt_client *btd_device_get_gatt_client(struct btd_device *device);
+struct bt_gatt_server *btd_device_get_gatt_server(struct btd_device *device);
 void btd_device_gatt_set_service_changed(struct btd_device *device,
                                                uint16_t start, uint16_t end);
 bool device_attach_att(struct btd_device *dev, GIOChannel *io);
@@ -106,7 +107,6 @@ bool device_is_bonded(struct btd_device *device, uint8_t bdaddr_type);
 gboolean device_is_trusted(struct btd_device *device);
 void device_set_paired(struct btd_device *dev, uint8_t bdaddr_type);
 void device_set_unpaired(struct btd_device *dev, uint8_t bdaddr_type);
-bool device_is_service_blocked(struct btd_device *device, const char *uuid);
 void btd_device_set_temporary(struct btd_device *device, gboolean temporary);
 void btd_device_set_trusted(struct btd_device *device, gboolean trusted);
 void device_set_bonded(struct btd_device *device, uint8_t bdaddr_type);
@@ -156,6 +156,7 @@ void device_set_adv_report_info(struct btd_device *device, void *data,
 void device_set_payload_timeout(struct btd_device *device,
                        uint16_t payload_timeout);
 void device_set_last_addr_type(struct btd_device *device, uint8_t type);
+void device_set_ipsp_connected(struct btd_device *device, gboolean connected);
 #endif
 
 struct btd_device *btd_device_ref(struct btd_device *device);
@@ -191,6 +192,3 @@ int btd_device_connect_services(struct btd_device *dev, GSList *services);
 
 void btd_device_init(void);
 void btd_device_cleanup(void);
-#ifdef BLUEZ5_GATT_CLIENT
-gboolean disconnect_le_device(gpointer user_data);
-#endif
index 30eb29f..cec119e 100644 (file)
--- a/src/eir.c
+++ b/src/eir.c
@@ -33,9 +33,9 @@
 #include <stdbool.h>
 #include <glib.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/sdp.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/sdp.h"
 
 #include "src/shared/util.h"
 #include "uuid-helper.h"
@@ -128,6 +128,9 @@ static char *name2utf8(const uint8_t *name, uint8_t len)
        char *ptr;
 
        in_name = g_malloc0(sizeof(char) * (len + 1));
+       /* Fix : NULL_RETURNS */
+       if (in_name == NULL)
+               return NULL;
        memcpy(in_name, name, sizeof(char) * len);
        in_name[len] = '\0';
 
index a80c1ab..8951707 100644 (file)
@@ -27,7 +27,7 @@
 #include <config.h>
 #endif
 
-#include <gdbus/gdbus.h>
+#include "gdbus/gdbus.h"
 
 #include "error.h"
 
@@ -40,7 +40,7 @@ DBusMessage *btd_error_invalid_args(DBusMessage *msg)
 DBusMessage *btd_error_invalid_args_str(DBusMessage *msg, const char *str)
 {
        return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments",
-                                                                       str);
+                                       "%s", str);
 }
 
 DBusMessage *btd_error_busy(DBusMessage *msg)
@@ -99,7 +99,8 @@ DBusMessage *btd_error_not_authorized(DBusMessage *msg)
 
 DBusMessage *btd_error_not_permitted(DBusMessage *msg, const char *str)
 {
-       return g_dbus_create_error(msg, ERROR_INTERFACE ".NotPermitted", str);
+       return g_dbus_create_error(msg, ERROR_INTERFACE ".NotPermitted",
+                                       "%s", str);
 }
 
 DBusMessage *btd_error_no_such_adapter(DBusMessage *msg)
index 809aca5..ab8081c 100644 (file)
 #include <stdint.h>
 
 #include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
 
-#include <bluetooth/bluetooth.h>
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
 
 #include "log.h"
 #include "error.h"
 #include "adapter.h"
 #include "device.h"
-#include "lib/uuid.h"
 #include "src/shared/queue.h"
 #include "src/shared/att.h"
 #include "src/shared/gatt-db.h"
 #include "gatt-client.h"
 #include "dbus-common.h"
 
+#ifndef NELEM
+#define NELEM(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
 #define GATT_SERVICE_IFACE             "org.bluez.GattService1"
 #define GATT_CHARACTERISTIC_IFACE      "org.bluez.GattCharacteristic1"
 #define GATT_DESCRIPTOR_IFACE          "org.bluez.GattDescriptor1"
 
 struct btd_gatt_client {
        struct btd_device *device;
+       bool ready;
        char devaddr[18];
        struct gatt_db *db;
        struct bt_gatt_client *gatt;
 
        struct queue *services;
+       struct queue *all_notify_clients;
 };
 
 struct service {
@@ -64,6 +72,8 @@ struct service {
        char *path;
        struct queue *chrcs;
        bool chrcs_ready;
+       struct queue *pending_ext_props;
+       guint idle_id;
 };
 
 struct characteristic {
@@ -72,13 +82,18 @@ struct characteristic {
        uint16_t handle;
        uint16_t value_handle;
        uint8_t props;
+       uint16_t ext_props;
+       uint16_t ext_props_handle;
        bt_uuid_t uuid;
        char *path;
 
-       bool in_read;
-       bool in_write;
+       unsigned int read_id;
+       unsigned int write_id;
 
        struct queue *descs;
+
+       bool notifying;
+       struct queue *notify_clients;
 };
 
 struct descriptor {
@@ -88,10 +103,19 @@ struct descriptor {
        bt_uuid_t uuid;
        char *path;
 
-       bool in_read;
-       bool in_write;
+       unsigned int read_id;
+       unsigned int write_id;
 };
 
+static bool uuid_cmp(const bt_uuid_t *uuid, uint16_t u16)
+{
+       bt_uuid_t uuid16;
+
+       bt_uuid16_create(&uuid16, u16);
+
+       return bt_uuid_cmp(uuid, &uuid16) == 0;
+}
+
 static gboolean descriptor_get_uuid(const GDBusPropertyTable *property,
                                        DBusMessageIter *iter, void *data)
 {
@@ -199,6 +223,43 @@ static bool parse_value_arg(DBusMessage *msg, uint8_t **value,
        return true;
 }
 
+#ifdef __TIZEN_PATCH__
+static bool parse_type_value_arg(DBusMessage *msg, uint8_t *type, uint8_t **value,
+                                                       size_t *value_len)
+{
+       DBusMessageIter iter;
+       DBusMessageIter array;
+       uint8_t *val;
+       int len;
+
+       if (!dbus_message_iter_init(msg, &iter))
+               return false;
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BYTE)
+               return false;
+       dbus_message_iter_get_basic(&iter, type);
+       dbus_message_iter_next(&iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+               return false;
+
+       dbus_message_iter_recurse(&iter, &array);
+       dbus_message_iter_get_fixed_array(&array, &val, &len);
+       dbus_message_iter_next(&iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID)
+               return false;
+
+       if (len < 0)
+               return false;
+
+       *value = val;
+       *value_len = len;
+
+       return true;
+}
+#endif
+
 typedef bool (*async_dbus_op_complete_t)(void *data);
 
 struct async_dbus_op {
@@ -213,7 +274,9 @@ static void async_dbus_op_free(void *data)
 {
        struct async_dbus_op *op = data;
 
-       dbus_message_unref(op->msg);
+       if (op->msg)
+               dbus_message_unref(op->msg);
+
        free(op);
 }
 
@@ -268,7 +331,7 @@ static DBusMessage *create_gatt_dbus_error(DBusMessage *msg, uint8_t att_ecode)
        case 0:
                return btd_error_failed(msg, "Operation failed");
        default:
-               return g_dbus_create_error(msg, ERROR_INTERFACE,
+               return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
                                "Operation failed with ATT error: 0x%02x",
                                att_ecode);
        }
@@ -322,12 +385,15 @@ static void desc_read_cb(bool success, uint8_t att_ecode,
        if (!success) {
                DBusMessage *reply = create_gatt_dbus_error(op->msg, att_ecode);
 
-               desc->in_read = false;
+               desc->read_id = 0;
                g_dbus_send_message(btd_get_dbus_connection(), reply);
                return;
        }
 
-       gatt_db_attribute_write(desc->attr, 0, value, length, 0, NULL,
+       if (!op->offset)
+               gatt_db_attribute_reset(desc->attr);
+
+       gatt_db_attribute_write(desc->attr, op->offset, value, length, 0, NULL,
                                                write_descriptor_cb, desc);
 
        /*
@@ -337,16 +403,18 @@ static void desc_read_cb(bool success, uint8_t att_ecode,
         */
        if (length == bt_gatt_client_get_mtu(service->client->gatt) - 1) {
                op->offset += length;
-               if (bt_gatt_client_read_long_value(service->client->gatt,
+               desc->read_id = bt_gatt_client_read_long_value(
+                                                       service->client->gatt,
                                                        desc->handle,
                                                        op->offset,
                                                        desc_read_cb,
                                                        async_dbus_op_ref(op),
-                                                       async_dbus_op_unref))
+                                                       async_dbus_op_unref);
+               if (desc->read_id)
                        return;
        }
 
-       desc->in_read = false;
+       desc->read_id = 0;
 
        /* Read the stored data from db */
        gatt_db_attribute_read(desc->attr, 0, 0, NULL, read_op_cb, op);
@@ -359,7 +427,10 @@ static DBusMessage *descriptor_read_value(DBusConnection *conn,
        struct bt_gatt_client *gatt = desc->chrc->service->client->gatt;
        struct async_dbus_op *op;
 
-       if (desc->in_read)
+       if (!gatt)
+               return btd_error_failed(msg, "Not connected");
+
+       if (desc->read_id)
                return btd_error_in_progress(msg);
 
        op = new0(struct async_dbus_op, 1);
@@ -369,12 +440,12 @@ static DBusMessage *descriptor_read_value(DBusConnection *conn,
        op->msg = dbus_message_ref(msg);
        op->data = desc;
 
-       if (bt_gatt_client_read_value(gatt, desc->handle, desc_read_cb,
+       desc->read_id = bt_gatt_client_read_value(gatt, desc->handle,
+                                                       desc_read_cb,
                                                        async_dbus_op_ref(op),
-                                                       async_dbus_op_unref)) {
-               desc->in_read = true;
+                                                       async_dbus_op_unref);
+       if (desc->read_id)
                return NULL;
-       }
 
        async_dbus_op_free(op);
 
@@ -418,13 +489,14 @@ static void write_cb(bool success, uint8_t att_ecode, void *user_data)
        write_result_cb(success, false, att_ecode, user_data);
 }
 
-static bool start_long_write(DBusMessage *msg, uint16_t handle,
+static unsigned int start_long_write(DBusMessage *msg, uint16_t handle,
                                        struct bt_gatt_client *gatt,
                                        bool reliable, const uint8_t *value,
                                        size_t value_len, void *data,
                                        async_dbus_op_complete_t complete)
 {
        struct async_dbus_op *op;
+       unsigned int id;
 
        op = new0(struct async_dbus_op, 1);
        if (!op)
@@ -434,24 +506,25 @@ static bool start_long_write(DBusMessage *msg, uint16_t handle,
        op->data = data;
        op->complete = complete;
 
-       if (bt_gatt_client_write_long_value(gatt, reliable, handle,
+       id = bt_gatt_client_write_long_value(gatt, reliable, handle,
                                                        0, value, value_len,
                                                        write_result_cb, op,
-                                                       async_dbus_op_free))
-               return true;
+                                                       async_dbus_op_free);
 
-       async_dbus_op_free(op);
+       if (!id)
+               async_dbus_op_free(op);
 
-       return false;
+       return id;
 }
 
-static bool start_write_request(DBusMessage *msg, uint16_t handle,
+static unsigned int start_write_request(DBusMessage *msg, uint16_t handle,
                                        struct bt_gatt_client *gatt,
                                        const uint8_t *value, size_t value_len,
                                        void *data,
                                        async_dbus_op_complete_t complete)
 {
        struct async_dbus_op *op;
+       unsigned int id;
 
        op = new0(struct async_dbus_op, 1);
        if (!op)
@@ -461,21 +534,20 @@ static bool start_write_request(DBusMessage *msg, uint16_t handle,
        op->data = data;
        op->complete = complete;
 
-       if (bt_gatt_client_write_value(gatt, handle, value, value_len,
+       id = bt_gatt_client_write_value(gatt, handle, value, value_len,
                                                        write_cb, op,
-                                                       async_dbus_op_free))
-               return true;
-
-       async_dbus_op_free(op);
+                                                       async_dbus_op_free);
+       if (!id)
+               async_dbus_op_free(op);
 
-       return false;
+       return id;
 }
 
 static bool desc_write_complete(void *data)
 {
        struct descriptor *desc = data;
 
-       desc->in_write = false;
+       desc->write_id = false;
 
        /*
         * The descriptor might have been unregistered during the read. Return
@@ -491,10 +563,11 @@ static DBusMessage *descriptor_write_value(DBusConnection *conn,
        struct bt_gatt_client *gatt = desc->chrc->service->client->gatt;
        uint8_t *value = NULL;
        size_t value_len = 0;
-       bool result;
-       bt_uuid_t uuid;
 
-       if (desc->in_write)
+       if (!gatt)
+               return btd_error_failed(msg, "Not connected");
+
+       if (desc->write_id)
                return btd_error_in_progress(msg);
 
        if (!parse_value_arg(msg, &value, &value_len))
@@ -505,8 +578,7 @@ static DBusMessage *descriptor_write_value(DBusConnection *conn,
         * descriptors. We achieve this through the StartNotify and StopNotify
         * methods on GattCharacteristic1.
         */
-       bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
-       if (bt_uuid_cmp(&desc->uuid, &uuid))
+       if (uuid_cmp(&desc->uuid, GATT_CLIENT_CHARAC_CFG_UUID))
                return btd_error_not_permitted(msg, "Write not permitted");
 
        /*
@@ -514,23 +586,30 @@ static DBusMessage *descriptor_write_value(DBusConnection *conn,
         * write.
         */
        if (value_len <= (unsigned) bt_gatt_client_get_mtu(gatt) - 3)
-               result = start_write_request(msg, desc->handle, gatt, value,
+               desc->write_id = start_write_request(msg, desc->handle,
+                                                       gatt, value,
                                                        value_len, desc,
                                                        desc_write_complete);
        else
-               result = start_long_write(msg, desc->handle, gatt, false, value,
+               desc->write_id = start_long_write(msg, desc->handle,
+                                                       gatt, false, value,
                                                        value_len, desc,
                                                        desc_write_complete);
 
-       if (!result)
+       if (!desc->write_id)
                return btd_error_failed(msg, "Failed to initiate write");
 
-       desc->in_write = true;
-
        return NULL;
 }
 
 static const GDBusPropertyTable descriptor_properties[] = {
+#ifdef __TIZEN_PATCH__
+       { "UUID", "s", descriptor_get_uuid },
+       { "Characteristic", "o", descriptor_get_characteristic },
+       { "Value", "ay", descriptor_get_value, NULL,
+                                       descriptor_value_exists },
+       { }
+#else
        { "UUID", "s", descriptor_get_uuid, NULL, NULL,
                                        G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
        { "Characteristic", "o", descriptor_get_characteristic, NULL, NULL,
@@ -538,9 +617,17 @@ static const GDBusPropertyTable descriptor_properties[] = {
        { "Value", "ay", descriptor_get_value, NULL, descriptor_value_exists,
                                        G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
        { }
+#endif
 };
 
 static const GDBusMethodTable descriptor_methods[] = {
+#ifdef __TIZEN_PATCH__
+       { GDBUS_ASYNC_METHOD("ReadValue", NULL, GDBUS_ARGS({ "value", "ay" }),
+                                               descriptor_read_value) },
+       { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" }),
+                                       NULL, descriptor_write_value) },
+       { }
+#else
        { GDBUS_EXPERIMENTAL_ASYNC_METHOD("ReadValue", NULL,
                                                GDBUS_ARGS({ "value", "ay" }),
                                                descriptor_read_value) },
@@ -549,6 +636,7 @@ static const GDBusMethodTable descriptor_methods[] = {
                                                NULL,
                                                descriptor_write_value) },
        { }
+#endif
 };
 
 static void descriptor_free(void *data)
@@ -590,15 +678,27 @@ static struct descriptor *descriptor_create(struct gatt_db_attribute *attr,
 
        DBG("Exported GATT characteristic descriptor: %s", desc->path);
 
+       if (uuid_cmp(&desc->uuid, GATT_CHARAC_EXT_PROPER_UUID))
+               chrc->ext_props_handle = desc->handle;
+
        return desc;
 }
 
 static void unregister_descriptor(void *data)
 {
        struct descriptor *desc = data;
+       struct bt_gatt_client *gatt = desc->chrc->service->client->gatt;
 
        DBG("Removing GATT descriptor: %s", desc->path);
 
+       if (desc->read_id)
+               bt_gatt_client_cancel(gatt, desc->read_id);
+
+       if (desc->write_id)
+               bt_gatt_client_cancel(gatt, desc->write_id);
+
+       desc->chrc = NULL;
+
        g_dbus_unregister_interface(btd_get_dbus_connection(), desc->path,
                                                        GATT_DESCRIPTOR_IFACE);
 }
@@ -656,22 +756,20 @@ static gboolean characteristic_value_exists(const GDBusPropertyTable *property,
 static gboolean characteristic_get_notifying(const GDBusPropertyTable *property,
                                        DBusMessageIter *iter, void *data)
 {
-       dbus_bool_t notifying = FALSE;
-
-       /*
-        * TODO: Return the correct value here once StartNotify and StopNotify
-        * methods are implemented.
-        */
+       struct characteristic *chrc = data;
+       dbus_bool_t notifying = chrc->notifying ? TRUE : FALSE;
 
        dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &notifying);
 
        return TRUE;
 }
 
-static struct {
+struct chrc_prop_data {
        uint8_t prop;
        char *str;
-} properties[] = {
+};
+
+static struct chrc_prop_data chrc_props[] = {
        /* Default Properties */
        { BT_GATT_CHRC_PROP_BROADCAST,          "broadcast" },
        { BT_GATT_CHRC_PROP_READ,               "read" },
@@ -680,7 +778,13 @@ static struct {
        { BT_GATT_CHRC_PROP_NOTIFY,             "notify" },
        { BT_GATT_CHRC_PROP_INDICATE,           "indicate" },
        { BT_GATT_CHRC_PROP_AUTH,               "authenticated-signed-writes" },
-       { },
+       { BT_GATT_CHRC_PROP_EXT_PROP,           "extended-properties" }
+};
+
+static struct chrc_prop_data chrc_ext_props[] = {
+       /* Extended Properties */
+       { BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE, "reliable-write" },
+       { BT_GATT_CHRC_EXT_PROP_WRITABLE_AUX,   "writable-auxiliaries" }
 };
 
 static gboolean characteristic_get_flags(const GDBusPropertyTable *property,
@@ -688,20 +792,21 @@ static gboolean characteristic_get_flags(const GDBusPropertyTable *property,
 {
        struct characteristic *chrc = data;
        DBusMessageIter array;
-       int i;
+       unsigned i;
 
        dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &array);
 
-       for (i = 0; properties[i].str; i++) {
-               if (chrc->props & properties[i].prop)
+       for (i = 0; i < NELEM(chrc_props); i++) {
+               if (chrc->props & chrc_props[i].prop)
                        dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
-                                                       &properties[i].str);
+                                                       &chrc_props[i].str);
        }
 
-       /*
-        * TODO: Handle extended properties if the descriptor is
-        * present.
-        */
+       for (i = 0; i < NELEM(chrc_ext_props); i++) {
+               if (chrc->ext_props & chrc_ext_props[i].prop)
+                       dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
+                                                       &chrc_ext_props[i].str);
+       }
 
        dbus_message_iter_close_container(iter, &array);
 
@@ -720,6 +825,20 @@ static void write_characteristic_cb(struct gatt_db_attribute *attr, int err,
                                        GATT_CHARACTERISTIC_IFACE, "Value");
 }
 
+#ifdef __TIZEN_PATCH__
+static void notify_characteristic_cb(struct gatt_db_attribute *attr, int err,
+                                                               void *user_data)
+{
+       struct characteristic *chrc = user_data;
+
+       if (err)
+               return;
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(), chrc->path,
+                                       GATT_CHARACTERISTIC_IFACE, "ChangedValue");
+}
+#endif
+
 static void chrc_read_cb(bool success, uint8_t att_ecode, const uint8_t *value,
                                        uint16_t length, void *user_data)
 {
@@ -730,12 +849,15 @@ static void chrc_read_cb(bool success, uint8_t att_ecode, const uint8_t *value,
        if (!success) {
                DBusMessage *reply = create_gatt_dbus_error(op->msg, att_ecode);
 
-               chrc->in_read = false;
+               chrc->read_id = 0;
                g_dbus_send_message(btd_get_dbus_connection(), reply);
                return ;
        }
 
-       gatt_db_attribute_write(chrc->attr, 0, value, length, op->offset, NULL,
+       if (!op->offset)
+               gatt_db_attribute_reset(chrc->attr);
+
+       gatt_db_attribute_write(chrc->attr, op->offset, value, length, 0, NULL,
                                                write_characteristic_cb, chrc);
 
        /*
@@ -745,16 +867,18 @@ static void chrc_read_cb(bool success, uint8_t att_ecode, const uint8_t *value,
         */
        if (length == bt_gatt_client_get_mtu(service->client->gatt) - 1) {
                op->offset += length;
-               if (bt_gatt_client_read_long_value(service->client->gatt,
+               chrc->read_id = bt_gatt_client_read_long_value(
+                                                       service->client->gatt,
                                                        chrc->value_handle,
                                                        op->offset,
                                                        chrc_read_cb,
                                                        async_dbus_op_ref(op),
-                                                       async_dbus_op_unref))
+                                                       async_dbus_op_unref);
+               if (chrc->read_id)
                        return;
        }
 
-       chrc->in_read = false;
+       chrc->read_id = 0;
 
        /* Read the stored data from db */
        gatt_db_attribute_read(chrc->attr, 0, 0, NULL, read_op_cb, op);
@@ -767,7 +891,10 @@ static DBusMessage *characteristic_read_value(DBusConnection *conn,
        struct bt_gatt_client *gatt = chrc->service->client->gatt;
        struct async_dbus_op *op;
 
-       if (chrc->in_read)
+       if (!gatt)
+               return btd_error_failed(msg, "Not connected");
+
+       if (chrc->read_id)
                return btd_error_in_progress(msg);
 
        op = new0(struct async_dbus_op, 1);
@@ -777,12 +904,12 @@ static DBusMessage *characteristic_read_value(DBusConnection *conn,
        op->msg = dbus_message_ref(msg);
        op->data = chrc;
 
-       if (bt_gatt_client_read_value(gatt, chrc->value_handle, chrc_read_cb,
-                                               async_dbus_op_ref(op),
-                                               async_dbus_op_unref)) {
-               chrc->in_read = true;
+       chrc->read_id = bt_gatt_client_read_value(gatt, chrc->value_handle,
+                                                       chrc_read_cb,
+                                                       async_dbus_op_ref(op),
+                                                       async_dbus_op_unref);
+       if (chrc->read_id)
                return NULL;
-       }
 
        async_dbus_op_free(op);
 
@@ -793,7 +920,7 @@ static bool chrc_write_complete(void *data)
 {
        struct characteristic *chrc = data;
 
-       chrc->in_write = false;
+       chrc->write_id = false;
 
        /*
         * The characteristic might have been unregistered during the read.
@@ -809,17 +936,17 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn,
        struct bt_gatt_client *gatt = chrc->service->client->gatt;
        uint8_t *value = NULL;
        size_t value_len = 0;
+       bool supported = false;
 
-       if (chrc->in_write)
+       if (!gatt)
+               return btd_error_failed(msg, "Not connected");
+
+       if (chrc->write_id)
                return btd_error_in_progress(msg);
 
        if (!parse_value_arg(msg, &value, &value_len))
                return btd_error_invalid_args(msg);
 
-       if (!(chrc->props & (BT_GATT_CHRC_PROP_WRITE |
-                                       BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP)))
-               return btd_error_not_supported(msg);
-
        /*
         * Decide which write to use based on characteristic properties. For now
         * we don't perform signed writes since gatt-client doesn't support them
@@ -831,55 +958,409 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn,
         *     - If value is larger than MTU - 3: long-write
         *   * "write-without-response" property set -> write command.
         */
+#ifndef __TIZEN_PATCH__
+       if ((chrc->ext_props & BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE)) {
+               supported = true;
+               chrc->write_id = start_long_write(msg, chrc->value_handle, gatt,
+                                               true, value, value_len,
+                                               chrc, chrc_write_complete);
+               if (chrc->write_id)
+                       return NULL;
+       }
+#endif
+
        if (chrc->props & BT_GATT_CHRC_PROP_WRITE) {
                uint16_t mtu;
-               bool result;
 
+               supported = true;
                mtu = bt_gatt_client_get_mtu(gatt);
                if (!mtu)
                        return btd_error_failed(msg, "No ATT transport");
 
                if (value_len <= (unsigned) mtu - 3)
-                       result = start_write_request(msg, chrc->value_handle,
-                                                       gatt, value,
-                                                       value_len, chrc,
-                                                       chrc_write_complete);
+                       chrc->write_id = start_write_request(msg,
+                                               chrc->value_handle,
+                                               gatt, value, value_len,
+                                               chrc, chrc_write_complete);
                else
-                       result = start_long_write(msg, chrc->value_handle, gatt,
-                                               false, value, value_len, chrc,
-                                               chrc_write_complete);
+                       chrc->write_id = start_long_write(msg,
+                                               chrc->value_handle, gatt,
+                                               false, value, value_len,
+                                               chrc, chrc_write_complete);
 
-               if (result)
-                       goto done_async;
+               if (chrc->write_id)
+                       return NULL;
        }
 
-       if ((chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP) &&
-                       bt_gatt_client_write_without_response(gatt,
-                                                       chrc->value_handle,
-                                                       false, value,
-                                                       value_len))
+       if (!(chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP))
+               goto fail;
+
+       supported = true;
+       chrc->write_id = bt_gatt_client_write_without_response(gatt,
+                                       chrc->value_handle,
+                                       chrc->props & BT_GATT_CHRC_PROP_AUTH,
+                                       value, value_len);
+       if (chrc->write_id) {
+#ifdef __TIZEN_PATCH__
+               chrc->write_id = 0;
+#endif
                return dbus_message_new_method_return(msg);
+       }
+
+fail:
+       if (supported)
+               return btd_error_failed(msg, "Failed to initiate write");
+
+       return btd_error_not_supported(msg);
+}
+
+#ifdef __TIZEN_PATCH__
+static DBusMessage *characteristic_write_value_by_type(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct characteristic *chrc = user_data;
+       struct bt_gatt_client *gatt = chrc->service->client->gatt;
+       uint8_t *value = NULL;
+       size_t value_len = 0;
+       bool supported = false;
+       uint8_t write_type = 0;
 
-       return btd_error_failed(msg, "Failed to initiate write");
+       if (!gatt)
+               return btd_error_failed(msg, "Not connected");
 
-done_async:
-       chrc->in_write = true;
+       if (chrc->write_id)
+               return btd_error_in_progress(msg);
 
-       return NULL;
+       if (!parse_type_value_arg(msg, &write_type, &value, &value_len))
+               return btd_error_invalid_args(msg);
+
+
+       if ((write_type & chrc->props) == BT_GATT_CHRC_PROP_WRITE) {
+               DBG("BT_GATT_CHRC_PROP_WRITE");
+               uint16_t mtu;
+               supported = true;
+               mtu = bt_gatt_client_get_mtu(gatt);
+               if (!mtu)
+                       return btd_error_failed(msg, "No ATT transport");
+
+               if (value_len <= (unsigned) mtu - 3)
+                       chrc->write_id = start_write_request(msg,
+                                               chrc->value_handle,
+                                               gatt, value, value_len,
+                                               chrc, chrc_write_complete);
+               else
+                       chrc->write_id = start_long_write(msg,
+                                               chrc->value_handle, gatt,
+                                               false, value, value_len,
+                                               chrc, chrc_write_complete);
+
+               if (chrc->write_id)
+                       return NULL;
+       } else if ((write_type & chrc->props) ==
+                       BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP) {
+               DBG("BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP");
+               supported = true;
+               chrc->write_id = bt_gatt_client_write_without_response(gatt,
+                                       chrc->value_handle,
+                                       chrc->props & BT_GATT_CHRC_PROP_AUTH,
+                                       value, value_len);
+               if (chrc->write_id) {
+                       chrc->write_id = 0;
+                       return dbus_message_new_method_return(msg);
+               }
+       }
+
+       if (supported)
+               return btd_error_failed(msg, "Failed to initiate write");
+
+       return btd_error_not_supported(msg);
+}
+#endif
+
+struct notify_client {
+       struct characteristic *chrc;
+       int ref_count;
+       char *owner;
+       guint watch;
+       unsigned int notify_id;
+};
+
+static void notify_client_free(struct notify_client *client)
+{
+       DBG("owner %s", client->owner);
+
+       g_dbus_remove_watch(btd_get_dbus_connection(), client->watch);
+       bt_gatt_client_unregister_notify(client->chrc->service->client->gatt,
+                                                       client->notify_id);
+       free(client->owner);
+       free(client);
+}
+
+static void notify_client_unref(void *data)
+{
+       struct notify_client *client = data;
+
+       DBG("owner %s", client->owner);
+
+       if (__sync_sub_and_fetch(&client->ref_count, 1))
+               return;
+
+       notify_client_free(client);
+}
+
+static struct notify_client *notify_client_ref(struct notify_client *client)
+{
+       DBG("owner %s", client->owner);
+
+       __sync_fetch_and_add(&client->ref_count, 1);
+
+       return client;
+}
+
+static bool match_notifying(const void *a, const void *b)
+{
+       const struct notify_client *client = a;
+
+       return !!client->notify_id;
+}
+
+static void update_notifying(struct characteristic *chrc)
+{
+       if (!chrc->notifying)
+               return;
+
+       if (queue_find(chrc->notify_clients, match_notifying, NULL))
+               return;
+
+       chrc->notifying = false;
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(), chrc->path,
+                                               GATT_CHARACTERISTIC_IFACE,
+                                               "Notifying");
+}
+
+static void notify_client_disconnect(DBusConnection *conn, void *user_data)
+{
+       struct notify_client *client = user_data;
+       struct characteristic *chrc = client->chrc;
+
+       DBG("owner %s", client->owner);
+
+       queue_remove(chrc->notify_clients, client);
+       queue_remove(chrc->service->client->all_notify_clients, client);
+
+       update_notifying(chrc);
+
+       notify_client_unref(client);
+}
+
+static struct notify_client *notify_client_create(struct characteristic *chrc,
+                                                       const char *owner)
+{
+       struct notify_client *client;
+
+       client = new0(struct notify_client, 1);
+       if (!client)
+               return NULL;
+
+       client->chrc = chrc;
+       client->owner = strdup(owner);
+       if (!client->owner) {
+               free(client);
+               return NULL;
+       }
+
+       client->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
+                                               owner, notify_client_disconnect,
+                                               client, NULL);
+       if (!client->watch) {
+               free(client->owner);
+               free(client);
+               return NULL;
+       }
+
+       return notify_client_ref(client);
+}
+
+static bool match_notify_sender(const void *a, const void *b)
+{
+       const struct notify_client *client = a;
+       const char *sender = b;
+
+       return strcmp(client->owner, sender) == 0;
+}
+
+static void notify_cb(uint16_t value_handle, const uint8_t *value,
+                                       uint16_t length, void *user_data)
+{
+       struct async_dbus_op *op = user_data;
+       struct notify_client *client = op->data;
+       struct characteristic *chrc = client->chrc;
+
+       /*
+        * Even if the value didn't change, we want to send a PropertiesChanged
+        * signal so that we propagate the notification/indication to
+        * applications.
+        */
+       gatt_db_attribute_reset(chrc->attr);
+#ifdef __TIZEN_PATCH__
+       gatt_db_attribute_write(chrc->attr, 0, value, length, 0, NULL,
+                                               notify_characteristic_cb, chrc);
+#else
+       gatt_db_attribute_write(chrc->attr, 0, value, length, 0, NULL,
+                                               write_characteristic_cb, chrc);
+#endif
+}
+
+static DBusMessage *create_notify_reply(struct async_dbus_op *op,
+                                               bool success, uint8_t att_ecode)
+{
+       DBusMessage *reply = NULL;
+
+       if (!op->msg)
+               return NULL;
+
+       if (success)
+               reply = g_dbus_create_reply(op->msg, DBUS_TYPE_INVALID);
+       else if (att_ecode)
+               reply = create_gatt_dbus_error(op->msg, att_ecode);
+       else
+               reply = btd_error_failed(op->msg,
+                                               "Characteristic not available");
+
+       if (!reply)
+               error("Failed to construct D-Bus message reply");
+
+       return reply;
+}
+
+static void register_notify_cb(uint16_t att_ecode, void *user_data)
+{
+       struct async_dbus_op *op = user_data;
+       struct notify_client *client = op->data;
+       struct characteristic *chrc = client->chrc;
+       DBusMessage *reply;
+
+       if (att_ecode) {
+               queue_remove(chrc->notify_clients, client);
+               queue_remove(chrc->service->client->all_notify_clients, client);
+               notify_client_free(client);
+
+               reply = create_notify_reply(op, false, att_ecode);
+
+               goto done;
+       }
+
+       if (!chrc->notifying) {
+               chrc->notifying = true;
+               g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                       chrc->path, GATT_CHARACTERISTIC_IFACE,
+                                       "Notifying");
+       }
+
+       reply = create_notify_reply(op, true, 0);
+
+done:
+       if (reply)
+               g_dbus_send_message(btd_get_dbus_connection(), reply);
 }
 
 static DBusMessage *characteristic_start_notify(DBusConnection *conn,
                                        DBusMessage *msg, void *user_data)
 {
-       /* TODO: Implement */
-       return btd_error_failed(msg, "Not implemented");
+       struct characteristic *chrc = user_data;
+       struct bt_gatt_client *gatt = chrc->service->client->gatt;
+       const char *sender = dbus_message_get_sender(msg);
+       struct async_dbus_op *op;
+       struct notify_client *client;
+
+       if (!(chrc->props & BT_GATT_CHRC_PROP_NOTIFY ||
+                               chrc->props & BT_GATT_CHRC_PROP_INDICATE))
+               return btd_error_not_supported(msg);
+
+       /* Each client can only have one active notify session. */
+       client = queue_find(chrc->notify_clients, match_notify_sender, sender);
+       if (client)
+               return client->notify_id ?
+                               btd_error_failed(msg, "Already notifying") :
+                               btd_error_in_progress(msg);
+
+       client = notify_client_create(chrc, sender);
+       if (!client)
+               return btd_error_failed(msg, "Failed allocate notify session");
+
+       queue_push_tail(chrc->notify_clients, client);
+       queue_push_tail(chrc->service->client->all_notify_clients, client);
+
+       /*
+        * If the device is currently not connected, return success. We will
+        * automatically try and register all clients when a GATT client becomes
+        * ready.
+        */
+       if (!gatt) {
+               DBusMessage *reply;
+
+               reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+               if (reply)
+                       return reply;
+
+               /*
+                * Clean up and respond with an error instead of timing out to
+                * avoid any ambiguities.
+                */
+               error("Failed to construct D-Bus message reply");
+               goto fail;
+       }
+
+       op = new0(struct async_dbus_op, 1);
+       if (!op)
+               goto fail;
+
+       op->data = client;
+       op->msg = dbus_message_ref(msg);
+
+       client->notify_id = bt_gatt_client_register_notify(gatt,
+                                               chrc->value_handle,
+                                               register_notify_cb, notify_cb,
+                                               op, async_dbus_op_free);
+       if (client->notify_id)
+               return NULL;
+
+       async_dbus_op_free(op);
+
+fail:
+       queue_remove(chrc->notify_clients, client);
+       queue_remove(chrc->service->client->all_notify_clients, client);
+
+       /* Directly free the client */
+       notify_client_free(client);
+
+       return btd_error_failed(msg, "Failed to register notify session");
 }
 
 static DBusMessage *characteristic_stop_notify(DBusConnection *conn,
                                        DBusMessage *msg, void *user_data)
 {
-       /* TODO: Implement */
-       return btd_error_failed(msg, "Not implemented");
+       struct characteristic *chrc = user_data;
+       struct bt_gatt_client *gatt = chrc->service->client->gatt;
+       const char *sender = dbus_message_get_sender(msg);
+       struct notify_client *client;
+
+       if (!chrc->notifying)
+               return btd_error_failed(msg, "Not notifying");
+
+       client = queue_remove_if(chrc->notify_clients, match_notify_sender,
+                                                       (void *) sender);
+       if (!client)
+               return btd_error_failed(msg, "No notify session started");
+
+       queue_remove(chrc->service->client->all_notify_clients, client);
+       bt_gatt_client_unregister_notify(gatt, client->notify_id);
+       update_notifying(chrc);
+
+       notify_client_unref(client);
+
+       return dbus_message_new_method_return(msg);
 }
 
 static void append_desc_path(void *data, void *user_data)
@@ -908,6 +1389,18 @@ static gboolean characteristic_get_descriptors(
 }
 
 static const GDBusPropertyTable characteristic_properties[] = {
+#ifdef __TIZEN_PATCH__
+       { "UUID", "s", characteristic_get_uuid },
+       { "Service", "o", characteristic_get_service },
+       { "Value", "ay", characteristic_get_value, NULL,
+                                       characteristic_value_exists },
+       { "ChangedValue", "ay", characteristic_get_value, NULL,
+                                       characteristic_value_exists },
+       { "Notifying", "b", characteristic_get_notifying },
+       { "Flags", "as", characteristic_get_flags },
+       { "Descriptors", "ao", characteristic_get_descriptors },
+       { }
+#else
        { "UUID", "s", characteristic_get_uuid, NULL, NULL,
                                        G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
        { "Service", "o", characteristic_get_service, NULL, NULL,
@@ -922,9 +1415,24 @@ static const GDBusPropertyTable characteristic_properties[] = {
        { "Descriptors", "ao", characteristic_get_descriptors, NULL, NULL,
                                        G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
        { }
+#endif
+
 };
 
 static const GDBusMethodTable characteristic_methods[] = {
+#ifdef __TIZEN_PATCH__
+       { GDBUS_ASYNC_METHOD("ReadValue", NULL, GDBUS_ARGS({ "value", "ay" }),
+                                               characteristic_read_value) },
+       { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" }),
+                                       NULL, characteristic_write_value) },
+       { GDBUS_ASYNC_METHOD("WriteValuebyType",
+                                       GDBUS_ARGS({ "type", "y" }, { "value", "ay" }),
+                                       NULL, characteristic_write_value_by_type) },
+       { GDBUS_ASYNC_METHOD("StartNotify", NULL, NULL,
+                                               characteristic_start_notify) },
+       { GDBUS_METHOD("StopNotify", NULL, NULL, characteristic_stop_notify) },
+       { }
+#else
        { GDBUS_EXPERIMENTAL_ASYNC_METHOD("ReadValue", NULL,
                                                GDBUS_ARGS({ "value", "ay" }),
                                                characteristic_read_value) },
@@ -937,13 +1445,17 @@ static const GDBusMethodTable characteristic_methods[] = {
        { GDBUS_EXPERIMENTAL_METHOD("StopNotify", NULL, NULL,
                                                characteristic_stop_notify) },
        { }
+#endif
 };
 
 static void characteristic_free(void *data)
 {
        struct characteristic *chrc = data;
 
-       queue_destroy(chrc->descs, NULL);  /* List should be empty here */
+       /* List should be empty here */
+       queue_destroy(chrc->descs, NULL);
+       queue_destroy(chrc->notify_clients, NULL);
+
        g_free(chrc->path);
        free(chrc);
 }
@@ -965,6 +1477,13 @@ static struct characteristic *characteristic_create(
                return NULL;
        }
 
+       chrc->notify_clients = queue_new();
+       if (!chrc->notify_clients) {
+               queue_destroy(chrc->descs, NULL);
+               free(chrc);
+               return NULL;
+       }
+
        chrc->service = service;
 
        gatt_db_attribute_get_char_data(attr, &chrc->handle,
@@ -994,12 +1513,30 @@ static struct characteristic *characteristic_create(
        return chrc;
 }
 
+static void remove_client(void *data)
+{
+       struct notify_client *ntfy_client = data;
+       struct btd_gatt_client *client = ntfy_client->chrc->service->client;
+
+       queue_remove(client->all_notify_clients, ntfy_client);
+
+       notify_client_unref(ntfy_client);
+}
+
 static void unregister_characteristic(void *data)
 {
        struct characteristic *chrc = data;
+       struct bt_gatt_client *gatt = chrc->service->client->gatt;
 
        DBG("Removing GATT characteristic: %s", chrc->path);
 
+       if (chrc->read_id)
+               bt_gatt_client_cancel(gatt, chrc->read_id);
+
+       if (chrc->write_id)
+               bt_gatt_client_cancel(gatt, chrc->write_id);
+
+       queue_remove_all(chrc->notify_clients, NULL, NULL, remove_client);
        queue_remove_all(chrc->descs, NULL, NULL, unregister_descriptor);
 
        g_dbus_unregister_interface(btd_get_dbus_connection(), chrc->path,
@@ -1069,6 +1606,13 @@ static gboolean service_get_characteristics(const GDBusPropertyTable *property,
 }
 
 static const GDBusPropertyTable service_properties[] = {
+#ifdef __TIZEN_PATCH__
+       { "UUID", "s", service_get_uuid },
+       { "Device", "o", service_get_device },
+       { "Primary", "b", service_get_primary },
+       { "Characteristics", "ao", service_get_characteristics },
+       { }
+#else
        { "UUID", "s", service_get_uuid, NULL, NULL,
                                        G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
        { "Device", "o", service_get_device, NULL, NULL,
@@ -1078,6 +1622,7 @@ static const GDBusPropertyTable service_properties[] = {
        { "Characteristics", "ao", service_get_characteristics, NULL, NULL,
                                        G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
        { }
+#endif
 };
 
 static void service_free(void *data)
@@ -1085,6 +1630,7 @@ static void service_free(void *data)
        struct service *service = data;
 
        queue_destroy(service->chrcs, NULL);  /* List should be empty here */
+       queue_destroy(service->pending_ext_props, NULL);
        g_free(service->path);
        free(service);
 }
@@ -1106,6 +1652,13 @@ static struct service *service_create(struct gatt_db_attribute *attr,
                return NULL;
        }
 
+       service->pending_ext_props = queue_new();
+       if (!service->pending_ext_props) {
+               queue_destroy(service->chrcs, NULL);
+               free(service);
+               return NULL;
+       }
+
        service->client = client;
 
        gatt_db_attribute_get_service_data(attr, &service->start_handle,
@@ -1142,12 +1695,29 @@ static void unregister_service(void *data)
 
        DBG("Removing GATT service: %s", service->path);
 
+       if (service->idle_id)
+               g_source_remove(service->idle_id);
+
        queue_remove_all(service->chrcs, NULL, NULL, unregister_characteristic);
 
        g_dbus_unregister_interface(btd_get_dbus_connection(), service->path,
                                                        GATT_SERVICE_IFACE);
 }
 
+static void notify_chrcs(struct service *service)
+{
+
+       if (service->chrcs_ready ||
+                               !queue_isempty(service->pending_ext_props))
+               return;
+
+       service->chrcs_ready = true;
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(), service->path,
+                                                       GATT_SERVICE_IFACE,
+                                                       "Characteristics");
+}
+
 struct export_data {
        void *root;
        bool failed;
@@ -1171,6 +1741,46 @@ static void export_desc(struct gatt_db_attribute *attr, void *user_data)
        queue_push_tail(charac->descs, desc);
 }
 
+static void read_ext_props_cb(bool success, uint8_t att_ecode,
+                                       const uint8_t *value, uint16_t length,
+                                       void *user_data)
+{
+       struct characteristic *chrc = user_data;
+       struct service *service = chrc->service;
+
+       if (!success) {
+               error("Failed to obtain extended properties - error: 0x%02x",
+                                                               att_ecode);
+               return;
+       }
+
+       if (!value || length != 2) {
+               error("Malformed extended properties value");
+               return;
+       }
+
+       chrc->ext_props = get_le16(value);
+       if (chrc->ext_props)
+               g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                               chrc->path,
+                                               GATT_CHARACTERISTIC_IFACE,
+                                               "Flags");
+
+       queue_remove(service->pending_ext_props, chrc);
+
+       notify_chrcs(service);
+}
+
+static void read_ext_props(void *data, void *user_data)
+{
+       struct characteristic *chrc = data;
+
+       bt_gatt_client_read_value(chrc->service->client->gatt,
+                                                       chrc->ext_props_handle,
+                                                       read_ext_props_cb,
+                                                       chrc, NULL);
+}
+
 static bool create_descriptors(struct gatt_db_attribute *attr,
                                        struct characteristic *charac)
 {
@@ -1204,6 +1814,9 @@ static void export_char(struct gatt_db_attribute *attr, void *user_data)
 
        queue_push_tail(service->chrcs, charac);
 
+       if (charac->ext_props_handle)
+               queue_push_tail(service->pending_ext_props, charac);
+
        return;
 
 fail:
@@ -1220,28 +1833,24 @@ static bool create_characteristics(struct gatt_db_attribute *attr,
 
        gatt_db_service_foreach_char(attr, export_char, &data);
 
-       return !data.failed;
-}
+       if (data.failed)
+               return false;
 
-static void notify_chrcs(void *data, void *user_data)
-{
-       struct service *service = data;
+       /* Obtain extended properties */
+       queue_foreach(service->pending_ext_props, read_ext_props, NULL);
 
-       service->chrcs_ready = true;
-
-       g_dbus_emit_property_changed(btd_get_dbus_connection(), service->path,
-                                                       GATT_SERVICE_IFACE,
-                                                       "Characteristics");
+       return true;
 }
 
 static gboolean set_chrcs_ready(gpointer user_data)
 {
-       struct btd_gatt_client *client = user_data;
+       struct service *service = user_data;
 
-       if (!client->gatt)
-               return FALSE;
+       notify_chrcs(service);
 
-       queue_foreach(client->services, notify_chrcs, NULL);
+#ifdef __TIZEN_PATCH__
+       device_set_gatt_connected(service->client->device, TRUE);
+#endif
 
        return FALSE;
 }
@@ -1251,6 +1860,9 @@ static void export_service(struct gatt_db_attribute *attr, void *user_data)
        struct btd_gatt_client *client = user_data;
        struct service *service;
 
+       if (gatt_db_service_get_claimed(attr))
+               return;
+
        service = service_create(attr, client);
        if (!service)
                return;
@@ -1262,6 +1874,14 @@ static void export_service(struct gatt_db_attribute *attr, void *user_data)
        }
 
        queue_push_tail(client->services, service);
+
+       /*
+        * Asynchronously update the "Characteristics" property of the service.
+        * If there are any pending reads to obtain the value of the "Extended
+        * Properties" descriptor then wait until they are complete.
+        */
+       if (!service->chrcs_ready && queue_isempty(service->pending_ext_props))
+               service->idle_id = g_idle_add(set_chrcs_ready, service);
 }
 
 static void create_services(struct btd_gatt_client *client)
@@ -1269,13 +1889,6 @@ static void create_services(struct btd_gatt_client *client)
        DBG("Exporting objects for GATT services: %s", client->devaddr);
 
        gatt_db_foreach_service(client->db, NULL, export_service, client);
-
-       /*
-        * Asynchronously update the "Characteristics" property of each service.
-        * We do this so that users have a way to know that all characteristics
-        * of a service have been exported.
-        */
-       g_idle_add(set_chrcs_ready, client);
 }
 
 struct btd_gatt_client *btd_gatt_client_new(struct btd_device *device)
@@ -1300,6 +1913,13 @@ struct btd_gatt_client *btd_gatt_client_new(struct btd_device *device)
                return NULL;
        }
 
+       client->all_notify_clients = queue_new();
+       if (!client->all_notify_clients) {
+               queue_destroy(client->services, NULL);
+               free(client);
+               return NULL;
+       }
+
        client->device = device;
        ba2str(device_get_address(device), client->devaddr);
 
@@ -1314,11 +1934,44 @@ void btd_gatt_client_destroy(struct btd_gatt_client *client)
                return;
 
        queue_destroy(client->services, unregister_service);
+       queue_destroy(client->all_notify_clients, NULL);
        bt_gatt_client_unref(client->gatt);
        gatt_db_unref(client->db);
        free(client);
 }
 
+static void register_notify(void *data, void *user_data)
+{
+       struct notify_client *notify_client = data;
+       struct btd_gatt_client *client = user_data;
+       struct async_dbus_op *op;
+
+       DBG("Re-register subscribed notification client");
+
+       op = new0(struct async_dbus_op, 1);
+       if (!op)
+               goto fail;
+
+       op->data = notify_client;
+
+       notify_client->notify_id = bt_gatt_client_register_notify(client->gatt,
+                                       notify_client->chrc->value_handle,
+                                       register_notify_cb, notify_cb,
+                                       op, async_dbus_op_free);
+       if (notify_client->notify_id)
+               return;
+
+       async_dbus_op_free(op);
+
+fail:
+       DBG("Failed to re-register notification client");
+
+       queue_remove(notify_client->chrc->notify_clients, client);
+       queue_remove(client->all_notify_clients, client);
+
+       notify_client_free(notify_client);
+}
+
 void btd_gatt_client_ready(struct btd_gatt_client *client)
 {
        struct bt_gatt_client *gatt;
@@ -1335,33 +1988,134 @@ void btd_gatt_client_ready(struct btd_gatt_client *client)
        bt_gatt_client_unref(client->gatt);
        client->gatt = bt_gatt_client_ref(gatt);
 
-       create_services(client);
+       client->ready = true;
+
+       DBG("GATT client ready");
+
+       if (queue_isempty(client->services)) {
+               DBG("Exporting services");
+               create_services(client);
+               return;
+       }
+
+       /*
+        * Services have already been created before. Re-enable notifications
+        * for any pre-registered notification sessions.
+        */
+       queue_foreach(client->all_notify_clients, register_notify, client);
+
+#ifdef __TIZEN_PATCH__
+       device_set_gatt_connected(client->device, TRUE);
+#endif
 }
 
 void btd_gatt_client_service_added(struct btd_gatt_client *client,
                                        struct gatt_db_attribute *attrib)
 {
-       /* TODO */
+       if (!client || !attrib || !client->ready)
+               return;
+
+       export_service(attrib, client);
+}
+
+static bool match_service_handle(const void *a, const void *b)
+{
+       const struct service *service = a;
+       uint16_t start_handle = PTR_TO_UINT(b);
+
+       return service->start_handle == start_handle;
 }
 
 void btd_gatt_client_service_removed(struct btd_gatt_client *client,
                                        struct gatt_db_attribute *attrib)
 {
-       /* TODO */
+       uint16_t start_handle, end_handle;
+
+       if (!client || !attrib || !client->ready)
+               return;
+
+       gatt_db_attribute_get_service_handles(attrib, &start_handle,
+                                                               &end_handle);
+
+       DBG("GATT Services Removed - start: 0x%04x, end: 0x%04x", start_handle,
+                                                               end_handle);
+       queue_remove_all(client->services, match_service_handle,
+                                               UINT_TO_PTR(start_handle),
+                                               unregister_service);
+}
+
+static void clear_notify_id(void *data, void *user_data)
+{
+       struct notify_client *client = data;
+
+       client->notify_id = 0;
+}
+
+static void cancel_desc_ops(void *data, void *user_data)
+{
+       struct descriptor *desc = data;
+       struct bt_gatt_client *gatt = user_data;
+
+       if (desc->read_id) {
+               bt_gatt_client_cancel(gatt, desc->read_id);
+               desc->read_id = 0;
+       }
+
+       if (desc->write_id) {
+               bt_gatt_client_cancel(gatt, desc->write_id);
+               desc->write_id = 0;
+       }
+}
+
+static void cancel_chrc_ops(void *data, void *user_data)
+{
+       struct characteristic *chrc = data;
+       struct bt_gatt_client *gatt = user_data;
+
+       if (chrc->read_id) {
+               bt_gatt_client_cancel(gatt, chrc->read_id);
+               chrc->read_id = 0;
+       }
+
+       if (chrc->write_id) {
+               bt_gatt_client_cancel(gatt, chrc->write_id);
+               chrc->write_id = 0;
+       }
+
+       queue_foreach(chrc->descs, cancel_desc_ops, user_data);
+}
+
+static void cancel_ops(void *data, void *user_data)
+{
+       struct service *service = data;
+
+       queue_foreach(service->chrcs, cancel_chrc_ops, user_data);
 }
 
 void btd_gatt_client_disconnected(struct btd_gatt_client *client)
 {
-       if (!client)
+       if (!client || !client->gatt)
                return;
 
-       DBG("Device disconnected. Cleaning up");
+       DBG("Device disconnected. Cleaning up.");
 
        /*
         * Remove all services. We'll recreate them when a new bt_gatt_client
-        * becomes ready.
+        * becomes ready. Leave the services around if the device is bonded.
+        * TODO: Once GATT over BR/EDR is properly supported, we should pass the
+        * correct bdaddr_type based on the transport over which GATT is being
+        * done.
         */
-       queue_remove_all(client->services, NULL, NULL, unregister_service);
+       if (!device_is_bonded(client->device, BDADDR_LE_PUBLIC)) {
+               DBG("Device not bonded. Removing exported services.");
+               queue_remove_all(client->services, NULL, NULL,
+                                                       unregister_service);
+       } else {
+               DBG("Device is bonded. Keeping exported services up.");
+               queue_foreach(client->all_notify_clients, clear_notify_id,
+                                                                       NULL);
+               queue_foreach(client->services, cancel_ops, client->gatt);
+       }
 
        bt_gatt_client_unref(client->gatt);
        client->gatt = NULL;
diff --git a/src/gatt-database.c b/src/gatt-database.c
new file mode 100644 (file)
index 0000000..e887bd2
--- /dev/null
@@ -0,0 +1,2242 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Google Inc.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+#include "lib/uuid.h"
+#include "btio/btio.h"
+#include "gdbus/gdbus.h"
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-server.h"
+#include "log.h"
+#include "error.h"
+#include "adapter.h"
+#include "device.h"
+#include "gatt-database.h"
+#include "dbus-common.h"
+
+#ifndef ATT_CID
+#define ATT_CID 4
+#endif
+
+#ifndef ATT_PSM
+#define ATT_PSM 31
+#endif
+
+#define GATT_MANAGER_IFACE     "org.bluez.GattManager1"
+#define GATT_SERVICE_IFACE     "org.bluez.GattService1"
+#define GATT_CHRC_IFACE                "org.bluez.GattCharacteristic1"
+#define GATT_DESC_IFACE                "org.bluez.GattDescriptor1"
+
+#define UUID_GAP       0x1800
+#define UUID_GATT      0x1801
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+struct btd_gatt_database {
+       struct btd_adapter *adapter;
+       struct gatt_db *db;
+       unsigned int db_id;
+       GIOChannel *le_io;
+       GIOChannel *l2cap_io;
+       uint32_t gap_handle;
+       uint32_t gatt_handle;
+       struct queue *device_states;
+       struct queue *ccc_callbacks;
+       struct gatt_db_attribute *svc_chngd;
+       struct gatt_db_attribute *svc_chngd_ccc;
+       struct queue *services;
+};
+
+struct external_service {
+       struct btd_gatt_database *database;
+       bool failed;
+       char *owner;
+       char *path;     /* Path to GattService1 */
+       DBusMessage *reg;
+       GDBusClient *client;
+       GDBusProxy *proxy;
+       struct gatt_db_attribute *attrib;
+       uint16_t attr_cnt;
+       struct queue *chrcs;
+       struct queue *descs;
+};
+
+struct external_chrc {
+       struct external_service *service;
+       char *path;
+       GDBusProxy *proxy;
+       uint8_t props;
+       uint8_t ext_props;
+       struct gatt_db_attribute *attrib;
+       struct gatt_db_attribute *ccc;
+       struct queue *pending_reads;
+       struct queue *pending_writes;
+       unsigned int ntfy_cnt;
+};
+
+struct external_desc {
+       struct external_service *service;
+       char *chrc_path;
+       GDBusProxy *proxy;
+       struct gatt_db_attribute *attrib;
+       bool handled;
+       struct queue *pending_reads;
+       struct queue *pending_writes;
+};
+
+struct pending_op {
+       unsigned int id;
+       struct gatt_db_attribute *attrib;
+       struct queue *owner_queue;
+       void *setup_data;
+};
+
+struct device_state {
+       bdaddr_t bdaddr;
+       uint8_t bdaddr_type;
+       struct queue *ccc_states;
+};
+
+struct ccc_state {
+       uint16_t handle;
+       uint8_t value[2];
+};
+
+struct ccc_cb_data {
+       uint16_t handle;
+       btd_gatt_database_ccc_write_t callback;
+       btd_gatt_database_destroy_t destroy;
+       void *user_data;
+};
+
+struct device_info {
+       bdaddr_t bdaddr;
+       uint8_t bdaddr_type;
+};
+
+static void ccc_cb_free(void *data)
+{
+       struct ccc_cb_data *ccc_cb = data;
+
+       if (ccc_cb->destroy)
+               ccc_cb->destroy(ccc_cb->user_data);
+
+       free(ccc_cb);
+}
+
+static bool ccc_cb_match_service(const void *data, const void *match_data)
+{
+       const struct ccc_cb_data *ccc_cb = data;
+       const struct gatt_db_attribute *attrib = match_data;
+       uint16_t start, end;
+
+       if (!gatt_db_attribute_get_service_handles(attrib, &start, &end))
+               return false;
+
+       return ccc_cb->handle >= start && ccc_cb->handle <= end;
+}
+
+static bool ccc_cb_match_handle(const void *data, const void *match_data)
+{
+       const struct ccc_cb_data *ccc_cb = data;
+       uint16_t handle = PTR_TO_UINT(match_data);
+
+       return ccc_cb->handle == handle;
+}
+
+static bool dev_state_match(const void *a, const void *b)
+{
+       const struct device_state *dev_state = a;
+       const struct device_info *dev_info = b;
+
+       return bacmp(&dev_state->bdaddr, &dev_info->bdaddr) == 0 &&
+                               dev_state->bdaddr_type == dev_info->bdaddr_type;
+}
+
+static struct device_state *
+find_device_state(struct btd_gatt_database *database, bdaddr_t *bdaddr,
+                                                       uint8_t bdaddr_type)
+{
+       struct device_info dev_info;
+
+       memset(&dev_info, 0, sizeof(dev_info));
+
+       bacpy(&dev_info.bdaddr, bdaddr);
+       dev_info.bdaddr_type = bdaddr_type;
+
+       return queue_find(database->device_states, dev_state_match, &dev_info);
+}
+
+static bool ccc_state_match(const void *a, const void *b)
+{
+       const struct ccc_state *ccc = a;
+       uint16_t handle = PTR_TO_UINT(b);
+
+       return ccc->handle == handle;
+}
+
+static struct ccc_state *find_ccc_state(struct device_state *dev_state,
+                                                               uint16_t handle)
+{
+       return queue_find(dev_state->ccc_states, ccc_state_match,
+                                                       UINT_TO_PTR(handle));
+}
+
+static struct device_state *device_state_create(bdaddr_t *bdaddr,
+                                                       uint8_t bdaddr_type)
+{
+       struct device_state *dev_state;
+
+       dev_state = new0(struct device_state, 1);
+       if (!dev_state)
+               return NULL;
+
+       dev_state->ccc_states = queue_new();
+       if (!dev_state->ccc_states) {
+               free(dev_state);
+               return NULL;
+       }
+
+       bacpy(&dev_state->bdaddr, bdaddr);
+       dev_state->bdaddr_type = bdaddr_type;
+
+       return dev_state;
+}
+
+static struct device_state *get_device_state(struct btd_gatt_database *database,
+                                                       bdaddr_t *bdaddr,
+                                                       uint8_t bdaddr_type)
+{
+       struct device_state *dev_state;
+
+       /*
+        * Find and return a device state. If a matching state doesn't exist,
+        * then create a new one.
+        */
+       dev_state = find_device_state(database, bdaddr, bdaddr_type);
+       if (dev_state)
+               return dev_state;
+
+       dev_state = device_state_create(bdaddr, bdaddr_type);
+       if (!dev_state)
+               return NULL;
+
+       queue_push_tail(database->device_states, dev_state);
+
+       return dev_state;
+}
+
+static struct ccc_state *get_ccc_state(struct btd_gatt_database *database,
+                                                       bdaddr_t *bdaddr,
+                                                       uint8_t bdaddr_type,
+                                                       uint16_t handle)
+{
+       struct device_state *dev_state;
+       struct ccc_state *ccc;
+
+       dev_state = get_device_state(database, bdaddr, bdaddr_type);
+       if (!dev_state)
+               return NULL;
+
+       ccc = find_ccc_state(dev_state, handle);
+       if (ccc)
+               return ccc;
+
+       ccc = new0(struct ccc_state, 1);
+       if (!ccc)
+               return NULL;
+
+       ccc->handle = handle;
+       queue_push_tail(dev_state->ccc_states, ccc);
+
+       return ccc;
+}
+
+static void device_state_free(void *data)
+{
+       struct device_state *state = data;
+
+       queue_destroy(state->ccc_states, free);
+       free(state);
+}
+
+static void cancel_pending_read(void *data)
+{
+       struct pending_op *op = data;
+
+       gatt_db_attribute_read_result(op->attrib, op->id,
+                                       BT_ATT_ERROR_REQUEST_NOT_SUPPORTED,
+                                       NULL, 0);
+       op->owner_queue = NULL;
+}
+
+static void cancel_pending_write(void *data)
+{
+       struct pending_op *op = data;
+
+       gatt_db_attribute_write_result(op->attrib, op->id,
+                                       BT_ATT_ERROR_REQUEST_NOT_SUPPORTED);
+       op->owner_queue = NULL;
+}
+
+static void chrc_free(void *data)
+{
+       struct external_chrc *chrc = data;
+
+       queue_destroy(chrc->pending_reads, cancel_pending_read);
+       queue_destroy(chrc->pending_writes, cancel_pending_write);
+
+       g_free(chrc->path);
+
+       g_dbus_proxy_set_property_watch(chrc->proxy, NULL, NULL);
+       g_dbus_proxy_unref(chrc->proxy);
+
+       free(chrc);
+}
+
+static void desc_free(void *data)
+{
+       struct external_desc *desc = data;
+
+       queue_destroy(desc->pending_reads, cancel_pending_read);
+       queue_destroy(desc->pending_writes, cancel_pending_write);
+
+       g_dbus_proxy_unref(desc->proxy);
+       g_free(desc->chrc_path);
+
+       free(desc);
+}
+
+static void service_free(void *data)
+{
+       struct external_service *service = data;
+
+       queue_destroy(service->chrcs, chrc_free);
+       queue_destroy(service->descs, desc_free);
+
+       gatt_db_remove_service(service->database->db, service->attrib);
+
+       if (service->client) {
+               g_dbus_client_set_disconnect_watch(service->client, NULL, NULL);
+               g_dbus_client_set_proxy_handlers(service->client, NULL, NULL,
+                                                               NULL, NULL);
+               g_dbus_client_set_ready_watch(service->client, NULL, NULL);
+               g_dbus_proxy_unref(service->proxy);
+               g_dbus_client_unref(service->client);
+       }
+
+       if (service->reg)
+               dbus_message_unref(service->reg);
+
+       g_free(service->owner);
+       g_free(service->path);
+
+       free(service);
+}
+
+static void gatt_database_free(void *data)
+{
+       struct btd_gatt_database *database = data;
+
+       if (database->le_io) {
+               g_io_channel_shutdown(database->le_io, FALSE, NULL);
+               g_io_channel_unref(database->le_io);
+       }
+
+       if (database->l2cap_io) {
+               g_io_channel_shutdown(database->l2cap_io, FALSE, NULL);
+               g_io_channel_unref(database->l2cap_io);
+       }
+
+       if (database->gatt_handle)
+               adapter_service_remove(database->adapter,
+                                                       database->gatt_handle);
+
+       if (database->gap_handle)
+               adapter_service_remove(database->adapter, database->gap_handle);
+
+       /* TODO: Persistently store CCC states before freeing them */
+       gatt_db_unregister(database->db, database->db_id);
+
+       queue_destroy(database->device_states, device_state_free);
+       queue_destroy(database->services, service_free);
+       queue_destroy(database->ccc_callbacks, ccc_cb_free);
+       database->device_states = NULL;
+       database->ccc_callbacks = NULL;
+
+       gatt_db_unref(database->db);
+
+       btd_adapter_unref(database->adapter);
+       free(database);
+}
+
+static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
+{
+       struct btd_adapter *adapter;
+       struct btd_device *device;
+       uint8_t dst_type;
+       bdaddr_t src, dst;
+
+       DBG("New incoming LE ATT connection");
+
+       if (gerr) {
+               error("%s", gerr->message);
+               return;
+       }
+
+       bt_io_get(io, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src,
+                                               BT_IO_OPT_DEST_BDADDR, &dst,
+                                               BT_IO_OPT_DEST_TYPE, &dst_type,
+                                               BT_IO_OPT_INVALID);
+       if (gerr) {
+               error("bt_io_get: %s", gerr->message);
+               g_error_free(gerr);
+               return;
+       }
+
+       adapter = adapter_find(&src);
+       if (!adapter)
+               return;
+
+       device = btd_adapter_get_device(adapter, &dst, dst_type);
+       if (!device)
+               return;
+
+       device_attach_att(device, io);
+}
+
+static void gap_device_name_read_cb(struct gatt_db_attribute *attrib,
+                                       unsigned int id, uint16_t offset,
+                                       uint8_t opcode, struct bt_att *att,
+                                       void *user_data)
+{
+       struct btd_gatt_database *database = user_data;
+       uint8_t error = 0;
+       size_t len = 0;
+       const uint8_t *value = NULL;
+       const char *device_name;
+
+       DBG("GAP Device Name read request\n");
+
+       device_name = btd_adapter_get_name(database->adapter);
+       len = strlen(device_name);
+
+       if (offset > len) {
+               error = BT_ATT_ERROR_INVALID_OFFSET;
+               goto done;
+       }
+
+       len -= offset;
+       value = len ? (const uint8_t *) &device_name[offset] : NULL;
+
+done:
+       gatt_db_attribute_read_result(attrib, id, error, value, len);
+}
+
+static void gap_appearance_read_cb(struct gatt_db_attribute *attrib,
+                                       unsigned int id, uint16_t offset,
+                                       uint8_t opcode, struct bt_att *att,
+                                       void *user_data)
+{
+       struct btd_gatt_database *database = user_data;
+       uint8_t error = 0;
+       size_t len = 2;
+       const uint8_t *value = NULL;
+       uint8_t appearance[2];
+       uint32_t dev_class;
+
+       DBG("GAP Appearance read request\n");
+
+       dev_class = btd_adapter_get_class(database->adapter);
+
+       if (offset > 2) {
+               error = BT_ATT_ERROR_INVALID_OFFSET;
+               goto done;
+       }
+
+       appearance[0] = dev_class & 0x00ff;
+       appearance[1] = (dev_class >> 8) & 0x001f;
+
+       len -= offset;
+       value = len ? &appearance[offset] : NULL;
+
+done:
+       gatt_db_attribute_read_result(attrib, id, error, value, len);
+}
+
+static sdp_record_t *record_new(uuid_t *uuid, uint16_t start, uint16_t end)
+{
+       sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto;
+       uuid_t root_uuid, proto_uuid, l2cap;
+       sdp_record_t *record;
+       sdp_data_t *psm, *sh, *eh;
+       uint16_t lp = ATT_PSM;
+
+       if (uuid == NULL)
+               return NULL;
+
+       if (start > end)
+               return NULL;
+
+       record = sdp_record_alloc();
+       if (record == NULL)
+               return NULL;
+
+       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+       root = sdp_list_append(NULL, &root_uuid);
+       sdp_set_browse_groups(record, root);
+       sdp_list_free(root, NULL);
+
+       svclass_id = sdp_list_append(NULL, uuid);
+       sdp_set_service_classes(record, svclass_id);
+       sdp_list_free(svclass_id, NULL);
+
+       sdp_uuid16_create(&l2cap, L2CAP_UUID);
+       proto[0] = sdp_list_append(NULL, &l2cap);
+       psm = sdp_data_alloc(SDP_UINT16, &lp);
+       proto[0] = sdp_list_append(proto[0], psm);
+       apseq = sdp_list_append(NULL, proto[0]);
+
+       sdp_uuid16_create(&proto_uuid, ATT_UUID);
+       proto[1] = sdp_list_append(NULL, &proto_uuid);
+       sh = sdp_data_alloc(SDP_UINT16, &start);
+       proto[1] = sdp_list_append(proto[1], sh);
+       eh = sdp_data_alloc(SDP_UINT16, &end);
+       proto[1] = sdp_list_append(proto[1], eh);
+       apseq = sdp_list_append(apseq, proto[1]);
+
+       aproto = sdp_list_append(NULL, apseq);
+       sdp_set_access_protos(record, aproto);
+
+       sdp_data_free(psm);
+       sdp_data_free(sh);
+       sdp_data_free(eh);
+       sdp_list_free(proto[0], NULL);
+       sdp_list_free(proto[1], NULL);
+       sdp_list_free(apseq, NULL);
+       sdp_list_free(aproto, NULL);
+
+       return record;
+}
+
+static uint32_t database_add_record(struct btd_gatt_database *database,
+                                       uint16_t uuid,
+                                       struct gatt_db_attribute *attr,
+                                       const char *name)
+{
+       sdp_record_t *record;
+       uint16_t start, end;
+       uuid_t svc, gap_uuid;
+
+       sdp_uuid16_create(&svc, uuid);
+       gatt_db_attribute_get_service_handles(attr, &start, &end);
+
+       record = record_new(&svc, start, end);
+       if (!record)
+               return 0;
+
+       if (name != NULL)
+               sdp_set_info_attr(record, name, "BlueZ", NULL);
+
+       sdp_uuid16_create(&gap_uuid, UUID_GAP);
+       if (sdp_uuid_cmp(&svc, &gap_uuid) == 0) {
+               sdp_set_url_attr(record, "http://www.bluez.org/",
+                               "http://www.bluez.org/",
+                               "http://www.bluez.org/");
+       }
+
+       if (adapter_service_add(database->adapter, record) == 0)
+               return record->handle;
+
+       sdp_record_free(record);
+       return 0;
+}
+
+static void populate_gap_service(struct btd_gatt_database *database)
+{
+       bt_uuid_t uuid;
+       struct gatt_db_attribute *service;
+
+       /* Add the GAP service */
+       bt_uuid16_create(&uuid, UUID_GAP);
+       service = gatt_db_add_service(database->db, &uuid, true, 5);
+       database->gap_handle = database_add_record(database, UUID_GAP, service,
+                                               "Generic Access Profile");
+
+       /*
+        * Device Name characteristic.
+        */
+       bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME);
+       gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_READ,
+                                                       BT_GATT_CHRC_PROP_READ,
+                                                       gap_device_name_read_cb,
+                                                       NULL, database);
+
+       /*
+        * Device Appearance characteristic.
+        */
+       bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE);
+       gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_READ,
+                                                       BT_GATT_CHRC_PROP_READ,
+                                                       gap_appearance_read_cb,
+                                                       NULL, database);
+
+       gatt_db_service_set_active(service, true);
+}
+
+static bool get_dst_info(struct bt_att *att, bdaddr_t *dst, uint8_t *dst_type)
+{
+       GIOChannel *io = NULL;
+       GError *gerr = NULL;
+
+       io = g_io_channel_unix_new(bt_att_get_fd(att));
+       if (!io)
+               return false;
+
+       bt_io_get(io, &gerr, BT_IO_OPT_DEST_BDADDR, dst,
+                                               BT_IO_OPT_DEST_TYPE, dst_type,
+                                               BT_IO_OPT_INVALID);
+       if (gerr) {
+               error("gatt: bt_io_get: %s", gerr->message);
+               g_error_free(gerr);
+               g_io_channel_unref(io);
+               return false;
+       }
+
+       g_io_channel_unref(io);
+       return true;
+}
+
+static void gatt_ccc_read_cb(struct gatt_db_attribute *attrib,
+                                       unsigned int id, uint16_t offset,
+                                       uint8_t opcode, struct bt_att *att,
+                                       void *user_data)
+{
+       struct btd_gatt_database *database = user_data;
+       struct ccc_state *ccc;
+       uint16_t handle;
+       uint8_t ecode = 0;
+       const uint8_t *value = NULL;
+       size_t len = 0;
+       bdaddr_t bdaddr;
+       uint8_t bdaddr_type;
+
+       handle = gatt_db_attribute_get_handle(attrib);
+
+       DBG("CCC read called for handle: 0x%04x", handle);
+
+       if (offset > 2) {
+               ecode = BT_ATT_ERROR_INVALID_OFFSET;
+               goto done;
+       }
+
+       if (!get_dst_info(att, &bdaddr, &bdaddr_type)) {
+               ecode = BT_ATT_ERROR_UNLIKELY;
+               goto done;
+       }
+
+       ccc = get_ccc_state(database, &bdaddr, bdaddr_type, handle);
+       if (!ccc) {
+               ecode = BT_ATT_ERROR_UNLIKELY;
+               goto done;
+       }
+
+       len = 2 - offset;
+       value = len ? &ccc->value[offset] : NULL;
+
+done:
+       gatt_db_attribute_read_result(attrib, id, ecode, value, len);
+}
+
+static void gatt_ccc_write_cb(struct gatt_db_attribute *attrib,
+                                       unsigned int id, uint16_t offset,
+                                       const uint8_t *value, size_t len,
+                                       uint8_t opcode, struct bt_att *att,
+                                       void *user_data)
+{
+       struct btd_gatt_database *database = user_data;
+       struct ccc_state *ccc;
+       struct ccc_cb_data *ccc_cb;
+       uint16_t handle;
+       uint8_t ecode = 0;
+       bdaddr_t bdaddr;
+       uint8_t bdaddr_type;
+
+       handle = gatt_db_attribute_get_handle(attrib);
+
+       DBG("CCC write called for handle: 0x%04x", handle);
+
+       if (!value || len != 2) {
+               ecode = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
+               goto done;
+       }
+
+       if (offset > 2) {
+               ecode = BT_ATT_ERROR_INVALID_OFFSET;
+               goto done;
+       }
+
+       if (!get_dst_info(att, &bdaddr, &bdaddr_type)) {
+               ecode = BT_ATT_ERROR_UNLIKELY;
+               goto done;
+       }
+
+       ccc = get_ccc_state(database, &bdaddr, bdaddr_type, handle);
+       if (!ccc) {
+               ecode = BT_ATT_ERROR_UNLIKELY;
+               goto done;
+       }
+
+       ccc_cb = queue_find(database->ccc_callbacks, ccc_cb_match_handle,
+                       UINT_TO_PTR(gatt_db_attribute_get_handle(attrib)));
+       if (!ccc_cb) {
+               ecode = BT_ATT_ERROR_UNLIKELY;
+               goto done;
+       }
+
+       /* If value is identical, then just succeed */
+       if (ccc->value[0] == value[0] && ccc->value[1] == value[1])
+               goto done;
+
+       if (ccc_cb->callback)
+               ecode = ccc_cb->callback(get_le16(value), ccc_cb->user_data);
+
+       if (!ecode) {
+               ccc->value[0] = value[0];
+               ccc->value[1] = value[1];
+       }
+
+done:
+       gatt_db_attribute_write_result(attrib, id, ecode);
+}
+
+static struct gatt_db_attribute *
+service_add_ccc(struct gatt_db_attribute *service,
+                               struct btd_gatt_database *database,
+                               btd_gatt_database_ccc_write_t write_callback,
+                               void *user_data,
+                               btd_gatt_database_destroy_t destroy)
+{
+       struct gatt_db_attribute *ccc;
+       struct ccc_cb_data *ccc_cb;
+       bt_uuid_t uuid;
+
+       ccc_cb = new0(struct ccc_cb_data, 1);
+       if (!ccc_cb) {
+               error("Could not allocate memory for callback data");
+               return NULL;
+       }
+
+       bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
+       ccc = gatt_db_service_add_descriptor(service, &uuid,
+                               BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                               gatt_ccc_read_cb, gatt_ccc_write_cb, database);
+       if (!ccc) {
+               error("Failed to create CCC entry in database");
+               free(ccc_cb);
+               return NULL;
+       }
+
+       ccc_cb->handle = gatt_db_attribute_get_handle(ccc);
+       ccc_cb->callback = write_callback;
+       ccc_cb->destroy = destroy;
+       ccc_cb->user_data = user_data;
+
+       queue_push_tail(database->ccc_callbacks, ccc_cb);
+
+       return ccc;
+}
+
+struct gatt_db_attribute *
+btd_gatt_database_add_ccc(struct btd_gatt_database *database,
+                               uint16_t service_handle,
+                               btd_gatt_database_ccc_write_t write_callback,
+                               void *user_data,
+                               btd_gatt_database_destroy_t destroy)
+{
+       struct gatt_db_attribute *service;
+
+       if (!database || !service_handle)
+               return NULL;
+
+       service = gatt_db_get_attribute(database->db, service_handle);
+       if (!service) {
+               error("No service exists with handle: 0x%04x", service_handle);
+               return NULL;
+       }
+
+       return service_add_ccc(service, database, write_callback, user_data,
+                                                               destroy);
+}
+
+static void populate_gatt_service(struct btd_gatt_database *database)
+{
+       bt_uuid_t uuid;
+       struct gatt_db_attribute *service;
+
+       /* Add the GATT service */
+       bt_uuid16_create(&uuid, UUID_GATT);
+       service = gatt_db_add_service(database->db, &uuid, true, 4);
+       database->gatt_handle = database_add_record(database, UUID_GATT,
+                                               service,
+                                               "Generic Attribute Profile");
+
+       bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
+       database->svc_chngd = gatt_db_service_add_characteristic(service, &uuid,
+                               BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_INDICATE,
+                               NULL, NULL, database);
+
+       database->svc_chngd_ccc = service_add_ccc(service, database, NULL, NULL,
+                                                                       NULL);
+
+       gatt_db_service_set_active(service, true);
+}
+
+static void register_core_services(struct btd_gatt_database *database)
+{
+       populate_gap_service(database);
+       populate_gatt_service(database);
+}
+
+struct notify {
+       struct btd_gatt_database *database;
+       uint16_t handle, ccc_handle;
+       const uint8_t *value;
+       uint16_t len;
+       bool indicate;
+};
+
+static void conf_cb(void *user_data)
+{
+       DBG("GATT server received confirmation");
+}
+
+static void send_notification_to_device(void *data, void *user_data)
+{
+       struct device_state *device_state = data;
+       struct notify *notify = user_data;
+       struct ccc_state *ccc;
+       struct btd_device *device;
+
+       ccc = find_ccc_state(device_state, notify->ccc_handle);
+       if (!ccc)
+               return;
+
+       if (!ccc->value[0] || (notify->indicate && !(ccc->value[0] & 0x02)))
+               return;
+
+       device = btd_adapter_get_device(notify->database->adapter,
+                                               &device_state->bdaddr,
+                                               device_state->bdaddr_type);
+       if (!device)
+               return;
+
+       /*
+        * TODO: If the device is not connected but bonded, send the
+        * notification/indication when it becomes connected.
+        */
+       if (!notify->indicate) {
+               DBG("GATT server sending notification");
+               bt_gatt_server_send_notification(
+                                       btd_device_get_gatt_server(device),
+                                       notify->handle, notify->value,
+                                       notify->len);
+               return;
+       }
+
+       DBG("GATT server sending indication");
+       bt_gatt_server_send_indication(btd_device_get_gatt_server(device),
+                                                       notify->handle,
+                                                       notify->value,
+                                                       notify->len, conf_cb,
+                                                       NULL, NULL);
+}
+
+static void send_notification_to_devices(struct btd_gatt_database *database,
+                                       uint16_t handle, const uint8_t *value,
+                                       uint16_t len, uint16_t ccc_handle,
+                                       bool indicate)
+{
+       struct notify notify;
+
+       memset(&notify, 0, sizeof(notify));
+
+       notify.database = database;
+       notify.handle = handle;
+       notify.ccc_handle = ccc_handle;
+       notify.value = value;
+       notify.len = len;
+       notify.indicate = indicate;
+
+       queue_foreach(database->device_states, send_notification_to_device,
+                                                               &notify);
+}
+
+static void send_service_changed(struct btd_gatt_database *database,
+                                       struct gatt_db_attribute *attrib)
+{
+       uint16_t start, end;
+       uint8_t value[4];
+       uint16_t handle, ccc_handle;
+
+       if (!gatt_db_attribute_get_service_handles(attrib, &start, &end)) {
+               error("Failed to obtain changed service handles");
+               return;
+       }
+
+       handle = gatt_db_attribute_get_handle(database->svc_chngd);
+       ccc_handle = gatt_db_attribute_get_handle(database->svc_chngd_ccc);
+
+       if (!handle || !ccc_handle) {
+               error("Failed to obtain handles for \"Service Changed\""
+                                                       " characteristic");
+               return;
+       }
+
+       put_le16(start, value);
+       put_le16(end, value + 2);
+
+       send_notification_to_devices(database, handle, value, sizeof(value),
+                                                       ccc_handle, true);
+}
+
+static void gatt_db_service_added(struct gatt_db_attribute *attrib,
+                                                               void *user_data)
+{
+       struct btd_gatt_database *database = user_data;
+
+       DBG("GATT Service added to local database");
+
+       send_service_changed(database, attrib);
+}
+
+static bool ccc_match_service(const void *data, const void *match_data)
+{
+       const struct ccc_state *ccc = data;
+       const struct gatt_db_attribute *attrib = match_data;
+       uint16_t start, end;
+
+       if (!gatt_db_attribute_get_service_handles(attrib, &start, &end))
+               return false;
+
+       return ccc->handle >= start && ccc->handle <= end;
+}
+
+static void remove_device_ccc(void *data, void *user_data)
+{
+       struct device_state *state = data;
+
+       queue_remove_all(state->ccc_states, ccc_match_service, user_data, free);
+}
+
+static void gatt_db_service_removed(struct gatt_db_attribute *attrib,
+                                                               void *user_data)
+{
+       struct btd_gatt_database *database = user_data;
+
+       DBG("Local GATT service removed");
+
+       send_service_changed(database, attrib);
+
+       queue_foreach(database->device_states, remove_device_ccc, attrib);
+       queue_remove_all(database->ccc_callbacks, ccc_cb_match_service, attrib,
+                                                               ccc_cb_free);
+}
+
+struct svc_match_data {
+       const char *path;
+       const char *sender;
+};
+
+static bool match_service(const void *a, const void *b)
+{
+       const struct external_service *service = a;
+       const struct svc_match_data *data = b;
+
+       return g_strcmp0(service->path, data->path) == 0 &&
+                               g_strcmp0(service->owner, data->sender) == 0;
+}
+
+static gboolean service_free_idle_cb(void *data)
+{
+       service_free(data);
+
+       return FALSE;
+}
+
+static void service_remove_helper(void *data)
+{
+       struct external_service *service = data;
+
+       queue_remove(service->database->services, service);
+
+       /*
+        * Do not run in the same loop, this may be a disconnect
+        * watch call and GDBusClient should not be destroyed.
+        */
+       g_idle_add(service_free_idle_cb, service);
+}
+
+static void client_disconnect_cb(DBusConnection *conn, void *user_data)
+{
+       DBG("Client disconnected");
+
+       service_remove_helper(user_data);
+}
+
+static void service_remove(void *data)
+{
+       struct external_service *service = data;
+
+       /*
+        * Set callback to NULL to avoid potential race condition
+        * when calling remove_service and GDBusClient unref.
+        */
+       g_dbus_client_set_disconnect_watch(service->client, NULL, NULL);
+
+       /*
+        * Set proxy handlers to NULL, so that this gets called only once when
+        * the first proxy that belongs to this service gets removed.
+        */
+       g_dbus_client_set_proxy_handlers(service->client, NULL, NULL,
+                                                               NULL, NULL);
+
+       service_remove_helper(service);
+}
+
+static struct external_chrc *chrc_create(struct external_service *service,
+                                                       GDBusProxy *proxy,
+                                                       const char *path)
+{
+       struct external_chrc *chrc;
+
+       chrc = new0(struct external_chrc, 1);
+       if (!chrc)
+               return NULL;
+
+       chrc->pending_reads = queue_new();
+       if (!chrc->pending_reads) {
+               free(chrc);
+               return NULL;
+       }
+
+       chrc->pending_writes = queue_new();
+       if (!chrc->pending_writes) {
+               queue_destroy(chrc->pending_reads, NULL);
+               free(chrc);
+               return NULL;
+       }
+
+       chrc->path = g_strdup(path);
+       if (!chrc->path) {
+               queue_destroy(chrc->pending_reads, NULL);
+               queue_destroy(chrc->pending_writes, NULL);
+               free(chrc);
+               return NULL;
+       }
+
+       chrc->service = service;
+       chrc->proxy = g_dbus_proxy_ref(proxy);
+
+       return chrc;
+}
+
+static struct external_desc *desc_create(struct external_service *service,
+                                                       GDBusProxy *proxy,
+                                                       const char *chrc_path)
+{
+       struct external_desc *desc;
+
+       desc = new0(struct external_desc, 1);
+       if (!desc)
+               return NULL;
+
+       desc->pending_reads = queue_new();
+       if (!desc->pending_reads) {
+               free(desc);
+               return NULL;
+       }
+
+       desc->pending_writes = queue_new();
+       if (!desc->pending_writes) {
+               queue_destroy(desc->pending_reads, NULL);
+               free(desc);
+               return NULL;
+       }
+
+       desc->chrc_path = g_strdup(chrc_path);
+       if (!desc->chrc_path) {
+               queue_destroy(desc->pending_reads, NULL);
+               queue_destroy(desc->pending_writes, NULL);
+               free(desc);
+               return NULL;
+       }
+
+       desc->service = service;
+       desc->proxy = g_dbus_proxy_ref(proxy);
+
+       return desc;
+}
+
+static bool incr_attr_count(struct external_service *service, uint16_t incr)
+{
+       if (service->attr_cnt > UINT16_MAX - incr)
+               return false;
+
+       service->attr_cnt += incr;
+
+       return true;
+}
+
+static bool parse_path(GDBusProxy *proxy, const char *name, const char **path)
+{
+       DBusMessageIter iter;
+
+       if (!g_dbus_proxy_get_property(proxy, name, &iter))
+               return false;
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
+               return false;
+
+       dbus_message_iter_get_basic(&iter, path);
+
+       return true;
+}
+
+static bool check_service_path(GDBusProxy *proxy,
+                                       struct external_service *service)
+{
+       const char *service_path;
+
+       if (!parse_path(proxy, "Service", &service_path))
+               return false;
+
+       return g_strcmp0(service_path, service->path) == 0;
+}
+
+static bool parse_flags(GDBusProxy *proxy, uint8_t *props, uint8_t *ext_props)
+{
+       DBusMessageIter iter, array;
+       const char *flag;
+
+       *props = *ext_props = 0;
+
+       if (!g_dbus_proxy_get_property(proxy, "Flags", &iter))
+               return false;
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+               return false;
+
+       dbus_message_iter_recurse(&iter, &array);
+
+       do {
+               if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING)
+                       return false;
+
+               dbus_message_iter_get_basic(&array, &flag);
+
+               if (!strcmp("broadcast", flag))
+                       *props |= BT_GATT_CHRC_PROP_BROADCAST;
+               else if (!strcmp("read", flag))
+                       *props |= BT_GATT_CHRC_PROP_READ;
+               else if (!strcmp("write-without-response", flag))
+                       *props |= BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP;
+               else if (!strcmp("write", flag))
+                       *props |= BT_GATT_CHRC_PROP_WRITE;
+               else if (!strcmp("notify", flag))
+                       *props |= BT_GATT_CHRC_PROP_NOTIFY;
+               else if (!strcmp("indicate", flag))
+                       *props |= BT_GATT_CHRC_PROP_INDICATE;
+               else if (!strcmp("authenticated-signed-writes", flag))
+                       *props |= BT_GATT_CHRC_PROP_AUTH;
+               else if (!strcmp("reliable-write", flag))
+                       *ext_props |= BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE;
+               else if (!strcmp("writable-auxiliaries", flag))
+                       *ext_props |= BT_GATT_CHRC_EXT_PROP_WRITABLE_AUX;
+               else {
+                       error("Invalid characteristic flag: %s", flag);
+                       return false;
+               }
+       } while (dbus_message_iter_next(&array));
+
+       if (*ext_props)
+               *props |= BT_GATT_CHRC_PROP_EXT_PROP;
+
+       return true;
+}
+
+static void proxy_added_cb(GDBusProxy *proxy, void *user_data)
+{
+       struct external_service *service = user_data;
+       const char *iface, *path;
+
+       if (service->failed || service->attrib)
+               return;
+
+       iface = g_dbus_proxy_get_interface(proxy);
+       path = g_dbus_proxy_get_path(proxy);
+
+       if (!g_str_has_prefix(path, service->path))
+               return;
+
+       if (g_strcmp0(iface, GATT_SERVICE_IFACE) == 0) {
+               if (service->proxy)
+                       return;
+
+               /*
+                * TODO: We may want to support adding included services in a
+                * single hierarchy.
+                */
+               if (g_strcmp0(path, service->path) != 0) {
+                       error("Multiple services added within hierarchy");
+                       service->failed = true;
+                       return;
+               }
+
+               /* Add 1 for the service declaration */
+               if (!incr_attr_count(service, 1)) {
+                       error("Failed to increment attribute count");
+                       service->failed = true;
+                       return;
+               }
+
+               service->proxy = g_dbus_proxy_ref(proxy);
+       } else if (g_strcmp0(iface, GATT_CHRC_IFACE) == 0) {
+               struct external_chrc *chrc;
+
+               if (g_strcmp0(path, service->path) == 0) {
+                       error("Characteristic path same as service path");
+                       service->failed = true;
+                       return;
+               }
+
+               chrc = chrc_create(service, proxy, path);
+               if (!chrc) {
+                       service->failed = true;
+                       return;
+               }
+
+               /*
+                * Add 2 for the characteristic declaration and the value
+                * attribute.
+                */
+               if (!incr_attr_count(service, 2)) {
+                       error("Failed to increment attribute count");
+                       service->failed = true;
+                       return;
+               }
+
+               /*
+                * Parse characteristic flags (i.e. properties) here since they
+                * are used to determine if any special descriptors should be
+                * created.
+                */
+               if (!parse_flags(proxy, &chrc->props, &chrc->ext_props)) {
+                       error("Failed to parse characteristic properties");
+                       service->failed = true;
+                       return;
+               }
+
+               if ((chrc->props & BT_GATT_CHRC_PROP_NOTIFY ||
+                               chrc->props & BT_GATT_CHRC_PROP_INDICATE) &&
+                               !incr_attr_count(service, 1)) {
+                       error("Failed to increment attribute count for CCC");
+                       service->failed = true;
+                       return;
+               }
+
+               if (chrc->ext_props && !incr_attr_count(service, 1)) {
+                       error("Failed to increment attribute count for CEP");
+                       service->failed = true;
+                       return;
+               }
+
+               queue_push_tail(service->chrcs, chrc);
+       } else if (g_strcmp0(iface, GATT_DESC_IFACE) == 0) {
+               struct external_desc *desc;
+               const char *chrc_path;
+
+               if (!parse_path(proxy, "Characteristic", &chrc_path)) {
+                       error("Failed to obtain characteristic path for "
+                                                               "descriptor");
+                       service->failed = true;
+                       return;
+               }
+
+               desc = desc_create(service, proxy, chrc_path);
+               if (!desc) {
+                       service->failed = true;
+                       return;
+               }
+
+               /* Add 1 for the descriptor attribute */
+               if (!incr_attr_count(service, 1)) {
+                       error("Failed to increment attribute count");
+                       service->failed = true;
+                       return;
+               }
+
+               queue_push_tail(service->descs, desc);
+       } else {
+               DBG("Ignoring unrelated interface: %s", iface);
+               return;
+       }
+
+       DBG("Object added to service - path: %s, iface: %s", path, iface);
+}
+
+static void proxy_removed_cb(GDBusProxy *proxy, void *user_data)
+{
+       struct external_service *service = user_data;
+       const char *path;
+
+       path = g_dbus_proxy_get_path(proxy);
+
+       if (!g_str_has_prefix(path, service->path))
+               return;
+
+       DBG("Proxy removed - removing service: %s", service->path);
+
+       service_remove(service);
+}
+
+static bool parse_uuid(GDBusProxy *proxy, bt_uuid_t *uuid)
+{
+       DBusMessageIter iter;
+       bt_uuid_t tmp;
+       const char *uuidstr;
+
+       if (!g_dbus_proxy_get_property(proxy, "UUID", &iter))
+               return false;
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+               return false;
+
+       dbus_message_iter_get_basic(&iter, &uuidstr);
+
+       if (bt_string_to_uuid(uuid, uuidstr) < 0)
+               return false;
+
+       /* GAP & GATT services are created and managed by BlueZ */
+       bt_uuid16_create(&tmp, UUID_GAP);
+       if (!bt_uuid_cmp(&tmp, uuid)) {
+               error("GAP service must be handled by BlueZ");
+               return false;
+       }
+
+       bt_uuid16_create(&tmp, UUID_GATT);
+       if (!bt_uuid_cmp(&tmp, uuid)) {
+               error("GATT service must be handled by BlueZ");
+               return false;
+       }
+
+       return true;
+}
+
+static bool parse_primary(GDBusProxy *proxy, bool *primary)
+{
+       DBusMessageIter iter;
+
+       if (!g_dbus_proxy_get_property(proxy, "Primary", &iter))
+               return false;
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
+               return false;
+
+       dbus_message_iter_get_basic(&iter, primary);
+       return true;
+}
+
+static uint8_t dbus_error_to_att_ecode(const char *error_name)
+{
+       /* TODO: Parse error ATT ecode from error_message */
+
+       if (strcmp(error_name, "org.bluez.Error.Failed") == 0)
+               return 0x80;  /* For now return this "application error" */
+
+       if (strcmp(error_name, "org.bluez.Error.NotSupported") == 0)
+               return BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
+
+       if (strcmp(error_name, "org.bluez.Error.NotAuthorized") == 0)
+               return BT_ATT_ERROR_AUTHORIZATION;
+
+       if (strcmp(error_name, "org.bluez.Error.InvalidValueLength") == 0)
+               return BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
+
+       return 0;
+}
+
+static void read_reply_cb(DBusMessage *message, void *user_data)
+{
+       struct pending_op *op = user_data;
+       DBusError err;
+       DBusMessageIter iter, array;
+       uint8_t ecode = 0;
+       uint8_t *value = NULL;
+       int len = 0;
+
+       if (!op->owner_queue) {
+               DBG("Pending read was canceled when object got removed");
+               return;
+       }
+
+       dbus_error_init(&err);
+
+       if (dbus_set_error_from_message(&err, message) == TRUE) {
+               DBG("Failed to read value: %s: %s", err.name, err.message);
+               ecode = dbus_error_to_att_ecode(err.name);
+               ecode = ecode ? ecode : BT_ATT_ERROR_READ_NOT_PERMITTED;
+               dbus_error_free(&err);
+               goto done;
+       }
+
+       dbus_message_iter_init(message, &iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
+               /*
+                * Return not supported for this, as the external app basically
+                * doesn't properly support reading from this characteristic.
+                */
+               ecode = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
+               error("Invalid return value received for \"ReadValue\"");
+               goto done;
+       }
+
+       dbus_message_iter_recurse(&iter, &array);
+       dbus_message_iter_get_fixed_array(&array, &value, &len);
+
+       if (len < 0) {
+               ecode = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
+               value = NULL;
+               len = 0;
+               goto done;
+       }
+
+       /* Truncate the value if it's too large */
+       len = MIN(BT_ATT_MAX_VALUE_LEN, len);
+       value = len ? value : NULL;
+
+done:
+       gatt_db_attribute_read_result(op->attrib, op->id, ecode, value, len);
+}
+
+static void pending_op_free(void *data)
+{
+       struct pending_op *op = data;
+
+       if (op->owner_queue)
+               queue_remove(op->owner_queue, op);
+
+       free(op);
+}
+
+static struct pending_op *pending_read_new(struct queue *owner_queue,
+                                       struct gatt_db_attribute *attrib,
+                                       unsigned int id)
+{
+       struct pending_op *op;
+
+       op = new0(struct pending_op, 1);
+       if (!op)
+               return NULL;
+
+       op->owner_queue = owner_queue;
+       op->attrib = attrib;
+       op->id = id;
+       queue_push_tail(owner_queue, op);
+
+       return op;
+}
+
+static void send_read(struct gatt_db_attribute *attrib, GDBusProxy *proxy,
+                                               struct queue *owner_queue,
+                                               unsigned int id)
+{
+       struct pending_op *op;
+       uint8_t ecode = BT_ATT_ERROR_UNLIKELY;
+
+       op = pending_read_new(owner_queue, attrib, id);
+       if (!op) {
+               error("Failed to allocate memory for pending read call");
+               ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
+               goto error;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "ReadValue", NULL, read_reply_cb,
+                                               op, pending_op_free) == TRUE)
+               return;
+
+       pending_op_free(op);
+
+error:
+       gatt_db_attribute_read_result(attrib, id, ecode, NULL, 0);
+}
+
+static void write_setup_cb(DBusMessageIter *iter, void *user_data)
+{
+       struct pending_op *op = user_data;
+       struct iovec *iov = op->setup_data;
+       DBusMessageIter array;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
+       dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
+                                               &iov->iov_base, iov->iov_len);
+       dbus_message_iter_close_container(iter, &array);
+}
+
+static void write_reply_cb(DBusMessage *message, void *user_data)
+{
+       struct pending_op *op = user_data;
+       DBusError err;
+       DBusMessageIter iter;
+       uint8_t ecode = 0;
+
+       if (!op->owner_queue) {
+               DBG("Pending write was canceled when object got removed");
+               return;
+       }
+
+       dbus_error_init(&err);
+
+       if (dbus_set_error_from_message(&err, message) == TRUE) {
+               DBG("Failed to write value: %s: %s", err.name, err.message);
+               ecode = dbus_error_to_att_ecode(err.name);
+               ecode = ecode ? ecode : BT_ATT_ERROR_WRITE_NOT_PERMITTED;
+               dbus_error_free(&err);
+               goto done;
+       }
+
+       dbus_message_iter_init(message, &iter);
+       if (dbus_message_iter_has_next(&iter)) {
+               /*
+                * Return not supported for this, as the external app basically
+                * doesn't properly support the "WriteValue" API.
+                */
+               ecode = BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
+               error("Invalid return value received for \"WriteValue\"");
+       }
+
+done:
+       gatt_db_attribute_write_result(op->attrib, op->id, ecode);
+}
+
+static struct pending_op *pending_write_new(struct queue *owner_queue,
+                                       struct gatt_db_attribute *attrib,
+                                       unsigned int id,
+                                       const uint8_t *value,
+                                       size_t len)
+{
+       struct pending_op *op;
+       struct iovec iov;
+
+       op = new0(struct pending_op, 1);
+       if (!op)
+               return NULL;
+
+       iov.iov_base = (uint8_t *) value;
+       iov.iov_len = len;
+
+       op->owner_queue = owner_queue;
+       op->attrib = attrib;
+       op->id = id;
+       op->setup_data = &iov;
+       queue_push_tail(owner_queue, op);
+
+       return op;
+}
+
+static void send_write(struct gatt_db_attribute *attrib, GDBusProxy *proxy,
+                                       struct queue *owner_queue,
+                                       unsigned int id,
+                                       const uint8_t *value, size_t len)
+{
+       struct pending_op *op;
+       uint8_t ecode = BT_ATT_ERROR_UNLIKELY;
+
+       op = pending_write_new(owner_queue, attrib, id, value, len);
+       if (!op) {
+               error("Failed to allocate memory for pending read call");
+               ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
+               goto error;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup_cb,
+                                               write_reply_cb, op,
+                                               pending_op_free) == TRUE)
+               return;
+
+       pending_op_free(op);
+
+error:
+       gatt_db_attribute_write_result(attrib, id, ecode);
+}
+
+static uint32_t permissions_from_props(uint8_t props, uint8_t ext_props)
+{
+       uint32_t perm = 0;
+
+       if (props & BT_GATT_CHRC_PROP_WRITE ||
+                       props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP ||
+                       ext_props & BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE)
+               perm |= BT_ATT_PERM_WRITE;
+
+       if (props & BT_GATT_CHRC_PROP_READ)
+               perm |= BT_ATT_PERM_READ;
+
+       return perm;
+}
+
+static uint8_t ccc_write_cb(uint16_t value, void *user_data)
+{
+       struct external_chrc *chrc = user_data;
+
+       DBG("External CCC write received with value: 0x%04x", value);
+
+       /* Notifications/indications disabled */
+       if (!value) {
+               if (!chrc->ntfy_cnt)
+                       return 0;
+
+               if (__sync_sub_and_fetch(&chrc->ntfy_cnt, 1))
+                       return 0;
+
+               /*
+                * Send request to stop notifying. This is best-effort
+                * operation, so simply ignore the return the value.
+                */
+               g_dbus_proxy_method_call(chrc->proxy, "StopNotify", NULL,
+                                                       NULL, NULL, NULL);
+               return 0;
+       }
+
+       /*
+        * TODO: All of the errors below should fall into the so called
+        * "Application Error" range. Since there is no well defined error for
+        * these, we return a generic ATT protocol error for now.
+        */
+
+       if (chrc->ntfy_cnt == UINT_MAX) {
+               /* Maximum number of per-device CCC descriptors configured */
+               return BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
+       }
+
+       /* Don't support undefined CCC values yet */
+       if (value > 2 ||
+               (value == 1 && !(chrc->props & BT_GATT_CHRC_PROP_NOTIFY)) ||
+               (value == 2 && !(chrc->props & BT_GATT_CHRC_PROP_INDICATE)))
+               return BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
+
+       /*
+        * Always call StartNotify for an incoming enable and ignore the return
+        * value for now.
+        */
+       if (g_dbus_proxy_method_call(chrc->proxy,
+                                               "StartNotify", NULL, NULL,
+                                               NULL, NULL) == FALSE)
+               return BT_ATT_ERROR_REQUEST_NOT_SUPPORTED;
+
+       __sync_fetch_and_add(&chrc->ntfy_cnt, 1);
+
+       return 0;
+}
+
+static void property_changed_cb(GDBusProxy *proxy, const char *name,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct external_chrc *chrc = user_data;
+       DBusMessageIter array;
+       uint8_t *value = NULL;
+       int len = 0;
+
+       if (strcmp(name, "Value"))
+               return;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) {
+               DBG("Malformed \"Value\" property received");
+               return;
+       }
+
+       dbus_message_iter_recurse(iter, &array);
+       dbus_message_iter_get_fixed_array(&array, &value, &len);
+
+       if (len < 0) {
+               DBG("Malformed \"Value\" property received");
+               return;
+       }
+
+       /* Truncate the value if it's too large */
+       len = MIN(BT_ATT_MAX_VALUE_LEN, len);
+       value = len ? value : NULL;
+
+       send_notification_to_devices(chrc->service->database,
+                               gatt_db_attribute_get_handle(chrc->attrib),
+                               value, len,
+                               gatt_db_attribute_get_handle(chrc->ccc),
+                               chrc->props & BT_GATT_CHRC_PROP_INDICATE);
+}
+
+static bool database_add_ccc(struct external_service *service,
+                                               struct external_chrc *chrc)
+{
+       if (!(chrc->props & BT_GATT_CHRC_PROP_NOTIFY) &&
+                               !(chrc->props & BT_GATT_CHRC_PROP_INDICATE))
+               return true;
+
+       chrc->ccc = service_add_ccc(service->attrib, service->database,
+                                               ccc_write_cb, chrc, NULL);
+       if (!chrc->ccc) {
+               error("Failed to create CCC entry for characteristic");
+               return false;
+       }
+
+       if (g_dbus_proxy_set_property_watch(chrc->proxy, property_changed_cb,
+                                                       chrc) == FALSE) {
+               error("Failed to set up property watch for characteristic");
+               return false;
+       }
+
+       DBG("Created CCC entry for characteristic");
+
+       return true;
+}
+
+static void cep_write_cb(struct gatt_db_attribute *attrib, int err,
+                                                               void *user_data)
+{
+       if (err)
+               DBG("Failed to store CEP value in the database");
+       else
+               DBG("Stored CEP value in the database");
+}
+
+static bool database_add_cep(struct external_service *service,
+                                               struct external_chrc *chrc)
+{
+       struct gatt_db_attribute *cep;
+       bt_uuid_t uuid;
+       uint8_t value[2];
+
+       if (!chrc->ext_props)
+               return true;
+
+       bt_uuid16_create(&uuid, GATT_CHARAC_EXT_PROPER_UUID);
+       cep = gatt_db_service_add_descriptor(service->attrib, &uuid,
+                                                       BT_ATT_PERM_READ,
+                                                       NULL, NULL, NULL);
+       if (!cep) {
+               error("Failed to create CEP entry for characteristic");
+               return false;
+       }
+
+       memset(value, 0, sizeof(value));
+       value[0] = chrc->ext_props;
+
+       if (!gatt_db_attribute_write(cep, 0, value, sizeof(value), 0, NULL,
+                                                       cep_write_cb, NULL)) {
+               DBG("Failed to store CEP value in the database");
+               return false;
+       }
+
+       DBG("Created CEP entry for characteristic");
+
+       return true;
+}
+
+static void desc_read_cb(struct gatt_db_attribute *attrib,
+                                       unsigned int id, uint16_t offset,
+                                       uint8_t opcode, struct bt_att *att,
+                                       void *user_data)
+{
+       struct external_desc *desc = user_data;
+
+       if (desc->attrib != attrib) {
+               error("Read callback called with incorrect attribute");
+               return;
+       }
+
+       send_read(attrib, desc->proxy, desc->pending_reads, id);
+}
+
+static void desc_write_cb(struct gatt_db_attribute *attrib,
+                                       unsigned int id, uint16_t offset,
+                                       const uint8_t *value, size_t len,
+                                       uint8_t opcode, struct bt_att *att,
+                                       void *user_data)
+{
+       struct external_desc *desc = user_data;
+
+       if (desc->attrib != attrib) {
+               error("Read callback called with incorrect attribute");
+               return;
+       }
+
+       send_write(attrib, desc->proxy, desc->pending_writes, id, value, len);
+}
+
+static bool database_add_desc(struct external_service *service,
+                                               struct external_desc *desc)
+{
+       bt_uuid_t uuid;
+
+       if (!parse_uuid(desc->proxy, &uuid)) {
+               error("Failed to read \"UUID\" property of descriptor");
+               return false;
+       }
+
+       /*
+        * TODO: Set permissions based on a D-Bus property of the external
+        * descriptor.
+        */
+       desc->attrib = gatt_db_service_add_descriptor(service->attrib, &uuid,
+                                       BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                       desc_read_cb, desc_write_cb, desc);
+       if (!desc->attrib) {
+               error("Failed to create descriptor entry in database");
+               return false;
+       }
+
+       desc->handled = true;
+
+       return true;
+}
+
+static void chrc_read_cb(struct gatt_db_attribute *attrib,
+                                       unsigned int id, uint16_t offset,
+                                       uint8_t opcode, struct bt_att *att,
+                                       void *user_data)
+{
+       struct external_chrc *chrc = user_data;
+
+       if (chrc->attrib != attrib) {
+               error("Read callback called with incorrect attribute");
+               return;
+       }
+
+       send_read(attrib, chrc->proxy, chrc->pending_reads, id);
+}
+
+static void chrc_write_cb(struct gatt_db_attribute *attrib,
+                                       unsigned int id, uint16_t offset,
+                                       const uint8_t *value, size_t len,
+                                       uint8_t opcode, struct bt_att *att,
+                                       void *user_data)
+{
+       struct external_chrc *chrc = user_data;
+
+       if (chrc->attrib != attrib) {
+               error("Write callback called with incorrect attribute");
+               return;
+       }
+
+       send_write(attrib, chrc->proxy, chrc->pending_writes, id, value, len);
+}
+
+static bool database_add_chrc(struct external_service *service,
+                                               struct external_chrc *chrc)
+{
+       bt_uuid_t uuid;
+       uint32_t perm;
+       const struct queue_entry *entry;
+
+       if (!parse_uuid(chrc->proxy, &uuid)) {
+               error("Failed to read \"UUID\" property of characteristic");
+               return false;
+       }
+
+       if (!check_service_path(chrc->proxy, service)) {
+               error("Invalid service path for characteristic");
+               return false;
+       }
+
+       /*
+        * TODO: Once shared/gatt-server properly supports permission checks,
+        * set the permissions based on a D-Bus property of the external
+        * characteristic.
+        */
+       perm = permissions_from_props(chrc->props, chrc->ext_props);
+       chrc->attrib = gatt_db_service_add_characteristic(service->attrib,
+                                               &uuid, perm,
+                                               chrc->props, chrc_read_cb,
+                                               chrc_write_cb, chrc);
+       if (!chrc->attrib) {
+               error("Failed to create characteristic entry in database");
+               return false;
+       }
+
+       if (!database_add_ccc(service, chrc))
+               return false;
+
+       if (!database_add_cep(service, chrc))
+               return false;
+
+       /* Handle the descriptors that belong to this characteristic. */
+       entry = queue_get_entries(service->descs);
+       while (entry) {
+               struct external_desc *desc = entry->data;
+
+               if (desc->handled || g_strcmp0(desc->chrc_path, chrc->path))
+                       continue;
+
+               if (!database_add_desc(service, desc)) {
+                       chrc->attrib = NULL;
+                       error("Failed to create descriptor entry");
+                       return false;
+               }
+
+               entry = entry->next;
+       }
+
+       return true;
+}
+
+static bool match_desc_unhandled(const void *a, const void *b)
+{
+       const struct external_desc *desc = a;
+
+       return !desc->handled;
+}
+
+static bool create_service_entry(struct external_service *service)
+{
+       bt_uuid_t uuid;
+       bool primary;
+       const struct queue_entry *entry;
+
+       if (!parse_uuid(service->proxy, &uuid)) {
+               error("Failed to read \"UUID\" property of service");
+               return false;
+       }
+
+       if (!parse_primary(service->proxy, &primary)) {
+               error("Failed to read \"Primary\" property of service");
+               return false;
+       }
+
+       service->attrib = gatt_db_add_service(service->database->db, &uuid,
+                                               primary, service->attr_cnt);
+       if (!service->attrib)
+               return false;
+
+       entry = queue_get_entries(service->chrcs);
+       while (entry) {
+               struct external_chrc *chrc = entry->data;
+
+               if (!database_add_chrc(service, chrc)) {
+                       error("Failed to add characteristic");
+                       goto fail;
+               }
+
+               entry = entry->next;
+       }
+
+       /* If there are any unhandled descriptors, return an error */
+       if (queue_find(service->descs, match_desc_unhandled, NULL)) {
+               error("Found descriptor with no matching characteristic!");
+               goto fail;
+       }
+
+       gatt_db_service_set_active(service->attrib, true);
+
+       return true;
+
+fail:
+       gatt_db_remove_service(service->database->db, service->attrib);
+       service->attrib = NULL;
+
+       return false;
+}
+
+static void client_ready_cb(GDBusClient *client, void *user_data)
+{
+       struct external_service *service = user_data;
+       DBusMessage *reply;
+       bool fail = false;
+
+       if (!service->proxy || service->failed) {
+               error("No valid external GATT objects found");
+               fail = true;
+               reply = btd_error_failed(service->reg,
+                                       "No valid service object found");
+               goto reply;
+       }
+
+       if (!create_service_entry(service)) {
+               error("Failed to create GATT service entry in local database");
+               fail = true;
+               reply = btd_error_failed(service->reg,
+                                       "Failed to create entry in database");
+               goto reply;
+       }
+
+       DBG("GATT service registered: %s", service->path);
+
+       reply = dbus_message_new_method_return(service->reg);
+
+reply:
+       g_dbus_send_message(btd_get_dbus_connection(), reply);
+       dbus_message_unref(service->reg);
+       service->reg = NULL;
+
+       if (fail)
+               service_remove(service);
+}
+
+static struct external_service *service_create(DBusConnection *conn,
+                                       DBusMessage *msg, const char *path)
+{
+       struct external_service *service;
+       const char *sender = dbus_message_get_sender(msg);
+
+       if (!path || !g_str_has_prefix(path, "/"))
+               return NULL;
+
+       service = new0(struct external_service, 1);
+       if (!service)
+               return NULL;
+
+       service->client = g_dbus_client_new_full(conn, sender, path, path);
+       if (!service->client)
+               goto fail;
+
+       service->owner = g_strdup(sender);
+       if (!service->owner)
+               goto fail;
+
+       service->path = g_strdup(path);
+       if (!service->path)
+               goto fail;
+
+       service->chrcs = queue_new();
+       if (!service->chrcs)
+               goto fail;
+
+       service->descs = queue_new();
+       if (!service->descs)
+               goto fail;
+
+       service->reg = dbus_message_ref(msg);
+
+       g_dbus_client_set_disconnect_watch(service->client,
+                                               client_disconnect_cb, service);
+       g_dbus_client_set_proxy_handlers(service->client, proxy_added_cb,
+                                                       proxy_removed_cb, NULL,
+                                                       service);
+       g_dbus_client_set_ready_watch(service->client, client_ready_cb,
+                                                               service);
+
+       return service;
+
+fail:
+       service_free(service);
+       return NULL;
+}
+
+static DBusMessage *manager_register_service(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct btd_gatt_database *database = user_data;
+       const char *sender = dbus_message_get_sender(msg);
+       DBusMessageIter args;
+       const char *path;
+       struct external_service *service;
+       struct svc_match_data match_data;
+
+       if (!dbus_message_iter_init(msg, &args))
+               return btd_error_invalid_args(msg);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
+               return btd_error_invalid_args(msg);
+
+       dbus_message_iter_get_basic(&args, &path);
+
+       match_data.path = path;
+       match_data.sender = sender;
+
+       if (queue_find(database->services, match_service, &match_data))
+               return btd_error_already_exists(msg);
+
+       dbus_message_iter_next(&args);
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
+               return btd_error_invalid_args(msg);
+
+       service = service_create(conn, msg, path);
+       if (!service)
+               return btd_error_failed(msg, "Failed to register service");
+
+       DBG("Registering service - path: %s", path);
+
+       service->database = database;
+       queue_push_tail(database->services, service);
+
+       return NULL;
+}
+
+static DBusMessage *manager_unregister_service(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct btd_gatt_database *database = user_data;
+       const char *sender = dbus_message_get_sender(msg);
+       const char *path;
+       DBusMessageIter args;
+       struct external_service *service;
+       struct svc_match_data match_data;
+
+       if (!dbus_message_iter_init(msg, &args))
+               return btd_error_invalid_args(msg);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
+               return btd_error_invalid_args(msg);
+
+       dbus_message_iter_get_basic(&args, &path);
+
+       match_data.path = path;
+       match_data.sender = sender;
+
+       service = queue_remove_if(database->services, match_service,
+                                                               &match_data);
+       if (!service)
+               return btd_error_does_not_exist(msg);
+
+       service_free(service);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable manager_methods[] = {
+       { GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterService",
+                       GDBUS_ARGS({ "service", "o" }, { "options", "a{sv}" }),
+                       NULL, manager_register_service) },
+       { GDBUS_EXPERIMENTAL_ASYNC_METHOD("UnregisterService",
+                                       GDBUS_ARGS({ "service", "o" }),
+                                       NULL, manager_unregister_service) },
+       { }
+};
+
+struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter)
+{
+       struct btd_gatt_database *database;
+       GError *gerr = NULL;
+       const bdaddr_t *addr;
+
+       if (!adapter)
+               return NULL;
+
+       database = new0(struct btd_gatt_database, 1);
+       if (!database)
+               return NULL;
+
+       database->adapter = btd_adapter_ref(adapter);
+       database->db = gatt_db_new();
+       if (!database->db)
+               goto fail;
+
+       database->device_states = queue_new();
+       if (!database->device_states)
+               goto fail;
+
+       database->services = queue_new();
+       if (!database->services)
+               goto fail;
+
+       database->ccc_callbacks = queue_new();
+       if (!database->ccc_callbacks)
+               goto fail;
+
+       database->db_id = gatt_db_register(database->db, gatt_db_service_added,
+                                                       gatt_db_service_removed,
+                                                       database, NULL);
+       if (!database->db_id)
+               goto fail;
+
+       addr = btd_adapter_get_address(adapter);
+       database->le_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &gerr,
+                                       BT_IO_OPT_SOURCE_BDADDR, addr,
+                                       BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC,
+                                       BT_IO_OPT_CID, ATT_CID,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                                       BT_IO_OPT_INVALID);
+       if (!database->le_io) {
+               error("Failed to start listening: %s", gerr->message);
+               g_error_free(gerr);
+               goto fail;
+       }
+
+       /* BR/EDR socket */
+       database->l2cap_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &gerr,
+                                       BT_IO_OPT_SOURCE_BDADDR, addr,
+                                       BT_IO_OPT_PSM, ATT_PSM,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                                       BT_IO_OPT_INVALID);
+       if (database->l2cap_io == NULL) {
+               error("Failed to start listening: %s", gerr->message);
+               g_error_free(gerr);
+               goto fail;
+       }
+
+       if (g_dbus_register_interface(btd_get_dbus_connection(),
+                                               adapter_get_path(adapter),
+                                               GATT_MANAGER_IFACE,
+                                               manager_methods, NULL, NULL,
+                                               database, NULL))
+               DBG("GATT Manager registered for adapter: %s",
+                                               adapter_get_path(adapter));
+
+       register_core_services(database);
+
+       return database;
+
+fail:
+       gatt_database_free(database);
+
+       return NULL;
+}
+
+void btd_gatt_database_destroy(struct btd_gatt_database *database)
+{
+       if (!database)
+               return;
+
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                       adapter_get_path(database->adapter),
+                                       GATT_MANAGER_IFACE);
+
+       gatt_database_free(database);
+}
+
+struct gatt_db *btd_gatt_database_get_db(struct btd_gatt_database *database)
+{
+       if (!database)
+               return NULL;
+
+       return database->db;
+}
diff --git a/src/gatt-database.h b/src/gatt-database.h
new file mode 100644 (file)
index 0000000..163b601
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Google Inc.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ */
+
+struct btd_gatt_database;
+
+struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter);
+void btd_gatt_database_destroy(struct btd_gatt_database *database);
+
+struct gatt_db *btd_gatt_database_get_db(struct btd_gatt_database *database);
+
+typedef uint8_t (*btd_gatt_database_ccc_write_t) (uint16_t value,
+                                                       void *user_data);
+typedef void (*btd_gatt_database_destroy_t) (void *data);
+
+struct gatt_db_attribute *
+btd_gatt_database_add_ccc(struct btd_gatt_database *database,
+                               uint16_t service_handle,
+                               btd_gatt_database_ccc_write_t write_callback,
+                               void *user_data,
+                               btd_gatt_database_destroy_t destroy);
index beda22f..c67194d 100644 (file)
@@ -1,3 +1,4 @@
+#ifdef __TIZEN_PATCH__
 /*
  *
  *  BlueZ - Bluetooth protocol stack for Linux
@@ -70,9 +71,6 @@ struct proxy_write_data {
  */
 static GHashTable *proxy_hash;
 
-static DBusMessage *get_service(DBusConnection *conn,
-                                        DBusMessage *msg, void *user_data);
-
 static GSList *external_services;
 
 static int external_service_path_cmp(gconstpointer a, gconstpointer b)
@@ -244,7 +242,7 @@ static void proxy_prop_changed(GDBusProxy *proxy, const char *name,
        const char *str;
        bt_uuid_t uuid;
        uint8_t *value;
-       size_t len;
+       int len;
 
        if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
                return;
@@ -267,21 +265,70 @@ static void proxy_prop_changed(GDBusProxy *proxy, const char *name,
         * send notification or indication if CCC is set */
        btd_gatt_update_char(&uuid, value, len);
 }
-#endif
 
+static DBusMessage *__bt_gatt_dbus_method_send(const char *path, const char *svc_path,
+                       const char *interface, const char *method, DBusError *err, int type, ...)
+{
+       DBusMessage *msg;
+       DBusMessage *reply;
+       va_list args;
+       int timeout = -1;
+       struct external_service *esvc;
+       GSList *list;
+
+       list = g_slist_find_custom(external_services, svc_path,
+                                               external_service_path_cmp);
+       if (!list) {
+               return NULL;
+       }
+
+       esvc = list->data;
+       msg = dbus_message_new_method_call(esvc->owner,
+                       svc_path, interface, method);
+       if (!msg) {
+               DBG("Unable to allocate new D-Bus %s message \n", method);
+               return NULL;
+       }
+
+       va_start(args, type);
+
+       if (!dbus_message_append_args_valist(msg, type, args)) {
+               dbus_message_unref(msg);
+               va_end(args);
+               return NULL;
+       }
+
+       va_end(args);
+
+       dbus_error_init(err);
+       reply = dbus_connection_send_with_reply_and_block(btd_get_dbus_connection(),
+               msg, timeout, err);
+       dbus_message_unref(msg);
+
+       return reply;
+}
+#endif
 #ifdef __TIZEN_PATCH__
-static uint8_t proxy_read_cb(struct btd_attribute *attr,
+static uint8_t proxy_read_cb(struct btd_attribute *attr, bdaddr_t *bdaddr,
                                btd_attr_read_result_t result, void *user_data)
 #else
 static void proxy_read_cb(struct btd_attribute *attr,
                                btd_attr_read_result_t result, void *user_data)
 #endif
 {
-       DBusMessageIter iter, array;
        GDBusProxy *proxy;
-       uint8_t *value;
-       int len;
-
+       uint8_t *value = NULL;
+       int len = 0;
+#ifdef __TIZEN_PATCH__
+       char dstaddr[18] = { 0 };
+       char *addr_value = NULL;
+       DBusMessage *reply;
+       DBusError err;
+       uint8_t request_id = 1;
+       uint16_t offset = 0;
+       const char *path = NULL;
+       const char *svc_path = NULL;
+#endif
        /*
         * Remote device is trying to read the informed attribute,
         * "Value" should be read from the proxy. GDBusProxy tracks
@@ -297,7 +344,7 @@ static void proxy_read_cb(struct btd_attribute *attr,
                return;
 #endif
        }
-
+#ifndef __TIZEN_PATCH__
        if (!g_dbus_proxy_get_property(proxy, "Value", &iter)) {
                /* Unusual situation, read property will checked earlier */
 #ifdef __TIZEN_PATCH__
@@ -320,7 +367,55 @@ static void proxy_read_cb(struct btd_attribute *attr,
 
        dbus_message_iter_recurse(&iter, &array);
        dbus_message_iter_get_fixed_array(&array, &value, &len);
-
+#else
+       ba2str(bdaddr, dstaddr);
+       addr_value = g_strdup(dstaddr);
+       path = btd_get_attrib_path(attr);
+       if (!path) {
+               /* Fix : RESOURCE_LEAK */
+               if (addr_value)
+                       g_free(addr_value);
+               return result(-EPERM, NULL, 0, user_data);
+       }
+       svc_path = btd_find_service_from_attr(attr);
+       if (!svc_path) {
+               /* Fix : RESOURCE_LEAK */
+               if (addr_value)
+                       g_free(addr_value);
+               return result(-EPERM, NULL, 0, user_data);
+       }
+       reply = __bt_gatt_dbus_method_send(path, svc_path,
+                       DBUS_INTERFACE_PROPERTIES,
+                       "ReadValue", &err,
+                       DBUS_TYPE_STRING, &addr_value,
+                       DBUS_TYPE_STRING, &path,
+                       DBUS_TYPE_BYTE, &request_id,
+                       DBUS_TYPE_UINT16, &offset,
+                       DBUS_TYPE_INVALID);
+       if (!reply) {
+               DBG("Error returned in method call\n");
+               if (dbus_error_is_set(&err))
+                       DBG("Error = %s", err.message);
+               /* Fix : RESOURCE_LEAK */
+               if (addr_value)
+                       g_free(addr_value);
+               return result(-EPERM, NULL, 0, user_data);
+       } else {
+               DBusMessageIter iter, array;
+               uint8_t *value = NULL;
+               int len;
+               dbus_message_iter_init(reply, &iter);
+
+               if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) {
+                       dbus_message_iter_recurse(&iter, &array);
+                       dbus_message_iter_get_fixed_array(&array, &value, &len);
+                       if (len > 0)
+                               return result(0, value, len, user_data);
+                       else
+                               return result(-ENOENT, NULL, 0, user_data);
+               }
+       }
+#endif
        DBG("attribute: %p read %d bytes", attr, len);
 
 #ifdef __TIZEN_PATCH__
@@ -813,3 +908,5 @@ void gatt_dbus_manager_unregister(void)
        g_dbus_unregister_interface(btd_get_dbus_connection(), "/org/bluez",
                                                        GATT_MGR_IFACE);
 }
+
+#endif
index 310cfa9..6d35ecd 100644 (file)
@@ -1,3 +1,4 @@
+#ifdef __TIZEN_PATCH__
 /*
  *
  *  BlueZ - Bluetooth protocol stack for Linux
@@ -23,3 +24,5 @@
 
 gboolean gatt_dbus_manager_register(void);
 void gatt_dbus_manager_unregister(void);
+
+#endif
index 9a37671..ff31efe 100644 (file)
@@ -1,3 +1,4 @@
+#ifdef __TIZEN_PATCH__
 /*
  *
  *  BlueZ - Bluetooth protocol stack for Linux
@@ -48,6 +49,7 @@
 #include "attrib/gatt.h"
 #include "src/attrib-server.h"
 #include "src/device.h"
+#include "dbus-common.h"
 #endif
 
 /* Common GATT UUIDs */
@@ -218,7 +220,7 @@ static void store_start_end_handle(bt_uuid_t *uuid, uint16_t start_handle,
        attrib->attr_start_handle = start_handle;
        attrib->attr_end_handle = end_handle;
 
-       g_list_insert_sorted (local_attribute_db, attrib, attribute_cmp);
+       local_attribute_db = g_list_insert_sorted (local_attribute_db, attrib, attribute_cmp);
 
        return;
 }
@@ -275,12 +277,6 @@ static uint8_t read_result(int err, uint8_t *value, size_t len,
        return status;
 }
 
-static uint8_t write_result(int err, void *user_data)
-{
-       DBG(" ");
-       return err;
-}
-
 static uint8_t read_desc_attr_db_value(struct attribute *a,
                                                struct btd_device *device,
                                                gpointer user_data)
@@ -290,7 +286,8 @@ static uint8_t read_desc_attr_db_value(struct attribute *a,
 
        local_attr = find_local_attr(&a->uuid);
        if (local_attr && local_attr->read_cb) {
-               status = local_attr->read_cb(local_attr, read_result, a);
+               bdaddr_t *bdaddr = (bdaddr_t *)device_get_address(device);
+               status = local_attr->read_cb(local_attr, bdaddr, read_result, a);
        } else
                return -ENOENT;
 
@@ -306,7 +303,8 @@ static uint8_t read_char_attr_db_value(struct attribute *a,
 
        local_attr = find_local_attr(&a->uuid);
        if (local_attr && local_attr->read_cb) {
-               status = local_attr->read_cb(local_attr, read_result, a);
+               bdaddr_t *bdaddr = (bdaddr_t *)device_get_address(device);
+               status = local_attr->read_cb(local_attr, bdaddr, read_result, a);
        } else
                return -ENOENT;
 
@@ -357,7 +355,6 @@ static unsigned int get_attr_char_size(void)
        GList *l;
        uint16_t nex_hndl = 0x0001;
        struct pending_hndl *temp_list;
-       struct btd_attribute *local_attr;
        unsigned int attr_size = 0;
 
        /* Calculate the size of the char attributes to be added to attribute DB */
@@ -367,7 +364,6 @@ static unsigned int get_attr_char_size(void)
                                        GUINT_TO_POINTER(nex_hndl),
                                        handle_cmp);
                if (l) {
-                       local_attr = l->data;
                        if (temp_list->type == GATT_TYPE_CHARAC_SVC) {
                                attr_size += 2;
                        }
@@ -423,7 +419,7 @@ bool gatt_send_service_changed_ind(struct btd_adapter *adapter, bt_uuid_t *uuid,
 
     do {
                l = g_list_find_custom(connections, GUINT_TO_POINTER(NULL),
-                                               is_connected);
+                                               (GCompareFunc)is_connected);
 
                if (l) {
                        dev = l->data;
@@ -546,10 +542,18 @@ bool btd_gatt_update_attr_db(void)
                                if (!svc_added) {
                                        new_service_add = FALSE;
                                        new_char_desc_add = FALSE;
+                                       /* Fix : RESOURCE_LEAK */
+                                       if (temp_att) {
+                                               free(temp_att);
+                                               temp_att = NULL;
+                                       }
                                        break;
                                } else {
                                        new_service_add = TRUE;
                                }
+                       }
+                       /* Fix : RESOURCE_LEAK */
+                       if (temp_att) {
                                free(temp_att);
                                temp_att = NULL;
                        }
@@ -625,6 +629,36 @@ char *btd_get_service_path(bt_uuid_t uuid)
        return attrib->path;
 }
 
+const char *btd_get_attrib_path(struct btd_attribute *attrib)
+{
+       if(attrib)
+               return attrib->path;
+       else
+               return NULL;
+}
+
+const char *btd_find_service_from_attr(struct btd_attribute *attrib)
+{
+       struct btd_attribute *svc_attrib = NULL;
+       GList *list;
+
+       for (list = local_attribute_db; list; list = g_list_next(list)) {
+               struct btd_attribute *attr = list->data;
+               if (attr && (attr->type.value.u16 == GATT_PRIM_SVC_UUID ||
+                       attr->type.value.u16 == GATT_SND_SVC_UUID)) {
+                       svc_attrib = attr;
+               } else {
+                       if (attr && !attribute_cmp(attrib, attr))
+                               break;
+                       else
+                               continue;
+               }
+       }
+       if (svc_attrib)
+               return svc_attrib->path;
+       else
+               return NULL;
+}
 DBusMessage *service_append_dict(bt_uuid_t uuid, DBusMessage *msg)
 {
        GList *list;
@@ -690,7 +724,7 @@ DBusMessage *service_append_dict(bt_uuid_t uuid, DBusMessage *msg)
 
 static void remove_attr_service(struct btd_attribute *service)
 {
-       uint16_t start_handle, end_handle;
+       uint16_t start_handle = 0, end_handle = 0;
        bt_uuid_t prim_uuid;
        struct btd_adapter *adapter;
 
@@ -708,9 +742,39 @@ void btd_gatt_set_notify_indicate_flag(struct btd_attribute *attrib,
                                                bool notify_indicate)
 {
        attrib->notify_indicate = notify_indicate;
-       g_list_insert_sorted (local_attribute_db, attrib,
+       local_attribute_db = g_list_insert_sorted (local_attribute_db, attrib,
                                        attribute_cmp);
 }
+
+gboolean gatt_register_internet_protocol_service(struct btd_adapter *adapter)
+{
+       bt_uuid_t uuid;
+
+       bt_uuid16_create(&uuid, GATT_IPSP_UUID);
+
+       return gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid,
+                       GATT_OPT_INVALID);
+}
+
+gboolean gatt_unregister_internet_protocol_service(struct btd_adapter *adapter)
+{
+       bt_uuid_t uuid;
+       struct attribute *a;
+
+       bt_uuid16_create(&uuid, GATT_IPSP_UUID);
+
+       a = attribute_find(adapter, &uuid);
+       if (!a) {
+               error("Attribute not found for handle 0x%04x", a->handle);
+               return FALSE;
+       }
+
+       if (attrib_db_del(adapter, a->handle) < 0) {
+               error("Can't delete handle 0x%04x", a->handle);
+               return FALSE;
+       }
+       return TRUE;
+}
 #endif
 
 #ifdef __TIZEN_PATCH__
@@ -829,7 +893,7 @@ bool btd_gatt_update_char(const bt_uuid_t *uuid, uint8_t *value, size_t len)
 
        attrib = l->data;
        notify_indicate = attrib->notify_indicate;
-       g_list_insert_sorted (local_attribute_db, attrib, attribute_cmp);
+       local_attribute_db = g_list_insert_sorted (local_attribute_db, attrib, attribute_cmp);
 
        l = g_list_find_custom(local_attribute_db,
                                GUINT_TO_POINTER(attrib->handle - 1),
@@ -986,6 +1050,9 @@ struct btd_attribute *btd_gatt_add_char(const bt_uuid_t *uuid,
 
 fail:
 #ifdef __TIZEN_PATCH__
+       /* Fix : RESOURCE_LEAK */
+       if (char_decl->path)
+               g_free(char_decl->path);
        if (char_decl)
                free(char_decl);
        if (char_value)
@@ -1063,3 +1130,5 @@ void gatt_cleanup(void)
 
        gatt_dbus_manager_unregister();
 }
+
+#endif
index 81f599c..0c7dc1a 100644 (file)
@@ -1,3 +1,4 @@
+#ifdef __TIZEN_PATCH__
 /*
  *
  *  BlueZ - Bluetooth protocol stack for Linux
@@ -47,12 +48,13 @@ typedef void (*btd_attr_read_result_t) (int err, uint8_t *value, size_t len,
  * Service implementation callback passed to core (ATT layer). It manages read
  * operations received from remote devices.
  * @attr:      reference of the attribute to be read.
+ * @bdaddr: Remote device address, which requets read value
  * @result:    callback called from the service implementation informing the
  *             value of attribute read.
  * @user_data: user_data passed in btd_attr_read_result_t callback.
  */
 #ifdef __TIZEN_PATCH__
-typedef uint8_t (*btd_attr_read_t) (struct btd_attribute *attr,
+typedef uint8_t (*btd_attr_read_t) (struct btd_attribute *attr, bdaddr_t *bdaddr,
                                                btd_attr_read_result_t result,
                                                void *user_data);
 #else
@@ -120,6 +122,16 @@ bool btd_gatt_update_attr_db(void);
 char *btd_get_service_path(bt_uuid_t uuid);
 
 /*
+ * btd_get_attrib_path - Gets the attribute path if registerd.
+ */
+const char *btd_get_attrib_path(struct btd_attribute *attrib);
+
+/*
+ * btd_find_service_from_attr - Gets the Service from attribute if registerd.
+ */
+const char *btd_find_service_from_attr(struct btd_attribute *attrib);
+
+/*
  * service_append_dict - Prepare the dictionar entry for a Service
  * along with characteristics and discriptors.
  */
@@ -203,3 +215,5 @@ struct btd_attribute *btd_gatt_add_char_desc(const bt_uuid_t *uuid,
  */
 bool btd_gatt_update_char(const bt_uuid_t *uuid, uint8_t *value, size_t len);
 #endif
+
+#endif
index 6e0fc06..7137258 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -124,13 +124,18 @@ void __hci_attach_log_init(void)
 {
        int option = LOG_NDELAY | LOG_PID;
 
-       enabled = g_strsplit_set(g_strdup("*"), ":, ", 0);
+       /* Fix : RESOURCE_LEAK */
+       char *str = g_strdup("*");
+
+       enabled = g_strsplit_set(str, ":, ", 0);
 
        __btd_enable_debug(__start___debug, __stop___debug);
 
        openlog("hciattach", option, LOG_DAEMON);
 
        syslog(LOG_INFO, "hciattach daemon for debugging");
+
+       g_free(str);
 }
 #endif
 
index 1c189ae..96cbae8 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <signal.h>
+#include <stdbool.h>
 #include <sys/signalfd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#include <bluetooth/bluetooth.h>
-
 #include <glib.h>
 
 #include <dbus/dbus.h>
 
-#include <gdbus/gdbus.h>
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+
+#include "gdbus/gdbus.h"
 
 #include "log.h"
 
 #include "dbus-common.h"
 #include "agent.h"
 #include "profile.h"
-#include "gatt.h"
 #include "systemd.h"
 
+#ifdef __TIZEN_PATCH__
+#include "gatt.h"
+#endif
+
 #define BLUEZ_NAME "org.bluez"
 
 #define DEFAULT_PAIRABLE_TIMEOUT       0 /* disabled */
 struct main_opts main_opts;
 static GKeyFile *main_conf;
 
+static enum {
+       MPS_OFF,
+       MPS_SINGLE,
+       MPS_MULTIPLE,
+} mps = MPS_OFF;
+
 static const char * const supported_options[] = {
        "Name",
        "Class",
@@ -80,6 +91,7 @@ static const char * const supported_options[] = {
        "NameResolving",
        "DebugKeys",
        "ControllerMode",
+       "MultiProfile",
 #ifdef __TIZEN_PATCH__
        "EnableLEPrivacy",
 #endif
@@ -310,6 +322,19 @@ static void parse_config(GKeyFile *config)
                g_free(str);
        }
 
+       str = g_key_file_get_string(config, "General", "MultiProfile", &err);
+       if (err) {
+               g_clear_error(&err);
+       } else {
+               DBG("MultiProfile=%s", str);
+
+               if (!strcmp(str, "single"))
+                       mps = MPS_SINGLE;
+               else if (!strcmp(str, "multiple"))
+                       mps = MPS_MULTIPLE;
+
+               g_free(str);
+       }
 #ifdef __TIZEN_PATCH__
        boolean = g_key_file_get_boolean(config, "General",
                                                "EnableLEPrivacy", &err);
@@ -334,7 +359,7 @@ static void init_defaults(void)
        main_opts.name_resolv = TRUE;
        main_opts.debug_keys = FALSE;
 #ifdef __TIZEN_PATCH__
-       main_opts.le_privacy = TRUE;
+       main_opts.le_privacy = FALSE;
 #endif
 
        if (sscanf(VERSION, "%hhu.%hhu", &major, &minor) != 2)
@@ -593,7 +618,9 @@ int main(int argc, char *argv[])
 
        g_dbus_set_flags(gdbus_flags);
 
+#ifdef __TIZEN_PATCH__
        gatt_init();
+#endif
 
        if (adapter_init() < 0) {
                error("Adapter handling initialization failed");
@@ -613,6 +640,9 @@ int main(int argc, char *argv[])
                register_device_id(main_opts.did_source, main_opts.did_vendor,
                                main_opts.did_product, main_opts.did_version);
 
+       if (mps != MPS_OFF)
+               register_mps(mps == MPS_MULTIPLE);
+
        /* Loading plugins has to be done after D-Bus has been setup since
         * the plugins might wanna expose some paths on the bus. However the
         * best order of how to init various subsystems of the Bluetooth
@@ -657,7 +687,9 @@ int main(int argc, char *argv[])
 
        adapter_cleanup();
 
+#ifdef __TIZEN_PATCH__
        gatt_cleanup();
+#endif
 
        rfkill_exit();
 
diff --git a/src/main.conf b/src/main.conf
deleted file mode 100755 (executable)
index 3ebadde..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-[General]
-
-# Default adaper name
-# %h - substituted for hostname
-# %d - substituted for adapter id
-# Defaults to 'BlueZ'
-#Name = %h-%d
-
-# Default device class. Only the major and minor device class bits are
-# considered. Defaults to '0x000000'.
-#Class = 0x000100
-
-# How long to stay in discoverable mode before going back to non-discoverable
-# The value is in seconds. Default is 180, i.e. 3 minutes.
-# 0 = disable timer, i.e. stay discoverable forever
-#DiscoverableTimeout = 0
-
-# How long to stay in pairable mode before going back to non-discoverable
-# The value is in seconds. Default is 0.
-# 0 = disable timer, i.e. stay pairable forever
-#PairableTimeout = 0
-
-# Automatic connection for bonded devices driven by platform/user events.
-# If a platform plugin uses this mechanism, automatic connections will be
-# enabled during the interval defined below. Initially, this feature
-# intends to be used to establish connections to ATT channels. Default is 60.
-#AutoConnectTimeout = 60
-
-# Use vendor id source (assigner), vendor, product and version information for
-# DID profile support. The values are separated by ":" and assigner, VID, PID
-# and version.
-# Possible vendor id source values: bluetooth, usb (defaults to usb)
-#DeviceID = bluetooth:1234:5678:abcd
-
-# Do reverse service discovery for previously unknown devices that connect to
-# us. This option is really only needed for qualification since the BITE tester
-# doesn't like us doing reverse SDP for some test cases (though there could in
-# theory be other useful purposes for this too). Defaults to 'true'.
-#ReverseServiceDiscovery = true
-
-# Enable name resolving after inquiry. Set it to 'false' if you don't need
-# remote devices name and want shorter discovery cycle. Defaults to 'true'.
-#NameResolving = true
-
-# Enable runtime persistency of debug link keys. Default is false which
-# makes debug link keys valid only for the duration of the connection
-# that they were created for.
-#DebugKeys = false
-
-#[Policy]
-#
-# The ReconnectUUIDs defines the set of remote services that should try
-# to be reconnected to in case of a link loss (link supervision
-# timeout). The policy plugin should contain a sane set of values by
-# default, but this list can be overridden here. By setting the list to
-# empty the reconnection feature gets disabled.
-#ReconnectUUIDs=
index 6812f4a..364a72c 100644 (file)
@@ -56,6 +56,19 @@ Class = 0x00020C        # Smart phone
 # Possible values: "dual", "bredr", "le"
 #ControllerMode = dual
 
+# Enables Multi Profile Specification support. This allows to specify if
+# system supports only Multiple Profiles Single Device (MPSD) configuration
+# or both Multiple Profiles Single Device (MPSD) and Multiple Profiles Multiple
+# Devices (MPMD) configurations.
+# Possible values: "off", "single", "multiple"
+#MultiProfile = off
+
+#ifdef __TIZEN_PATCH__
+# Enable the LE Privacy feature. If value is true, i.e. LE Privacy is enabled
+# otherwise the feature is disabled by default for the local device.
+EnableLEPrivacy = false
+#endif
+
 #[Policy]
 #
 # The ReconnectUUIDs defines the set of remote services that should try
@@ -63,10 +76,4 @@ Class = 0x00020C        # Smart phone
 # timeout). The policy plugin should contain a sane set of values by
 # default, but this list can be overridden here. By setting the list to
 # empty the reconnection feature gets disabled.
-#ReconnectUUIDs=
-
-#ifdef __TIZEN_PATCH__
-# Enable the LE Privacy feature. If value is true, i.e. LE Privacy is enabled
-# otherwise the feature is disabled by default for the local device.
-EnableLEPrivacy = true
-#endif
\ No newline at end of file
+#ReconnectUUIDs=
\ No newline at end of file
index 2a38165..459d616 100644 (file)
@@ -56,17 +56,22 @@ Class = 0x000704        # Wearable, Wrist Watch
 # Possible values: "dual", "bredr", "le"
 #ControllerMode = dual
 
-#[Policy]
+#ifdef __TIZEN_PATCH__
+# Enable the LE Privacy feature. If value is true, i.e. LE Privacy is enabled
+# otherwise the feature is disabled by default for the local device.
+EnableLEPrivacy = false
+#endif
+
+[Policy]
 #
 # The ReconnectUUIDs defines the set of remote services that should try
 # to be reconnected to in case of a link loss (link supervision
 # timeout). The policy plugin should contain a sane set of values by
 # default, but this list can be overridden here. By setting the list to
 # empty the reconnection feature gets disabled.
-#ReconnectUUIDs=
-
 #ifdef __TIZEN_PATCH__
-# Enable the LE Privacy feature. If value is true, i.e. LE Privacy is enabled
-# otherwise the feature is disabled by default for the local device.
-EnableLEPrivacy = true
+ReconnectUUIDs=
+#else
+#ReconnectUUIDs=
 #endif
+
old mode 100755 (executable)
new mode 100644 (file)
index ff2408b..dd7ae8f
@@ -3,6 +3,3 @@ Name=org.bluez
 Exec=/bin/false
 User=root
 SystemdService=dbus-org.bluez.service
-#test
-#SystemdService=bluetooth.service
-
index 8422986..5fe2c5c 100644 (file)
--- a/src/oui.c
+++ b/src/oui.c
@@ -25,6 +25,7 @@
 #include <config.h>
 #endif
 
+#include "lib/bluetooth.h"
 #include "oui.h"
 
 #ifdef HAVE_UDEV_HWDB_NEW
index abd0386..2ddc27f 100644 (file)
--- a/src/oui.h
+++ b/src/oui.h
@@ -21,6 +21,4 @@
  *
  */
 
-#include <bluetooth/bluetooth.h>
-
 char *batocomp(const bdaddr_t *ba);
index edb47db..39310a7 100644 (file)
 #include <string.h>
 #include <sys/stat.h>
 
-#include <bluetooth/bluetooth.h>
-
 #include <glib.h>
 
+#include "lib/bluetooth.h"
+
 #include "btio/btio.h"
 #include "src/plugin.h"
 #include "src/log.h"
index 0874ecb..99948a7 100644 (file)
 
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+#include "lib/uuid.h"
+
+#include "gdbus/gdbus.h"
 
 #include "btio/btio.h"
-#include "lib/uuid.h"
 #include "sdpd.h"
 #include "log.h"
 #include "error.h"
 #define BTD_PROFILE_PSM_AUTO   -1
 #define BTD_PROFILE_CHAN_AUTO  -1
 
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+#define HID_DEVICE_INTR_PSM 17
+#define HID_DEVICE_CTRL_PSM 19
+#endif
+
 #define HFP_HF_RECORD                                                  \
        "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>                    \
        <record>                                                        \
                </attribute>                                            \
        </record>"
 
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+#define HID_DEVICE_RECORD      \
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>    \
+       <record>        \
+       <attribute id=\"0x0001\">       \
+               <sequence>      \
+                       <uuid value=\"0x1124\" />       \
+               </sequence>     \
+       </attribute>    \
+       <attribute id=\"0x0004\">       \
+               <sequence>      \
+                       <sequence>      \
+                               <uuid value=\"0x0100\" />       \
+                               <uint16 value=\"0x0011\" />     \
+                       </sequence>     \
+                       <sequence>      \
+                               <uuid value=\"0x0011\" />       \
+                       </sequence>     \
+               </sequence>     \
+       </attribute>    \
+       <attribute id=\"0x0005\">       \
+               <sequence>      \
+                       <uuid value=\"0x1002\" />       \
+               </sequence>     \
+       </attribute>    \
+       <attribute id=\"0x0006\">       \
+               <sequence>      \
+                       <uint16 value=\"0x656e\" />     \
+                       <uint16 value=\"0x006a\" />     \
+                       <uint16 value=\"0x0100\" />     \
+               </sequence>     \
+       </attribute>    \
+       <attribute id=\"0x0009\">       \
+               <sequence>      \
+                       <sequence>      \
+                               <uuid value=\"0x0011\" />       \
+                               <uint16 value=\"0x0100\" />     \
+                       </sequence>     \
+               </sequence>     \
+       </attribute>    \
+       <attribute id=\"0x000d\">       \
+               <sequence>      \
+                       <sequence>      \
+                               <sequence>      \
+                                       <uuid value=\"0x0100\" />       \
+                                       <uint16 value=\"0x0013\" />     \
+                               </sequence>     \
+                               <sequence>      \
+                                       <uuid value=\"0x0011\" />       \
+                               </sequence>     \
+                       </sequence>     \
+               </sequence>     \
+       </attribute>    \
+       <attribute id=\"0x0100\">       \
+               <text value=\"Bluez Mouse\" />  \
+       </attribute>    \
+       <attribute id=\"0x0101\">       \
+               <text value=\"Mouse\" />        \
+       </attribute>    \
+       <attribute id=\"0x0200\">       \
+               <uint16 value=\"0x0100\" />     \
+       </attribute>    \
+       <attribute id=\"0x0201\">       \
+               <uint16 value=\"0x0111\" />     \
+       </attribute>    \
+       <attribute id=\"0x0202\">       \
+               <uint8 value=\"0x40\" />                \
+       </attribute>    \
+       <attribute id=\"0x0203\">       \
+               <uint8 value=\"0x00\" />                \
+       </attribute>    \
+       <attribute id=\"0x0204\">       \
+               <boolean value=\"true\" />      \
+       </attribute>    \
+       <attribute id=\"0x0205\">       \
+               <boolean value=\"true\" />      \
+       </attribute>    \
+       <attribute id=\"0x0206\">       \
+               <sequence>      \
+                       <sequence>      \
+                               <uint8 value=\"0x22\" />                \
+                               <text encoding=\"hex\" value=\"05010902a10185010901a1000509190129031500250175019503810275059501810105010930093109381581257f750895028106c0c005010906a1018502a100050719e029e71500250175019508810295087508150025650507190029658100c0c0\" />        \
+                       </sequence>     \
+               </sequence>     \
+       </attribute>    \
+       <attribute id=\"0x0207\">       \
+               <sequence>      \
+                       <sequence>      \
+                               <uint16 value=\"0x0409\" />     \
+                               <uint16 value=\"0x0100\" />     \
+                       </sequence>     \
+               </sequence>     \
+       </attribute>    \
+       <attribute id=\"0x020b\">       \
+               <uint16 value=\"0x0100\" />     \
+       </attribute>    \
+       <attribute id=\"0x020e\">       \
+               <boolean value=\"true\" />      \
+       </attribute>    \
+       </record>"
+#endif
+
+
 struct ext_io;
 
 struct ext_profile {
@@ -724,7 +833,6 @@ struct ext_profile {
        char *uuid;
        char *service;
        char *role;
-
        char *record;
        char *(*get_record)(struct ext_profile *ext, struct ext_io *l2cap,
                                                        struct ext_io *rfcomm);
@@ -754,6 +862,13 @@ struct ext_profile {
        GSList *conns;
 
        GSList *connects;
+#ifdef __TIZEN_PATCH__
+       char *destination;
+       char *app_path;
+#endif
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+       bool local_connect;
+#endif
 };
 
 struct ext_io {
@@ -797,6 +912,11 @@ static GSList *custom_props = NULL;
 static GSList *profiles = NULL;
 static GSList *ext_profiles = NULL;
 
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+static int connect_io(struct ext_io *conn, const bdaddr_t *src,
+                                                       const bdaddr_t *dst);
+#endif
+
 void btd_profile_foreach(void (*func)(struct btd_profile *p, void *data),
                                                                void *data)
 {
@@ -1056,7 +1176,7 @@ static bool send_new_connection(struct ext_profile *ext, struct ext_io *conn)
        const sdp_record_t *rec;
        const char *path;
        int fd;
-
+       DBG("Sending New Connection owner %s path %s", ext->owner, ext->path);
        msg = dbus_message_new_method_call(ext->owner, ext->path,
                                                        "org.bluez.Profile1",
                                                        "NewConnection");
@@ -1109,6 +1229,16 @@ static bool send_new_connection(struct ext_profile *ext, struct ext_io *conn)
        return true;
 }
 
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+static int check_connection_psm(gconstpointer a, gconstpointer b)
+{
+       const struct ext_io *conn = a;
+       const int *psm = b;
+       DBG("conn->psm %d, psm %d", conn->psm, *psm);
+       return (conn->psm == *psm ? 0 : -1);
+}
+#endif
+
 static void ext_connect(GIOChannel *io, GError *err, gpointer user_data)
 {
        struct ext_io *conn = user_data;
@@ -1143,7 +1273,31 @@ static void ext_connect(GIOChannel *io, GError *err, gpointer user_data)
                conn->io_id = g_io_add_watch(io, cond, ext_io_disconnected,
                                                                        conn);
        }
-
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+       if (g_strcmp0(ext->uuid, HID_UUID) == 0 && ext->local_connect == TRUE) {
+               GSList *l = NULL;
+               int psm = HID_DEVICE_CTRL_PSM;
+               ext->local_connect = FALSE;
+               l = g_slist_find_custom(ext->conns, &psm, check_connection_psm);
+               if (l == NULL) {
+                       struct ext_io *conn1 = g_new0(struct ext_io, 1);
+                       int error = 0;
+                       ext->remote_psm = psm;
+                       conn1->ext = ext;
+                       conn1->psm = ext->remote_psm;
+                       conn1->chan = ext->remote_chan;
+                       error = connect_io(conn1, btd_adapter_get_address(conn->adapter),
+                                                       device_get_address(conn->device));
+                       DBG("error from connect_io %d", error);
+                       conn1->adapter = btd_adapter_ref(conn->adapter);
+                       conn1->device = btd_device_ref(conn->device);
+                       conn1->service = btd_service_ref(conn->service);
+                       ext->conns = g_slist_append(ext->conns, conn1);
+               } else {
+                       DBG("Connection Already there");
+               }
+       }
+#endif
        if (send_new_connection(ext, conn))
                return;
 
@@ -1253,7 +1407,6 @@ static void ext_confirm(GIOChannel *io, gpointer user_data)
        GError *gerr = NULL;
        bdaddr_t src, dst;
        char addr[18];
-       int fd;
 
        bt_io_get(io, &gerr,
                        BT_IO_OPT_SOURCE_BDADDR, &src,
@@ -1273,9 +1426,8 @@ static void ext_confirm(GIOChannel *io, gpointer user_data)
        if (conn == NULL)
                return;
 
-       fd = g_io_channel_unix_get_fd(conn->io);
        conn->auth_id = btd_request_authorization(&src, &dst, uuid, ext_auth,
-                                                                       conn, fd);
+                                                                       conn);
        if (conn->auth_id == 0) {
                error("%s authorization failure", ext->name);
                ext_io_destroy(conn);
@@ -1354,11 +1506,17 @@ static uint32_t ext_start_servers(struct ext_profile *ext,
                                                struct btd_adapter *adapter)
 {
        struct ext_io *l2cap = NULL;
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+       struct ext_io *l2cap1 = NULL;
+#endif
        struct ext_io *rfcomm = NULL;
        BtIOConfirm confirm;
        BtIOConnect connect;
        GError *err = NULL;
        GIOChannel *io;
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+       GIOChannel *io1;
+#endif
 
        if (ext->authorize) {
                confirm = ext_confirm;
@@ -1404,6 +1562,26 @@ static uint32_t ext_start_servers(struct ext_profile *ext,
                        ext->servers = g_slist_append(ext->servers, l2cap);
                        DBG("%s listening on PSM %u", ext->name, psm);
                }
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+               if (g_strcmp0(ext->uuid , HID_UUID) == 0) {
+                       psm = HID_DEVICE_CTRL_PSM;
+                       l2cap1 = g_new0(struct ext_io, 1);
+                       l2cap1->ext = ext;
+                       io1 = bt_io_listen(connect, confirm, l2cap, NULL, &err,
+                                               BT_IO_OPT_SOURCE_BDADDR,
+                                               btd_adapter_get_address(adapter),
+                                               BT_IO_OPT_MODE, ext->mode,
+                                               BT_IO_OPT_PSM, psm,
+                                               BT_IO_OPT_SEC_LEVEL, ext->sec_level,
+                                               BT_IO_OPT_INVALID);
+                       l2cap1->io = io1;
+                       l2cap1->proto = BTPROTO_L2CAP;
+                       l2cap1->psm = psm;
+                       l2cap1->adapter = btd_adapter_ref(adapter);
+                       ext->servers = g_slist_append(ext->servers, l2cap1);
+                       DBG("%s listening on PSM %u", ext->name, psm);
+               }
+#endif
        }
 
        if (ext->local_chan) {
@@ -1704,7 +1882,7 @@ static void record_cb(sdp_list_t *recs, int err, gpointer user_data)
 
                DBG("profile uuid %s port uuid %s", profile_uuid, ext->remote_uuid);
 
-               if (g_strncasecmp(profile_uuid, ext->remote_uuid,
+               if (g_ascii_strncasecmp(profile_uuid, ext->remote_uuid,
                                                strlen(profile_uuid)) != 0) {
                        free(profile_uuid);
                        continue;
@@ -1804,7 +1982,7 @@ static int ext_connect_dev(struct btd_service *service)
 
        conn = g_new0(struct ext_io, 1);
        conn->ext = ext;
-
+#ifndef TIZEN_BT_HID_DEVICE_ENABLE
        if (ext->remote_psm || ext->remote_chan) {
                conn->psm = ext->remote_psm;
                conn->chan = ext->remote_chan;
@@ -1817,7 +1995,28 @@ static int ext_connect_dev(struct btd_service *service)
 
        if (err < 0)
                goto failed;
-
+#else
+       if (g_strcmp0(ext->uuid, HID_UUID) == 0) {
+               ext->local_connect = TRUE;
+               ext->remote_psm = HID_DEVICE_INTR_PSM;
+               conn->psm = ext->remote_psm;
+               conn->chan = ext->remote_chan;
+               err = connect_io(conn, btd_adapter_get_address(adapter),
+                                               device_get_address(dev));
+       } else {
+               if (ext->remote_psm || ext->remote_chan) {
+                       conn->psm = ext->remote_psm;
+                       conn->chan = ext->remote_chan;
+                       err = connect_io(conn, btd_adapter_get_address(adapter),
+                                                       device_get_address(dev));
+               } else {
+                       err = resolve_service(conn, btd_adapter_get_address(adapter),
+                                                       device_get_address(dev));
+               }
+       }
+       if (err < 0)
+               goto failed;
+#endif
        conn->adapter = btd_adapter_ref(adapter);
        conn->device = btd_device_ref(dev);
        conn->service = btd_service_ref(service);
@@ -1875,6 +2074,7 @@ static int ext_disconnect_dev(struct btd_service *service)
        if (!ext)
                return -ENOENT;
 
+#ifndef TIZEN_BT_HID_DEVICE_ENABLE
        conn = find_connection(ext, dev);
        if (!conn || !conn->connected)
                return -ENOTCONN;
@@ -1885,7 +2085,30 @@ static int ext_disconnect_dev(struct btd_service *service)
        err = send_disconn_req(ext, conn);
        if (err < 0)
                return err;
+#else
+       if (g_strcmp0(ext->uuid, HID_UUID) != 0) {
+               conn = find_connection(ext, dev);
+               if (!conn || !conn->connected)
+                       return -ENOTCONN;
+
+               if (conn->pending)
+                       return -EBUSY;
 
+               err = send_disconn_req(ext, conn);
+               if (err < 0)
+                       return err;
+       } else {
+               GSList *l;
+               /* As HID will be using two psm we need to send disconnect
+                 * request for both the psms */
+               for (l = ext->conns; l != NULL; l = g_slist_next(l)) {
+                       struct ext_io *conn1 = l->data;
+                       if (conn1->device == dev) {
+                               err = send_disconn_req(ext, conn1);
+                       }
+               }
+       }
+#endif
        return 0;
 }
 
@@ -1987,15 +2210,25 @@ static char *get_sync_record(struct ext_profile *ext, struct ext_io *l2cap,
        return g_strdup_printf(SYNC_RECORD, rfcomm->chan, ext->version,
                                                                ext->name);
 }
-
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+static char *get_hid_device_record(struct ext_profile *ext, struct ext_io *l2cap,
+                                                       struct ext_io *rfcomm)
+{
+       return g_strdup(HID_DEVICE_RECORD);
+}
+#endif
 static char *get_opp_record(struct ext_profile *ext, struct ext_io *l2cap,
                                                        struct ext_io *rfcomm)
 {
+#ifndef __TIZEN_PATCH__
        uint16_t psm = 0;
+#endif
        uint8_t chan = 0;
 
+#ifndef __TIZEN_PATCH__
        if (l2cap)
                psm = l2cap->psm;
+#endif
        if (rfcomm)
                chan = rfcomm->chan;
 
@@ -2101,11 +2334,7 @@ static struct default_settings {
                .channel        = SPP_DEFAULT_CHANNEL,
                .authorize      = true,
                .get_record     = get_spp_record,
-#ifdef __TIZEN_PATCH__
-               .version        = 0x0100,
-#else
                .version        = 0x0102,
-#endif
        }, {
                .uuid           = DUN_GW_UUID,
                .name           = "Dial-Up Networking",
@@ -2207,7 +2436,18 @@ static struct default_settings {
                .authorize      = true,
                .get_record     = get_mns_record,
                .version        = 0x0102
+#ifdef TIZEN_BT_HID_DEVICE_ENABLE
+       }, {
+               .uuid           = HID_UUID,
+               .name           = "HID Device",
+               .psm            = HID_DEVICE_INTR_PSM,
+               .authorize      = TRUE,
+               .get_record     = get_hid_device_record,
+               .version                = 0x0100,
+       },
+#else
        },
+#endif
 };
 
 static void ext_set_defaults(struct ext_profile *ext)
@@ -2390,6 +2630,89 @@ static void set_service(struct ext_profile *ext)
        }
 }
 
+#ifdef __TIZEN_PATCH__
+static struct ext_profile *create_ext2(const char *owner, const char *path,
+                                       const char *uuid, const char *destination, const char *app_path,
+                                       DBusMessageIter *opts)
+{
+       struct btd_profile *p;
+       struct ext_profile *ext;
+
+       ext = g_new0(struct ext_profile, 1);
+
+       ext->uuid = bt_name2string(uuid);
+       if (ext->uuid == NULL) {
+               g_free(ext);
+               return NULL;
+       }
+
+       ext->owner = g_strdup(destination);
+       ext->path = g_strdup(app_path);
+       ext->destination = g_strdup(destination);
+       ext->app_path = g_strdup(app_path);
+       DBG("VALUES Dest %s, path2 %s", destination, app_path);
+       ext_set_defaults(ext);
+
+       while (dbus_message_iter_get_arg_type(opts) == DBUS_TYPE_DICT_ENTRY) {
+               DBusMessageIter value, entry;
+               const char *key;
+
+               dbus_message_iter_recurse(opts, &entry);
+               dbus_message_iter_get_basic(&entry, &key);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               if (parse_ext_opt(ext, key, &value) < 0)
+                       error("Invalid value for profile option %s", key);
+
+               dbus_message_iter_next(opts);
+       }
+
+       if (!ext->service)
+               set_service(ext);
+
+       if (ext->enable_server && !(ext->record || ext->get_record))
+               ext->get_record = get_generic_record;
+
+       if (!ext->name)
+               ext->name = g_strdup_printf("%s%s/%s", owner, path, uuid);
+
+       if (!ext->remote_uuid) {
+               if (ext->service)
+                       ext->remote_uuid = g_strdup(ext->service);
+               else
+                       ext->remote_uuid = g_strdup(ext->uuid);
+       }
+
+       p = &ext->p;
+
+       p->name = ext->name;
+       p->local_uuid = ext->service ? ext->service : ext->uuid;
+       p->remote_uuid = ext->remote_uuid;
+
+       if (ext->enable_server) {
+               p->adapter_probe = ext_adapter_probe;
+               p->adapter_remove = ext_adapter_remove;
+       }
+
+       if (ext->enable_client) {
+               p->device_probe = ext_device_probe;
+               p->device_remove = ext_device_remove;
+               p->connect = ext_connect_dev;
+               p->disconnect = ext_disconnect_dev;
+       }
+
+       DBG("Created \"%s\"", ext->name);
+
+       ext_profiles = g_slist_append(ext_profiles, ext);
+
+       adapter_foreach(adapter_add_profile, &ext->p);
+
+       return ext;
+}
+#endif
+
 static struct ext_profile *create_ext(const char *owner, const char *path,
                                        const char *uuid,
                                        DBusMessageIter *opts)
@@ -2565,6 +2888,54 @@ static DBusMessage *unregister_profile(DBusConnection *conn,
        return dbus_message_new_method_return(msg);
 }
 
+#ifdef __TIZEN_PATCH__
+static DBusMessage *register_profile2(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       const char *path, *sender, *uuid;
+       DBusMessageIter args, opts;
+       struct ext_profile *ext;
+       const char *destination, *app_path;
+       sender = dbus_message_get_sender(msg);
+
+       DBG("sender %s", sender);
+
+       dbus_message_iter_init(msg, &args);
+
+       dbus_message_iter_get_basic(&args, &path);
+       dbus_message_iter_next(&args);
+       DBG("path %s", path);
+
+       DBG("path %s", path);
+       dbus_message_iter_get_basic(&args, &uuid);
+       dbus_message_iter_next(&args);
+       DBG("uuid %s", uuid);
+       dbus_message_iter_get_basic(&args, &destination);
+       dbus_message_iter_next(&args);
+       DBG("destination %s", destination);
+       dbus_message_iter_get_basic(&args, &app_path);
+       dbus_message_iter_next(&args);
+       DBG("path2 %s", app_path);
+       ext = find_ext_profile(destination, path);
+       if (ext)
+               return btd_error_already_exists(msg);
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
+               return btd_error_invalid_args(msg);
+       DBG("interator");
+       dbus_message_iter_recurse(&args, &opts);
+
+       ext = create_ext2(sender, path, uuid, destination, app_path, &opts);
+       if (!ext)
+               return btd_error_invalid_args(msg);
+#if 0
+       ext->id = g_dbus_add_disconnect_watch(conn, sender, ext_exited, ext,
+                                                                       NULL);
+#endif
+
+       return dbus_message_new_method_return(msg);
+}
+#endif
+
 static const GDBusMethodTable methods[] = {
        { GDBUS_METHOD("RegisterProfile",
                        GDBUS_ARGS({ "profile", "o"}, { "UUID", "s" },
@@ -2576,6 +2947,11 @@ static const GDBusMethodTable methods[] = {
                        GDBUS_ARGS({ "profile", "o"}, { "UUID", "s" },
                                                { "options", "a{sv}" }),
                        NULL, register_profile) },
+       { GDBUS_METHOD("RegisterProfile2",
+                       GDBUS_ARGS({"profile", "o"}, { "UUID", "s" },
+                                               {"destination", "s"}, {"path", "s"},
+                                               { "options", "a{sv}"}),
+                       NULL, register_profile2) },
 #endif
 
        { GDBUS_METHOD("UnregisterProfile", GDBUS_ARGS({ "profile", "o" }),
index 254d85e..cd3eb2c 100644 (file)
@@ -30,11 +30,9 @@ struct btd_service;
 struct btd_profile {
        const char *name;
        int priority;
-       uint16_t version;
 
        const char *local_uuid;
        const char *remote_uuid;
-       const char *auth_uuid;
 
        bool auto_connect;
 
@@ -74,5 +72,9 @@ bool btd_profile_add_custom_prop(const char *uuid, const char *type,
                                        void *user_data);
 bool btd_profile_remove_custom_prop(const char *uuid, const char *name);
 
+#ifdef __TIZEN_PATCH__
+gboolean ext_profile_is_registered_as_client_role(struct btd_profile *p);
+#endif
+
 void btd_profile_init(void);
 void btd_profile_cleanup(void);
index 70588c0..74eeb6a 100644 (file)
@@ -35,6 +35,9 @@
 
 #include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+
 #include "log.h"
 #include "adapter.h"
 #include "hcid.h"
index bca2496..413cf30 100644 (file)
 
 #include <errno.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
 #include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+
 #include "btio/btio.h"
 #include "log.h"
 #include "sdp-client.h"
index df36607..d8eb02f 100644 (file)
@@ -34,8 +34,8 @@
 
 #include <glib.h>
 
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 
 #include "sdp-xml.h"
 
index d6a2f73..80a4f44 100644 (file)
  *
  */
 
-
-#ifndef __SDP_XML_H
-#define __SDP_XML_H
-
-#include <bluetooth/sdp.h>
-
 void convert_sdp_record_to_xml(sdp_record_t *rec,
                void *user_data, void (*append_func) (void *, const char *));
 
 sdp_record_t *sdp_xml_parse_record(const char *data, int size);
-
-#endif /* __SDP_XML_H */
index 6f5577b..843b6d0 100644 (file)
 #endif
 
 #include <stdlib.h>
+#include <stdbool.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 
 #include "sdpd.h"
 #include "log.h"
index 3e58c22..1eefdce 100644 (file)
 #include <errno.h>
 #include <stdlib.h>
 #include <limits.h>
+#include <stdbool.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/l2cap.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 
 #include "src/shared/util.h"
 
index 015551d..e6b611a 100644 (file)
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <sys/stat.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
 #include <sys/un.h>
 
 #include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/l2cap.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+
 #include "log.h"
 #include "sdpd.h"
 
index a90b299..c3ee3eb 100644 (file)
 #include <stdlib.h>
 #include <assert.h>
 #include <sys/time.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include <stdbool.h>
 
 #include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+
 #include "src/shared/util.h"
 #include "sdpd.h"
 #include "log.h"
 
+#define MPSD_HFP_AG_A2DP_SRC_ANSWER_CALL_DURING_AUDIO          (1ULL << 0)
+#define MPSD_HFP_HF_A2DP_SNK_ANSWER_CALL_DURING_AUDIO          (1ULL << 1)
+#define MPSD_HFP_AG_A2DP_SRC_OUTGOING_CALL_DURING_AUDIO                (1ULL << 2)
+#define MPSD_HFP_HF_A2DP_SNK_OUTGOING_CALL_DURING_AUDIO                (1ULL << 3)
+#define MPSD_HFP_AG_A2DP_SRC_REJECT_CALL_DURING_AUDIO          (1ULL << 4)
+#define MPSD_HFP_HF_A2DP_SNK_SRC_REJECT_CALL_DURING_AUDIO      (1ULL << 5)
+#define MPSD_HFP_AG_A2DP_SRC_TERMINATE_CALL_DURING_AVP         (1ULL << 6)
+#define MPSD_HFP_HF_A2DP_SNK_TERMINATE_CALL_DURING_AVP         (1ULL << 7)
+#define MPSD_HFP_AG_A2DP_SRC_PRESS_PLAY_DURING_ACTIVE_CALL     (1ULL << 8)
+#define MPSD_HFP_HF_A2DP_SNK_PRESS_PLAY_DURING_ACTIVE_CALL     (1ULL << 9)
+#define MPSD_HFP_AG_A2DP_SRC_START_AUDIO_STREAM_AFTER_PLAY     (1ULL << 10)
+#define MPSD_HFP_HF_A2DP_SNK_START_AUDIO_STREAM_AFTER_PLAY     (1ULL << 11)
+#define MPSD_HFP_AG_A2DP_SRC_SUSPEND_AUDIO_STREAM_ON_PAUSE     (1ULL << 12)
+#define MPSD_HFP_HF_A2DP_SNK_SUSPEND_AUDIO_STREAM_ON_PAUSE     (1ULL << 13)
+#define MPSD_HFP_AG_DUN_GW_DATA_COMM_DURING_VOICE_CALL         (1ULL << 14)
+#define MPSD_HFP_HF_DUN_DT_DATA_COMM_DURING_VOICE_CALL         (1ULL << 15)
+#define MPSD_HFP_AG_DUN_GW_OUTGOING_CALL_DURING_DATA_COMM      (1ULL << 16)
+#define MPSD_HFP_HF_DUN_DT_OUTGOING_CALL_DURING_DATA_COMM      (1ULL << 17)
+#define MPSD_HFP_AG_DUN_GW_INCOMING_CALL_DURING_DATA_COMM      (1ULL << 18)
+#define MPSD_HFP_HF_DUN_DT_INCOMING_CALL_DURING_DATA_COMM      (1ULL << 19)
+#define MPSD_A2DP_SRC_DUN_GW_START_AUDIO_DURING_DATA_COMM      (1ULL << 20)
+#define MPSD_A2DP_SNK_DUN_DT_START_AUDIO_DURING_DATA_COMM      (1ULL << 21)
+#define MPSD_A2DP_SRC_DUN_GW_DATA_COMM_DURING_AUDIO_STREAM     (1ULL << 22)
+#define MPSD_A2DP_SNK_DUN_DT_DATA_COMM_DURING_AUDIO_STREAM     (1ULL << 23)
+#define MPSD_HFP_AG_DUN_GW_TERMINATE_CALL_DURING_DATA_COMM     (1ULL << 24)
+#define MPSD_HFP_HF_DUN_DT_TERMINATE_CALL_DURING_DATA_COMM     (1ULL << 25)
+#define MPSD_HFP_AG_PAN_NAP_DATA_COMM_DURING_VOICE_CALL                (1ULL << 26)
+#define MPSD_HFP_HF_PAN_PANU_DATA_COMM_DURING_VOICE_CALL       (1ULL << 27)
+#define MPSD_HFP_AG_PAN_NAP_OUTGOING_CALL_DURING_DATA_COMM     (1ULL << 28)
+#define MPSD_HFP_HF_PAN_PANU_OUTGOING_CALL_DURING_DATA_COMM    (1ULL << 29)
+#define MPSD_HFP_AG_PAN_NAP_INCOMING_CALL_DURING_DATA_COMM     (1ULL << 30)
+#define MPSD_HFP_HF_PAN_PANU_INCOMING_CALL_DURING_DATA_COMM    (1ULL << 31)
+#define MPSD_A2DP_SRC_PAN_NAP_START_AUDIO_DURING_DATA_COMM     (1ULL << 32)
+#define MPSD_A2DP_SNK_PAN_PANU_START_AUDIO_DURING_DATA_COMM    (1ULL << 33)
+#define MPSD_A2DP_SRC_PAN_NAP_DATA_COMM_DURING_AUDIO_STREAM    (1ULL << 34)
+#define MPSD_A2DP_SNK_PAN_PANU_DATA_COMM_DURING_AUDIO_STREAM   (1ULL << 35)
+#define MPSD_A2DP_SRC_PBAP_SRV_PB_DL_DURING_AUDIO_STREAM       (1ULL << 36)
+#define MPSD_A2DP_SNK_PBAP_CLI_PB_DL_DURING_AUDIO_STREAM       (1ULL << 37)
+
+#define MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_ANSWER_CALL_DURING_AUDIO (1ULL << 0)
+#define MPMD_A2DP_SRC_AVRCP_TG_ANSWER_CALL_DURING_AUDIO                (1ULL << 1)
+#define MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_OUTGOING_CALL_DURING_AUDIO (1ULL << 2)
+#define MPMD_A2DP_SRC_AVRCP_TG_OUTGOING_CALL_DURING_AUDIO      (1ULL << 3)
+#define MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_REJECT_CALL_DURING_AUDIO (1ULL << 4)
+#define MPMD_A2DP_SRC_AVRCP_TG_REJECT_CALL_DURING_AUDIO                (1ULL << 5)
+#define MPMD_HFP_AG_CALL_TERMINATION_DURING_AVP                        (1ULL << 6)
+#define MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_TERMINATION_DURING_AVP   (1ULL << 7)
+#define MPMD_A2DP_SRC_AVRCP_TG_TERMINATION_DURING_AVP          (1ULL << 8)
+#define MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_PLAY_DURING_CALL         (1ULL << 9)
+#define MPMD_A2DP_SRC_AVRCP_TG_PRESS_PLAY_DURING_CALL          (1ULL << 10)
+#define MPMD_AVRCP_CT_NO_A2DP_SNK_START_AUDIO_AFTER_PLAY       (1ULL << 11)
+#define MPMD_A2DP_SRC_AVRCP_TG_START_AUDIO_AFTER_PLAY          (1ULL << 12)
+#define MPMD_AVRCP_CT_NO_A2DP_SNK_SUSPEND_AUDIO_AFTER_PAUSE    (1ULL << 13)
+#define MPMD_A2DP_SRC_AVRCP_TG_SUSPEND_AUDIO_AFTER_PAUSE       (1ULL << 14)
+#define MPMD_A2DP_SRC_AVRCP_TG_START_AUDIO_DURING_DATA_COMM    (1ULL << 15)
+#define MPMD_A2DP_SNK_AVRCP_CT_DUN_DT_AUDIO_DURING_DATA_COMM   (1ULL << 16)
+#define MPMD_A2DP_SRC_AVRCP_TG_START_DATA_DURING_AUDIO         (1ULL << 17)
+#define MPMD_A2DP_SNK_AVRCP_CT_DUN_DT_START_DATA_DURING_AUDIO  (1ULL << 18)
+
+/* Note: in spec dependency bit position starts from 1 (bit 0 unused?) */
+#define MPS_DEPS_SNIFF_MODE_DURRING_STREAMING  (1ULL << 1)
+#define MPS_DEPS_GAVDP_REQUIREMENTS            (1ULL << 2)
+#define MPS_DEPS_DIS_CONNECTION_ORDER_BEHAVIOR (1ULL << 3)
+
+/*
+ * default MPS features are all disabled, will be updated if relevant service
+ * is (un)registered
+ */
+#define MPS_MPSD_DEFAULT_FEATURES 0
+#define MPS_MPMD_DEFAULT_FEATURES 0
+
+/*
+ * Those defines bits for all features that depend on specific profile and role.
+ * If profile is not supported then all those bits should not be set in record
+ */
+#define MPS_MPSD_HFP_AG (MPSD_HFP_AG_A2DP_SRC_ANSWER_CALL_DURING_AUDIO | \
+                       MPSD_HFP_AG_A2DP_SRC_OUTGOING_CALL_DURING_AUDIO | \
+                       MPSD_HFP_AG_A2DP_SRC_REJECT_CALL_DURING_AUDIO | \
+                       MPSD_HFP_AG_A2DP_SRC_TERMINATE_CALL_DURING_AVP | \
+                       MPSD_HFP_AG_A2DP_SRC_PRESS_PLAY_DURING_ACTIVE_CALL | \
+                       MPSD_HFP_AG_A2DP_SRC_START_AUDIO_STREAM_AFTER_PLAY | \
+                       MPSD_HFP_AG_DUN_GW_DATA_COMM_DURING_VOICE_CALL | \
+                       MPSD_HFP_AG_A2DP_SRC_SUSPEND_AUDIO_STREAM_ON_PAUSE | \
+                       MPSD_HFP_AG_DUN_GW_OUTGOING_CALL_DURING_DATA_COMM | \
+                       MPSD_HFP_AG_DUN_GW_INCOMING_CALL_DURING_DATA_COMM | \
+                       MPSD_HFP_AG_DUN_GW_TERMINATE_CALL_DURING_DATA_COMM | \
+                       MPSD_HFP_AG_PAN_NAP_DATA_COMM_DURING_VOICE_CALL | \
+                       MPSD_HFP_AG_PAN_NAP_OUTGOING_CALL_DURING_DATA_COMM | \
+                       MPSD_HFP_AG_PAN_NAP_INCOMING_CALL_DURING_DATA_COMM)
+
+#define MPS_MPSD_HFP_HF (MPSD_HFP_HF_A2DP_SNK_ANSWER_CALL_DURING_AUDIO | \
+                       MPSD_HFP_HF_A2DP_SNK_OUTGOING_CALL_DURING_AUDIO | \
+                       MPSD_HFP_HF_A2DP_SNK_SRC_REJECT_CALL_DURING_AUDIO | \
+                       MPSD_HFP_HF_A2DP_SNK_TERMINATE_CALL_DURING_AVP | \
+                       MPSD_HFP_HF_A2DP_SNK_PRESS_PLAY_DURING_ACTIVE_CALL | \
+                       MPSD_HFP_HF_A2DP_SNK_START_AUDIO_STREAM_AFTER_PLAY | \
+                       MPSD_HFP_HF_A2DP_SNK_SUSPEND_AUDIO_STREAM_ON_PAUSE | \
+                       MPSD_HFP_HF_DUN_DT_DATA_COMM_DURING_VOICE_CALL | \
+                       MPSD_HFP_HF_DUN_DT_OUTGOING_CALL_DURING_DATA_COMM | \
+                       MPSD_HFP_HF_DUN_DT_INCOMING_CALL_DURING_DATA_COMM | \
+                       MPSD_HFP_HF_DUN_DT_TERMINATE_CALL_DURING_DATA_COMM | \
+                       MPSD_HFP_HF_PAN_PANU_DATA_COMM_DURING_VOICE_CALL | \
+                       MPSD_HFP_HF_PAN_PANU_OUTGOING_CALL_DURING_DATA_COMM | \
+                       MPSD_HFP_HF_PAN_PANU_INCOMING_CALL_DURING_DATA_COMM)
+
+#define MPS_MPSD_A2DP_SRC (MPSD_HFP_AG_A2DP_SRC_ANSWER_CALL_DURING_AUDIO | \
+                       MPSD_HFP_AG_A2DP_SRC_OUTGOING_CALL_DURING_AUDIO | \
+                       MPSD_HFP_AG_A2DP_SRC_REJECT_CALL_DURING_AUDIO | \
+                       MPSD_HFP_AG_A2DP_SRC_TERMINATE_CALL_DURING_AVP | \
+                       MPSD_HFP_AG_A2DP_SRC_PRESS_PLAY_DURING_ACTIVE_CALL | \
+                       MPSD_HFP_AG_A2DP_SRC_START_AUDIO_STREAM_AFTER_PLAY | \
+                       MPSD_HFP_AG_A2DP_SRC_SUSPEND_AUDIO_STREAM_ON_PAUSE | \
+                       MPSD_A2DP_SRC_DUN_GW_START_AUDIO_DURING_DATA_COMM | \
+                       MPSD_A2DP_SRC_DUN_GW_DATA_COMM_DURING_AUDIO_STREAM | \
+                       MPSD_A2DP_SRC_PAN_NAP_START_AUDIO_DURING_DATA_COMM | \
+                       MPSD_A2DP_SRC_PAN_NAP_DATA_COMM_DURING_AUDIO_STREAM | \
+                       MPSD_A2DP_SRC_PBAP_SRV_PB_DL_DURING_AUDIO_STREAM)
+
+#define MPS_MPSD_A2DP_SNK (MPSD_HFP_HF_A2DP_SNK_ANSWER_CALL_DURING_AUDIO | \
+                       MPSD_HFP_HF_A2DP_SNK_OUTGOING_CALL_DURING_AUDIO | \
+                       MPSD_HFP_HF_A2DP_SNK_SRC_REJECT_CALL_DURING_AUDIO | \
+                       MPSD_HFP_HF_A2DP_SNK_TERMINATE_CALL_DURING_AVP | \
+                       MPSD_HFP_HF_A2DP_SNK_PRESS_PLAY_DURING_ACTIVE_CALL | \
+                       MPSD_HFP_HF_A2DP_SNK_START_AUDIO_STREAM_AFTER_PLAY | \
+                       MPSD_HFP_HF_A2DP_SNK_SUSPEND_AUDIO_STREAM_ON_PAUSE | \
+                       MPSD_A2DP_SNK_DUN_DT_START_AUDIO_DURING_DATA_COMM | \
+                       MPSD_A2DP_SNK_DUN_DT_DATA_COMM_DURING_AUDIO_STREAM | \
+                       MPSD_A2DP_SNK_PAN_PANU_START_AUDIO_DURING_DATA_COMM | \
+                       MPSD_A2DP_SNK_PAN_PANU_DATA_COMM_DURING_AUDIO_STREAM | \
+                       MPSD_A2DP_SNK_PBAP_CLI_PB_DL_DURING_AUDIO_STREAM)
+
+#define MPS_MPSD_AVRCP_CT MPS_MPSD_A2DP_SNK
+
+#define MPS_MPSD_AVRCP_TG MPS_MPSD_A2DP_SRC
+
+#define MPS_MPSD_DUN_GW (MPSD_HFP_AG_DUN_GW_DATA_COMM_DURING_VOICE_CALL | \
+                       MPSD_HFP_AG_DUN_GW_OUTGOING_CALL_DURING_DATA_COMM | \
+                       MPSD_HFP_AG_DUN_GW_INCOMING_CALL_DURING_DATA_COMM | \
+                       MPSD_A2DP_SRC_DUN_GW_START_AUDIO_DURING_DATA_COMM | \
+                       MPSD_A2DP_SRC_DUN_GW_DATA_COMM_DURING_AUDIO_STREAM | \
+                       MPSD_HFP_AG_DUN_GW_TERMINATE_CALL_DURING_DATA_COMM)
+
+#define MPS_MPSD_DUN_DT (MPSD_HFP_HF_DUN_DT_DATA_COMM_DURING_VOICE_CALL | \
+                       MPSD_HFP_HF_DUN_DT_OUTGOING_CALL_DURING_DATA_COMM | \
+                       MPSD_HFP_HF_DUN_DT_INCOMING_CALL_DURING_DATA_COMM | \
+                       MPSD_A2DP_SNK_DUN_DT_START_AUDIO_DURING_DATA_COMM | \
+                       MPSD_A2DP_SNK_DUN_DT_DATA_COMM_DURING_AUDIO_STREAM | \
+                       MPSD_HFP_HF_DUN_DT_TERMINATE_CALL_DURING_DATA_COMM)
+
+#define MPS_MPSD_PAN_NAP (MPSD_HFP_AG_PAN_NAP_DATA_COMM_DURING_VOICE_CALL | \
+                       MPSD_HFP_AG_PAN_NAP_OUTGOING_CALL_DURING_DATA_COMM | \
+                       MPSD_HFP_AG_PAN_NAP_INCOMING_CALL_DURING_DATA_COMM | \
+                       MPSD_A2DP_SRC_PAN_NAP_START_AUDIO_DURING_DATA_COMM | \
+                       MPSD_A2DP_SRC_PAN_NAP_DATA_COMM_DURING_AUDIO_STREAM)
+
+#define MPS_MPSD_PAN_PANU (MPSD_HFP_HF_PAN_PANU_DATA_COMM_DURING_VOICE_CALL | \
+                       MPSD_HFP_HF_PAN_PANU_OUTGOING_CALL_DURING_DATA_COMM | \
+                       MPSD_HFP_HF_PAN_PANU_INCOMING_CALL_DURING_DATA_COMM | \
+                       MPSD_A2DP_SNK_PAN_PANU_START_AUDIO_DURING_DATA_COMM | \
+                       MPSD_A2DP_SNK_PAN_PANU_DATA_COMM_DURING_AUDIO_STREAM)
+
+#define MPS_MPSD_PBAP_SRC MPSD_A2DP_SRC_PBAP_SRV_PB_DL_DURING_AUDIO_STREAM
+
+#define MPS_MPSD_PBAP_CLI MPSD_A2DP_SNK_PBAP_CLI_PB_DL_DURING_AUDIO_STREAM
+
+#define MPS_MPSD_ALL (MPS_MPSD_HFP_AG | MPS_MPSD_HFP_HF | \
+                       MPS_MPSD_A2DP_SRC | MPS_MPSD_A2DP_SNK | \
+                       MPS_MPSD_AVRCP_CT | MPS_MPSD_AVRCP_TG | \
+                       MPS_MPSD_DUN_GW | MPS_MPSD_DUN_DT | \
+                       MPS_MPSD_PAN_NAP | MPS_MPSD_PAN_PANU | \
+                       MPS_MPSD_PBAP_SRC | MPS_MPSD_PBAP_CLI)
+
+#define MPS_MPMD_HFP_AG MPMD_HFP_AG_CALL_TERMINATION_DURING_AVP
+
+#define MPS_MPMD_HFP_HF ( \
+               MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_ANSWER_CALL_DURING_AUDIO | \
+               MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_OUTGOING_CALL_DURING_AUDIO | \
+               MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_REJECT_CALL_DURING_AUDIO | \
+               MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_TERMINATION_DURING_AVP | \
+               MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_PLAY_DURING_CALL)
+
+#define MPS_MPMD_A2DP_SRC (MPMD_A2DP_SRC_AVRCP_TG_ANSWER_CALL_DURING_AUDIO | \
+                       MPMD_A2DP_SRC_AVRCP_TG_OUTGOING_CALL_DURING_AUDIO | \
+                       MPMD_A2DP_SRC_AVRCP_TG_REJECT_CALL_DURING_AUDIO | \
+                       MPMD_A2DP_SRC_AVRCP_TG_TERMINATION_DURING_AVP | \
+                       MPMD_A2DP_SRC_AVRCP_TG_PRESS_PLAY_DURING_CALL | \
+                       MPMD_A2DP_SRC_AVRCP_TG_START_AUDIO_AFTER_PLAY | \
+                       MPMD_A2DP_SRC_AVRCP_TG_SUSPEND_AUDIO_AFTER_PAUSE | \
+                       MPMD_A2DP_SRC_AVRCP_TG_START_AUDIO_DURING_DATA_COMM | \
+                       MPMD_A2DP_SRC_AVRCP_TG_START_DATA_DURING_AUDIO)
+
+#define MPS_MPMD_A2DP_SNK ( \
+               MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_ANSWER_CALL_DURING_AUDIO | \
+               MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_OUTGOING_CALL_DURING_AUDIO | \
+               MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_REJECT_CALL_DURING_AUDIO | \
+               MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_TERMINATION_DURING_AVP | \
+               MPMD_HFP_HF_A2DP_SNK_AVRCP_CT_PLAY_DURING_CALL | \
+               MPMD_A2DP_SNK_AVRCP_CT_DUN_DT_AUDIO_DURING_DATA_COMM | \
+               MPMD_A2DP_SNK_AVRCP_CT_DUN_DT_START_DATA_DURING_AUDIO)
+
+#define MPS_MPMD_AVRCP_CT MPS_MPMD_A2DP_SNK
+
+/* should be set only if CT is supported but SNK is not supported */
+#define MPS_MPMD_AVRCP_CT_ONLY ( \
+               MPMD_AVRCP_CT_NO_A2DP_SNK_START_AUDIO_AFTER_PLAY | \
+               MPMD_AVRCP_CT_NO_A2DP_SNK_SUSPEND_AUDIO_AFTER_PAUSE)
+
+#define MPS_MPMD_AVRCP_TG MPS_MPMD_A2DP_SRC
+
+#define MPS_MPMD_DUN_DT ( \
+               MPMD_A2DP_SNK_AVRCP_CT_DUN_DT_AUDIO_DURING_DATA_COMM | \
+               MPMD_A2DP_SNK_AVRCP_CT_DUN_DT_START_DATA_DURING_AUDIO)
+
+#define MPS_MPMD_ALL (MPS_MPMD_HFP_AG | MPS_MPMD_HFP_HF | MPS_MPMD_A2DP_SRC | \
+                       MPS_MPMD_A2DP_SNK | MPS_MPMD_AVRCP_CT | \
+                       MPS_MPMD_AVRCP_CT_ONLY | MPS_MPMD_AVRCP_TG | \
+                       MPS_MPMD_DUN_DT)
+
+/* Assume all dependencies are supported */
+#define MPS_DEFAULT_DEPS (MPS_DEPS_SNIFF_MODE_DURRING_STREAMING | \
+                       MPS_DEPS_GAVDP_REQUIREMENTS | \
+                       MPS_DEPS_DIS_CONNECTION_ORDER_BEHAVIOR)
+
 static sdp_record_t *server = NULL;
 static uint32_t fixed_dbts = 0;
 
@@ -55,6 +279,9 @@ static sdp_version_t sdpVnumArray[1] = {
 };
 static const int sdpServerVnumEntries = 1;
 
+static uint32_t mps_handle = 0;
+static bool mps_mpmd = false;
+
 /*
  * A simple function which returns the time of day in
  * seconds. Used for updating the service db state
@@ -235,6 +462,186 @@ void register_device_id(uint16_t source, uint16_t vendor,
        update_db_timestamp();
 }
 
+static bool class_supported(uint16_t class)
+{
+       sdp_list_t *list;
+       uuid_t uuid;
+
+       sdp_uuid16_create(&uuid, class);
+
+       for (list = sdp_get_record_list(); list; list = list->next) {
+               sdp_record_t *rec = list->data;
+
+               if (sdp_uuid_cmp(&rec->svclass, &uuid) == 0)
+                       return true;
+       }
+
+       return false;
+}
+
+static uint64_t mps_mpsd_features(void)
+{
+       uint64_t feat = MPS_MPSD_ALL;
+
+       if (!class_supported(HANDSFREE_AGW_SVCLASS_ID))
+               feat &= ~MPS_MPSD_HFP_AG;
+
+       if (!class_supported(HANDSFREE_SVCLASS_ID))
+               feat &= ~MPS_MPSD_HFP_HF;
+
+       if (!class_supported(AUDIO_SOURCE_SVCLASS_ID))
+               feat &= ~MPS_MPSD_A2DP_SRC;
+
+       if (!class_supported(AUDIO_SINK_SVCLASS_ID))
+               feat &= ~MPS_MPSD_A2DP_SNK;
+
+       if (!class_supported(AV_REMOTE_CONTROLLER_SVCLASS_ID))
+               feat &= ~MPS_MPSD_AVRCP_CT;
+
+       if (!class_supported(AV_REMOTE_TARGET_SVCLASS_ID))
+               feat &= ~MPS_MPSD_AVRCP_TG;
+
+       if (!class_supported(DIALUP_NET_SVCLASS_ID))
+               feat &= ~MPS_MPSD_DUN_GW;
+
+       /* TODO */
+       feat &= ~MPS_MPSD_DUN_DT;
+
+       if (!class_supported(NAP_SVCLASS_ID))
+               feat &= ~MPS_MPSD_PAN_NAP;
+
+       if (!class_supported(PANU_SVCLASS_ID))
+               feat &= ~MPS_MPSD_PAN_PANU;
+
+       if (!class_supported(PBAP_PSE_SVCLASS_ID))
+               feat &= ~MPS_MPSD_PBAP_SRC;
+
+       if (!class_supported(PBAP_PCE_SVCLASS_ID))
+               feat &= ~MPS_MPSD_PBAP_CLI;
+
+       return feat;
+}
+
+static uint64_t mps_mpmd_features(void)
+{
+       uint64_t feat = MPS_MPMD_ALL;
+
+       if (!class_supported(HANDSFREE_AGW_SVCLASS_ID))
+               feat &= ~MPS_MPMD_HFP_AG;
+
+       if (!class_supported(HANDSFREE_SVCLASS_ID))
+               feat &= ~MPS_MPMD_HFP_HF;
+
+       if (!class_supported(AUDIO_SOURCE_SVCLASS_ID))
+               feat &= ~MPS_MPMD_A2DP_SRC;
+
+       if (!class_supported(AUDIO_SINK_SVCLASS_ID))
+               feat &= ~MPS_MPMD_A2DP_SNK;
+       else
+               feat &= ~MPS_MPMD_AVRCP_CT_ONLY;
+
+       if (!class_supported(AV_REMOTE_CONTROLLER_SVCLASS_ID)) {
+               feat &= ~MPS_MPMD_AVRCP_CT;
+               feat &= ~MPS_MPMD_AVRCP_CT_ONLY;
+       }
+
+       if (!class_supported(AV_REMOTE_TARGET_SVCLASS_ID))
+               feat &= ~MPS_MPMD_AVRCP_TG;
+
+       /* TODO */
+       feat &= ~MPS_MPMD_DUN_DT;
+
+       return feat;
+}
+
+static sdp_record_t *mps_record(int mpmd)
+{
+       sdp_data_t *mpsd_features, *mpmd_features, *dependencies;
+       sdp_list_t *svclass_id, *pfseq, *root;
+       uuid_t root_uuid, svclass_uuid;
+       sdp_profile_desc_t profile;
+       sdp_record_t *record;
+       uint64_t mpsd_feat = MPS_MPSD_DEFAULT_FEATURES;
+       uint64_t mpmd_feat = MPS_MPMD_DEFAULT_FEATURES;
+       uint16_t deps = MPS_DEFAULT_DEPS;
+
+       record = sdp_record_alloc();
+       if (!record)
+               return NULL;
+
+       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+       root = sdp_list_append(NULL, &root_uuid);
+       sdp_set_browse_groups(record, root);
+       sdp_list_free(root, NULL);
+
+       sdp_uuid16_create(&svclass_uuid, MPS_SVCLASS_ID);
+       svclass_id = sdp_list_append(NULL, &svclass_uuid);
+       sdp_set_service_classes(record, svclass_id);
+       sdp_list_free(svclass_id, NULL);
+
+       sdp_uuid16_create(&profile.uuid, MPS_PROFILE_ID);
+       profile.version = 0x0100;
+       pfseq = sdp_list_append(NULL, &profile);
+       sdp_set_profile_descs(record, pfseq);
+       sdp_list_free(pfseq, NULL);
+
+       mpsd_features = sdp_data_alloc(SDP_UINT64, &mpsd_feat);
+       sdp_attr_add(record, SDP_ATTR_MPSD_SCENARIOS, mpsd_features);
+
+       if (mpmd) {
+               mpmd_features = sdp_data_alloc(SDP_UINT64, &mpmd_feat);
+               sdp_attr_add(record, SDP_ATTR_MPMD_SCENARIOS, mpmd_features);
+       }
+
+       dependencies = sdp_data_alloc(SDP_UINT16, &deps);
+       sdp_attr_add(record, SDP_ATTR_MPS_DEPENDENCIES, dependencies);
+
+       sdp_set_info_attr(record, "Multi Profile", 0, 0);
+
+       return record;
+}
+
+void register_mps(bool mpmd)
+{
+       sdp_record_t *record;
+
+       record = mps_record(mpmd);
+       if (!record)
+               return;
+
+       if (add_record_to_server(BDADDR_ANY, record) < 0) {
+               sdp_record_free(record);
+               return;
+       }
+
+       mps_handle = record->handle;
+       mps_mpmd = mpmd;
+}
+
+static void update_mps(void)
+{
+       sdp_record_t *rec;
+       sdp_data_t *data;
+       uint64_t mpsd_feat, mpmd_feat;
+
+       if (!mps_handle)
+               return;
+
+       rec = sdp_record_find(mps_handle);
+       if (!rec)
+               return;
+
+       mpsd_feat = mps_mpsd_features();
+       data = sdp_data_alloc(SDP_UINT64, &mpsd_feat);
+       sdp_attr_replace(rec, SDP_ATTR_MPSD_SCENARIOS, data);
+
+       if (mps_mpmd) {
+               mpmd_feat = mps_mpmd_features();
+               data = sdp_data_alloc(SDP_UINT64, &mpmd_feat);
+               sdp_attr_replace(rec, SDP_ATTR_MPMD_SCENARIOS, data);
+       }
+}
+
 int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec)
 {
        sdp_data_t *data;
@@ -272,6 +679,7 @@ int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec)
                DBG("Record pattern UUID %s", uuid);
        }
 
+       update_mps();
        update_db_timestamp();
 
        return 0;
@@ -291,8 +699,10 @@ int remove_record_from_server(uint32_t handle)
        if (!rec)
                return -ENOENT;
 
-       if (sdp_record_remove(handle) == 0)
+       if (sdp_record_remove(handle) == 0) {
+               update_mps();
                update_db_timestamp();
+       }
 
        sdp_record_free(rec);
 
index 6de0af7..49cd98a 100644 (file)
@@ -24,9 +24,6 @@
  *
  */
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-
 #ifdef SDP_DEBUG
 #include <syslog.h>
 #define SDPDBG(fmt, arg...) syslog(LOG_DEBUG, "%s: " fmt "\n", __func__ , ## arg)
@@ -58,6 +55,7 @@ void register_public_browse_group(void);
 void register_server_service(void);
 void register_device_id(uint16_t source, uint16_t vendor,
                                        uint16_t product, uint16_t version);
+void register_mps(bool mpmd);
 
 int record_sort(const void *r1, const void *r2);
 void sdp_svcdb_reset(void);
index 8ecb7d4..250f56e 100644 (file)
 #include <sys/ioctl.h>
 #include <errno.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
 #include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+
 #include "log.h"
 
 #include "adapter.h"
@@ -55,10 +54,6 @@ struct btd_service {
        void                    *user_data;
        btd_service_state_t     state;
        int                     err;
-       uint16_t                start_handle;
-       uint16_t                end_handle;
-       bool                    auto_connect;
-       bool                    blocked;
 };
 
 struct service_state_callback {
@@ -150,32 +145,11 @@ struct btd_service *service_create(struct btd_device *device,
        service->ref = 1;
        service->device = device; /* Weak ref */
        service->profile = profile;
-       service->auto_connect = profile->auto_connect;
        service->state = BTD_SERVICE_STATE_UNAVAILABLE;
 
        return service;
 }
 
-struct btd_service *service_create_gatt(struct btd_device *device,
-                                               struct btd_profile *profile,
-                                               uint16_t start_handle,
-                                               uint16_t end_handle)
-{
-       struct btd_service *service;
-
-       if (!start_handle || !end_handle || start_handle > end_handle)
-               return NULL;
-
-       service = service_create(device, profile);
-       if (!service)
-               return NULL;
-
-       service->start_handle = start_handle;
-       service->end_handle = end_handle;
-
-       return service;
-}
-
 int service_probe(struct btd_service *service)
 {
        char addr[18];
@@ -197,6 +171,7 @@ int service_probe(struct btd_service *service)
 
 void service_remove(struct btd_service *service)
 {
+       change_state(service, BTD_SERVICE_STATE_DISCONNECTED, -ECONNABORTED);
        change_state(service, BTD_SERVICE_STATE_UNAVAILABLE, 0);
        service->profile->device_remove(service);
        service->device = NULL;
@@ -330,67 +305,6 @@ int btd_service_get_error(const struct btd_service *service)
        return service->err;
 }
 
-uint16_t btd_service_get_version(const struct btd_service *service)
-{
-       const sdp_record_t *rec;
-       sdp_list_t *list;
-       sdp_profile_desc_t *desc;
-       uint16_t version;
-
-       if (!service->profile->version)
-               return 0;
-
-       rec = btd_device_get_record(service->device,
-                                       service->profile->remote_uuid);
-       if (rec == NULL)
-               return 0;
-
-       if (sdp_get_profile_descs(rec, &list) < 0)
-               return 0;
-
-       desc = list->data;
-       version = desc->version;
-       sdp_list_free(list, free);
-
-       return MIN(version, service->profile->version);
-}
-
-void btd_service_set_auto_connect(struct btd_service *service, bool value)
-{
-       service->auto_connect = value;
-}
-
-bool btd_service_get_auto_connect(const struct btd_service *service)
-{
-       return service->auto_connect;
-}
-
-void btd_service_set_blocked(struct btd_service *service, bool value)
-{
-       service->blocked = value;
-}
-
-bool btd_service_is_blocked(const struct btd_service *service)
-{
-       return service->blocked;
-}
-
-bool btd_service_get_gatt_handles(const struct btd_service *service,
-                                                       uint16_t *start_handle,
-                                                       uint16_t *end_handle)
-{
-       if (!service || !service->start_handle || !service->end_handle)
-               return false;
-
-       if (start_handle)
-               *start_handle = service->start_handle;
-
-       if (end_handle)
-               *end_handle = service->end_handle;
-
-       return true;
-}
-
 unsigned int btd_service_add_state_cb(btd_service_state_cb cb, void *user_data)
 {
        struct service_state_callback *state_cb;
index d092cc4..c1f97f6 100644 (file)
@@ -44,10 +44,6 @@ void btd_service_unref(struct btd_service *service);
 /* Service management functions used by the core */
 struct btd_service *service_create(struct btd_device *device,
                                                struct btd_profile *profile);
-struct btd_service *service_create_gatt(struct btd_device *device,
-                                               struct btd_profile *profile,
-                                               uint16_t start_handle,
-                                               uint16_t end_handle);
 
 int service_probe(struct btd_service *service);
 void service_remove(struct btd_service *service);
@@ -63,14 +59,6 @@ struct btd_device *btd_service_get_device(const struct btd_service *service);
 struct btd_profile *btd_service_get_profile(const struct btd_service *service);
 btd_service_state_t btd_service_get_state(const struct btd_service *service);
 int btd_service_get_error(const struct btd_service *service);
-uint16_t btd_service_get_version(const struct btd_service *service);
-void btd_service_set_auto_connect(struct btd_service *service, bool value);
-bool btd_service_get_auto_connect(const struct btd_service *service);
-void btd_service_set_blocked(struct btd_service *service, bool value);
-bool btd_service_is_blocked(const struct btd_service *service);
-bool btd_service_get_gatt_handles(const struct btd_service *service,
-                                                       uint16_t *start_handle,
-                                                       uint16_t *end_handle);
 
 unsigned int btd_service_add_state_cb(btd_service_state_cb cb,
                                                        void *user_data);
index 8b6d537..aa7f0da 100644 (file)
 
 #define BT_ATT_DEFAULT_LE_MTU  23
 #define BT_ATT_MAX_LE_MTU      517
+#define BT_ATT_MAX_VALUE_LEN   512
 
 /* ATT protocol opcodes */
-#define BT_ATT_OP_ERROR_RSP                    0x01
+#define BT_ATT_OP_ERROR_RSP                    0x01
 #define BT_ATT_OP_MTU_REQ                      0x02
 #define BT_ATT_OP_MTU_RSP                      0x03
 #define BT_ATT_OP_FIND_INFO_REQ                        0x04
index 4be0652..7671d67 100644 (file)
 #include "src/shared/queue.h"
 #include "src/shared/util.h"
 #include "src/shared/timeout.h"
+#include "lib/bluetooth.h"
 #include "lib/uuid.h"
 #include "src/shared/att.h"
+#include "src/shared/crypto.h"
 
 #define ATT_MIN_PDU_LEN                        1  /* At least 1 byte for the opcode. */
 #define ATT_OP_CMD_MASK                        0x40
 #define BT_ERROR_ALREADY_IN_PROGRESS           0xfe
 #define BT_ERROR_OUT_OF_RANGE                  0xff
 
+/* Length of signature in write signed packet */
+#define BT_ATT_SIGNATURE_LEN           12
+
 struct att_send_op;
 
 struct bt_att {
        int ref_count;
        int fd;
        struct io *io;
+       bool io_on_l2cap;
+       int io_sec_level;               /* Only used for non-L2CAP */
 
        struct queue *req_queue;        /* Queued ATT protocol requests */
        struct att_send_op *pending_req;
@@ -83,6 +90,17 @@ struct bt_att {
        bt_att_debug_func_t debug_callback;
        bt_att_destroy_func_t debug_destroy;
        void *debug_data;
+
+       struct bt_crypto *crypto;
+
+       struct sign_info *local_sign;
+       struct sign_info *remote_sign;
+};
+
+struct sign_info {
+       uint8_t key[16];
+       bt_att_counter_func_t counter;
+       void *user_data;
 };
 
 enum att_op_type {
@@ -260,15 +278,20 @@ static bool match_disconn_id(const void *a, const void *b)
        return disconn->id == id;
 }
 
-static bool encode_pdu(struct att_send_op *op, const void *pdu,
-                                               uint16_t length, uint16_t mtu)
+static bool encode_pdu(struct bt_att *att, struct att_send_op *op,
+                                       const void *pdu, uint16_t length)
 {
        uint16_t pdu_len = 1;
+       struct sign_info *sign = att->local_sign;
+       uint32_t sign_cnt;
+
+       if (sign && (op->opcode & ATT_OP_SIGNED_MASK))
+               pdu_len += BT_ATT_SIGNATURE_LEN;
 
        if (length && pdu)
                pdu_len += length;
 
-       if (pdu_len > mtu)
+       if (pdu_len > att->mtu)
                return false;
 
        op->len = pdu_len;
@@ -280,11 +303,28 @@ static bool encode_pdu(struct att_send_op *op, const void *pdu,
        if (pdu_len > 1)
                memcpy(op->pdu + 1, pdu, length);
 
-       return true;
+       if (!sign || !(op->opcode & ATT_OP_SIGNED_MASK))
+               return true;
+
+       if (!sign->counter(&sign_cnt, sign->user_data))
+               goto fail;
+
+       if ((bt_crypto_sign_att(att->crypto, sign->key, op->pdu, 1 + length,
+                               sign_cnt, &((uint8_t *) op->pdu)[1 + length])))
+               return true;
+
+       util_debug(att->debug_callback, att->debug_data,
+                                       "ATT unable to generate signature");
+
+fail:
+       free(op->pdu);
+       return false;
 }
 
-static struct att_send_op *create_att_send_op(uint8_t opcode, const void *pdu,
-                                               uint16_t length, uint16_t mtu,
+static struct att_send_op *create_att_send_op(struct bt_att *att,
+                                               uint8_t opcode,
+                                               const void *pdu,
+                                               uint16_t length,
                                                bt_att_response_func_t callback,
                                                void *user_data,
                                                bt_att_destroy_func_t destroy)
@@ -322,7 +362,7 @@ static struct att_send_op *create_att_send_op(uint8_t opcode, const void *pdu,
        op->destroy = destroy;
        op->user_data = user_data;
 
-       if (!encode_pdu(op, pdu, length, mtu)) {
+       if (!encode_pdu(att, op, pdu, length)) {
                free(op);
                return NULL;
        }
@@ -647,21 +687,6 @@ static bool opcode_match(uint8_t opcode, uint8_t test_opcode)
        return opcode == test_opcode;
 }
 
-static void notify_handler(void *data, void *user_data)
-{
-       struct att_notify *notify = data;
-       struct notify_data *not_data = user_data;
-
-       if (!opcode_match(notify->opcode, not_data->opcode))
-               return;
-
-       not_data->handler_found = true;
-
-       if (notify->callback)
-               notify->callback(not_data->opcode, not_data->pdu,
-                                       not_data->pdu_len, notify->user_data);
-}
-
 static void respond_not_supported(struct bt_att *att, uint8_t opcode)
 {
        uint8_t pdu[4];
@@ -675,31 +700,87 @@ static void respond_not_supported(struct bt_att *att, uint8_t opcode)
                                                                        NULL);
 }
 
+static bool handle_signed(struct bt_att *att, uint8_t opcode, uint8_t *pdu,
+                                                               ssize_t pdu_len)
+{
+       uint8_t *signature;
+       uint32_t sign_cnt;
+       struct sign_info *sign;
+
+       /* Check if there is enough data for a signature */
+       if (pdu_len < 2 + BT_ATT_SIGNATURE_LEN)
+               goto fail;
+
+       sign = att->remote_sign;
+       if (!sign)
+               goto fail;
+
+       signature = pdu + (pdu_len - BT_ATT_SIGNATURE_LEN);
+       sign_cnt = get_le32(signature);
+
+       /* Validate counter */
+       if (!sign->counter(&sign_cnt, sign->user_data))
+               goto fail;
+
+       /* Generate signature and verify it */
+       if (!bt_crypto_sign_att(att->crypto, sign->key, pdu,
+                               pdu_len - BT_ATT_SIGNATURE_LEN, sign_cnt,
+                               signature))
+               goto fail;
+
+       return true;
+
+fail:
+       util_debug(att->debug_callback, att->debug_data,
+                       "ATT failed to verify signature: 0x%02x", opcode);
+
+       return false;
+}
+
 static void handle_notify(struct bt_att *att, uint8_t opcode, uint8_t *pdu,
                                                                ssize_t pdu_len)
 {
-       struct notify_data data;
+       const struct queue_entry *entry;
+       bool found;
+
+       if (opcode & ATT_OP_SIGNED_MASK) {
+               if (!handle_signed(att, opcode, pdu, pdu_len))
+                       return;
+               pdu_len -= BT_ATT_SIGNATURE_LEN;
+       }
 
        bt_att_ref(att);
 
-       memset(&data, 0, sizeof(data));
-       data.opcode = opcode;
+       found = false;
+       entry = queue_get_entries(att->notify_list);
 
-       if (pdu_len > 0) {
-               data.pdu = pdu;
-               data.pdu_len = pdu_len;
-       }
+       while (entry) {
+               struct att_notify *notify = entry->data;
 
-       queue_foreach(att->notify_list, notify_handler, &data);
+               entry = entry->next;
 
-       bt_att_unref(att);
+               if (!opcode_match(notify->opcode, opcode))
+                       continue;
+
+               found = true;
+
+               if (notify->callback)
+                       notify->callback(opcode, pdu, pdu_len,
+                                                       notify->user_data);
+
+               /* callback could remove all entries from notify list */
+               if (queue_isempty(att->notify_list))
+                       break;
+       }
 
        /*
         * If this was a request and no handler was registered for it, respond
         * with "Not Supported"
         */
-       if (!data.handler_found && get_op_type(opcode) == ATT_OP_TYPE_REQ)
+       if (!found && get_op_type(opcode) == ATT_OP_TYPE_REQ)
                respond_not_supported(att, opcode);
+
+       bt_att_unref(att);
 }
 
 static bool can_read_data(struct io *io, void *user_data)
@@ -774,6 +855,31 @@ static bool can_read_data(struct io *io, void *user_data)
        return true;
 }
 
+static bool is_io_l2cap_based(int fd)
+{
+       int domain;
+       int proto;
+       int err;
+       socklen_t len;
+
+       domain = 0;
+       len = sizeof(domain);
+       err = getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &domain, &len);
+       if (err < 0)
+               return false;
+
+       if (domain != AF_BLUETOOTH)
+               return false;
+
+       proto = 0;
+       len = sizeof(proto);
+       err = getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &proto, &len);
+       if (err < 0)
+               return false;
+
+       return proto == BTPROTO_L2CAP;
+}
+
 static void bt_att_free(struct bt_att *att)
 {
        if (att->pending_req)
@@ -783,6 +889,7 @@ static void bt_att_free(struct bt_att *att)
                destroy_att_send_op(att->pending_ind);
 
        io_destroy(att->io);
+       bt_crypto_unref(att->crypto);
 
        queue_destroy(att->req_queue, NULL);
        queue_destroy(att->ind_queue, NULL);
@@ -796,6 +903,9 @@ static void bt_att_free(struct bt_att *att)
        if (att->debug_destroy)
                att->debug_destroy(att->debug_data);
 
+       free(att->local_sign);
+       free(att->remote_sign);
+
        free(att->buf);
 
        free(att);
@@ -823,6 +933,9 @@ struct bt_att *bt_att_new(int fd)
        if (!att->io)
                goto fail;
 
+       /* crypto is optional, if not available leave it NULL */
+       att->crypto = bt_crypto_new();
+
        att->req_queue = queue_new();
        if (!att->req_queue)
                goto fail;
@@ -849,6 +962,10 @@ struct bt_att *bt_att_new(int fd)
        if (!io_set_disconnect_handler(att->io, disconnect_cb, att, NULL))
                goto fail;
 
+       att->io_on_l2cap = is_io_l2cap_based(att->fd);
+       if (!att->io_on_l2cap)
+               att->io_sec_level = BT_SECURITY_LOW;
+
        return bt_att_ref(att);
 
 fail:
@@ -889,6 +1006,14 @@ bool bt_att_set_close_on_unref(struct bt_att *att, bool do_close)
        return io_set_close_on_destroy(att->io, do_close);
 }
 
+int bt_att_get_fd(struct bt_att *att)
+{
+       if (!att)
+               return -1;
+
+       return att->fd;
+}
+
 bool bt_att_set_debug(struct bt_att *att, bt_att_debug_func_t callback,
                                void *user_data, bt_att_destroy_func_t destroy)
 {
@@ -1010,8 +1135,8 @@ unsigned int bt_att_send(struct bt_att *att, uint8_t opcode,
        if (!att || !att->io)
                return 0;
 
-       op = create_att_send_op(opcode, pdu, length, att->mtu, callback,
-                                                       user_data, destroy);
+       op = create_att_send_op(att, opcode, pdu, length, callback, user_data,
+                                                               destroy);
        if (!op)
                return 0;
 
@@ -1226,3 +1351,78 @@ bool bt_att_unregister_all(struct bt_att *att)
 
        return true;
 }
+
+int bt_att_get_sec_level(struct bt_att *att)
+{
+       struct bt_security sec;
+       socklen_t len;
+
+       if (!att)
+               return -EINVAL;
+
+       if (!att->io_on_l2cap)
+               return att->io_sec_level;
+
+       memset(&sec, 0, sizeof(sec));
+       len = sizeof(sec);
+       if (getsockopt(att->fd, SOL_BLUETOOTH, BT_SECURITY, &sec, &len) < 0)
+               return -EIO;
+
+       return sec.level;
+}
+
+bool bt_att_set_sec_level(struct bt_att *att, int level)
+{
+       struct bt_security sec;
+
+       if (!att || level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH)
+               return false;
+
+       if (!att->io_on_l2cap) {
+               att->io_sec_level = level;
+               return true;
+       }
+
+       memset(&sec, 0, sizeof(sec));
+       sec.level = level;
+
+       if (setsockopt(att->fd, SOL_BLUETOOTH, BT_SECURITY, &sec,
+                                                       sizeof(sec)) < 0)
+               return false;
+
+       return true;
+}
+
+static bool sign_set_key(struct sign_info **sign, uint8_t key[16],
+                               bt_att_counter_func_t func, void *user_data)
+{
+       if (!(*sign)) {
+               *sign = new0(struct sign_info, 1);
+               if (!(*sign))
+                       return false;
+       }
+
+       (*sign)->counter = func;
+       (*sign)->user_data = user_data;
+       memcpy((*sign)->key, key, 16);
+
+       return true;
+}
+
+bool bt_att_set_local_key(struct bt_att *att, uint8_t sign_key[16],
+                               bt_att_counter_func_t func, void *user_data)
+{
+       if (!att)
+               return false;
+
+       return sign_set_key(&att->local_sign, sign_key, func, user_data);
+}
+
+bool bt_att_set_remote_key(struct bt_att *att, uint8_t sign_key[16],
+                               bt_att_counter_func_t func, void *user_data)
+{
+       if (!att)
+               return false;
+
+       return sign_set_key(&att->remote_sign, sign_key, func, user_data);
+}
index cd00a1e..a440aaf 100644 (file)
@@ -35,6 +35,8 @@ void bt_att_unref(struct bt_att *att);
 
 bool bt_att_set_close_on_unref(struct bt_att *att, bool do_close);
 
+int bt_att_get_fd(struct bt_att *att);
+
 typedef void (*bt_att_response_func_t)(uint8_t opcode, const void *pdu,
                                        uint16_t length, void *user_data);
 typedef void (*bt_att_notify_func_t)(uint8_t opcode, const void *pdu,
@@ -44,6 +46,7 @@ typedef void (*bt_att_debug_func_t)(const char *str, void *user_data);
 typedef void (*bt_att_timeout_func_t)(unsigned int id, uint8_t opcode,
                                                        void *user_data);
 typedef void (*bt_att_disconnect_func_t)(int err, void *user_data);
+typedef bool (*bt_att_counter_func_t)(uint32_t *sign_cnt, void *user_data);
 
 bool bt_att_set_debug(struct bt_att *att, bt_att_debug_func_t callback,
                                void *user_data, bt_att_destroy_func_t destroy);
@@ -79,3 +82,11 @@ unsigned int bt_att_register_disconnect(struct bt_att *att,
 bool bt_att_unregister_disconnect(struct bt_att *att, unsigned int id);
 
 bool bt_att_unregister_all(struct bt_att *att);
+
+int bt_att_get_sec_level(struct bt_att *att);
+bool bt_att_set_sec_level(struct bt_att *att, int level);
+
+bool bt_att_set_local_key(struct bt_att *att, uint8_t sign_key[16],
+                       bt_att_counter_func_t func, void *user_data);
+bool bt_att_set_remote_key(struct bt_att *att, uint8_t sign_key[16],
+                       bt_att_counter_func_t func, void *user_data);
index 7f77674..d5cd915 100644 (file)
 #include "src/shared/util.h"
 #include "src/shared/crypto.h"
 
-#ifndef PF_ALG
+#ifndef HAVE_LINUX_IF_ALG_H
+#ifndef HAVE_LINUX_TYPES_H
+typedef uint8_t __u8;
+typedef uint16_t __u16;
+typedef uint32_t __u32;
+#else
 #include <linux/types.h>
+#endif
 
 struct sockaddr_alg {
        __u16   salg_family;
index 33c4187..41be02b 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/types.h>
index 19059e8..cc48a02 100644 (file)
@@ -276,5 +276,10 @@ bool bt_gap_add_peer_irk(struct bt_gap *gap, uint8_t addr_type,
        memcpy(irk->addr, addr, 6);
        memcpy(irk->key, key, 16);
 
+       if (!queue_push_tail(gap->irk_list, irk)) {
+               free(irk);
+               return false;
+       }
+
        return true;
 }
index 6cf7e29..28d7ee5 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include "src/shared/att.h"
+#include "lib/bluetooth.h"
 #include "lib/uuid.h"
 #include "src/shared/gatt-helpers.h"
 #include "src/shared/util.h"
 #include "src/shared/gatt-db.h"
 #include "src/shared/gatt-client.h"
 
-#ifdef BLUEZ5_GATT_CLIENT
+#ifdef BLUEZ5_27_GATT_CLIENT
 #include "../log.h"
 #endif
 
 #include <assert.h>
 #include <limits.h>
+#include <sys/uio.h>
 
 #ifndef MAX
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
@@ -69,7 +71,8 @@ struct bt_gatt_client {
        bool in_init;
        bool ready;
 
-       /* Queue of long write requests. An error during "prepare write"
+       /*
+        * Queue of long write requests. An error during "prepare write"
         * requests can result in a cancel through "execute write". To prevent
         * cancelation of prepared writes to the wrong attribute and multiple
         * requests to the same attribute that may result in a corrupted final
@@ -84,15 +87,80 @@ struct bt_gatt_client {
        int next_reg_id;
        unsigned int disc_id, notify_id, ind_id;
 
-       /* Handles of the GATT Service and the Service Changed characteristic
+       /*
+        * Handles of the GATT Service and the Service Changed characteristic
         * value handle. These will have the value 0 if they are not present on
         * the remote peripheral.
         */
        unsigned int svc_chngd_ind_id;
+       bool svc_chngd_registered;
        struct queue *svc_chngd_queue;  /* Queued service changed events */
        bool in_svc_chngd;
+
+       /*
+        * List of pending read/write operations. For operations that span
+        * across multiple PDUs, this list provides a mapping from an operation
+        * id to an ATT request id.
+        */
+       struct queue *pending_requests;
+       unsigned int next_request_id;
+
+       struct bt_gatt_request *discovery_req;
+       unsigned int mtu_req_id;
 };
 
+struct request {
+       struct bt_gatt_client *client;
+       bool long_write;
+       bool removed;
+       int ref_count;
+       unsigned int id;
+       unsigned int att_id;
+       void *data;
+       void (*destroy)(void *);
+};
+
+static struct request *request_ref(struct request *req)
+{
+       __sync_fetch_and_add(&req->ref_count, 1);
+
+       return req;
+}
+
+static struct request *request_create(struct bt_gatt_client *client)
+{
+       struct request *req;
+
+       req = new0(struct request, 1);
+       if (!req)
+               return NULL;
+
+       if (client->next_request_id < 1)
+               client->next_request_id = 1;
+
+       queue_push_tail(client->pending_requests, req);
+       req->client = client;
+       req->id = client->next_request_id++;
+
+       return request_ref(req);
+}
+
+static void request_unref(void *data)
+{
+       struct request *req = data;
+
+       if (__sync_sub_and_fetch(&req->ref_count, 1))
+               return;
+
+       if (req->destroy)
+               req->destroy(req->data);
+
+       if (!req->removed)
+               queue_remove(req->client->pending_requests, req);
+
+       free(req);
+}
+
 struct notify_chrc {
        uint16_t value_handle;
        uint16_t ccc_handle;
@@ -108,11 +176,11 @@ struct notify_chrc {
 
 struct notify_data {
        struct bt_gatt_client *client;
-       bool invalid;
        unsigned int id;
+       unsigned int att_id;
        int ref_count;
        struct notify_chrc *chrc;
-       bt_gatt_client_notify_id_callback_t callback;
+       bt_gatt_client_register_callback_t callback;
        bt_gatt_client_notify_callback_t notify;
        void *user_data;
        bt_gatt_client_destroy_func_t destroy;
@@ -175,12 +243,6 @@ static struct notify_chrc *notify_chrc_create(struct bt_gatt_client *client,
                                                        &properties, NULL))
                        return NULL;
 
-       /* Find the CCC characteristic */
-       ccc = NULL;
-       gatt_db_service_foreach_desc(attr, find_ccc, &ccc);
-       if (!ccc)
-               return NULL;
-
        chrc = new0(struct notify_chrc, 1);
        if (!chrc)
                return NULL;
@@ -191,8 +253,17 @@ static struct notify_chrc *notify_chrc_create(struct bt_gatt_client *client,
                return NULL;
        }
 
+       /*
+        * Find the CCC characteristic. Some characteristics that allow
+        * notifications may not have a CCC descriptor. We treat these as
+        * automatically successful.
+        */
+       ccc = NULL;
+       gatt_db_service_foreach_desc(attr, find_ccc, &ccc);
+       if (ccc)
+               chrc->ccc_handle = gatt_db_attribute_get_handle(ccc);
+
        chrc->value_handle = value_handle;
-       chrc->ccc_handle = gatt_db_attribute_get_handle(ccc);
        chrc->properties = properties;
 
        queue_push_tail(client->notify_chrcs, chrc);
@@ -351,6 +422,15 @@ static void discovery_op_unref(void *data)
        discovery_op_free(op);
 }
 
+static void discovery_req_clear(struct bt_gatt_client *client)
+{
+       if (!client->discovery_req)
+               return;
+
+       bt_gatt_request_unref(client->discovery_req);
+       client->discovery_req = NULL;
+}
+
 static void discover_chrcs_cb(bool success, uint8_t att_ecode,
                                                struct bt_gatt_result *result,
                                                void *user_data);
@@ -368,6 +448,8 @@ static void discover_incl_cb(bool success, uint8_t att_ecode,
        char uuid_str[MAX_LEN_UUID_STR];
        unsigned int includes_count, i;
 
+       discovery_req_clear(client);
+
        if (!success) {
                if (att_ecode == BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND)
                        goto next;
@@ -444,11 +526,14 @@ next:
                        goto failed;
 
                op->cur_svc = attr;
-               if (bt_gatt_discover_characteristics(client->att,
+
+               client->discovery_req = bt_gatt_discover_characteristics(
+                                                       client->att,
                                                        start, end,
                                                        discover_chrcs_cb,
                                                        discovery_op_ref(op),
-                                                       discovery_op_unref))
+                                                       discovery_op_unref);
+               if (client->discovery_req)
                        return;
 
                util_debug(client->debug_callback, client->debug_data,
@@ -462,10 +547,15 @@ next:
        if (!gatt_db_attribute_get_service_handles(attr, &start, &end))
                goto failed;
 
-       if (bt_gatt_discover_included_services(client->att, start, end,
+       if (start == end)
+               goto next;
+
+       client->discovery_req = bt_gatt_discover_included_services(client->att,
+                                                       start, end,
                                                        discover_incl_cb,
                                                        discovery_op_ref(op),
-                                                       discovery_op_unref))
+                                                       discovery_op_unref);
+       if (client->discovery_req)
                return;
 
        util_debug(client->debug_callback, client->debug_data,
@@ -499,7 +589,8 @@ static bool discover_descs(struct discovery_op *op, bool *discovering)
        *discovering = false;
 
        while ((chrc_data = queue_pop_head(op->pending_chrcs))) {
-               attr = gatt_db_service_add_characteristic(op->cur_svc,
+               attr = gatt_db_service_insert_characteristic(op->cur_svc,
+                                                       chrc_data->value_handle,
                                                        &chrc_data->uuid, 0,
                                                        chrc_data->properties,
                                                        NULL, NULL, NULL);
@@ -511,18 +602,27 @@ static bool discover_descs(struct discovery_op *op, bool *discovering)
                                                        chrc_data->value_handle)
                        goto failed;
 
+#ifdef __TIZEN_PATCH__
+               if (chrc_data->value_handle >= chrc_data->end_handle) {
+                       free(chrc_data);
+                       continue;
+               }
+               desc_start = chrc_data->value_handle + 1;
+#else
                desc_start = chrc_data->value_handle + 1;
-
                if (desc_start > chrc_data->end_handle) {
                        free(chrc_data);
                        continue;
                }
+#endif
 
-               if (bt_gatt_discover_descriptors(client->att, desc_start,
+               client->discovery_req = bt_gatt_discover_descriptors(
+                                                       client->att, desc_start,
                                                        chrc_data->end_handle,
                                                        discover_descs_cb,
                                                        discovery_op_ref(op),
-                                                       discovery_op_unref)) {
+                                                       discovery_op_unref);
+               if (client->discovery_req) {
                        *discovering = true;
                        goto done;
                }
@@ -558,6 +658,8 @@ static void discover_descs_cb(bool success, uint8_t att_ecode,
        unsigned int desc_count;
        bool discovering;
 
+       discovery_req_clear(client);
+
        if (!success) {
                if (att_ecode == BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND) {
                        success = true;
@@ -586,8 +688,9 @@ static void discover_descs_cb(bool success, uint8_t att_ecode,
                                                "handle: 0x%04x, uuid: %s",
                                                handle, uuid_str);
 
-               attr = gatt_db_service_add_descriptor(op->cur_svc, &uuid, 0,
-                                                       NULL, NULL, NULL);
+               attr = gatt_db_service_insert_descriptor(op->cur_svc, handle,
+                                                       &uuid, 0, NULL, NULL,
+                                                       NULL);
                if (!attr)
                        goto failed;
 
@@ -595,13 +698,13 @@ static void discover_descs_cb(bool success, uint8_t att_ecode,
                        goto failed;
        }
 
+next:
        if (!discover_descs(op, &discovering))
                goto failed;
 
        if (discovering)
                return;
 
-next:
        /* Done with the current service */
        gatt_db_service_set_active(op->cur_svc, true);
 
@@ -612,12 +715,18 @@ next:
        if (!gatt_db_attribute_get_service_handles(attr, &start, &end))
                goto failed;
 
+       if (start == end)
+               goto next;
+
        /* Move on to the next service */
        op->cur_svc = attr;
-       if (bt_gatt_discover_characteristics(client->att, start, end,
+
+       client->discovery_req = bt_gatt_discover_characteristics(client->att,
+                                                       start, end,
                                                        discover_chrcs_cb,
                                                        discovery_op_ref(op),
-                                                       discovery_op_unref))
+                                                       discovery_op_unref);
+       if (client->discovery_req)
                return;
 
        util_debug(client->debug_callback, client->debug_data,
@@ -649,6 +758,8 @@ static void discover_chrcs_cb(bool success, uint8_t att_ecode,
        unsigned int chrc_count;
        bool discovering;
 
+       discovery_req_clear(client);
+
        if (!success) {
                if (att_ecode == BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND) {
                        success = true;
@@ -713,12 +824,18 @@ next:
        if (!gatt_db_attribute_get_service_handles(attr, &start, &end))
                goto failed;
 
+       if (start == end)
+               goto next;
+
        /* Move on to the next service */
        op->cur_svc = attr;
-       if (bt_gatt_discover_characteristics(client->att, start, end,
+
+       client->discovery_req = bt_gatt_discover_characteristics(client->att,
+                                                       start, end,
                                                        discover_chrcs_cb,
                                                        discovery_op_ref(op),
-                                                       discovery_op_unref))
+                                                       discovery_op_unref);
+       if (client->discovery_req)
                return;
 
        util_debug(client->debug_callback, client->debug_data,
@@ -746,6 +863,8 @@ static void discover_secondary_cb(bool success, uint8_t att_ecode,
        bt_uuid_t uuid;
        char uuid_str[MAX_LEN_UUID_STR];
 
+       discovery_req_clear(client);
+
        if (!success) {
                util_debug(client->debug_callback, client->debug_data,
                                        "Secondary service discovery failed."
@@ -810,10 +929,12 @@ next:
                goto done;
        }
 
-       if (bt_gatt_discover_included_services(client->att, start, end,
+       client->discovery_req = bt_gatt_discover_included_services(client->att,
+                                                       start, end,
                                                        discover_incl_cb,
                                                        discovery_op_ref(op),
-                                                       discovery_op_unref))
+                                                       discovery_op_unref);
+       if (client->discovery_req)
                return;
 
        util_debug(client->debug_callback, client->debug_data,
@@ -838,11 +959,13 @@ static void discover_primary_cb(bool success, uint8_t att_ecode,
        bt_uuid_t uuid;
        char uuid_str[MAX_LEN_UUID_STR];
 
+       discovery_req_clear(client);
+
        if (!success) {
                util_debug(client->debug_callback, client->debug_data,
                                        "Primary service discovery failed."
                                        " ATT ECODE: 0x%02x", att_ecode);
-               goto done;
+               goto secondary;
        }
 
        if (!result || !bt_gatt_iter_init(&iter, result)) {
@@ -875,12 +998,14 @@ static void discover_primary_cb(bool success, uint8_t att_ecode,
                queue_push_tail(op->pending_svcs, attr);
        }
 
+secondary:
        /* Discover secondary services */
-       if (bt_gatt_discover_secondary_services(client->att, NULL,
-                                                       op->start, op->end,
-                                                       discover_secondary_cb,
-                                                       discovery_op_ref(op),
-                                                       discovery_op_unref))
+       client->discovery_req = bt_gatt_discover_secondary_services(client->att,
+                                               NULL, op->start, op->end,
+                                               discover_secondary_cb,
+                                               discovery_op_ref(op),
+                                               discovery_op_unref);
+       if (client->discovery_req)
                return;
 
        util_debug(client->debug_callback, client->debug_data,
@@ -910,6 +1035,7 @@ static void exchange_mtu_cb(bool success, uint8_t att_ecode, void *user_data)
        struct bt_gatt_client *client = op->client;
 
        op->success = success;
+       client->mtu_req_id = 0;
 
        if (!success) {
                util_debug(client->debug_callback, client->debug_data,
@@ -932,10 +1058,12 @@ static void exchange_mtu_cb(bool success, uint8_t att_ecode, void *user_data)
                return;
        }
 
-       if (bt_gatt_discover_all_primary_services(client->att, NULL,
+       client->discovery_req = bt_gatt_discover_all_primary_services(
+                                                       client->att, NULL,
                                                        discover_primary_cb,
                                                        discovery_op_ref(op),
-                                                       discovery_op_unref))
+                                                       discovery_op_unref);
+       if (client->discovery_req)
                return;
 
        util_debug(client->debug_callback, client->debug_data,
@@ -953,7 +1081,7 @@ struct service_changed_op {
        uint16_t end_handle;
 };
 
-#ifdef BLUEZ5_GATT_CLIENT
+#ifdef BLUEZ5_27_GATT_CLIENT
 bool bt_gatt_discover_services(struct bt_gatt_client *client)
 {
        struct discovery_op *op;
@@ -966,7 +1094,7 @@ bool bt_gatt_discover_services(struct bt_gatt_client *client)
                return false;
 
        op->client = client;
-       gatt_client_clear_services(op->client);
+       gatt_db_unref(op->client->db);
 
        if (bt_gatt_discover_all_primary_services(client->att, NULL,
                                                        discover_primary_cb,
@@ -980,22 +1108,21 @@ bool bt_gatt_discover_services(struct bt_gatt_client *client)
 }
 #endif
 
-static void service_changed_reregister_cb(unsigned int id, uint16_t att_ecode,
-                                                               void *user_data)
+static void service_changed_reregister_cb(uint16_t att_ecode, void *user_data)
 {
        struct bt_gatt_client *client = user_data;
 
-       if (!id || att_ecode) {
+       if (!att_ecode) {
                util_debug(client->debug_callback, client->debug_data,
-                       "Failed to register handler for \"Service Changed\"");
+                       "Re-registered handler for \"Service Changed\" after "
+                       "change in GATT service");
+               client->svc_chngd_registered = true;
                return;
        }
 
-       client->svc_chngd_ind_id = id;
-
        util_debug(client->debug_callback, client->debug_data,
-               "Re-registered handler for \"Service Changed\" after change in "
-               "GATT service");
+               "Failed to register handler for \"Service Changed\"");
+       client->svc_chngd_ind_id = 0;
 }
 
 static void process_service_changed(struct bt_gatt_client *client,
@@ -1004,6 +1131,17 @@ static void process_service_changed(struct bt_gatt_client *client,
 static void service_changed_cb(uint16_t value_handle, const uint8_t *value,
                                        uint16_t length, void *user_data);
 
+static void get_first_attribute(struct gatt_db_attribute *attrib,
+                                                               void *user_data)
+{
+       struct gatt_db_attribute **stored = user_data;
+
+       if (*stored)
+               return;
+
+       *stored = attrib;
+}
+
 static void service_changed_complete(struct discovery_op *op, bool success,
                                                        uint8_t att_ecode)
 {
@@ -1011,9 +1149,8 @@ static void service_changed_complete(struct discovery_op *op, bool success,
        struct service_changed_op *next_sc_op;
        uint16_t start_handle = op->start;
        uint16_t end_handle = op->end;
-       struct gatt_db_attribute *attr;
+       struct gatt_db_attribute *attr = NULL;
        bt_uuid_t uuid;
-       struct queue *q;
 
        client->in_svc_chngd = false;
 
@@ -1039,30 +1176,23 @@ static void service_changed_complete(struct discovery_op *op, bool success,
                return;
        }
 
-       /* Check if the GATT service was among the changed services */
-       q = queue_new();
-       if (!q)
-               return;
-
        bt_uuid16_create(&uuid, SVC_CHNGD_UUID);
 
-       gatt_db_find_by_type(client->db, start_handle, end_handle, &uuid, q);
-       if (queue_isempty(q)) {
-               queue_destroy(q, NULL);
+       gatt_db_find_by_type(client->db, start_handle, end_handle, &uuid,
+                                               get_first_attribute, &attr);
+       if (!attr)
                return;
-       }
-
-       attr = queue_pop_head(q);
-       queue_destroy(q, NULL);
 
        /* The GATT service was modified. Re-register the handler for
         * indications from the "Service Changed" characteristic.
         */
-       if (bt_gatt_client_register_notify(client,
+       client->svc_chngd_registered = false;
+       client->svc_chngd_ind_id = bt_gatt_client_register_notify(client,
                                        gatt_db_attribute_get_handle(attr),
                                        service_changed_reregister_cb,
                                        service_changed_cb,
-                                       client, NULL))
+                                       client, NULL);
+       if (client->svc_chngd_ind_id)
                return;
 
        util_debug(client->debug_callback, client->debug_data,
@@ -1071,7 +1201,9 @@ static void service_changed_complete(struct discovery_op *op, bool success,
 
 static void service_changed_failure(struct discovery_op *op)
 {
-       gatt_db_clear_range(op->client->db, op->start, op->end);
+       struct bt_gatt_client *client = op->client;
+
+       gatt_db_clear_range(client->db, op->start, op->end);
 }
 
 static void process_service_changed(struct bt_gatt_client *client,
@@ -1097,20 +1229,22 @@ static void process_service_changed(struct bt_gatt_client *client,
        if (!op)
                goto fail;
 
-       if (bt_gatt_discover_primary_services(client->att, NULL,
-                                               start_handle, end_handle,
+       client->discovery_req = bt_gatt_discover_primary_services(client->att,
+                                               NULL, start_handle, end_handle,
                                                discover_primary_cb,
                                                discovery_op_ref(op),
-                                               discovery_op_unref)) {
+                                               discovery_op_unref);
+       if (client->discovery_req) {
                client->in_svc_chngd = true;
                return;
        }
 
+       discovery_op_free(op);
+
 fail:
        util_debug(client->debug_callback, client->debug_data,
                                        "Failed to initiate service discovery"
                                        " after Service Changed");
-       discovery_op_free(op);
 }
 
 static void service_changed_cb(uint16_t value_handle, const uint8_t *value,
@@ -1151,24 +1285,25 @@ static void service_changed_cb(uint16_t value_handle, const uint8_t *value,
        queue_push_tail(client->svc_chngd_queue, op);
 }
 
-static void service_changed_register_cb(unsigned int id, uint16_t att_ecode,
-                                                               void *user_data)
+static void service_changed_register_cb(uint16_t att_ecode, void *user_data)
 {
        bool success;
        struct bt_gatt_client *client = user_data;
 
-       if (!id || att_ecode) {
+       if (att_ecode) {
                util_debug(client->debug_callback, client->debug_data,
                        "Failed to register handler for \"Service Changed\"");
                success = false;
+               client->svc_chngd_ind_id = 0;
                goto done;
        }
 
-       client->svc_chngd_ind_id = id;
+       client->svc_chngd_registered = true;
        client->ready = true;
        success = true;
        util_debug(client->debug_callback, client->debug_data,
-                       "Registered handler for \"Service Changed\": %u", id);
+                       "Registered handler for \"Service Changed\": %u",
+                       client->svc_chngd_ind_id);
 
 done:
        notify_client_ready(client, success, att_ecode);
@@ -1178,50 +1313,44 @@ static void init_complete(struct discovery_op *op, bool success,
                                                        uint8_t att_ecode)
 {
        struct bt_gatt_client *client = op->client;
-       bool registered;
-       struct gatt_db_attribute *attr;
+       struct gatt_db_attribute *attr = NULL;
        bt_uuid_t uuid;
-       struct queue *q;
 
        client->in_init = false;
 
        if (!success)
                goto fail;
 
-       q = queue_new();
-       if (!q)
-               goto fail;
-
        bt_uuid16_create(&uuid, SVC_CHNGD_UUID);
 
-       gatt_db_find_by_type(client->db, 0x0001, 0xffff, &uuid, q);
-       if (queue_isempty(q)) {
-               queue_destroy(q, NULL);
+       gatt_db_find_by_type(client->db, 0x0001, 0xffff, &uuid,
+                                               get_first_attribute, &attr);
+       if (!attr) {
                client->ready = true;
                goto done;
        }
 
-       attr = queue_pop_head(q);
-       queue_destroy(q, NULL);
-
        /* Register an indication handler for the "Service Changed"
         * characteristic and report ready only if the handler is registered
         * successfully. Temporarily set "ready" to true so that we can register
         * the handler using the existing framework.
         */
        client->ready = true;
-       registered = bt_gatt_client_register_notify(client,
+       client->svc_chngd_ind_id = bt_gatt_client_register_notify(client,
                                        gatt_db_attribute_get_handle(attr),
                                        service_changed_register_cb,
                                        service_changed_cb,
                                        client, NULL);
-       client->ready = false;
 
-       if (registered)
+       if (!client->svc_chngd_registered)
+               client->ready = false;
+
+       if (client->svc_chngd_ind_id)
                return;
 
        util_debug(client->debug_callback, client->debug_data,
                        "Failed to register handler for \"Service Changed\"");
+       success = false;
 
 fail:
        util_debug(client->debug_callback, client->debug_data,
@@ -1235,7 +1364,9 @@ done:
 
 static void init_fail(struct discovery_op *op)
 {
-       gatt_db_clear(op->client->db);
+       struct bt_gatt_client *client = op->client;
+
+       gatt_db_clear(client->db);
 }
 
 static bool gatt_client_init(struct bt_gatt_client *client, uint16_t mtu)
@@ -1251,10 +1382,12 @@ static bool gatt_client_init(struct bt_gatt_client *client, uint16_t mtu)
                return false;
 
        /* Configure the MTU */
-       if (!bt_gatt_exchange_mtu(client->att, MAX(BT_ATT_DEFAULT_LE_MTU, mtu),
-                                                       exchange_mtu_cb,
-                                                       discovery_op_ref(op),
-                                                       discovery_op_unref)) {
+       client->mtu_req_id = bt_gatt_exchange_mtu(client->att,
+                                               MAX(BT_ATT_DEFAULT_LE_MTU, mtu),
+                                               exchange_mtu_cb,
+                                               discovery_op_ref(op),
+                                               discovery_op_unref);
+       if (!client->mtu_req_id) {
                discovery_op_free(op);
                return false;
        }
@@ -1276,24 +1409,15 @@ static void complete_notify_request(void *data)
        /* Increment the per-characteristic ref count of notify handlers */
        __sync_fetch_and_add(&notify_data->chrc->notify_count, 1);
 
-       /* Add the handler to the bt_gatt_client's general list */
-       queue_push_tail(notify_data->client->notify_list,
-                                               notify_data_ref(notify_data));
-
-       /* Assign an ID to the handler and notify the caller that it was
-        * successfully registered.
-        */
-       if (notify_data->client->next_reg_id < 1)
-               notify_data->client->next_reg_id = 1;
-
-       notify_data->id = notify_data->client->next_reg_id++;
-       notify_data->callback(notify_data->id, 0, notify_data->user_data);
+       notify_data->att_id = 0;
+       notify_data->callback(0, notify_data->user_data);
 }
 
 static bool notify_data_write_ccc(struct notify_data *notify_data, bool enable,
                                                bt_att_response_func_t callback)
 {
        uint8_t pdu[4];
+       unsigned int att_id;
 
        assert(notify_data->chrc->ccc_handle);
        memset(pdu, 0, sizeof(pdu));
@@ -1313,13 +1437,13 @@ static bool notify_data_write_ccc(struct notify_data *notify_data, bool enable,
                        return false;
        }
 
-       notify_data->chrc->ccc_write_id = bt_att_send(notify_data->client->att,
-                                               BT_ATT_OP_WRITE_REQ,
-                                               pdu, sizeof(pdu),
-                                               callback,
-                                               notify_data, notify_data_unref);
+       att_id = bt_att_send(notify_data->client->att, BT_ATT_OP_WRITE_REQ,
+                                               pdu, sizeof(pdu), callback,
+                                               notify_data_ref(notify_data),
+                                               notify_data_unref);
+       notify_data->chrc->ccc_write_id = notify_data->att_id = att_id;
 
-       return !!notify_data->chrc->ccc_write_id;
+       return !!att_id;
 }
 
 static uint8_t process_error(const void *pdu, uint16_t length)
@@ -1352,7 +1476,8 @@ static void enable_ccc_callback(uint8_t opcode, const void *pdu,
                 * the next one in the queue. If there was an error sending the
                 * write request, then just move on to the next queued entry.
                 */
-               notify_data->callback(0, att_ecode, notify_data->user_data);
+               queue_remove(notify_data->client->notify_list, notify_data);
+               notify_data->callback(att_ecode, notify_data->user_data);
 
                while ((notify_data = queue_pop_head(
                                        notify_data->chrc->reg_notify_queue))) {
@@ -1401,12 +1526,24 @@ static void complete_unregister_notify(void *data)
 {
        struct notify_data *notify_data = data;
 
-       if (__sync_sub_and_fetch(&notify_data->chrc->notify_count, 1)) {
-               notify_data_unref(notify_data);
-               return;
+       /*
+        * If a procedure to enable the CCC is still pending, then cancel it and
+        * return.
+        */
+       if (notify_data->att_id) {
+               bt_att_cancel(notify_data->client->att, notify_data->att_id);
+               goto done;
        }
 
-       notify_data_write_ccc(notify_data, false, disable_ccc_callback);
+       if (__sync_sub_and_fetch(&notify_data->chrc->notify_count, 1) ||
+                                               !notify_data->chrc->ccc_handle)
+               goto done;
+
+       if (notify_data_write_ccc(notify_data, false, disable_ccc_callback))
+               return;
+
+done:
+       notify_data_unref(notify_data);
 }
 
 static void notify_handler(void *data, void *user_data)
@@ -1424,6 +1561,10 @@ static void notify_handler(void *data, void *user_data)
        if (pdu_data->length > 2)
                value = pdu_data->pdu + 2;
 
+       /*
+        * Even if the notify data has a pending ATT request to write to the
+        * CCC, there is really no reason not to notify the handlers.
+        */
        if (notify_data->notify)
                notify_data->notify(value_handle, value, pdu_data->length - 2,
                                                        notify_data->user_data);
@@ -1450,10 +1591,22 @@ static void notify_cb(uint8_t opcode, const void *pdu, uint16_t length,
        bt_gatt_client_unref(client);
 }
 
-static void long_write_op_unref(void *data);
+static void notify_data_cleanup(void *data)
+{
+       struct notify_data *notify_data = data;
+
+       if (notify_data->att_id)
+               bt_att_cancel(notify_data->client->att, notify_data->att_id);
+
+       notify_data_unref(notify_data);
+}
 
 static void bt_gatt_client_free(struct bt_gatt_client *client)
 {
+       bt_gatt_client_cancel_all(client);
+
+       queue_destroy(client->notify_list, notify_data_cleanup);
+
        if (client->ready_destroy)
                client->ready_destroy(client->ready_data);
 
@@ -1470,9 +1623,9 @@ static void bt_gatt_client_free(struct bt_gatt_client *client)
        gatt_db_unref(client->db);
 
        queue_destroy(client->svc_chngd_queue, free);
-       queue_destroy(client->long_write_queue, long_write_op_unref);
-       queue_destroy(client->notify_list, notify_data_unref);
+       queue_destroy(client->long_write_queue, request_unref);
        queue_destroy(client->notify_chrcs, notify_chrc_free);
+       queue_destroy(client->pending_requests, request_unref);
 
        free(client);
 }
@@ -1528,6 +1681,10 @@ struct bt_gatt_client *bt_gatt_client_new(struct gatt_db *db,
        if (!client->notify_chrcs)
                goto fail;
 
+       client->pending_requests = queue_new();
+       if (!client->pending_requests)
+               goto fail;
+
        client->notify_id = bt_att_register(att, BT_ATT_OP_HANDLE_VAL_NOT,
                                                notify_cb, client, NULL);
        if (!client->notify_id)
@@ -1638,6 +1795,101 @@ uint16_t bt_gatt_client_get_mtu(struct bt_gatt_client *client)
        return bt_att_get_mtu(client->att);
 }
 
+static bool match_req_id(const void *a, const void *b)
+{
+       const struct request *req = a;
+       unsigned int id = PTR_TO_UINT(b);
+
+       return req->id == id;
+}
+
+static void cancel_long_write_cb(uint8_t opcode, const void *pdu, uint16_t len,
+                                                               void *user_data)
+{
+       /* Do nothing */
+}
+
+bool bt_gatt_client_cancel(struct bt_gatt_client *client, unsigned int id)
+{
+       struct request *req;
+       uint8_t pdu = 0x00;
+
+       if (!client || !id || !client->att)
+               return false;
+
+       req = queue_remove_if(client->pending_requests, match_req_id,
+                                                       UINT_TO_PTR(id));
+       if (!req)
+               return false;
+
+       req->removed = true;
+
+       if (!bt_att_cancel(client->att, req->att_id) && !req->long_write)
+               return false;
+
+       /* If this was a long-write, we need to abort all prepared writes */
+       if (!req->long_write)
+               return true;
+
+       if (!req->att_id)
+               queue_remove(client->long_write_queue, req);
+       else
+               bt_att_send(client->att, BT_ATT_OP_EXEC_WRITE_REQ,
+                                                       &pdu, sizeof(pdu),
+                                                       cancel_long_write_cb,
+                                                       NULL, NULL);
+
+       if (queue_isempty(client->long_write_queue))
+               client->in_long_write = false;
+
+       return true;
+}
+
+static void cancel_request(void *data)
+{
+       struct request *req = data;
+       uint8_t pdu = 0x00;
+
+       req->removed = true;
+
+       if (!req->long_write) {
+               bt_att_cancel(req->client->att, req->att_id);
+               return;
+       }
+
+       if (!req->att_id)
+               queue_remove(req->client->long_write_queue, req);
+
+       if (queue_isempty(req->client->long_write_queue))
+               req->client->in_long_write = false;
+
+       bt_att_send(req->client->att, BT_ATT_OP_EXEC_WRITE_REQ,
+                                                       &pdu, sizeof(pdu),
+                                                       cancel_long_write_cb,
+                                                       NULL, NULL);
+
+       bt_att_cancel(req->client->att, req->att_id);
+}
+
+bool bt_gatt_client_cancel_all(struct bt_gatt_client *client)
+{
+       if (!client || !client->att)
+               return false;
+
+       queue_remove_all(client->pending_requests, NULL, NULL, cancel_request);
+
+       if (client->discovery_req) {
+               bt_gatt_request_cancel(client->discovery_req);
+               bt_gatt_request_unref(client->discovery_req);
+               client->discovery_req = NULL;
+       }
+
+       if (client->mtu_req_id)
+               bt_att_cancel(client->att, client->mtu_req_id);
+
+       return true;
+}
+
 struct read_op {
        bt_gatt_client_read_callback_t callback;
        void *user_data;
@@ -1657,7 +1909,8 @@ static void destroy_read_op(void *data)
 static void read_cb(uint8_t opcode, const void *pdu, uint16_t length,
                                                                void *user_data)
 {
-       struct read_op *op = user_data;
+       struct request *req = user_data;
+       struct read_op *op = req->data;
        bool success;
        uint8_t att_ecode = 0;
        const uint8_t *value = NULL;
@@ -1684,42 +1937,56 @@ done:
                op->callback(success, att_ecode, value, length, op->user_data);
 }
 
-bool bt_gatt_client_read_value(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_read_value(struct bt_gatt_client *client,
                                        uint16_t value_handle,
                                        bt_gatt_client_read_callback_t callback,
                                        void *user_data,
                                        bt_gatt_client_destroy_func_t destroy)
 {
+       struct request *req;
        struct read_op *op;
        uint8_t pdu[2];
 
        if (!client)
-               return false;
+               return 0;
 
        op = new0(struct read_op, 1);
        if (!op)
-               return false;
+               return 0;
+
+       req = request_create(client);
+       if (!req) {
+               free(op);
+               return 0;
+       }
 
        op->callback = callback;
        op->user_data = user_data;
        op->destroy = destroy;
 
+       req->data = op;
+       req->destroy = destroy_read_op;
+
        put_le16(value_handle, pdu);
 
-       if (!bt_att_send(client->att, BT_ATT_OP_READ_REQ, pdu, sizeof(pdu),
-                                                       read_cb, op,
-                                                       destroy_read_op)) {
-               free(op);
-               return false;
+       req->att_id = bt_att_send(client->att, BT_ATT_OP_READ_REQ,
+                                                       pdu, sizeof(pdu),
+                                                       read_cb, req,
+                                                       request_unref);
+       if (!req->att_id) {
+               op->destroy = NULL;
+               request_unref(req);
+               return 0;
        }
 
-       return true;
+       return req->id;
 }
 
 static void read_multiple_cb(uint8_t opcode, const void *pdu, uint16_t length,
                                                                void *user_data)
 {
-       struct read_op *op = user_data;
+       struct request *req = user_data;
+       struct read_op *op = req->data;
        uint8_t att_ecode;
        bool success;
 
@@ -1742,157 +2009,109 @@ static void read_multiple_cb(uint8_t opcode, const void *pdu, uint16_t length,
                op->callback(success, att_ecode, pdu, length, op->user_data);
 }
 
-bool bt_gatt_client_read_multiple(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_read_multiple(struct bt_gatt_client *client,
                                        uint16_t *handles, uint8_t num_handles,
                                        bt_gatt_client_read_callback_t callback,
                                        void *user_data,
                                        bt_gatt_client_destroy_func_t destroy)
 {
        uint8_t pdu[num_handles * 2];
+       struct request *req;
        struct read_op *op;
        int i;
 
        if (!client)
-               return false;
+               return 0;
 
        if (num_handles < 2)
-               return false;
+               return 0;
 
        if (num_handles * 2 > bt_att_get_mtu(client->att) - 1)
-               return false;
+               return 0;
 
        op = new0(struct read_op, 1);
        if (!op)
-               return false;
+               return 0;
+
+       req = request_create(client);
+       if (!req) {
+               free(op);
+               return 0;
+       }
 
        op->callback = callback;
        op->user_data = user_data;
        op->destroy = destroy;
 
+       req->data = op;
+       req->destroy = destroy_read_op;
+
        for (i = 0; i < num_handles; i++)
                put_le16(handles[i], pdu + (2 * i));
 
-       if (!bt_att_send(client->att, BT_ATT_OP_READ_MULT_REQ, pdu, sizeof(pdu),
-                               read_multiple_cb, op, destroy_read_op)) {
-               free(op);
-               return false;
+       req->att_id = bt_att_send(client->att, BT_ATT_OP_READ_MULT_REQ,
+                                                       pdu, sizeof(pdu),
+                                                       read_multiple_cb, req,
+                                                       request_unref);
+       if (!req->att_id) {
+               op->destroy = NULL;
+               request_unref(req);
+               return 0;
        }
 
-       return true;
+       return req->id;
 }
 
 struct read_long_op {
        struct bt_gatt_client *client;
        int ref_count;
        uint16_t value_handle;
-       size_t orig_offset;
-       size_t offset;
-       struct queue *blobs;
+       uint16_t offset;
+       struct iovec iov;
        bt_gatt_client_read_callback_t callback;
        void *user_data;
        bt_gatt_client_destroy_func_t destroy;
 };
 
-struct blob {
-       uint8_t *data;
-       uint16_t offset;
-       uint16_t length;
-};
-
-static struct blob *create_blob(const uint8_t *data, uint16_t len,
-                                                               uint16_t offset)
-{
-       struct blob *blob;
-
-       blob = new0(struct blob, 1);
-       if (!blob)
-               return NULL;
-
-       blob->data = malloc(len);
-       if (!blob->data) {
-               free(blob);
-               return NULL;
-       }
-
-       memcpy(blob->data, data, len);
-       blob->length = len;
-       blob->offset = offset;
-
-       return blob;
-}
-
-static void destroy_blob(void *data)
-{
-       struct blob *blob = data;
-
-       free(blob->data);
-       free(blob);
-}
-
-static struct read_long_op *read_long_op_ref(struct read_long_op *op)
-{
-       __sync_fetch_and_add(&op->ref_count, 1);
-
-       return op;
-}
-
-static void read_long_op_unref(void *data)
+static void destroy_read_long_op(void *data)
 {
        struct read_long_op *op = data;
 
-       if (__sync_sub_and_fetch(&op->ref_count, 1))
-               return;
-
        if (op->destroy)
                op->destroy(op->user_data);
 
-       queue_destroy(op->blobs, destroy_blob);
-
+       free(op->iov.iov_base);
        free(op);
 }
 
-static void append_blob(void *data, void *user_data)
-{
-       struct blob *blob = data;
-       uint8_t *value = user_data;
-
-       memcpy(value + blob->offset, blob->data, blob->length);
-}
-
-static void complete_read_long_op(struct read_long_op *op, bool success,
-                                                       uint8_t att_ecode)
+static bool append_chunk(struct read_long_op *op, const uint8_t *data,
+                                                               uint16_t len)
 {
-       uint8_t *value = NULL;
-       uint16_t length = 0;
+       void *buf;
 
-       if (!success)
-               goto done;
-
-       length = op->offset - op->orig_offset;
+       /* Truncate if the data would exceed maximum length */
+       if (op->offset + len > BT_ATT_MAX_VALUE_LEN)
+               len = BT_ATT_MAX_VALUE_LEN - op->offset;
 
-       if (!length)
-               goto done;
+       buf = realloc(op->iov.iov_base, op->iov.iov_len + len);
+       if (!buf)
+               return false;
 
-       value = malloc(length);
-       if (!value) {
-               success = false;
-               goto done;
-       }
+       op->iov.iov_base = buf;
 
-       queue_foreach(op->blobs, append_blob, value - op->orig_offset);
+       memcpy(op->iov.iov_base + op->iov.iov_len, data, len);
 
-done:
-       if (op->callback)
-               op->callback(success, att_ecode, value, length, op->user_data);
+       op->iov.iov_len += len;
+       op->offset += len;
 
-       free(value);
+       return true;
 }
 
 static void read_long_cb(uint8_t opcode, const void *pdu,
                                        uint16_t length, void *user_data)
 {
-       struct read_long_op *op = user_data;
-       struct blob *blob;
+       struct request *req = user_data;
+       struct read_long_op *op = req->data;
        bool success;
        uint8_t att_ecode = 0;
 
@@ -1910,15 +2129,12 @@ static void read_long_cb(uint8_t opcode, const void *pdu,
        if (!length)
                goto success;
 
-       blob = create_blob(pdu, length, op->offset);
-       if (!blob) {
+       if (!append_chunk(op, pdu, length)) {
                success = false;
                goto done;
        }
 
-       queue_push_tail(op->blobs, blob);
-       op->offset += length;
-       if (op->offset > UINT16_MAX)
+       if (op->offset >= BT_ATT_MAX_VALUE_LEN)
                goto success;
 
        if (length >= bt_att_get_mtu(op->client->att) - 1) {
@@ -1927,14 +2143,16 @@ static void read_long_cb(uint8_t opcode, const void *pdu,
                put_le16(op->value_handle, pdu);
                put_le16(op->offset, pdu + 2);
 
-               if (bt_att_send(op->client->att, BT_ATT_OP_READ_BLOB_REQ,
+               req->att_id = bt_att_send(op->client->att,
+                                                       BT_ATT_OP_READ_BLOB_REQ,
                                                        pdu, sizeof(pdu),
                                                        read_long_cb,
-                                                       read_long_op_ref(op),
-                                                       read_long_op_unref))
+                                                       request_ref(req),
+                                                       request_unref);
+               if (req->att_id)
                        return;
 
-               read_long_op_unref(op);
+               request_unref(req);
                success = false;
                goto done;
        }
@@ -1943,76 +2161,100 @@ success:
        success = true;
 
 done:
-       complete_read_long_op(op, success, att_ecode);
+       if (op->callback)
+               op->callback(success, att_ecode, op->iov.iov_base,
+                                               op->iov.iov_len, op->user_data);
 }
 
-bool bt_gatt_client_read_long_value(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_read_long_value(struct bt_gatt_client *client,
                                        uint16_t value_handle, uint16_t offset,
                                        bt_gatt_client_read_callback_t callback,
                                        void *user_data,
                                        bt_gatt_client_destroy_func_t destroy)
 {
+       struct request *req;
        struct read_long_op *op;
        uint8_t pdu[4];
 
        if (!client)
-               return false;
+               return 0;
 
        op = new0(struct read_long_op, 1);
        if (!op)
-               return false;
+               return 0;
 
-       op->blobs = queue_new();
-       if (!op->blobs) {
+       req = request_create(client);
+       if (!req) {
                free(op);
-               return false;
+               return 0;
        }
 
        op->client = client;
        op->value_handle = value_handle;
-       op->orig_offset = offset;
        op->offset = offset;
        op->callback = callback;
        op->user_data = user_data;
        op->destroy = destroy;
 
+       req->data = op;
+       req->destroy = destroy_read_long_op;
+
        put_le16(value_handle, pdu);
        put_le16(offset, pdu + 2);
 
-       if (!bt_att_send(client->att, BT_ATT_OP_READ_BLOB_REQ, pdu, sizeof(pdu),
-                                                       read_long_cb,
-                                                       read_long_op_ref(op),
-                                                       read_long_op_unref)) {
-               queue_destroy(op->blobs, free);
-               free(op);
-               return false;
+       req->att_id = bt_att_send(client->att, BT_ATT_OP_READ_BLOB_REQ,
+                                                       pdu, sizeof(pdu),
+                                                       read_long_cb, req,
+                                                       request_unref);
+       if (!req->att_id) {
+               op->destroy = NULL;
+               request_unref(req);
+               return 0;
        }
 
-       return true;
+       return req->id;
 }
 
-bool bt_gatt_client_write_without_response(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_write_without_response(
+                                       struct bt_gatt_client *client,
                                        uint16_t value_handle,
                                        bool signed_write,
                                        const uint8_t *value, uint16_t length) {
        uint8_t pdu[2 + length];
+       struct request *req;
+       int security;
+       uint8_t op;
 
        if (!client)
                return 0;
 
-       /* TODO: Support this once bt_att_send supports signed writes. */
-       if (signed_write)
+       req = request_create(client);
+       if (!req)
                return 0;
 
+       /* Only use signed write if unencrypted */
+       if (signed_write) {
+               security = bt_att_get_sec_level(client->att);
+               op = security > BT_SECURITY_LOW ?  BT_ATT_OP_WRITE_CMD :
+                                               BT_ATT_OP_SIGNED_WRITE_CMD;
+       } else
+               op = BT_ATT_OP_WRITE_CMD;
+
        put_le16(value_handle, pdu);
        memcpy(pdu + 2, value, length);
 
-       return bt_att_send(client->att, BT_ATT_OP_WRITE_CMD, pdu, sizeof(pdu),
-                                                       NULL, NULL, NULL);
+       req->att_id = bt_att_send(client->att, op, pdu, sizeof(pdu), NULL, req,
+                                                               request_unref);
+       if (!req->att_id) {
+               request_unref(req);
+               return 0;
+       }
+
+       return req->id;
 }
 
 struct write_op {
-       bt_gatt_result_callback_t callback;
+       bt_gatt_client_callback_t callback;
        void *user_data;
        bt_gatt_destroy_func_t destroy;
 };
@@ -2030,7 +2272,8 @@ static void destroy_write_op(void *data)
 static void write_cb(uint8_t opcode, const void *pdu, uint16_t length,
                                                                void *user_data)
 {
-       struct write_op *op = user_data;
+       struct request *req = user_data;
+       struct write_op *op = req->data;
        bool success = true;
        uint8_t att_ecode = 0;
 
@@ -2048,43 +2291,55 @@ done:
                op->callback(success, att_ecode, op->user_data);
 }
 
-bool bt_gatt_client_write_value(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_write_value(struct bt_gatt_client *client,
                                        uint16_t value_handle,
                                        const uint8_t *value, uint16_t length,
                                        bt_gatt_client_callback_t callback,
                                        void *user_data,
                                        bt_gatt_client_destroy_func_t destroy)
 {
+       struct request *req;
        struct write_op *op;
        uint8_t pdu[2 + length];
 
        if (!client)
-               return false;
+               return 0;
 
        op = new0(struct write_op, 1);
        if (!op)
-               return false;
+               return 0;
+
+       req = request_create(client);
+       if (!req) {
+               free(op);
+               return 0;
+       }
 
        op->callback = callback;
        op->user_data = user_data;
        op->destroy = destroy;
 
+       req->data = op;
+       req->destroy = destroy_write_op;
+
        put_le16(value_handle, pdu);
        memcpy(pdu + 2, value, length);
 
-       if (!bt_att_send(client->att, BT_ATT_OP_WRITE_REQ, pdu, sizeof(pdu),
-                                                       write_cb, op,
-                                                       destroy_write_op)) {
-               free(op);
-               return false;
+       req->att_id = bt_att_send(client->att, BT_ATT_OP_WRITE_REQ,
+                                                       pdu, sizeof(pdu),
+                                                       write_cb, req,
+                                                       request_unref);
+       if (!req->att_id) {
+               op->destroy = NULL;
+               request_unref(req);
+               return 0;
        }
 
-       return true;
+       return req->id;
 }
 
 struct long_write_op {
        struct bt_gatt_client *client;
-       int ref_count;
        bool reliable;
        bool success;
        uint8_t att_ecode;
@@ -2100,20 +2355,10 @@ struct long_write_op {
        bt_gatt_client_destroy_func_t destroy;
 };
 
-static struct long_write_op *long_write_op_ref(struct long_write_op *op)
-{
-       __sync_fetch_and_add(&op->ref_count, 1);
-
-       return op;
-}
-
-static void long_write_op_unref(void *data)
+static void long_write_op_free(void *data)
 {
        struct long_write_op *op = data;
 
-       if (__sync_sub_and_fetch(&op->ref_count, 1))
-               return;
-
        if (op->destroy)
                op->destroy(op->user_data);
 
@@ -2123,11 +2368,12 @@ static void long_write_op_unref(void *data)
 
 static void prepare_write_cb(uint8_t opcode, const void *pdu, uint16_t length,
                                                        void *user_data);
-static void complete_write_long_op(struct long_write_op *op, bool success,
+static void complete_write_long_op(struct request *req, bool success,
                                        uint8_t att_ecode, bool reliable_error);
 
-static void handle_next_prep_write(struct long_write_op *op)
+static void handle_next_prep_write(struct request *req)
 {
+       struct long_write_op *op = req->data;
        bool success = true;
        uint8_t *pdu;
 
@@ -2141,12 +2387,13 @@ static void handle_next_prep_write(struct long_write_op *op)
        put_le16(op->offset + op->index, pdu + 2);
        memcpy(pdu + 4, op->value + op->index, op->cur_length);
 
-       if (!bt_att_send(op->client->att, BT_ATT_OP_PREP_WRITE_REQ,
+       req->att_id = bt_att_send(op->client->att, BT_ATT_OP_PREP_WRITE_REQ,
                                                        pdu, op->cur_length + 4,
                                                        prepare_write_cb,
-                                                       long_write_op_ref(op),
-                                                       long_write_op_unref)) {
-               long_write_op_unref(op);
+                                                       request_ref(req),
+                                                       request_unref);
+       if (!req->att_id) {
+               request_unref(req);
                success = false;
        }
 
@@ -2160,34 +2407,36 @@ static void handle_next_prep_write(struct long_write_op *op)
                return;
 
 done:
-       complete_write_long_op(op, success, 0, false);
+       complete_write_long_op(req, success, 0, false);
 }
 
 static void start_next_long_write(struct bt_gatt_client *client)
 {
-       struct long_write_op *op;
+       struct request *req;
 
        if (queue_isempty(client->long_write_queue)) {
                client->in_long_write = false;
                return;
        }
 
-       op = queue_pop_head(client->long_write_queue);
-       if (!op)
+       req  = queue_pop_head(client->long_write_queue);
+       if (!req)
                return;
 
-       handle_next_prep_write(op);
+       handle_next_prep_write(req);
 
-       /* send_next_prep_write adds an extra ref. Unref here to clean up if
+       /*
+        * send_next_prep_write adds an extra ref. Unref here to clean up if
         * necessary, since we also added a ref before pushing to the queue.
         */
-       long_write_op_unref(op);
+       request_unref(req);
 }
 
 static void execute_write_cb(uint8_t opcode, const void *pdu, uint16_t length,
                                                                void *user_data)
 {
-       struct long_write_op *op = user_data;
+       struct request *req = user_data;
+       struct long_write_op *op = req->data;
        bool success = op->success;
        uint8_t att_ecode = op->att_ecode;
 
@@ -2204,9 +2453,10 @@ static void execute_write_cb(uint8_t opcode, const void *pdu, uint16_t length,
        start_next_long_write(op->client);
 }
 
-static void complete_write_long_op(struct long_write_op *op, bool success,
+static void complete_write_long_op(struct request *req, bool success,
                                        uint8_t att_ecode, bool reliable_error)
 {
+       struct long_write_op *op = req->data;
        uint8_t pdu;
 
        op->success = success;
@@ -2218,14 +2468,16 @@ static void complete_write_long_op(struct long_write_op *op, bool success,
        else
                pdu = 0x00;  /* Cancel */
 
-       if (bt_att_send(op->client->att, BT_ATT_OP_EXEC_WRITE_REQ,
+       req->att_id = bt_att_send(op->client->att, BT_ATT_OP_EXEC_WRITE_REQ,
                                                        &pdu, sizeof(pdu),
                                                        execute_write_cb,
-                                                       long_write_op_ref(op),
-                                                       long_write_op_unref))
+                                                       request_ref(req),
+                                                       request_unref);
+       if (req->att_id)
                return;
 
-       long_write_op_unref(op);
+
+       request_unref(req);
        success = false;
 
        if (op->callback)
@@ -2237,7 +2489,8 @@ static void complete_write_long_op(struct long_write_op *op, bool success,
 static void prepare_write_cb(uint8_t opcode, const void *pdu, uint16_t length,
                                                                void *user_data)
 {
-       struct long_write_op *op = user_data;
+       struct request *req = user_data;
+       struct long_write_op *op = req->data;
        bool success = true;
        bool reliable_error = false;
        uint8_t att_ecode = 0;
@@ -2288,15 +2541,15 @@ static void prepare_write_cb(uint8_t opcode, const void *pdu, uint16_t length,
                op->index = next_index;
                op->cur_length = MIN(op->length - op->index,
                                        bt_att_get_mtu(op->client->att) - 5);
-               handle_next_prep_write(op);
+               handle_next_prep_write(req);
                return;
        }
 
 done:
-       complete_write_long_op(op, success, att_ecode, reliable_error);
+       complete_write_long_op(req, success, att_ecode, reliable_error);
 }
 
-bool bt_gatt_client_write_long_value(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_write_long_value(struct bt_gatt_client *client,
                                bool reliable,
                                uint16_t value_handle, uint16_t offset,
                                const uint8_t *value, uint16_t length,
@@ -2304,30 +2557,37 @@ bool bt_gatt_client_write_long_value(struct bt_gatt_client *client,
                                void *user_data,
                                bt_gatt_client_destroy_func_t destroy)
 {
+       struct request *req;
        struct long_write_op *op;
        uint8_t *pdu;
-       bool status;
 
        if (!client)
-               return false;
+               return 0;
 
        if ((size_t)(length + offset) > UINT16_MAX)
-               return false;
+               return 0;
 
        /* Don't allow writing a 0-length value using this procedure. The
         * upper-layer should use bt_gatt_write_value for that instead.
         */
        if (!length || !value)
-               return false;
+               return 0;
 
        op = new0(struct long_write_op, 1);
        if (!op)
-               return false;
+               return 0;
 
        op->value = malloc(length);
        if (!op->value) {
                free(op);
-               return false;
+               return 0;
+       }
+
+       req = request_create(client);
+       if (!req) {
+               free(op->value);
+               free(op);
+               return 0;
        }
 
        memcpy(op->value, value, length);
@@ -2342,40 +2602,41 @@ bool bt_gatt_client_write_long_value(struct bt_gatt_client *client,
        op->user_data = user_data;
        op->destroy = destroy;
 
+       req->data = op;
+       req->destroy = long_write_op_free;
+       req->long_write = true;
+
        if (client->in_long_write) {
-               queue_push_tail(client->long_write_queue,
-                                               long_write_op_ref(op));
-               return true;
+               queue_push_tail(client->long_write_queue, req);
+               return req->id;
        }
 
        pdu = malloc(op->cur_length + 4);
        if (!pdu) {
                free(op->value);
                free(op);
-               return false;
+               return 0;
        }
 
        put_le16(value_handle, pdu);
        put_le16(offset, pdu + 2);
        memcpy(pdu + 4, op->value, op->cur_length);
 
-       status = bt_att_send(client->att, BT_ATT_OP_PREP_WRITE_REQ,
+       req->att_id = bt_att_send(client->att, BT_ATT_OP_PREP_WRITE_REQ,
                                                        pdu, op->cur_length + 4,
-                                                       prepare_write_cb,
-                                                       long_write_op_ref(op),
-                                                       long_write_op_unref);
-
+                                                       prepare_write_cb, req,
+                                                       request_unref);
        free(pdu);
 
-       if (!status) {
-               free(op->value);
-               free(op);
-               return false;
+       if (!req->att_id) {
+               op->destroy = NULL;
+               request_unref(req);
+               return 0;
        }
 
        client->in_long_write = true;
 
-       return true;
+       return req->id;
 }
 
 static bool match_notify_chrc_value_handle(const void *a, const void *b)
@@ -2386,9 +2647,9 @@ static bool match_notify_chrc_value_handle(const void *a, const void *b)
        return chrc->value_handle == value_handle;
 }
 
-bool bt_gatt_client_register_notify(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_register_notify(struct bt_gatt_client *client,
                                uint16_t chrc_value_handle,
-                               bt_gatt_client_notify_id_callback_t callback,
+                               bt_gatt_client_register_callback_t callback,
                                bt_gatt_client_notify_callback_t notify,
                                void *user_data,
                                bt_gatt_client_destroy_func_t destroy)
@@ -2397,10 +2658,10 @@ bool bt_gatt_client_register_notify(struct bt_gatt_client *client,
        struct notify_chrc *chrc = NULL;
 
        if (!client || !client->db || !chrc_value_handle || !callback)
-               return false;
+               return 0;
 
        if (!bt_gatt_client_is_ready(client) || client->in_svc_chngd)
-               return false;
+               return 0;
 
        /* Check if a characteristic ref count has been started already */
        chrc = queue_find(client->notify_chrcs, match_notify_chrc_value_handle,
@@ -2413,17 +2674,16 @@ bool bt_gatt_client_register_notify(struct bt_gatt_client *client,
                 */
                chrc = notify_chrc_create(client, chrc_value_handle);
                if (!chrc)
-                       return false;
-
+                       return 0;
        }
 
        /* Fail if we've hit the maximum allowed notify sessions */
        if (chrc->notify_count == INT_MAX)
-               return false;
+               return 0;
 
        notify_data = new0(struct notify_data, 1);
        if (!notify_data)
-               return false;
+               return 0;
 
        notify_data->client = client;
        notify_data->ref_count = 1;
@@ -2433,30 +2693,40 @@ bool bt_gatt_client_register_notify(struct bt_gatt_client *client,
        notify_data->user_data = user_data;
        notify_data->destroy = destroy;
 
+       /* Add the handler to the bt_gatt_client's general list */
+       queue_push_tail(client->notify_list, notify_data);
+
+       /* Assign an ID to the handler. */
+       if (client->next_reg_id < 1)
+               client->next_reg_id = 1;
+
+       notify_data->id = client->next_reg_id++;
+
        /*
         * If a write to the CCC descriptor is in progress, then queue this
         * request.
         */
        if (chrc->ccc_write_id) {
                queue_push_tail(chrc->reg_notify_queue, notify_data);
-               return true;
+               return notify_data->id;
        }
 
        /*
         * If the ref count is not zero, then notifications are already enabled.
         */
-       if (chrc->notify_count > 0) {
+       if (chrc->notify_count > 0 || !chrc->ccc_handle) {
                complete_notify_request(notify_data);
-               return true;
+               return notify_data->id;
        }
 
        /* Write to the CCC descriptor */
        if (!notify_data_write_ccc(notify_data, true, enable_ccc_callback)) {
+               queue_remove(client->notify_list, notify_data);
                free(notify_data);
-               return false;
+               return 0;
        }
 
-       return true;
+       return notify_data->id;
 }
 
 bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client,
@@ -2478,3 +2748,20 @@ bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client,
        complete_unregister_notify(notify_data);
        return true;
 }
+
+bool bt_gatt_client_set_sec_level(struct bt_gatt_client *client,
+                                                               int level)
+{
+       if (!client)
+               return false;
+
+       return bt_att_set_sec_level(client->att, level);
+}
+
+int bt_gatt_client_get_sec_level(struct bt_gatt_client *client)
+{
+       if (!client)
+               return -1;
+
+       return bt_att_get_sec_level(client->att);
+}
index 4ea4af3..819019e 100644 (file)
@@ -49,8 +49,7 @@ typedef void (*bt_gatt_client_write_long_callback_t)(bool success,
 typedef void (*bt_gatt_client_notify_callback_t)(uint16_t value_handle,
                                        const uint8_t *value, uint16_t length,
                                        void *user_data);
-typedef void (*bt_gatt_client_notify_id_callback_t)(unsigned int id,
-                                                       uint16_t att_ecode,
+typedef void (*bt_gatt_client_register_callback_t)(uint16_t att_ecode,
                                                        void *user_data);
 typedef void (*bt_gatt_client_service_changed_callback_t)(uint16_t start_handle,
                                                        uint16_t end_handle,
@@ -72,33 +71,37 @@ bool bt_gatt_client_set_debug(struct bt_gatt_client *client,
 
 uint16_t bt_gatt_client_get_mtu(struct bt_gatt_client *client);
 
-bool bt_gatt_client_read_value(struct bt_gatt_client *client,
+bool bt_gatt_client_cancel(struct bt_gatt_client *client, unsigned int id);
+bool bt_gatt_client_cancel_all(struct bt_gatt_client *client);
+
+unsigned int bt_gatt_client_read_value(struct bt_gatt_client *client,
                                        uint16_t value_handle,
                                        bt_gatt_client_read_callback_t callback,
                                        void *user_data,
                                        bt_gatt_client_destroy_func_t destroy);
-bool bt_gatt_client_read_long_value(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_read_long_value(struct bt_gatt_client *client,
                                        uint16_t value_handle, uint16_t offset,
                                        bt_gatt_client_read_callback_t callback,
                                        void *user_data,
                                        bt_gatt_client_destroy_func_t destroy);
-bool bt_gatt_client_read_multiple(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_read_multiple(struct bt_gatt_client *client,
                                        uint16_t *handles, uint8_t num_handles,
                                        bt_gatt_client_read_callback_t callback,
                                        void *user_data,
                                        bt_gatt_client_destroy_func_t destroy);
 
-bool bt_gatt_client_write_without_response(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_write_without_response(
+                                       struct bt_gatt_client *client,
                                        uint16_t value_handle,
                                        bool signed_write,
                                        const uint8_t *value, uint16_t length);
-bool bt_gatt_client_write_value(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_write_value(struct bt_gatt_client *client,
                                        uint16_t value_handle,
                                        const uint8_t *value, uint16_t length,
                                        bt_gatt_client_callback_t callback,
                                        void *user_data,
                                        bt_gatt_client_destroy_func_t destroy);
-bool bt_gatt_client_write_long_value(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_write_long_value(struct bt_gatt_client *client,
                                bool reliable,
                                uint16_t value_handle, uint16_t offset,
                                const uint8_t *value, uint16_t length,
@@ -106,14 +109,18 @@ bool bt_gatt_client_write_long_value(struct bt_gatt_client *client,
                                void *user_data,
                                bt_gatt_client_destroy_func_t destroy);
 
-bool bt_gatt_client_register_notify(struct bt_gatt_client *client,
+unsigned int bt_gatt_client_register_notify(struct bt_gatt_client *client,
                                uint16_t chrc_value_handle,
-                               bt_gatt_client_notify_id_callback_t callback,
+                               bt_gatt_client_register_callback_t callback,
                                bt_gatt_client_notify_callback_t notify,
                                void *user_data,
                                bt_gatt_client_destroy_func_t destroy);
 bool bt_gatt_client_unregister_notify(struct bt_gatt_client *client,
                                                        unsigned int id);
-#ifdef BLUEZ5_GATT_CLIENT
+
+bool bt_gatt_client_set_sec_level(struct bt_gatt_client *client, int level);
+int bt_gatt_client_get_sec_level(struct bt_gatt_client *client);
+
+#ifdef BLUEZ5_27_GATT_CLIENT
 bool bt_gatt_discover_services(struct bt_gatt_client *client);
 #endif
index bb60904..2b2090c 100644 (file)
 #include <stdbool.h>
 #include <errno.h>
 
+#include "lib/bluetooth.h"
 #include "lib/uuid.h"
 #include "src/shared/util.h"
 #include "src/shared/queue.h"
 #include "src/shared/timeout.h"
+#include "src/shared/att.h"
 #include "src/shared/gatt-db.h"
 
 #ifndef MAX
@@ -36,7 +38,7 @@
 
 #define MAX_CHAR_DECL_VALUE_LEN 19
 #define MAX_INCLUDED_VALUE_LEN 6
-#define ATTRIBUTE_TIMEOUT 1000
+#define ATTRIBUTE_TIMEOUT 5000
 
 static const bt_uuid_t primary_service_uuid = { .type = BT_UUID16,
                                        .value.u16 = GATT_PRIM_SVC_UUID };
@@ -102,24 +104,61 @@ struct gatt_db_attribute {
 struct gatt_db_service {
        struct gatt_db *db;
        bool active;
+       bool claimed;
        uint16_t num_handles;
        struct gatt_db_attribute **attributes;
 };
 
+static void pending_read_result(struct pending_read *p, int err,
+                                       const uint8_t *data, size_t length)
+{
+       if (p->timeout_id > 0)
+               timeout_remove(p->timeout_id);
+
+       p->func(p->attrib, err, data, length, p->user_data);
+
+       free(p);
+}
+
+static void pending_read_free(void *data)
+{
+       struct pending_read *p = data;
+
+       pending_read_result(p, -ECANCELED, NULL, 0);
+}
+
+static void pending_write_result(struct pending_write *p, int err)
+{
+       if (p->timeout_id > 0)
+               timeout_remove(p->timeout_id);
+
+       p->func(p->attrib, err, p->user_data);
+
+       free(p);
+}
+
+static void pending_write_free(void *data)
+{
+       struct pending_write *p = data;
+
+       pending_write_result(p, -ECANCELED);
+}
+
 static void attribute_destroy(struct gatt_db_attribute *attribute)
 {
        /* Attribute was not initialized by user */
        if (!attribute)
                return;
 
-       queue_destroy(attribute->pending_reads, free);
-       queue_destroy(attribute->pending_writes, free);
+       queue_destroy(attribute->pending_reads, pending_read_free);
+       queue_destroy(attribute->pending_writes, pending_write_free);
 
        free(attribute->value);
        free(attribute);
 }
 
 static struct gatt_db_attribute *new_attribute(struct gatt_db_service *service,
+                                                       uint16_t handle,
                                                        const bt_uuid_t *type,
                                                        const uint8_t *val,
                                                        uint16_t len)
@@ -131,6 +170,7 @@ static struct gatt_db_attribute *new_attribute(struct gatt_db_service *service,
                return NULL;
 
        attribute->service = service;
+       attribute->handle = handle;
        attribute->uuid = *type;
        attribute->value_len = len;
        if (len) {
@@ -333,6 +373,7 @@ static bool le_to_uuid(const uint8_t *src, size_t len, bt_uuid_t *uuid)
 }
 
 static struct gatt_db_service *gatt_db_service_create(const bt_uuid_t *uuid,
+                                                       uint16_t handle,
                                                        bool primary,
                                                        uint16_t num_handles)
 {
@@ -361,7 +402,8 @@ static struct gatt_db_service *gatt_db_service_create(const bt_uuid_t *uuid,
 
        len = uuid_to_le(uuid, value);
 
-       service->attributes[0] = new_attribute(service, type, value, len);
+       service->attributes[0] = new_attribute(service, handle, type, value,
+                                                                       len);
        if (!service->attributes[0]) {
                gatt_db_service_destroy(service);
                return NULL;
@@ -495,7 +537,7 @@ struct gatt_db_attribute *gatt_db_insert_service(struct gatt_db *db,
        if (!find_insert_loc(db, handle, handle + num_handles - 1, &after))
                return NULL;
 
-       service = gatt_db_service_create(uuid, primary, num_handles);
+       service = gatt_db_service_create(uuid, handle, primary, num_handles);
 
        if (!service)
                return NULL;
@@ -625,8 +667,9 @@ static void set_attribute_data(struct gatt_db_attribute *attribute,
        attribute->user_data = user_data;
 }
 
-struct gatt_db_attribute *
-gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
+static struct gatt_db_attribute *
+service_insert_characteristic(struct gatt_db_service *service,
+                                       uint16_t handle,
                                        const bt_uuid_t *uuid,
                                        uint32_t permissions,
                                        uint8_t properties,
@@ -634,35 +677,38 @@ gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
                                        gatt_db_write_t write_func,
                                        void *user_data)
 {
-       struct gatt_db_service *service;
        uint8_t value[MAX_CHAR_DECL_VALUE_LEN];
        uint16_t len = 0;
        int i;
 
-       if (!attrib)
+       /* Check if handle is in within service range */
+       if (handle && handle <= service->attributes[0]->handle)
                return NULL;
 
-       service = attrib->service;
-
        i = get_attribute_index(service, 1);
        if (!i)
                return NULL;
 
+       if (!handle)
+               handle = get_handle_at_index(service, i - 1) + 2;
+
        value[0] = properties;
        len += sizeof(properties);
+
        /* We set handle of characteristic value, which will be added next */
-       put_le16(get_handle_at_index(service, i - 1) + 2, &value[1]);
+       put_le16(handle, &value[1]);
        len += sizeof(uint16_t);
        len += uuid_to_le(uuid, &value[3]);
 
-       service->attributes[i] = new_attribute(service, &characteristic_uuid,
-                                                               value, len);
+       service->attributes[i] = new_attribute(service, handle - 1,
+                                                       &characteristic_uuid,
+                                                       value, len);
        if (!service->attributes[i])
                return NULL;
 
-       attribute_update(service, i++);
+       i++;
 
-       service->attributes[i] = new_attribute(service, uuid, NULL, 0);
+       service->attributes[i] = new_attribute(service, handle, uuid, NULL, 0);
        if (!service->attributes[i]) {
                free(service->attributes[i - 1]);
                return NULL;
@@ -671,37 +717,109 @@ gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
        set_attribute_data(service->attributes[i], read_func, write_func,
                                                        permissions, user_data);
 
-       return attribute_update(service, i);
+       return service->attributes[i];
 }
 
 struct gatt_db_attribute *
-gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
+gatt_db_service_insert_characteristic(struct gatt_db_attribute *attrib,
+                                       uint16_t handle,
                                        const bt_uuid_t *uuid,
                                        uint32_t permissions,
+                                       uint8_t properties,
                                        gatt_db_read_t read_func,
                                        gatt_db_write_t write_func,
                                        void *user_data)
 {
-       struct gatt_db_service *service;
-       int i;
+       if (!attrib || !handle)
+               return NULL;
 
+       return service_insert_characteristic(attrib->service, handle, uuid,
+                                               permissions, properties,
+                                               read_func, write_func,
+                                               user_data);
+}
+
+struct gatt_db_attribute *
+gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
+                                       const bt_uuid_t *uuid,
+                                       uint32_t permissions,
+                                       uint8_t properties,
+                                       gatt_db_read_t read_func,
+                                       gatt_db_write_t write_func,
+                                       void *user_data)
+{
        if (!attrib)
-               return false;
+               return NULL;
 
-       service = attrib->service;
+       return service_insert_characteristic(attrib->service, 0, uuid,
+                                               permissions, properties,
+                                               read_func, write_func,
+                                               user_data);
+}
+
+static struct gatt_db_attribute *
+service_insert_descriptor(struct gatt_db_service *service,
+                                       uint16_t handle,
+                                       const bt_uuid_t *uuid,
+                                       uint32_t permissions,
+                                       gatt_db_read_t read_func,
+                                       gatt_db_write_t write_func,
+                                       void *user_data)
+{
+       int i;
 
        i = get_attribute_index(service, 0);
        if (!i)
                return NULL;
 
-       service->attributes[i] = new_attribute(service, uuid, NULL, 0);
+       /* Check if handle is in within service range */
+       if (handle && handle <= service->attributes[0]->handle)
+               return NULL;
+
+       if (!handle)
+               handle = get_handle_at_index(service, i - 1) + 1;
+
+       service->attributes[i] = new_attribute(service, handle, uuid, NULL, 0);
        if (!service->attributes[i])
                return NULL;
 
        set_attribute_data(service->attributes[i], read_func, write_func,
                                                        permissions, user_data);
 
-       return attribute_update(service, i);
+       return service->attributes[i];
+}
+
+struct gatt_db_attribute *
+gatt_db_service_insert_descriptor(struct gatt_db_attribute *attrib,
+                                       uint16_t handle,
+                                       const bt_uuid_t *uuid,
+                                       uint32_t permissions,
+                                       gatt_db_read_t read_func,
+                                       gatt_db_write_t write_func,
+                                       void *user_data)
+{
+       if (!attrib || !handle)
+               return NULL;
+
+       return service_insert_descriptor(attrib->service, handle, uuid,
+                                       permissions, read_func, write_func,
+                                       user_data);
+}
+
+struct gatt_db_attribute *
+gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
+                                       const bt_uuid_t *uuid,
+                                       uint32_t permissions,
+                                       gatt_db_read_t read_func,
+                                       gatt_db_write_t write_func,
+                                       void *user_data)
+{
+       if (!attrib)
+               return NULL;
+
+       return service_insert_descriptor(attrib->service, 0, uuid,
+                                       permissions, read_func, write_func,
+                                       user_data);
 }
 
 struct gatt_db_attribute *
@@ -743,7 +861,7 @@ gatt_db_service_add_included(struct gatt_db_attribute *attrib,
        if (!index)
                return NULL;
 
-       service->attributes[index] = new_attribute(service,
+       service->attributes[index] = new_attribute(service, 0,
                                                        &included_service_uuid,
                                                        value, len);
        if (!service->attributes[index])
@@ -767,6 +885,10 @@ bool gatt_db_service_set_active(struct gatt_db_attribute *attrib, bool active)
                return false;
 
        service = attrib->service;
+
+       if (service->active == active)
+               return true;
+
        service->active = active;
 
        notify_service_changed(service->db, service, active);
@@ -774,6 +896,33 @@ bool gatt_db_service_set_active(struct gatt_db_attribute *attrib, bool active)
        return true;
 }
 
+bool gatt_db_service_get_active(struct gatt_db_attribute *attrib)
+{
+       if (!attrib)
+               return false;
+
+       return attrib->service->active;
+}
+
+bool gatt_db_service_set_claimed(struct gatt_db_attribute *attrib,
+                                                               bool claimed)
+{
+       if (!attrib)
+               return false;
+
+       attrib->service->claimed = claimed;
+
+       return true;
+}
+
+bool gatt_db_service_get_claimed(struct gatt_db_attribute *attrib)
+{
+       if (!attrib)
+               return false;
+
+       return attrib->service->claimed;
+}
+
 void gatt_db_read_by_group_type(struct gatt_db *db, uint16_t start_handle,
                                                        uint16_t end_handle,
                                                        const bt_uuid_t type,
@@ -818,10 +967,14 @@ next_service:
 }
 
 struct find_by_type_value_data {
-       struct queue *queue;
        bt_uuid_t uuid;
        uint16_t start_handle;
        uint16_t end_handle;
+       gatt_db_attribute_cb_t func;
+       void *user_data;
+       const void *value;
+       size_t value_len;
+       unsigned int num_of_res;
 };
 
 static void find_by_type(void *data, void *user_data)
@@ -847,23 +1000,60 @@ static void find_by_type(void *data, void *user_data)
                if (bt_uuid_cmp(&search_data->uuid, &attribute->uuid))
                        continue;
 
-               queue_push_tail(search_data->queue, attribute);
+               /* TODO: fix for read-callback based attributes */
+               if (search_data->value && memcmp(attribute->value,
+                                                       search_data->value,
+                                                       search_data->value_len))
+                       continue;
+
+               search_data->num_of_res++;
+               search_data->func(attribute, search_data->user_data);
        }
 }
 
-void gatt_db_find_by_type(struct gatt_db *db, uint16_t start_handle,
-                                                       uint16_t end_handle,
-                                                       const bt_uuid_t *type,
-                                                       struct queue *queue)
+unsigned int gatt_db_find_by_type(struct gatt_db *db, uint16_t start_handle,
+                                               uint16_t end_handle,
+                                               const bt_uuid_t *type,
+                                               gatt_db_attribute_cb_t func,
+                                               void *user_data)
 {
        struct find_by_type_value_data data;
 
+       memset(&data, 0, sizeof(data));
+
        data.uuid = *type;
        data.start_handle = start_handle;
        data.end_handle = end_handle;
-       data.queue = queue;
+       data.func = func;
+       data.user_data = user_data;
+
+       queue_foreach(db->services, find_by_type, &data);
+
+       return data.num_of_res;
+}
+
+unsigned int gatt_db_find_by_type_value(struct gatt_db *db,
+                                               uint16_t start_handle,
+                                               uint16_t end_handle,
+                                               const bt_uuid_t *type,
+                                               const void *value,
+                                               size_t value_len,
+                                               gatt_db_attribute_cb_t func,
+                                               void *user_data)
+{
+       struct find_by_type_value_data data;
+
+       data.uuid = *type;
+       data.start_handle = start_handle;
+       data.end_handle = end_handle;
+       data.func = func;
+       data.user_data = user_data;
+       data.value = value;
+       data.value_len = value_len;
 
        queue_foreach(db->services, find_by_type, &data);
+
+       return data.num_of_res;
 }
 
 struct read_by_type_data {
@@ -1074,7 +1264,13 @@ void gatt_db_service_foreach_desc(struct gatt_db_attribute *attrib,
        service = attrib->service;
 
        /* Start from the attribute following the value handle */
-       i = attrib->handle - service->attributes[0]->handle + 2;
+       for (i = 0; i < service->num_handles; i++) {
+               if (service->attributes[i] == attrib) {
+                       i += 2;
+                       break;
+               }
+       }
+
        for (; i < service->num_handles; i++) {
                attr = service->attributes[i];
                if (!attr)
@@ -1103,17 +1299,16 @@ static bool find_service_for_handle(const void *data, const void *user_data)
        uint16_t handle = PTR_TO_UINT(user_data);
        uint16_t start, end;
 
-       start = service->attributes[0]->handle;
-       end = start + service->num_handles;
+       gatt_db_service_get_handles(service, &start, &end);
 
-       return (start <= handle) && (handle < end);
+       return (start <= handle) && (handle <= end);
 }
 
 struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *db,
                                                        uint16_t handle)
 {
        struct gatt_db_service *service;
-       uint16_t service_handle;
+       int i;
 
        if (!db || !handle)
                return NULL;
@@ -1123,14 +1318,41 @@ struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *db,
        if (!service)
                return NULL;
 
-       service_handle = service->attributes[0]->handle;
+       for (i = 0; i < service->num_handles; i++) {
+               if (!service->attributes[i])
+                       continue;
+
+               if (service->attributes[i]->handle == handle)
+                       return service->attributes[i];
+       }
 
-       /*
-        * We can safely get attribute from attributes array with offset,
-        * because find_service_for_handle() check if given handle is
-        * in service range.
-        */
-       return service->attributes[handle - service_handle];
+       return NULL;
+}
+
+static bool find_service_with_uuid(const void *data, const void *user_data)
+{
+       const struct gatt_db_service *service = data;
+       const bt_uuid_t *uuid = user_data;
+       bt_uuid_t svc_uuid;
+
+       gatt_db_attribute_get_service_uuid(service->attributes[0], &svc_uuid);
+
+       return bt_uuid_cmp(uuid, &svc_uuid) == 0;
+}
+
+struct gatt_db_attribute *gatt_db_get_service_with_uuid(struct gatt_db *db,
+                                                       const bt_uuid_t *uuid)
+{
+       struct gatt_db_service *service;
+
+       if (!db || !uuid)
+               return NULL;
+
+       service = queue_find(db->services, find_service_with_uuid, uuid);
+       if (!service)
+               return NULL;
+
+       return service->attributes[0];
 }
 
 const bt_uuid_t *gatt_db_attribute_get_type(
@@ -1301,26 +1523,13 @@ bool gatt_db_attribute_get_incl_data(const struct gatt_db_attribute *attrib,
        return true;
 }
 
-bool gatt_db_attribute_get_permissions(const struct gatt_db_attribute *attrib,
-                                                       uint32_t *permissions)
-{
-       if (!attrib || !permissions)
-               return false;
-
-       *permissions = attrib->permissions;
-
-       return true;
-}
-
-static void pending_read_result(struct pending_read *p, int err,
-                                       const uint8_t *data, size_t length)
+uint32_t
+gatt_db_attribute_get_permissions(const struct gatt_db_attribute *attrib)
 {
-       if (p->timeout_id > 0)
-               timeout_remove(p->timeout_id);
-
-       p->func(p->attrib, err, data, length, p->user_data);
+       if (!attrib)
+               return 0;
 
-       free(p);
+       return attrib->permissions;
 }
 
 static bool read_timeout(void *user_data)
@@ -1337,7 +1546,7 @@ static bool read_timeout(void *user_data)
 }
 
 bool gatt_db_attribute_read(struct gatt_db_attribute *attrib, uint16_t offset,
-                               uint8_t opcode, bdaddr_t *bdaddr,
+                               uint8_t opcode, struct bt_att *att,
                                gatt_db_attribute_read_t func, void *user_data)
 {
        uint8_t *value;
@@ -1361,14 +1570,16 @@ bool gatt_db_attribute_read(struct gatt_db_attribute *attrib, uint16_t offset,
 
                queue_push_tail(attrib->pending_reads, p);
 
-               attrib->read_func(attrib, p->id, offset, opcode, bdaddr,
+               attrib->read_func(attrib, p->id, offset, opcode, att,
                                                        attrib->user_data);
                return true;
        }
 
        /* Check boundary if value is stored in the db */
-       if (offset > attrib->value_len)
-               return false;
+       if (offset > attrib->value_len) {
+               func(attrib, BT_ATT_ERROR_INVALID_OFFSET, NULL, 0, user_data);
+               return true;
+       }
 
        /* Guard against invalid access if offset equals to value length */
        value = offset == attrib->value_len ? NULL : &attrib->value[offset];
@@ -1405,16 +1616,6 @@ bool gatt_db_attribute_read_result(struct gatt_db_attribute *attrib,
        return true;
 }
 
-static void pending_write_result(struct pending_write *p, int err)
-{
-       if (p->timeout_id > 0)
-               timeout_remove(p->timeout_id);
-
-       p->func(p->attrib, err, p->user_data);
-
-       free(p);
-}
-
 static bool write_timeout(void *user_data)
 {
        struct pending_write *p = user_data;
@@ -1430,7 +1631,7 @@ static bool write_timeout(void *user_data)
 
 bool gatt_db_attribute_write(struct gatt_db_attribute *attrib, uint16_t offset,
                                        const uint8_t *value, size_t len,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        gatt_db_attribute_write_t func,
                                        void *user_data)
 {
@@ -1454,10 +1655,14 @@ bool gatt_db_attribute_write(struct gatt_db_attribute *attrib, uint16_t offset,
                queue_push_tail(attrib->pending_writes, p);
 
                attrib->write_func(attrib, p->id, offset, value, len, opcode,
-                                               bdaddr, attrib->user_data);
+                                                       att, attrib->user_data);
                return true;
        }
 
+       /* Nothing to write just skip */
+       if (len == 0)
+               goto done;
+
        /* For values stored in db allocate on demand */
        if (!attrib->value || offset >= attrib->value_len ||
                                len > (unsigned) (attrib->value_len - offset)) {
@@ -1478,6 +1683,7 @@ bool gatt_db_attribute_write(struct gatt_db_attribute *attrib, uint16_t offset,
 
        memcpy(&attrib->value[offset], value, len);
 
+done:
        func(attrib, 0, user_data);
 
        return true;
@@ -1500,3 +1706,18 @@ bool gatt_db_attribute_write_result(struct gatt_db_attribute *attrib,
 
        return true;
 }
+
+bool gatt_db_attribute_reset(struct gatt_db_attribute *attrib)
+{
+       if (!attrib)
+               return false;
+
+       if (!attrib->value || !attrib->value_len)
+               return true;
+
+       free(attrib->value);
+       attrib->value = NULL;
+       attrib->value_len = 0;
+
+       return true;
+}
index e5fe6bb..96cceb9 100644 (file)
@@ -50,13 +50,13 @@ struct gatt_db_attribute *gatt_db_insert_service(struct gatt_db *db,
 
 typedef void (*gatt_db_read_t) (struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data);
 
 typedef void (*gatt_db_write_t) (struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
                                        const uint8_t *value, size_t len,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data);
 
 struct gatt_db_attribute *
@@ -67,6 +67,15 @@ gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
                                        gatt_db_read_t read_func,
                                        gatt_db_write_t write_func,
                                        void *user_data);
+struct gatt_db_attribute *
+gatt_db_service_insert_characteristic(struct gatt_db_attribute *attrib,
+                                       uint16_t handle,
+                                       const bt_uuid_t *uuid,
+                                       uint32_t permissions,
+                                       uint8_t properties,
+                                       gatt_db_read_t read_func,
+                                       gatt_db_write_t write_func,
+                                       void *user_data);
 
 struct gatt_db_attribute *
 gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
@@ -75,22 +84,48 @@ gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
                                        gatt_db_read_t read_func,
                                        gatt_db_write_t write_func,
                                        void *user_data);
+struct gatt_db_attribute *
+gatt_db_service_insert_descriptor(struct gatt_db_attribute *attrib,
+                                       uint16_t handle,
+                                       const bt_uuid_t *uuid,
+                                       uint32_t permissions,
+                                       gatt_db_read_t read_func,
+                                       gatt_db_write_t write_func,
+                                       void *user_data);
 
 struct gatt_db_attribute *
 gatt_db_service_add_included(struct gatt_db_attribute *attrib,
                                        struct gatt_db_attribute *include);
 
 bool gatt_db_service_set_active(struct gatt_db_attribute *attrib, bool active);
+bool gatt_db_service_get_active(struct gatt_db_attribute *attrib);
+
+bool gatt_db_service_set_claimed(struct gatt_db_attribute *attrib,
+                                                               bool claimed);
+bool gatt_db_service_get_claimed(struct gatt_db_attribute *attrib);
+
+typedef void (*gatt_db_attribute_cb_t)(struct gatt_db_attribute *attrib,
+                                                       void *user_data);
 
 void gatt_db_read_by_group_type(struct gatt_db *db, uint16_t start_handle,
                                                        uint16_t end_handle,
                                                        const bt_uuid_t type,
                                                        struct queue *queue);
 
-void gatt_db_find_by_type(struct gatt_db *db, uint16_t start_handle,
-                                                       uint16_t end_handle,
-                                                       const bt_uuid_t *type,
-                                                       struct queue *queue);
+unsigned int gatt_db_find_by_type(struct gatt_db *db, uint16_t start_handle,
+                                               uint16_t end_handle,
+                                               const bt_uuid_t *type,
+                                               gatt_db_attribute_cb_t func,
+                                               void *user_data);
+
+unsigned int gatt_db_find_by_type_value(struct gatt_db *db,
+                                               uint16_t start_handle,
+                                               uint16_t end_handle,
+                                               const bt_uuid_t *type,
+                                               const void *value,
+                                               size_t value_len,
+                                               gatt_db_attribute_cb_t func,
+                                               void *user_data);
 
 void gatt_db_read_by_type(struct gatt_db *db, uint16_t start_handle,
                                                        uint16_t end_handle,
@@ -102,9 +137,6 @@ void gatt_db_find_information(struct gatt_db *db, uint16_t start_handle,
                                                        struct queue *queue);
 
 
-typedef void (*gatt_db_attribute_cb_t)(struct gatt_db_attribute *attrib,
-                                                       void *user_data);
-
 void gatt_db_foreach_service(struct gatt_db *db, const bt_uuid_t *uuid,
                                                gatt_db_attribute_cb_t func,
                                                void *user_data);
@@ -141,6 +173,9 @@ bool gatt_db_unregister(struct gatt_db *db, unsigned int id);
 struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *db,
                                                        uint16_t handle);
 
+struct gatt_db_attribute *gatt_db_get_service_with_uuid(struct gatt_db *db,
+                                                       const bt_uuid_t *uuid);
+
 const bt_uuid_t *gatt_db_attribute_get_type(
                                        const struct gatt_db_attribute *attrib);
 
@@ -171,15 +206,15 @@ bool gatt_db_attribute_get_incl_data(const struct gatt_db_attribute *attrib,
                                                        uint16_t *start_handle,
                                                        uint16_t *end_handle);
 
-bool gatt_db_attribute_get_permissions(const struct gatt_db_attribute *attrib,
-                                                       uint32_t *permissions);
+uint32_t
+gatt_db_attribute_get_permissions(const struct gatt_db_attribute *attrib);
 
 typedef void (*gatt_db_attribute_read_t) (struct gatt_db_attribute *attrib,
                                                int err, const uint8_t *value,
                                                size_t length, void *user_data);
 
 bool gatt_db_attribute_read(struct gatt_db_attribute *attrib, uint16_t offset,
-                               uint8_t opcode, bdaddr_t *bdaddr,
+                               uint8_t opcode, struct bt_att *att,
                                gatt_db_attribute_read_t func, void *user_data);
 
 bool gatt_db_attribute_read_result(struct gatt_db_attribute *attrib,
@@ -191,9 +226,11 @@ typedef void (*gatt_db_attribute_write_t) (struct gatt_db_attribute *attrib,
 
 bool gatt_db_attribute_write(struct gatt_db_attribute *attrib, uint16_t offset,
                                        const uint8_t *value, size_t len,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        gatt_db_attribute_write_t func,
                                        void *user_data);
 
 bool gatt_db_attribute_write_result(struct gatt_db_attribute *attrib,
                                                unsigned int id, int err);
+
+bool gatt_db_attribute_reset(struct gatt_db_attribute *attrib);
index c6e179c..2d6088e 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "src/shared/queue.h"
 #include "src/shared/att.h"
+#include "lib/bluetooth.h"
 #include "lib/uuid.h"
 #include "src/shared/gatt-helpers.h"
 #include "src/shared/util.h"
@@ -208,15 +209,16 @@ static bool convert_uuid_le(const uint8_t *src, size_t len, uint8_t dst[16])
        return true;
 }
 
-struct discovery_op {
+struct bt_gatt_request {
        struct bt_att *att;
+       unsigned int id;
        uint16_t end_handle;
        int ref_count;
        bt_uuid_t uuid;
        uint16_t service_type;
        struct bt_gatt_result *result_head;
        struct bt_gatt_result *result_tail;
-       bt_gatt_discovery_callback_t callback;
+       bt_gatt_request_callback_t callback;
        void *user_data;
        bt_gatt_destroy_func_t destroy;
 };
@@ -224,7 +226,7 @@ struct discovery_op {
 static struct bt_gatt_result *result_append(uint8_t opcode, const void *pdu,
                                                uint16_t pdu_len,
                                                uint16_t data_len,
-                                               struct discovery_op *op)
+                                               struct bt_gatt_request *op)
 {
        struct bt_gatt_result *result;
 
@@ -247,7 +249,7 @@ bool bt_gatt_iter_next_included_service(struct bt_gatt_iter *iter,
                                uint16_t *end_handle, uint8_t uuid[16])
 {
        struct bt_gatt_result *read_result;
-       struct discovery_op *op;
+       struct bt_gatt_request *op;
        const void *pdu_ptr;
        int i = 0;
 
@@ -326,7 +328,7 @@ bool bt_gatt_iter_next_service(struct bt_gatt_iter *iter,
                                uint16_t *start_handle, uint16_t *end_handle,
                                uint8_t uuid[16])
 {
-       struct discovery_op *op;
+       struct bt_gatt_request *op;
        const void *pdu_ptr;
        bt_uuid_t tmp;
 
@@ -368,7 +370,7 @@ bool bt_gatt_iter_next_characteristic(struct bt_gatt_iter *iter,
                                uint16_t *value_handle, uint8_t *properties,
                                uint8_t uuid[16])
 {
-       struct discovery_op *op;
+       struct bt_gatt_request *op;
        const void *pdu_ptr;
 
        if (!iter || !iter->result || !start_handle || !end_handle ||
@@ -444,7 +446,7 @@ bool bt_gatt_iter_next_read_by_type(struct bt_gatt_iter *iter,
                                uint16_t *handle, uint16_t *length,
                                const uint8_t **value)
 {
-       struct discovery_op *op;
+       struct bt_gatt_request *op;
        const void *pdu_ptr;
 
        if (!iter || !iter->result || !handle || !length || !value)
@@ -533,13 +535,14 @@ done:
                op->callback(success, att_ecode, op->user_data);
 }
 
-bool bt_gatt_exchange_mtu(struct bt_att *att, uint16_t client_rx_mtu,
+unsigned int bt_gatt_exchange_mtu(struct bt_att *att, uint16_t client_rx_mtu,
                                        bt_gatt_result_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy)
 {
        struct mtu_op *op;
        uint8_t pdu[2];
+       unsigned int id;
 
        if (!att || !client_rx_mtu)
                return false;
@@ -556,35 +559,12 @@ bool bt_gatt_exchange_mtu(struct bt_att *att, uint16_t client_rx_mtu,
 
        put_le16(client_rx_mtu, pdu);
 
-       if (!bt_att_send(att, BT_ATT_OP_MTU_REQ, pdu, sizeof(pdu),
-                                                       mtu_cb, op,
-                                                       destroy_mtu_op)) {
+       id = bt_att_send(att, BT_ATT_OP_MTU_REQ, pdu, sizeof(pdu), mtu_cb, op,
+                                                               destroy_mtu_op);
+       if (!id)
                free(op);
-               return false;
-       }
-
-       return true;
-}
 
-static void put_uuid_le(const bt_uuid_t *src, void *dst)
-{
-       bt_uuid_t uuid;
-
-       switch (src->type) {
-       case BT_UUID16:
-               put_le16(src->value.u16, dst);
-               break;
-       case BT_UUID128:
-               bswap_128(&src->value.u128, dst);
-               break;
-       case BT_UUID32:
-               bt_uuid_to_uuid128(src, &uuid);
-               bswap_128(&uuid.value.u128, dst);
-               break;
-       case BT_UUID_UNSPEC:
-       default:
-               break;
-       }
+       return id;
 }
 
 static inline int get_uuid_len(const bt_uuid_t *uuid)
@@ -595,35 +575,73 @@ static inline int get_uuid_len(const bt_uuid_t *uuid)
        return (uuid->type == BT_UUID16) ? 2 : 16;
 }
 
-static struct discovery_op* discovery_op_ref(struct discovery_op *op)
+struct bt_gatt_request *bt_gatt_request_ref(struct bt_gatt_request *req)
 {
-       __sync_fetch_and_add(&op->ref_count, 1);
+       if (!req)
+               return NULL;
 
-       return op;
+       __sync_fetch_and_add(&req->ref_count, 1);
+
+       return req;
 }
 
-static void discovery_op_unref(void *data)
+void bt_gatt_request_unref(struct bt_gatt_request *req)
 {
-       struct discovery_op *op = data;
+       if (!req)
+               return;
 
-       if (__sync_sub_and_fetch(&op->ref_count, 1))
+       if (__sync_sub_and_fetch(&req->ref_count, 1))
                return;
 
-       if (op->destroy)
-               op->destroy(op->user_data);
+       bt_gatt_request_cancel(req);
 
-       result_destroy(op->result_head);
+       if (req->destroy)
+               req->destroy(req->user_data);
+
+       result_destroy(req->result_head);
+
+       free(req);
+}
+
+void bt_gatt_request_cancel(struct bt_gatt_request *req)
+{
+       if (!req)
+               return;
+
+       if (!req->id)
+               return;
+
+       bt_att_cancel(req->att, req->id);
+       req->id = 0;
+}
+
+static void async_req_unref(void *data)
+{
+       struct bt_gatt_request *req = data;
+
+       bt_gatt_request_unref(req);
+}
+
+static void discovery_op_complete(struct bt_gatt_request *op, bool success,
+                                                               uint8_t ecode)
+{
+       if (op->callback)
+               op->callback(success, ecode, success ? op->result_head : NULL,
+                                                               op->user_data);
+
+       if (!op->id)
+               async_req_unref(op);
+       else
+               op->id = 0;
 
-       free(op);
 }
 
 static void read_by_grp_type_cb(uint8_t opcode, const void *pdu,
                                        uint16_t length, void *user_data)
 {
-       struct discovery_op *op = user_data;
+       struct bt_gatt_request *op = user_data;
        bool success;
        uint8_t att_ecode = 0;
-       struct bt_gatt_result *final_result = NULL;
        struct bt_gatt_result *cur_result;
        size_t data_length;
        size_t list_length;
@@ -655,8 +673,8 @@ static void read_by_grp_type_cb(uint8_t opcode, const void *pdu,
        data_length = ((uint8_t *) pdu)[0];
        list_length = length - 1;
 
-       if ((list_length % data_length) ||
-                               (data_length != 6 && data_length != 20)) {
+       if ((data_length != 6 && data_length != 20) ||
+                                       (list_length % data_length)) {
                success = false;
                goto done;
        }
@@ -679,14 +697,14 @@ static void read_by_grp_type_cb(uint8_t opcode, const void *pdu,
                put_le16(op->end_handle, pdu + 2);
                put_le16(op->service_type, pdu + 4);
 
-               if (bt_att_send(op->att, BT_ATT_OP_READ_BY_GRP_TYPE_REQ,
-                                                       pdu, sizeof(pdu),
-                                                       read_by_grp_type_cb,
-                                                       discovery_op_ref(op),
-                                                       discovery_op_unref))
+               op->id = bt_att_send(op->att, BT_ATT_OP_READ_BY_GRP_TYPE_REQ,
+                                               pdu, sizeof(pdu),
+                                               read_by_grp_type_cb,
+                                               bt_gatt_request_ref(op),
+                                               async_req_unref);
+               if (op->id)
                        return;
 
-               discovery_op_unref(op);
                success = false;
                goto done;
        }
@@ -701,22 +719,18 @@ static void read_by_grp_type_cb(uint8_t opcode, const void *pdu,
                                cur_result->pdu + length - data_length + 1);
 
 success:
-       /* End of procedure */
-       final_result = op->result_head;
        success = true;
 
 done:
-       if (op->callback)
-               op->callback(success, att_ecode, final_result, op->user_data);
+       discovery_op_complete(op, success, att_ecode);
 }
 
 static void find_by_type_val_cb(uint8_t opcode, const void *pdu,
                                        uint16_t length, void *user_data)
 {
-       struct discovery_op *op = user_data;
+       struct bt_gatt_request *op = user_data;
        bool success;
        uint8_t att_ecode = 0;
-       struct bt_gatt_result *final_result = NULL;
        uint16_t last_end;
 
        if (opcode == BT_ATT_OP_ERROR_RSP) {
@@ -757,46 +771,43 @@ static void find_by_type_val_cb(uint8_t opcode, const void *pdu,
                put_le16(last_end + 1, pdu);
                put_le16(op->end_handle, pdu + 2);
                put_le16(op->service_type, pdu + 4);
-               put_uuid_le(&op->uuid, pdu + 6);
+               bt_uuid_to_le(&op->uuid, pdu + 6);
 
-               if (bt_att_send(op->att, BT_ATT_OP_FIND_BY_TYPE_VAL_REQ,
-                                                       pdu, sizeof(pdu),
-                                                       find_by_type_val_cb,
-                                                       discovery_op_ref(op),
-                                                       discovery_op_unref))
+               op->id = bt_att_send(op->att, BT_ATT_OP_FIND_BY_TYPE_VAL_REQ,
+                                               pdu, sizeof(pdu),
+                                               find_by_type_val_cb,
+                                               bt_gatt_request_ref(op),
+                                               async_req_unref);
+               if (op->id)
                        return;
 
-               discovery_op_unref(op);
                success = false;
                goto done;
        }
 
 success:
-       /* End of procedure */
-       final_result = op->result_head;
        success = true;
 
 done:
-       if (op->callback)
-               op->callback(success, att_ecode, final_result, op->user_data);
+       discovery_op_complete(op, success, att_ecode);
 }
 
-static bool discover_services(struct bt_att *att, bt_uuid_t *uuid,
+static struct bt_gatt_request *discover_services(struct bt_att *att,
+                                       bt_uuid_t *uuid,
                                        uint16_t start, uint16_t end,
-                                       bt_gatt_discovery_callback_t callback,
+                                       bt_gatt_request_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy,
                                        bool primary)
 {
-       struct discovery_op *op;
-       bool result;
+       struct bt_gatt_request *op;
 
        if (!att)
-               return false;
+               return NULL;
 
-       op = new0(struct discovery_op, 1);
+       op = new0(struct bt_gatt_request, 1);
        if (!op)
-               return false;
+               return NULL;
 
        op->att = att;
        op->end_handle = end;
@@ -814,17 +825,17 @@ static bool discover_services(struct bt_att *att, bt_uuid_t *uuid,
                put_le16(end, pdu + 2);
                put_le16(op->service_type, pdu + 4);
 
-               result = bt_att_send(att, BT_ATT_OP_READ_BY_GRP_TYPE_REQ,
-                                                       pdu, sizeof(pdu),
-                                                       read_by_grp_type_cb,
-                                                       discovery_op_ref(op),
-                                                       discovery_op_unref);
+               op->id = bt_att_send(att, BT_ATT_OP_READ_BY_GRP_TYPE_REQ,
+                                               pdu, sizeof(pdu),
+                                               read_by_grp_type_cb,
+                                               bt_gatt_request_ref(op),
+                                               async_req_unref);
        } else {
                uint8_t pdu[6 + get_uuid_len(uuid)];
 
                if (uuid->type == BT_UUID_UNSPEC) {
                        free(op);
-                       return false;
+                       return NULL;
                }
 
                /* Discover by UUID */
@@ -833,23 +844,26 @@ static bool discover_services(struct bt_att *att, bt_uuid_t *uuid,
                put_le16(start, pdu);
                put_le16(end, pdu + 2);
                put_le16(op->service_type, pdu + 4);
-               put_uuid_le(&op->uuid, pdu + 6);
+               bt_uuid_to_le(&op->uuid, pdu + 6);
 
-               result = bt_att_send(att, BT_ATT_OP_FIND_BY_TYPE_VAL_REQ,
-                                                       pdu, sizeof(pdu),
-                                                       find_by_type_val_cb,
-                                                       discovery_op_ref(op),
-                                                       discovery_op_unref);
+               op->id = bt_att_send(att, BT_ATT_OP_FIND_BY_TYPE_VAL_REQ,
+                                               pdu, sizeof(pdu),
+                                               find_by_type_val_cb,
+                                               bt_gatt_request_ref(op),
+                                               async_req_unref);
        }
 
-       if (!result)
+       if (!op->id) {
                free(op);
+               return NULL;
+       }
 
-       return result;
+       return bt_gatt_request_ref(op);
 }
 
-bool bt_gatt_discover_all_primary_services(struct bt_att *att, bt_uuid_t *uuid,
-                                       bt_gatt_discovery_callback_t callback,
+struct bt_gatt_request *bt_gatt_discover_all_primary_services(
+                                       struct bt_att *att, bt_uuid_t *uuid,
+                                       bt_gatt_request_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy)
 {
@@ -858,9 +872,10 @@ bool bt_gatt_discover_all_primary_services(struct bt_att *att, bt_uuid_t *uuid,
                                                        destroy);
 }
 
-bool bt_gatt_discover_primary_services(struct bt_att *att, bt_uuid_t *uuid,
+struct bt_gatt_request *bt_gatt_discover_primary_services(
+                                       struct bt_att *att, bt_uuid_t *uuid,
                                        uint16_t start, uint16_t end,
-                                       bt_gatt_discovery_callback_t callback,
+                                       bt_gatt_request_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy)
 {
@@ -868,9 +883,10 @@ bool bt_gatt_discover_primary_services(struct bt_att *att, bt_uuid_t *uuid,
                                                                destroy, true);
 }
 
-bool bt_gatt_discover_secondary_services(struct bt_att *att, bt_uuid_t *uuid,
+struct bt_gatt_request *bt_gatt_discover_secondary_services(
+                                       struct bt_att *att, bt_uuid_t *uuid,
                                        uint16_t start, uint16_t end,
-                                       bt_gatt_discovery_callback_t callback,
+                                       bt_gatt_request_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy)
 {
@@ -879,7 +895,7 @@ bool bt_gatt_discover_secondary_services(struct bt_att *att, bt_uuid_t *uuid,
 }
 
 struct read_incl_data {
-       struct discovery_op *op;
+       struct bt_gatt_request *op;
        struct bt_gatt_result *result;
        int pos;
        int ref_count;
@@ -893,7 +909,7 @@ static struct read_incl_data *new_read_included(struct bt_gatt_result *res)
        if (!data)
                return NULL;
 
-       data->op = discovery_op_ref(res->op);
+       data->op = bt_gatt_request_ref(res->op);
        data->result = res;
 
        return data;
@@ -913,7 +929,7 @@ static void read_included_unref(void *data)
        if (__sync_sub_and_fetch(&read_data->ref_count, 1))
                return;
 
-       discovery_op_unref(read_data->op);
+       async_req_unref(read_data->op);
 
        free(read_data);
 }
@@ -925,8 +941,7 @@ static void read_included_cb(uint8_t opcode, const void *pdu,
                                        uint16_t length, void *user_data)
 {
        struct read_incl_data *data = user_data;
-       struct bt_gatt_result *final_result = NULL;
-       struct discovery_op *op = data->op;
+       struct bt_gatt_request *op = data->op;
        uint8_t att_ecode = 0;
        uint8_t read_pdu[2];
        bool success;
@@ -963,7 +978,6 @@ static void read_included_cb(uint8_t opcode, const void *pdu,
                last_handle = get_le16(data->result->pdu + data->pos -
                                                        data->result->data_len);
                if (last_handle == op->end_handle) {
-                       final_result = op->result_head;
                        success = true;
                        goto done;
                }
@@ -972,12 +986,14 @@ static void read_included_cb(uint8_t opcode, const void *pdu,
                put_le16(op->end_handle, pdu + 2);
                put_le16(GATT_INCLUDE_UUID, pdu + 4);
 
-               if (bt_att_send(op->att, BT_ATT_OP_READ_BY_TYPE_REQ,
-                               pdu, sizeof(pdu), discover_included_cb,
-                               discovery_op_ref(op), discovery_op_unref))
+               op->id = bt_att_send(op->att, BT_ATT_OP_READ_BY_TYPE_REQ,
+                                               pdu, sizeof(pdu),
+                                               discover_included_cb,
+                                               bt_gatt_request_ref(op),
+                                               async_req_unref);
+               if (op->id)
                        return;
 
-               discovery_op_unref(op);
                success = false;
                goto done;
        }
@@ -995,13 +1011,12 @@ static void read_included_cb(uint8_t opcode, const void *pdu,
        success = false;
 
 done:
-       if (op->callback)
-               op->callback(success, att_ecode, final_result, op->user_data);
+       discovery_op_complete(op, success, att_ecode);
 }
 
 static void read_included(struct read_incl_data *data)
 {
-       struct discovery_op *op = data->op;
+       struct bt_gatt_request *op = data->op;
        uint8_t pdu[2];
 
        memcpy(pdu, data->result->pdu + 2, sizeof(uint16_t));
@@ -1014,17 +1029,16 @@ static void read_included(struct read_incl_data *data)
                                                        read_included_unref))
                return;
 
-       read_included_unref(data);
-
        if (op->callback)
                op->callback(false, 0, NULL, data->op->user_data);
+
+       read_included_unref(data);
 }
 
 static void discover_included_cb(uint8_t opcode, const void *pdu,
                                        uint16_t length, void *user_data)
 {
-       struct bt_gatt_result *final_result = NULL;
-       struct discovery_op *op = user_data;
+       struct bt_gatt_request *op = user_data;
        struct bt_gatt_result *cur_result;
        uint8_t att_ecode = 0;
        uint16_t last_handle;
@@ -1092,40 +1106,38 @@ static void discover_included_cb(uint8_t opcode, const void *pdu,
                put_le16(op->end_handle, pdu + 2);
                put_le16(GATT_INCLUDE_UUID, pdu + 4);
 
-               if (bt_att_send(op->att, BT_ATT_OP_READ_BY_TYPE_REQ,
-                                                       pdu, sizeof(pdu),
-                                                       discover_included_cb,
-                                                       discovery_op_ref(op),
-                                                       discovery_op_unref))
+               op->id = bt_att_send(op->att, BT_ATT_OP_READ_BY_TYPE_REQ,
+                                               pdu, sizeof(pdu),
+                                               discover_included_cb,
+                                               bt_gatt_request_ref(op),
+                                               async_req_unref);
+               if (op->id)
                        return;
 
-               discovery_op_unref(op);
                success = false;
                goto failed;
        }
 
 done:
        success = true;
-       final_result = op->result_head;
 
 failed:
-       if (op->callback)
-               op->callback(success, att_ecode, final_result, op->user_data);
+       discovery_op_complete(op, success, att_ecode);
 }
 
-bool bt_gatt_discover_included_services(struct bt_att *att,
+struct bt_gatt_request *bt_gatt_discover_included_services(struct bt_att *att,
                                        uint16_t start, uint16_t end,
-                                       bt_gatt_discovery_callback_t callback,
+                                       bt_gatt_request_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy)
 {
-       struct discovery_op *op;
+       struct bt_gatt_request *op;
        uint8_t pdu[6];
 
        if (!att)
                return false;
 
-       op = new0(struct discovery_op, 1);
+       op = new0(struct bt_gatt_request, 1);
        if (!op)
                return false;
 
@@ -1139,25 +1151,23 @@ bool bt_gatt_discover_included_services(struct bt_att *att,
        put_le16(end, pdu + 2);
        put_le16(GATT_INCLUDE_UUID, pdu + 4);
 
-       if (!bt_att_send(att, BT_ATT_OP_READ_BY_TYPE_REQ,
-                                       pdu, sizeof(pdu),
-                                       discover_included_cb,
-                                       discovery_op_ref(op),
-                                       discovery_op_unref)) {
+       op->id = bt_att_send(att, BT_ATT_OP_READ_BY_TYPE_REQ, pdu, sizeof(pdu),
+                               discover_included_cb, bt_gatt_request_ref(op),
+                               async_req_unref);
+       if (!op->id) {
                free(op);
-               return false;
+               return NULL;
        }
 
-       return true;
+       return bt_gatt_request_ref(op);
 }
 
 static void discover_chrcs_cb(uint8_t opcode, const void *pdu,
                                        uint16_t length, void *user_data)
 {
-       struct discovery_op *op = user_data;
+       struct bt_gatt_request *op = user_data;
        bool success;
        uint8_t att_ecode = 0;
-       struct bt_gatt_result *final_result = NULL;
        size_t data_length;
        uint16_t last_handle;
 
@@ -1187,8 +1197,8 @@ static void discover_chrcs_cb(uint8_t opcode, const void *pdu,
 
        data_length = ((uint8_t *) pdu)[0];
 
-       if (((length - 1) % data_length) ||
-                       (data_length != 7 && data_length != 21)) {
+       if ((data_length != 7 && data_length != 21) ||
+                                       ((length - 1) % data_length)) {
                success = false;
                goto done;
        }
@@ -1206,41 +1216,38 @@ static void discover_chrcs_cb(uint8_t opcode, const void *pdu,
                put_le16(op->end_handle, pdu + 2);
                put_le16(GATT_CHARAC_UUID, pdu + 4);
 
-               if (bt_att_send(op->att, BT_ATT_OP_READ_BY_TYPE_REQ,
+               op->id = bt_att_send(op->att, BT_ATT_OP_READ_BY_TYPE_REQ,
                                                pdu, sizeof(pdu),
                                                discover_chrcs_cb,
-                                               discovery_op_ref(op),
-                                               discovery_op_unref))
+                                               bt_gatt_request_ref(op),
+                                               async_req_unref);
+               if (op->id)
                        return;
 
-               discovery_op_unref(op);
                success = false;
                goto done;
        }
 
 success:
-       final_result = op->result_head;
        success = true;
 
 done:
-       if (op->callback)
-               op->callback(success, att_ecode, final_result,
-                                                       op->user_data);
+       discovery_op_complete(op, success, att_ecode);
 }
 
-bool bt_gatt_discover_characteristics(struct bt_att *att,
+struct bt_gatt_request *bt_gatt_discover_characteristics(struct bt_att *att,
                                        uint16_t start, uint16_t end,
-                                       bt_gatt_discovery_callback_t callback,
+                                       bt_gatt_request_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy)
 {
-       struct discovery_op *op;
+       struct bt_gatt_request *op;
        uint8_t pdu[6];
 
        if (!att)
                return false;
 
-       op = new0(struct discovery_op, 1);
+       op = new0(struct bt_gatt_request, 1);
        if (!op)
                return false;
 
@@ -1254,22 +1261,21 @@ bool bt_gatt_discover_characteristics(struct bt_att *att,
        put_le16(end, pdu + 2);
        put_le16(GATT_CHARAC_UUID, pdu + 4);
 
-       if (!bt_att_send(att, BT_ATT_OP_READ_BY_TYPE_REQ,
-                                       pdu, sizeof(pdu),
-                                       discover_chrcs_cb,
-                                       discovery_op_ref(op),
-                                       discovery_op_unref)) {
+       op->id = bt_att_send(att, BT_ATT_OP_READ_BY_TYPE_REQ, pdu, sizeof(pdu),
+                               discover_chrcs_cb, bt_gatt_request_ref(op),
+                               async_req_unref);
+       if (!op->id) {
                free(op);
-               return false;
+               return NULL;
        }
 
-       return true;
+       return bt_gatt_request_ref(op);
 }
 
 static void read_by_type_cb(uint8_t opcode, const void *pdu,
                                        uint16_t length, void *user_data)
 {
-       struct discovery_op *op = user_data;
+       struct bt_gatt_request *op = user_data;
        bool success;
        uint8_t att_ecode = 0;
        size_t data_length;
@@ -1312,16 +1318,16 @@ static void read_by_type_cb(uint8_t opcode, const void *pdu,
 
                put_le16(last_handle + 1, pdu);
                put_le16(op->end_handle, pdu + 2);
-               put_uuid_le(&op->uuid, pdu + 4);
+               bt_uuid_to_le(&op->uuid, pdu + 4);
 
-               if (bt_att_send(op->att, BT_ATT_OP_READ_BY_TYPE_REQ,
+               op->id = bt_att_send(op->att, BT_ATT_OP_READ_BY_TYPE_REQ,
                                                pdu, sizeof(pdu),
                                                read_by_type_cb,
-                                               discovery_op_ref(op),
-                                               discovery_op_unref))
+                                               bt_gatt_request_ref(op),
+                                               async_req_unref);
+               if (op->id)
                        return;
 
-               discovery_op_unref(op);
                success = false;
                goto done;
        }
@@ -1329,24 +1335,22 @@ static void read_by_type_cb(uint8_t opcode, const void *pdu,
        success = true;
 
 done:
-       if (op->callback)
-               op->callback(success, att_ecode, success ? op->result_head :
-                                                       NULL, op->user_data);
+       discovery_op_complete(op, success, att_ecode);
 }
 
 bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end,
                                        const bt_uuid_t *uuid,
-                                       bt_gatt_discovery_callback_t callback,
+                                       bt_gatt_request_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy)
 {
-       struct discovery_op *op;
+       struct bt_gatt_request *op;
        uint8_t pdu[4 + get_uuid_len(uuid)];
 
        if (!att || !uuid || uuid->type == BT_UUID_UNSPEC)
                return false;
 
-       op = new0(struct discovery_op, 1);
+       op = new0(struct bt_gatt_request, 1);
        if (!op)
                return false;
 
@@ -1359,25 +1363,25 @@ bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end,
 
        put_le16(start, pdu);
        put_le16(end, pdu + 2);
-       put_uuid_le(uuid, pdu + 4);
+       bt_uuid_to_le(uuid, pdu + 4);
 
-       if (!bt_att_send(att, BT_ATT_OP_READ_BY_TYPE_REQ, pdu, sizeof(pdu),
-                                       read_by_type_cb, discovery_op_ref(op),
-                                       discovery_op_unref)) {
-               free(op);
-               return false;
-       }
+       op->id = bt_att_send(att, BT_ATT_OP_READ_BY_TYPE_REQ, pdu, sizeof(pdu),
+                                               read_by_type_cb,
+                                               bt_gatt_request_ref(op),
+                                               async_req_unref);
+       if (op->id)
+               return true;
 
-       return true;
+       free(op);
+       return false;
 }
 
 static void discover_descs_cb(uint8_t opcode, const void *pdu,
                                        uint16_t length, void *user_data)
 {
-       struct discovery_op *op = user_data;
+       struct bt_gatt_request *op = user_data;
        bool success;
        uint8_t att_ecode = 0;
-       struct bt_gatt_result *final_result = NULL;
        uint8_t format;
        uint16_t last_handle;
        size_t data_length;
@@ -1432,40 +1436,38 @@ static void discover_descs_cb(uint8_t opcode, const void *pdu,
                put_le16(last_handle + 1, pdu);
                put_le16(op->end_handle, pdu + 2);
 
-               if (bt_att_send(op->att, BT_ATT_OP_FIND_INFO_REQ,
+               op->id = bt_att_send(op->att, BT_ATT_OP_FIND_INFO_REQ,
                                                pdu, sizeof(pdu),
                                                discover_descs_cb,
-                                               discovery_op_ref(op),
-                                               discovery_op_unref))
+                                               bt_gatt_request_ref(op),
+                                               async_req_unref);
+               if (op->id)
                        return;
 
-               discovery_op_unref(op);
                success = false;
                goto done;
        }
 
 success:
-       final_result = op->result_head;
        success = true;
 
 done:
-       if (op->callback)
-               op->callback(success, att_ecode, final_result, op->user_data);
+       discovery_op_complete(op, success, att_ecode);
 }
 
-bool bt_gatt_discover_descriptors(struct bt_att *att,
+struct bt_gatt_request *bt_gatt_discover_descriptors(struct bt_att *att,
                                        uint16_t start, uint16_t end,
-                                       bt_gatt_discovery_callback_t callback,
+                                       bt_gatt_request_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy)
 {
-       struct discovery_op *op;
+       struct bt_gatt_request *op;
        uint8_t pdu[4];
 
        if (!att)
                return false;
 
-       op = new0(struct discovery_op, 1);
+       op = new0(struct bt_gatt_request, 1);
        if (!op)
                return false;
 
@@ -1478,13 +1480,14 @@ bool bt_gatt_discover_descriptors(struct bt_att *att,
        put_le16(start, pdu);
        put_le16(end, pdu + 2);
 
-       if (!bt_att_send(att, BT_ATT_OP_FIND_INFO_REQ, pdu, sizeof(pdu),
+       op->id = bt_att_send(att, BT_ATT_OP_FIND_INFO_REQ, pdu, sizeof(pdu),
                                                discover_descs_cb,
-                                               discovery_op_ref(op),
-                                               discovery_op_unref)) {
+                                               bt_gatt_request_ref(op),
+                                               async_req_unref);
+       if (!op->id) {
                free(op);
-               return false;
+               return NULL;
        }
 
-       return true;
+       return bt_gatt_request_ref(op);
 }
index 0217e82..dd9dd1c 100644 (file)
@@ -61,47 +61,56 @@ typedef void (*bt_gatt_destroy_func_t)(void *user_data);
 
 typedef void (*bt_gatt_result_callback_t)(bool success, uint8_t att_ecode,
                                                        void *user_data);
-typedef void (*bt_gatt_discovery_callback_t)(bool success, uint8_t att_ecode,
+typedef void (*bt_gatt_request_callback_t)(bool success, uint8_t att_ecode,
                                                struct bt_gatt_result *result,
                                                void *user_data);
 
-bool bt_gatt_exchange_mtu(struct bt_att *att, uint16_t client_rx_mtu,
+struct bt_gatt_request;
+
+struct bt_gatt_request *bt_gatt_request_ref(struct bt_gatt_request *req);
+void bt_gatt_request_unref(struct bt_gatt_request *req);
+void bt_gatt_request_cancel(struct bt_gatt_request *req);
+
+unsigned int bt_gatt_exchange_mtu(struct bt_att *att, uint16_t client_rx_mtu,
                                        bt_gatt_result_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy);
 
-bool bt_gatt_discover_all_primary_services(struct bt_att *att, bt_uuid_t *uuid,
-                                       bt_gatt_discovery_callback_t callback,
+struct bt_gatt_request *bt_gatt_discover_all_primary_services(
+                                       struct bt_att *att, bt_uuid_t *uuid,
+                                       bt_gatt_request_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy);
-bool bt_gatt_discover_primary_services(struct bt_att *att, bt_uuid_t *uuid,
+struct bt_gatt_request *bt_gatt_discover_primary_services(
+                                       struct bt_att *att, bt_uuid_t *uuid,
                                        uint16_t start, uint16_t end,
-                                       bt_gatt_discovery_callback_t callback,
+                                       bt_gatt_request_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy);
-bool bt_gatt_discover_secondary_services(struct bt_att *att, bt_uuid_t *uuid,
+struct bt_gatt_request *bt_gatt_discover_secondary_services(
+                                       struct bt_att *att, bt_uuid_t *uuid,
                                        uint16_t start, uint16_t end,
-                                       bt_gatt_discovery_callback_t callback,
+                                       bt_gatt_request_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy);
-bool bt_gatt_discover_included_services(struct bt_att *att,
+struct bt_gatt_request *bt_gatt_discover_included_services(struct bt_att *att,
                                        uint16_t start, uint16_t end,
-                                       bt_gatt_discovery_callback_t callback,
+                                       bt_gatt_request_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy);
-bool bt_gatt_discover_characteristics(struct bt_att *att,
+struct bt_gatt_request *bt_gatt_discover_characteristics(struct bt_att *att,
                                        uint16_t start, uint16_t end,
-                                       bt_gatt_discovery_callback_t callback,
+                                       bt_gatt_request_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy);
-bool bt_gatt_discover_descriptors(struct bt_att *att,
+struct bt_gatt_request *bt_gatt_discover_descriptors(struct bt_att *att,
                                        uint16_t start, uint16_t end,
-                                       bt_gatt_discovery_callback_t callback,
+                                       bt_gatt_request_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy);
 
 bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end,
                                        const bt_uuid_t *uuid,
-                                       bt_gatt_discovery_callback_t callback,
+                                       bt_gatt_request_callback_t callback,
                                        void *user_data,
                                        bt_gatt_destroy_func_t destroy);
index 00f36fd..1485e8c 100644 (file)
@@ -25,6 +25,7 @@
 #include <errno.h>
 
 #include "src/shared/att.h"
+#include "lib/bluetooth.h"
 #include "lib/uuid.h"
 #include "src/shared/queue.h"
 #include "src/shared/gatt-db.h"
@@ -87,10 +88,12 @@ struct bt_gatt_server {
        unsigned int read_by_grp_type_id;
        unsigned int read_by_type_id;
        unsigned int find_info_id;
+       unsigned int find_by_type_value_id;
        unsigned int write_id;
        unsigned int write_cmd_id;
        unsigned int read_id;
        unsigned int read_blob_id;
+       unsigned int read_multiple_id;
        unsigned int prep_write_id;
        unsigned int exec_write_id;
 
@@ -114,10 +117,12 @@ static void bt_gatt_server_free(struct bt_gatt_server *server)
        bt_att_unregister(server->att, server->read_by_grp_type_id);
        bt_att_unregister(server->att, server->read_by_type_id);
        bt_att_unregister(server->att, server->find_info_id);
+       bt_att_unregister(server->att, server->find_by_type_value_id);
        bt_att_unregister(server->att, server->write_id);
        bt_att_unregister(server->att, server->write_cmd_id);
        bt_att_unregister(server->att, server->read_id);
        bt_att_unregister(server->att, server->read_blob_id);
+       bt_att_unregister(server->att, server->read_multiple_id);
        bt_att_unregister(server->att, server->prep_write_id);
        bt_att_unregister(server->att, server->exec_write_id);
 
@@ -164,13 +169,14 @@ static void attribute_read_cb(struct gatt_db_attribute *attrib, int err,
 }
 
 static bool encode_read_by_grp_type_rsp(struct gatt_db *db, struct queue *q,
-                                               uint16_t mtu,
-                                               uint8_t *pdu, uint16_t *len)
+                                               struct bt_att *att,
+                                               uint16_t mtu, uint8_t *pdu,
+                                               uint16_t *len)
 {
        int iter = 0;
        uint16_t start_handle, end_handle;
        struct iovec value;
-       uint8_t data_val_len;
+       uint8_t data_val_len = 0;
 
        *len = 0;
 
@@ -186,7 +192,7 @@ static bool encode_read_by_grp_type_rsp(struct gatt_db *db, struct queue *q,
                 */
                if (!gatt_db_attribute_read(attrib, 0,
                                                BT_ATT_OP_READ_BY_GRP_TYPE_REQ,
-                                               NULL, attribute_read_cb,
+                                               att, attribute_read_cb,
                                                &value) || !value.iov_len)
                        return false;
 
@@ -287,8 +293,8 @@ static void read_by_grp_type_cb(uint8_t opcode, const void *pdu,
                goto error;
        }
 
-       if (!encode_read_by_grp_type_rsp(server->db, q, mtu, rsp_pdu,
-                                                               &rsp_len)) {
+       if (!encode_read_by_grp_type_rsp(server->db, q, server->att, mtu,
+                                                       rsp_pdu, &rsp_len)) {
                ecode = BT_ATT_ERROR_UNLIKELY;
                goto error;
        }
@@ -389,10 +395,7 @@ static void process_read_by_type(struct async_read_op *op)
                return;
        }
 
-       if (!gatt_db_attribute_get_permissions(attr, &perm)) {
-               ecode = BT_ATT_ERROR_UNLIKELY;
-               goto error;
-       }
+       perm = gatt_db_attribute_get_permissions(attr);
 
        /*
         * Check for the READ access permission. Encryption,
@@ -405,8 +408,8 @@ static void process_read_by_type(struct async_read_op *op)
                goto error;
        }
 
-       if (gatt_db_attribute_read(attr, 0, op->opcode, NULL,
-                               read_by_type_read_complete_cb, op))
+       if (gatt_db_attribute_read(attr, 0, op->opcode, server->att,
+                                       read_by_type_read_complete_cb, op))
                return;
 
        ecode = BT_ATT_ERROR_UNLIKELY;
@@ -498,27 +501,6 @@ error:
        queue_destroy(q, NULL);
 }
 
-static void put_uuid_le(const bt_uuid_t *src, void *dst)
-{
-       bt_uuid_t uuid;
-
-       switch (src->type) {
-       case BT_UUID16:
-               put_le16(src->value.u16, dst);
-               break;
-       case BT_UUID128:
-               bswap_128(&src->value.u128, dst);
-               break;
-       case BT_UUID32:
-               bt_uuid_to_uuid128(src, &uuid);
-               bswap_128(&uuid.value.u128, dst);
-               break;
-       case BT_UUID_UNSPEC:
-       default:
-               break;
-       }
-}
-
 static bool encode_find_info_rsp(struct gatt_db *db, struct queue *q,
                                                uint16_t mtu,
                                                uint8_t *pdu, uint16_t *len)
@@ -526,7 +508,7 @@ static bool encode_find_info_rsp(struct gatt_db *db, struct queue *q,
        uint16_t handle;
        struct gatt_db_attribute *attr;
        const bt_uuid_t *type;
-       int uuid_len, cur_uuid_len;
+       int uuid_len = 0, cur_uuid_len;
        int iter = 0;
 
        *len = 0;
@@ -563,7 +545,7 @@ static bool encode_find_info_rsp(struct gatt_db *db, struct queue *q,
                        break;
 
                put_le16(handle, pdu + iter);
-               put_uuid_le(type, pdu + iter + 2);
+               bt_uuid_to_le(type, pdu + iter + 2);
 
                iter += uuid_len + 2;
        }
@@ -639,6 +621,98 @@ error:
 
 }
 
+struct find_by_type_val_data {
+       uint8_t *pdu;
+       uint16_t len;
+       uint16_t mtu;
+       uint8_t ecode;
+};
+
+static void find_by_type_val_att_cb(struct gatt_db_attribute *attrib,
+                                                               void *user_data)
+{
+       uint16_t handle, end_handle;
+       struct find_by_type_val_data *data = user_data;
+
+       if (data->ecode)
+               return;
+
+       if (data->len + 4 > data->mtu - 1)
+               return;
+
+       /*
+        * This OP is only valid for Primary Service per the spec
+        * page 562, so this should work.
+        */
+       gatt_db_attribute_get_service_data(attrib, &handle, &end_handle, NULL,
+                                                                       NULL);
+
+       if (!handle || !end_handle) {
+               data->ecode = BT_ATT_ERROR_UNLIKELY;
+               return;
+       }
+
+       put_le16(handle, data->pdu + data->len);
+       put_le16(end_handle, data->pdu + data->len + 2);
+
+       data->len += 4;
+}
+
+static void find_by_type_val_cb(uint8_t opcode, const void *pdu,
+                                       uint16_t length, void *user_data)
+{
+       struct bt_gatt_server *server = user_data;
+       uint16_t start, end, uuid16;
+       struct find_by_type_val_data data;
+       uint16_t mtu = bt_att_get_mtu(server->att);
+       uint8_t rsp_pdu[mtu];
+       uint16_t ehandle = 0;
+       bt_uuid_t uuid;
+
+       if (length < 6) {
+               data.ecode = BT_ATT_ERROR_INVALID_PDU;
+               goto error;
+       }
+
+       data.pdu = rsp_pdu;
+       data.len = 0;
+       data.mtu = mtu;
+       data.ecode = 0;
+
+       start = get_le16(pdu);
+       end = get_le16(pdu + 2);
+       uuid16 = get_le16(pdu + 4);
+
+       util_debug(server->debug_callback, server->debug_data,
+                       "Find By Type Value - start: 0x%04x end: 0x%04x uuid: 0x%04x",
+                       start, end, uuid16);
+       ehandle = start;
+       if (start > end) {
+               data.ecode = BT_ATT_ERROR_INVALID_HANDLE;
+               goto error;
+       }
+
+       bt_uuid16_create(&uuid, uuid16);
+       gatt_db_find_by_type_value(server->db, start, end, &uuid, pdu + 6,
+                                                       length - 6,
+                                                       find_by_type_val_att_cb,
+                                                       &data);
+
+       if (!data.len)
+               data.ecode = BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND;
+
+       if (data.ecode)
+               goto error;
+
+       bt_att_send(server->att, BT_ATT_OP_FIND_BY_TYPE_VAL_RSP, data.pdu,
+                                               data.len, NULL, NULL, NULL);
+
+       return;
+
+error:
+       bt_att_send_error_rsp(server->att, opcode, ehandle, data.ecode);
+}
+
 static void async_write_op_destroy(struct async_write_op *op)
 {
        if (op->server)
@@ -697,10 +771,7 @@ static void write_cb(uint8_t opcode, const void *pdu,
                                (opcode == BT_ATT_OP_WRITE_REQ) ? "Req" : "Cmd",
                                handle);
 
-       if (!gatt_db_attribute_get_permissions(attr, &perm)) {
-               ecode = BT_ATT_ERROR_INVALID_HANDLE;
-               goto error;
-       }
+       perm = gatt_db_attribute_get_permissions(attr);
 
        if (!(perm & BT_ATT_PERM_WRITE)) {
                ecode = BT_ATT_ERROR_WRITE_NOT_PERMITTED;
@@ -723,7 +794,8 @@ static void write_cb(uint8_t opcode, const void *pdu,
        server->pending_write_op = op;
 
        if (gatt_db_attribute_write(attr, 0, pdu + 2, length - 2, opcode,
-                                               NULL, write_complete_cb, op))
+                                                       server->att,
+                                                       write_complete_cb, op))
                return;
 
        if (op)
@@ -813,10 +885,7 @@ static void handle_read_req(struct bt_gatt_server *server, uint8_t opcode,
                        opcode == BT_ATT_OP_READ_BLOB_REQ ? "Blob " : "",
                        handle);
 
-       if (!gatt_db_attribute_get_permissions(attr, &perm)) {
-               ecode = BT_ATT_ERROR_INVALID_HANDLE;
-               goto error;
-       }
+       perm = gatt_db_attribute_get_permissions(attr);
 
        if (perm && !(perm & BT_ATT_PERM_READ)) {
                ecode = BT_ATT_ERROR_READ_NOT_PERMITTED;
@@ -838,7 +907,7 @@ static void handle_read_req(struct bt_gatt_server *server, uint8_t opcode,
        op->server = server;
        server->pending_read_op = op;
 
-       if (gatt_db_attribute_read(attr, offset, opcode, NULL,
+       if (gatt_db_attribute_read(attr, offset, opcode, server->att,
                                                        read_complete_cb, op))
                return;
 
@@ -886,6 +955,149 @@ static void read_blob_cb(uint8_t opcode, const void *pdu,
        handle_read_req(server, opcode, handle, offset);
 }
 
+struct read_multiple_resp_data {
+       struct bt_gatt_server *server;
+       uint16_t *handles;
+       size_t cur_handle;
+       size_t num_handles;
+       uint8_t *rsp_data;
+       size_t length;
+       size_t mtu;
+};
+
+static void read_multiple_resp_data_free(struct read_multiple_resp_data *data)
+{
+       free(data->handles);
+       data->handles = NULL;
+
+       free(data->rsp_data);
+       data->rsp_data = NULL;
+}
+
+static void read_multiple_complete_cb(struct gatt_db_attribute *attr, int err,
+                                       const uint8_t *value, size_t len,
+                                       void *user_data)
+{
+       struct read_multiple_resp_data *data = user_data;
+       struct gatt_db_attribute *next_attr;
+       uint32_t perm;
+       uint16_t handle = gatt_db_attribute_get_handle(attr);
+
+       if (err != 0) {
+               bt_att_send_error_rsp(data->server->att,
+                                       BT_ATT_OP_READ_MULT_REQ, handle, err);
+               read_multiple_resp_data_free(data);
+               return;
+       }
+
+       perm = gatt_db_attribute_get_permissions(attr);
+
+       if (perm && !(perm & BT_ATT_PERM_READ)) {
+               bt_att_send_error_rsp(data->server->att,
+                                       BT_ATT_OP_READ_MULT_REQ, handle,
+                                       BT_ATT_ERROR_READ_NOT_PERMITTED);
+               read_multiple_resp_data_free(data);
+               return;
+       }
+
+       len = MIN(len, data->mtu - data->length - 1);
+
+       memcpy(data->rsp_data + data->length, value, len);
+       data->length += len;
+
+       data->cur_handle++;
+
+       if ((data->length >= data->mtu - 1) ||
+                               (data->cur_handle == data->num_handles)) {
+               bt_att_send(data->server->att, BT_ATT_OP_READ_MULT_RSP,
+                               data->rsp_data, data->length, NULL, NULL, NULL);
+               read_multiple_resp_data_free(data);
+               return;
+       }
+
+       util_debug(data->server->debug_callback, data->server->debug_data,
+                               "Read Multiple Req - #%zu of %zu: 0x%04x",
+                               data->cur_handle + 1, data->num_handles,
+                               data->handles[data->cur_handle]);
+
+       next_attr = gatt_db_get_attribute(data->server->db,
+                                       data->handles[data->cur_handle]);
+
+       if (!next_attr) {
+               bt_att_send_error_rsp(data->server->att,
+                                       BT_ATT_OP_READ_MULT_REQ,
+                                       data->handles[data->cur_handle],
+                                       BT_ATT_ERROR_INVALID_HANDLE);
+               read_multiple_resp_data_free(data);
+               return;
+       }
+
+       if (!gatt_db_attribute_read(next_attr, 0, BT_ATT_OP_READ_MULT_REQ,
+                                       data->server->att,
+                                       read_multiple_complete_cb, data)) {
+               bt_att_send_error_rsp(data->server->att,
+                                               BT_ATT_OP_READ_MULT_REQ,
+                                               data->handles[data->cur_handle],
+                                               BT_ATT_ERROR_UNLIKELY);
+               read_multiple_resp_data_free(data);
+       }
+}
+
+static void read_multiple_cb(uint8_t opcode, const void *pdu,
+                                       uint16_t length, void *user_data)
+{
+       struct bt_gatt_server *server = user_data;
+       struct gatt_db_attribute *attr;
+       struct read_multiple_resp_data data;
+       uint8_t ecode = BT_ATT_ERROR_UNLIKELY;
+       size_t i = 0;
+
+       data.handles = NULL;
+       data.rsp_data = NULL;
+
+       if (length < 4) {
+               ecode = BT_ATT_ERROR_INVALID_PDU;
+               goto error;
+       }
+
+       data.server = server;
+       data.num_handles = length / 2;
+       data.cur_handle = 0;
+       data.mtu = bt_att_get_mtu(server->att);
+       data.length = 0;
+       data.rsp_data = malloc(data.mtu - 1);
+
+       if (!data.rsp_data)
+               goto error;
+
+       data.handles = new0(uint16_t, data.num_handles);
+
+       if (!data.handles)
+               goto error;
+
+       for (i = 0; i < data.num_handles; i++)
+               data.handles[i] = get_le16(pdu + i * 2);
+
+       util_debug(server->debug_callback, server->debug_data,
+                       "Read Multiple Req - %zu handles, 1st: 0x%04x",
+                       data.num_handles, data.handles[0]);
+
+       attr = gatt_db_get_attribute(server->db, data.handles[0]);
+
+       if (!attr) {
+               ecode = BT_ATT_ERROR_INVALID_HANDLE;
+               goto error;
+       }
+
+       if (gatt_db_attribute_read(attr, 0, opcode, server->att,
+                                       read_multiple_complete_cb, &data))
+               return;
+
+error:
+       read_multiple_resp_data_free(&data);
+       bt_att_send_error_rsp(server->att, opcode, 0, ecode);
+}
+
 static void prep_write_cb(uint8_t opcode, const void *pdu,
                                        uint16_t length, void *user_data)
 {
@@ -919,10 +1131,7 @@ static void prep_write_cb(uint8_t opcode, const void *pdu,
        util_debug(server->debug_callback, server->debug_data,
                                "Prep Write Req - handle: 0x%04x", handle);
 
-       if (!gatt_db_attribute_get_permissions(attr, &perm)) {
-               ecode = BT_ATT_ERROR_INVALID_HANDLE;
-               goto error;
-       }
+       perm = gatt_db_attribute_get_permissions(attr);
 
        /*
         * TODO: The "Prepare Write" request requires security permission checks
@@ -1007,7 +1216,8 @@ static void exec_next_prep_write(struct bt_gatt_server *server,
 
        status = gatt_db_attribute_write(attr, next->offset,
                                                next->value, next->length,
-                                               BT_ATT_OP_EXEC_WRITE_REQ, NULL,
+                                               BT_ATT_OP_EXEC_WRITE_REQ,
+                                               server->att,
                                                exec_write_complete_cb, server);
 
        prep_write_data_destroy(next);
@@ -1128,6 +1338,15 @@ static bool gatt_server_register_att_handlers(struct bt_gatt_server *server)
        if (!server->find_info_id)
                return false;
 
+       /* Find By Type Value */
+       server->find_by_type_value_id = bt_att_register(server->att,
+                                               BT_ATT_OP_FIND_BY_TYPE_VAL_REQ,
+                                               find_by_type_val_cb,
+                                               server, NULL);
+
+       if (!server->find_by_type_value_id)
+               return false;
+
        /* Write Request */
        server->write_id = bt_att_register(server->att, BT_ATT_OP_WRITE_REQ,
                                                                write_cb,
@@ -1157,6 +1376,15 @@ static bool gatt_server_register_att_handlers(struct bt_gatt_server *server)
        if (!server->read_blob_id)
                return false;
 
+       /* Read Multiple Request */
+       server->read_multiple_id = bt_att_register(server->att,
+                                                       BT_ATT_OP_READ_MULT_REQ,
+                                                       read_multiple_cb,
+                                                       server, NULL);
+
+       if (!server->read_multiple_id)
+               return false;
+
        /* Prepare Write Request */
        server->prep_write_id = bt_att_register(server->att,
                                                BT_ATT_OP_PREP_WRITE_REQ,
@@ -1255,13 +1483,13 @@ bool bt_gatt_server_send_notification(struct bt_gatt_server *server,
        if (!server || (length && !value))
                return false;
 
-       pdu_len = MIN(bt_att_get_mtu(server->att), length + 2);
+       pdu_len = MIN(bt_att_get_mtu(server->att) - 1, length + 2);
        pdu = malloc(pdu_len);
        if (!pdu)
                return false;
 
        put_le16(handle, pdu);
-       memcpy(pdu + 2, value, length);
+       memcpy(pdu + 2, value, pdu_len - 2);
 
        result = !!bt_att_send(server->att, BT_ATT_OP_HANDLE_VAL_NOT, pdu,
                                                pdu_len, NULL, NULL, NULL);
@@ -1310,7 +1538,7 @@ bool bt_gatt_server_send_indication(struct bt_gatt_server *server,
        if (!server || (length && !value))
                return false;
 
-       pdu_len = MIN(bt_att_get_mtu(server->att), length + 2);
+       pdu_len = MIN(bt_att_get_mtu(server->att) - 1, length + 2);
        pdu = malloc(pdu_len);
        if (!pdu)
                return false;
@@ -1326,7 +1554,7 @@ bool bt_gatt_server_send_indication(struct bt_gatt_server *server,
        data->user_data = user_data;
 
        put_le16(handle, pdu);
-       memcpy(pdu + 2, value, length);
+       memcpy(pdu + 2, value, pdu_len - 2);
 
        result = !!bt_att_send(server->att, BT_ATT_OP_HANDLE_VAL_IND, pdu,
                                                        pdu_len, conf_cb,
index 9ab8c6e..0db0146 100644 (file)
@@ -32,7 +32,7 @@
 #include <sys/uio.h>
 
 #include "monitor/bt.h"
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
 #include "src/shared/io.h"
 #include "src/shared/util.h"
 #include "src/shared/queue.h"
index 9d937a5..74ee979 100644 (file)
@@ -183,8 +183,8 @@ static void handle_unknown_at_command(struct hfp_gw *hfp,
                                                        const char *data)
 {
        if (hfp->command_callback) {
-               hfp->command_callback(data, hfp->command_data);
                hfp->result_pending = true;
+               hfp->command_callback(data, hfp->command_data);
        } else {
                hfp_gw_send_result(hfp, HFP_RESULT_ERROR);
        }
@@ -263,6 +263,7 @@ done:
                return true;
        }
 
+       hfp->result_pending = true;
        handler->callback(&context, type, handler->user_data);
 
        return true;
@@ -610,10 +611,9 @@ struct hfp_gw *hfp_gw_new(int fd)
                return NULL;
        }
 
-       if (!io_set_read_handler(hfp->io, can_read_data,
-                                       hfp, read_watch_destroy)) {
-               queue_destroy(hfp->cmd_handlers,
-                                               destroy_cmd_handler);
+       if (!io_set_read_handler(hfp->io, can_read_data, hfp,
+                                                       read_watch_destroy)) {
+               queue_destroy(hfp->cmd_handlers, destroy_cmd_handler);
                io_destroy(hfp->io);
                ringbuf_free(hfp->write_buf);
                ringbuf_free(hfp->read_buf);
@@ -762,7 +762,7 @@ bool hfp_gw_send_result(struct hfp_gw *hfp, enum hfp_result result)
         */
        if (hfp->result_pending) {
                hfp->result_pending = false;
-               can_read_data(hfp->io, hfp);
+               process_input(hfp);
        }
 
        return true;
@@ -778,7 +778,14 @@ bool hfp_gw_send_error(struct hfp_gw *hfp, enum hfp_error error)
 
        wakeup_writer(hfp);
 
-       hfp->result_pending = false;
+       /*
+        * There might be already something to read in the ring buffer.
+        * If so, let's read it.
+        */
+       if (hfp->result_pending) {
+               hfp->result_pending = false;
+               process_input(hfp);
+       }
 
        return true;
 }
@@ -1192,10 +1199,6 @@ static void hf_process_input(struct hfp_hf *hfp)
        if (len == ringbuf_len(hfp->read_buf))
                goto done;
 
-       /* If we are here second time for some reason, that is wrong */
-       if (free_tmp)
-               goto done;
-
        str2 = ringbuf_peek(hfp->read_buf, len, &len2);
        if (!str2)
                goto done;
index 7f80d8f..4923710 100644 (file)
@@ -29,7 +29,7 @@
 #include <errno.h>
 #include <sys/socket.h>
 
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
 #include "src/shared/util.h"
 #include "src/shared/io.h"
 
similarity index 95%
rename from monitor/mainloop.c
rename to src/shared/mainloop.c
index 8d4b391..9fff615 100644 (file)
@@ -42,6 +42,7 @@
 
 static int epoll_fd;
 static int epoll_terminate;
+static int exit_status;
 
 struct mainloop_data {
        int fd;
@@ -89,6 +90,18 @@ void mainloop_quit(void)
        epoll_terminate = 1;
 }
 
+void mainloop_exit_success(void)
+{
+       exit_status = EXIT_SUCCESS;
+       epoll_terminate = 1;
+}
+
+void mainloop_exit_failure(void)
+{
+       exit_status = EXIT_FAILURE;
+       epoll_terminate = 1;
+}
+
 static void signal_callback(int fd, uint32_t events, void *user_data)
 {
        struct signal_data *data = user_data;
@@ -114,20 +127,22 @@ int mainloop_run(void)
 
        if (signal_data) {
                if (sigprocmask(SIG_BLOCK, &signal_data->mask, NULL) < 0)
-                       return 1;
+                       return EXIT_FAILURE;
 
                signal_data->fd = signalfd(-1, &signal_data->mask,
                                                SFD_NONBLOCK | SFD_CLOEXEC);
                if (signal_data->fd < 0)
-                       return 1;
+                       return EXIT_FAILURE;
 
                if (mainloop_add_fd(signal_data->fd, EPOLLIN,
                                signal_callback, signal_data, NULL) < 0) {
                        close(signal_data->fd);
-                       return 1;
+                       return EXIT_FAILURE;
                }
        }
 
+       exit_status = EXIT_SUCCESS;
+
        while (!epoll_terminate) {
                struct epoll_event events[MAX_EPOLL_EVENTS];
                int n, nfds;
@@ -170,7 +185,7 @@ int mainloop_run(void)
        close(epoll_fd);
        epoll_fd = 0;
 
-       return 0;
+       return exit_status;
 }
 
 int mainloop_add_fd(int fd, uint32_t events, mainloop_event_func callback,
similarity index 96%
rename from monitor/mainloop.h
rename to src/shared/mainloop.h
index dafec8b..b83caab 100644 (file)
@@ -33,6 +33,8 @@ typedef void (*mainloop_signal_func) (int signum, void *user_data);
 
 void mainloop_init(void);
 void mainloop_quit(void);
+void mainloop_exit_success(void);
+void mainloop_exit_failure(void);
 int mainloop_run(void);
 
 int mainloop_add_fd(int fd, uint32_t events, mainloop_event_func callback,
index ccf2f07..3507ed1 100644 (file)
@@ -362,9 +362,10 @@ unsigned int queue_remove_all(struct queue *queue, queue_match_func_t function,
        if (function) {
                while (entry) {
                        void *data;
+                       unsigned int entries = queue->entries;
 
                        data = queue_remove_if(queue, function, user_data);
-                       if (!data)
+                       if (entries == queue->entries)
                                break;
 
                        if (destroy)
@@ -372,8 +373,6 @@ unsigned int queue_remove_all(struct queue *queue, queue_match_func_t function,
 
                        count++;
                }
-
-               queue->entries -= count;
        } else {
                queue->head = NULL;
                queue->tail = NULL;
index fb645a0..ffcc2ea 100644 (file)
@@ -270,7 +270,7 @@ void *tester_get_data(void)
        return test->user_data;
 }
 
-static void tester_summarize(void)
+static int tester_summarize(void)
 {
        unsigned int not_run = 0, passed = 0, failed = 0;
        gdouble execution_time;
@@ -321,6 +321,7 @@ static void tester_summarize(void)
        execution_time = g_timer_elapsed(test_timer, NULL);
        printf("Overall execution time: %.3g seconds\n", execution_time);
 
+       return failed;
 }
 
 static gboolean teardown_callback(gpointer user_data)
@@ -800,6 +801,7 @@ void tester_init(int *argc, char ***argv)
 int tester_run(void)
 {
        guint signal;
+       int ret;
 
        if (!main_loop)
                return EXIT_FAILURE;
@@ -818,9 +820,9 @@ int tester_run(void)
 
        g_main_loop_unref(main_loop);
 
-       tester_summarize();
+       ret = tester_summarize();
 
        g_list_free_full(test_list, test_destroy);
 
-       return EXIT_SUCCESS;
+       return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
index 77aaa63..f099312 100644 (file)
@@ -19,8 +19,7 @@
 
 #include <stdlib.h>
 
-#include "monitor/mainloop.h"
-
+#include "mainloop.h"
 #include "util.h"
 #include "timeout.h"
 
index 74ffb08..a70c709 100644 (file)
@@ -33,6 +33,7 @@
 #include <unistd.h>
 #include <dirent.h>
 #include <limits.h>
+#include <string.h>
 
 #include "src/shared/util.h"
 
@@ -106,3 +107,31 @@ unsigned char util_get_dt(const char *parent, const char *name)
 
        return DT_UNKNOWN;
 }
+
+/* Helpers for bitfield operations */
+
+/* Find unique id in range from 1 to max but no bigger then
+ * sizeof(int) * 8. ffs() is used since it is POSIX standard
+ */
+uint8_t util_get_uid(unsigned int *bitmap, uint8_t max)
+{
+       uint8_t id;
+
+       id = ffs(~*bitmap);
+
+       if (!id || id > max)
+               return 0;
+
+       *bitmap |= 1 << (id - 1);
+
+       return id;
+}
+
+/* Clear id bit in bitmap */
+void util_clear_uid(unsigned int *bitmap, uint8_t id)
+{
+       if (!id)
+               return;
+
+       *bitmap &= ~(1 << (id - 1));
+}
index 8437662..30b7d92 100644 (file)
@@ -93,15 +93,8 @@ void util_hexdump(const char dir, const unsigned char *buf, size_t len,
 
 unsigned char util_get_dt(const char *parent, const char *name);
 
-static inline void bswap_128(const void *src, void *dst)
-{
-       const uint8_t *s = src;
-       uint8_t *d = dst;
-       int i;
-
-       for (i = 0; i < 16; i++)
-               d[15 - i] = s[i];
-}
+uint8_t util_get_uid(unsigned int *bitmap, uint8_t max);
+void util_clear_uid(unsigned int *bitmap, uint8_t id);
 
 static inline uint16_t get_le16(const void *ptr)
 {
index 7601547..aba4523 100644 (file)
 
 #include <glib.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 #include "lib/uuid.h"
+
 #include "textfile.h"
 #include "uuid-helper.h"
 #include "storage.h"
index bce36b0..d751817 100644 (file)
@@ -31,9 +31,9 @@
 #include <errno.h>
 #include <arpa/inet.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 
 #include "uuid-helper.h"
 
old mode 100755 (executable)
new mode 100644 (file)
index 51e26eb..16a786b
@@ -170,6 +170,6 @@ if  __name__ == '__main__':
 
                pbap_client.flush_transfers(lambda: test_paths(paths[1:]))
 
-       test_paths(["PB", "ICH", "OCH", "MCH", "CCH"])
+       test_paths(["PB", "ICH", "OCH", "MCH", "CCH", "SPD", "FAV"])
 
        mainloop.run()
index 68dcbb5..686fe13 100644 (file)
 #include <string.h>
 #include <getopt.h>
 
-#include "monitor/mainloop.h"
 #include "monitor/bt.h"
+#include "src/shared/mainloop.h"
 #include "src/shared/timeout.h"
 #include "src/shared/util.h"
 #include "src/shared/hci.h"
 
 #define LT_ADDR 0x01
 #define PKT_TYPE 0x0008                /* 0x0008 = EDR + DM1, 0xff1e = BR only */
-#define SERVICE_DATA LT_ADDR
+#define SERVICE_DATA 0x00
+
+struct broadcast_message {
+       uint32_t frame_sync_instant;
+       uint16_t bluetooth_clock_phase;
+       uint16_t left_open_offset;
+       uint16_t left_close_offset;
+       uint16_t right_open_offset;
+       uint16_t right_close_offset;
+       uint16_t frame_sync_period;
+       uint8_t  frame_sync_period_fraction;
+} __attribute__ ((packed));
+
+struct brcm_evt_sync_train_received {
+       uint8_t  status;
+       uint8_t  bdaddr[6];
+       uint32_t offset;
+       uint8_t  map[10];
+       uint8_t  service_data;
+       uint8_t  lt_addr;
+       uint32_t instant;
+       uint16_t interval;
+} __attribute__ ((packed));
 
 static struct bt_hci *hci_dev;
 
@@ -76,7 +98,34 @@ static void shutdown_device(void)
                mainloop_quit();
 }
 
-static void slave_broadcast_receive(const void *data, uint8_t size,
+static void inquiry_started(const void *data, uint8_t size, void *user_data)
+{
+       uint8_t status = *((uint8_t *) data);
+
+       if (status) {
+               printf("Failed to search for 3D display\n");
+               shutdown_device();
+               return;
+       }
+
+       printf("Searching for 3D display\n");
+}
+
+static void start_inquiry(void)
+{
+       struct bt_hci_cmd_inquiry cmd;
+
+       cmd.lap[0] = 0x33;
+       cmd.lap[1] = 0x8b;
+       cmd.lap[2] = 0x9e;
+       cmd.length = 0x08;
+       cmd.num_resp = 0x00;
+
+       bt_hci_send(hci_dev, BT_HCI_CMD_INQUIRY, &cmd, sizeof(cmd),
+                                               inquiry_started, NULL, NULL);
+}
+
+static void set_slave_broadcast_receive(const void *data, uint8_t size,
                                                        void *user_data)
 {
        printf("Slave broadcast receiption enabled\n");
@@ -90,7 +139,12 @@ static void sync_train_received(const void *data, uint8_t size,
 
        if (evt->status) {
                printf("Failed to synchronize with 3D display\n");
-               shutdown_device();
+               start_inquiry();
+               return;
+       }
+
+       if (evt->lt_addr != LT_ADDR) {
+               printf("Ignoring synchronization for non 3D display\n");
                return;
        }
 
@@ -107,8 +161,42 @@ static void sync_train_received(const void *data, uint8_t size,
        memcpy(cmd.map, evt->map, 10);
 
        bt_hci_send(hci_dev, BT_HCI_CMD_SET_SLAVE_BROADCAST_RECEIVE,
-                                       &cmd, sizeof(cmd),
-                                       slave_broadcast_receive, NULL, NULL);
+                               &cmd, sizeof(cmd),
+                               set_slave_broadcast_receive, NULL, NULL);
+}
+
+static void brcm_sync_train_received(const void *data, uint8_t size,
+                                                       void *user_data)
+{
+       const struct brcm_evt_sync_train_received *evt = data;
+       struct bt_hci_cmd_set_slave_broadcast_receive cmd;
+
+       if (evt->status) {
+               printf("Failed to synchronize with 3D display\n");
+               start_inquiry();
+               return;
+       }
+
+       if (evt->lt_addr != LT_ADDR) {
+               printf("Ignoring synchronization for non 3D display\n");
+               return;
+       }
+
+       cmd.enable = 0x01;
+       memcpy(cmd.bdaddr, evt->bdaddr, 6);
+       cmd.lt_addr = evt->lt_addr;
+       cmd.interval = evt->interval;
+       cmd.offset = evt->offset;
+       cmd.instant = evt->instant;
+       cmd.timeout = cpu_to_le16(0xfffe);
+       cmd.accuracy = 250;
+       cmd.skip = 20;
+       cmd.pkt_type = cpu_to_le16(PKT_TYPE);
+       memcpy(cmd.map, evt->map, 10);
+
+       bt_hci_send(hci_dev, BT_HCI_CMD_SET_SLAVE_BROADCAST_RECEIVE,
+                               &cmd, sizeof(cmd),
+                               set_slave_broadcast_receive, NULL, NULL);
 }
 
 static void truncated_page_complete(const void *data, uint8_t size,
@@ -125,8 +213,22 @@ static void truncated_page_complete(const void *data, uint8_t size,
 
        printf("Attempt to synchronize with 3D display\n");
 
-       bt_hci_register(hci_dev, BT_HCI_EVT_SYNC_TRAIN_RECEIVED,
-                                       sync_train_received, NULL, NULL);
+       memcpy(cmd.bdaddr, evt->bdaddr, 6);
+       cmd.timeout = cpu_to_le16(0x4000);
+       cmd.window = cpu_to_le16(0x0100);
+       cmd.interval = cpu_to_le16(0x0080);
+
+       bt_hci_send(hci_dev, BT_HCI_CMD_RECEIVE_SYNC_TRAIN, &cmd, sizeof(cmd),
+                                                       NULL, NULL, NULL);
+}
+
+static void slave_broadcast_timeout(const void *data, uint8_t size,
+                                                       void *user_data)
+{
+       const struct bt_hci_evt_slave_broadcast_timeout *evt = data;
+       struct bt_hci_cmd_receive_sync_train cmd;
+
+       printf("Re-synchronizing with 3D display\n");
 
        memcpy(cmd.bdaddr, evt->bdaddr, 6);
        cmd.timeout = cpu_to_le16(0x4000);
@@ -137,6 +239,25 @@ static void truncated_page_complete(const void *data, uint8_t size,
                                                        NULL, NULL, NULL);
 }
 
+static void slave_broadcast_receive(const void *data, uint8_t size,
+                                                       void *user_data)
+{
+       const struct bt_hci_evt_slave_broadcast_receive *evt = data;
+       struct bt_hci_cmd_read_clock cmd;
+
+       if (evt->status != 0x00)
+               return;
+
+       if (le32_to_cpu(evt->clock) != 0x00000000)
+               return;
+
+       cmd.handle = cpu_to_le16(0x0000);
+       cmd.type = 0x00;
+
+       bt_hci_send(hci_dev, BT_HCI_CMD_READ_CLOCK, &cmd, sizeof(cmd),
+                                                       NULL, NULL, NULL);
+}
+
 static void ext_inquiry_result(const void *data, uint8_t size, void *user_data)
 {
        const struct bt_hci_evt_ext_inquiry_result *evt = data;
@@ -153,9 +274,6 @@ static void ext_inquiry_result(const void *data, uint8_t size, void *user_data)
                bt_hci_send(hci_dev, BT_HCI_CMD_INQUIRY_CANCEL, NULL, 0,
                                                        NULL, NULL, NULL);
 
-               bt_hci_register(hci_dev, BT_HCI_EVT_TRUNCATED_PAGE_COMPLETE,
-                                       truncated_page_complete, NULL, NULL);
-
                memcpy(cmd.bdaddr, evt->bdaddr, 6);
                cmd.pscan_rep_mode = evt->pscan_rep_mode;
                cmd.clock_offset = evt->clock_offset;
@@ -169,25 +287,32 @@ static void inquiry_complete(const void *data, uint8_t size, void *user_data)
 {
        printf("No 3D display found\n");
 
-       shutdown_device();
+       start_inquiry();
 }
 
-static void inquiry_started(const void *data, uint8_t size, void *user_data)
+static void read_local_version(const void *data, uint8_t size, void *user_data)
 {
-       uint8_t status = *((uint8_t *) data);
+       const struct bt_hci_rsp_read_local_version *rsp = data;
 
-       if (status) {
-               printf("Failed to search for 3D display\n");
+       if (rsp->status) {
+               printf("Failed to read local version information\n");
                shutdown_device();
                return;
        }
 
-       printf("Searching for 3D display\n");
+       if (rsp->manufacturer == 15) {
+               printf("Enabling receiver workaround for Broadcom\n");
+
+               bt_hci_register(hci_dev, BT_HCI_EVT_SYNC_TRAIN_RECEIVED,
+                                       brcm_sync_train_received, NULL, NULL);
+       } else {
+               bt_hci_register(hci_dev, BT_HCI_EVT_SYNC_TRAIN_RECEIVED,
+                                       sync_train_received, NULL, NULL);
+       }
 }
 
 static void start_glasses(void)
 {
-       struct bt_hci_cmd_inquiry cmd;
        uint8_t evtmask1[] = { 0x03, 0xe0, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00 };
        uint8_t evtmask2[] = { 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00 };
        uint8_t inqmode = 0x02;
@@ -199,6 +324,9 @@ static void start_glasses(void)
                                                        NULL, NULL, NULL);
        }
 
+       bt_hci_send(hci_dev, BT_HCI_CMD_READ_LOCAL_VERSION, NULL, 0,
+                                       read_local_version, NULL, NULL);
+
        bt_hci_send(hci_dev, BT_HCI_CMD_SET_EVENT_MASK_PAGE2, evtmask2, 8,
                                                        NULL, NULL, NULL);
        bt_hci_send(hci_dev, BT_HCI_CMD_WRITE_INQUIRY_MODE, &inqmode, 1,
@@ -209,28 +337,14 @@ static void start_glasses(void)
        bt_hci_register(hci_dev, BT_HCI_EVT_EXT_INQUIRY_RESULT,
                                                ext_inquiry_result, NULL, NULL);
 
-       cmd.lap[0] = 0x33;
-       cmd.lap[1] = 0x8b;
-       cmd.lap[2] = 0x9e;
-       cmd.length = 0x08;
-       cmd.num_resp = 0x00;
-
-       bt_hci_send(hci_dev, BT_HCI_CMD_INQUIRY, &cmd, sizeof(cmd),
-                                               inquiry_started, NULL, NULL);
-}
-
-static void conn_request(const void *data, uint8_t size, void *user_data)
-{
-       const struct bt_hci_evt_conn_request *evt = data;
-       struct bt_hci_cmd_accept_conn_request cmd;
-
-       printf("Incoming connection from 3D glasses\n");
-
-       memcpy(cmd.bdaddr, evt->bdaddr, 6);
-       cmd.role = 0x00;
+       bt_hci_register(hci_dev, BT_HCI_EVT_TRUNCATED_PAGE_COMPLETE,
+                                       truncated_page_complete, NULL, NULL);
+       bt_hci_register(hci_dev, BT_HCI_EVT_SLAVE_BROADCAST_TIMEOUT,
+                                       slave_broadcast_timeout, NULL, NULL);
+       bt_hci_register(hci_dev, BT_HCI_EVT_SLAVE_BROADCAST_RECEIVE,
+                                       slave_broadcast_receive, NULL, NULL);
 
-       bt_hci_send(hci_dev, BT_HCI_CMD_ACCEPT_CONN_REQUEST, &cmd, sizeof(cmd),
-                                                       NULL, NULL, NULL);
+       start_inquiry();
 }
 
 static bool sync_train_active = false;
@@ -241,8 +355,7 @@ static void sync_train_complete(const void *data, uint8_t size,
        sync_train_active = false;
 }
 
-static void slave_page_response_timeout(const void *data, uint8_t size,
-                                                       void *user_data)
+static void start_sync_train(void)
 {
        struct bt_hci_cmd_write_sync_train_params cmd;
 
@@ -259,15 +372,44 @@ static void slave_page_response_timeout(const void *data, uint8_t size,
        bt_hci_send(hci_dev, BT_HCI_CMD_WRITE_SYNC_TRAIN_PARAMS,
                                        &cmd, sizeof(cmd), NULL, NULL, NULL);
 
-       bt_hci_send(hci_dev, BT_HCI_CMD_READ_SYNC_TRAIN_PARAMS, NULL, 0,
-                                                       NULL, NULL, NULL);
-
        bt_hci_send(hci_dev, BT_HCI_CMD_START_SYNC_TRAIN, NULL, 0,
                                                        NULL, NULL, NULL);
 
        sync_train_active = true;
 }
 
+static void conn_request(const void *data, uint8_t size, void *user_data)
+{
+       const struct bt_hci_evt_conn_request *evt = data;
+       struct bt_hci_cmd_accept_conn_request cmd;
+
+       printf("Incoming connection from 3D glasses\n");
+
+       memcpy(cmd.bdaddr, evt->bdaddr, 6);
+       cmd.role = 0x00;
+
+       bt_hci_send(hci_dev, BT_HCI_CMD_ACCEPT_CONN_REQUEST, &cmd, sizeof(cmd),
+                                                       NULL, NULL, NULL);
+
+       start_sync_train();
+}
+
+static void slave_page_response_timeout(const void *data, uint8_t size,
+                                                       void *user_data)
+{
+       printf("Incoming truncated page received\n");
+
+       start_sync_train();
+}
+
+static void slave_broadcast_channel_map_change(const void *data, uint8_t size,
+                                                               void *user_data)
+{
+       printf("Broadcast channel map changed\n");
+
+       start_sync_train();
+}
+
 static void inquiry_resp_tx_power(const void *data, uint8_t size,
                                                        void *user_data)
 {
@@ -292,10 +434,53 @@ static void inquiry_resp_tx_power(const void *data, uint8_t size,
                                                        NULL, NULL, NULL);
 }
 
+static void read_clock(const void *data, uint8_t size, void *user_data)
+{
+       const struct bt_hci_rsp_read_clock *rsp = data;
+       struct broadcast_message msg;
+       uint8_t bcastdata[sizeof(msg) + 3] = { LT_ADDR, 0x03, 0x11, };
+
+       if (rsp->status) {
+               printf("Failed to read local clock information\n");
+               shutdown_device();
+               return;
+       }
+
+       msg.frame_sync_instant = rsp->clock;
+       msg.bluetooth_clock_phase = rsp->accuracy;
+       msg.left_open_offset = cpu_to_le16(50);
+       msg.left_close_offset = cpu_to_le16(300);
+       msg.right_open_offset = cpu_to_le16(350);
+       msg.right_close_offset = cpu_to_le16(600);
+       msg.frame_sync_period = cpu_to_le16(650);
+       msg.frame_sync_period_fraction = 0;
+       memcpy(bcastdata + 3, &msg, sizeof(msg));
+
+       bt_hci_send(hci_dev, BT_HCI_CMD_SET_SLAVE_BROADCAST_DATA,
+                       bcastdata, sizeof(bcastdata), NULL, NULL, NULL);
+}
+
+static void set_slave_broadcast(const void *data, uint8_t size, void *user_data)
+{
+       const struct bt_hci_rsp_set_slave_broadcast *rsp = data;
+       struct bt_hci_cmd_read_clock cmd;
+
+       if (rsp->status) {
+               printf("Failed to set slave broadcast transmission\n");
+               shutdown_device();
+               return;
+       }
+
+       cmd.handle = cpu_to_le16(0x0000);
+       cmd.type = 0x00;
+
+       bt_hci_send(hci_dev, BT_HCI_CMD_READ_CLOCK, &cmd, sizeof(cmd),
+                                               read_clock, NULL, NULL);
+}
+
 static void start_display(void)
 {
        struct bt_hci_cmd_set_slave_broadcast cmd;
-       uint8_t bcastdata[20] = { LT_ADDR, 0x03, 0x11, 0x23, 0x42, };
        uint8_t evtmask1[] = { 0x1c, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
        uint8_t evtmask2[] = { 0x00, 0xc0, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00 };
        uint8_t sspmode = 0x01;
@@ -322,15 +507,14 @@ static void start_display(void)
 
        bt_hci_register(hci_dev, BT_HCI_EVT_SLAVE_PAGE_RESPONSE_TIMEOUT,
                                slave_page_response_timeout, NULL, NULL);
+       bt_hci_register(hci_dev, BT_HCI_EVT_SLAVE_BROADCAST_CHANNEL_MAP_CHANGE,
+                               slave_broadcast_channel_map_change, NULL, NULL);
        bt_hci_register(hci_dev, BT_HCI_EVT_SYNC_TRAIN_COMPLETE,
                                        sync_train_complete, NULL, NULL);
 
        bt_hci_send(hci_dev, BT_HCI_CMD_READ_INQUIRY_RESP_TX_POWER, NULL, 0,
                                        inquiry_resp_tx_power, NULL, NULL);
 
-       bt_hci_send(hci_dev, BT_HCI_CMD_SET_SLAVE_BROADCAST_DATA,
-                       bcastdata, sizeof(bcastdata), NULL, NULL, NULL);
-
        cmd.enable = 0x01;
        cmd.lt_addr = LT_ADDR;
        cmd.lpo_allowed = 0x01;
@@ -340,7 +524,7 @@ static void start_display(void)
        cmd.timeout = cpu_to_le16(0xfffe);
 
        bt_hci_send(hci_dev, BT_HCI_CMD_SET_SLAVE_BROADCAST, &cmd, sizeof(cmd),
-                                                       NULL, NULL, NULL);
+                                       set_slave_broadcast, NULL, NULL);
 }
 
 static void signal_callback(int signum, void *user_data)
index bba0a9a..5574707 100644 (file)
@@ -36,9 +36,9 @@
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 static int activate_amp_controller(int dev_id)
 {
index d9f809b..3f406ca 100644 (file)
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 
-#include "profiles/audio/a2dp-codecs.h"
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/l2cap.h"
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
+#include "profiles/audio/a2dp-codecs.h"
 
 #define AVDTP_PSM                      25
 
index 541b3cd..70c9b65 100644 (file)
 #include <sys/socket.h>
 #include <netinet/in.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/sdp.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/l2cap.h"
+#include "lib/sdp.h"
 
 #define AVDTP_PKT_TYPE_SINGLE          0x00
 #define AVDTP_PKT_TYPE_START           0x01
index 4649ad5..7cce426 100644 (file)
@@ -31,9 +31,9 @@
 #include <getopt.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 #include "csr.h"
 
@@ -279,7 +279,6 @@ static int cmd_keylen(int transport, int argc, char *argv[])
        if (err < 0)
                return -1;
 
-       handle = array[0] | (array[1] << 8);
        keylen = array[2] | (array[3] << 8);
 
        printf("Crypt key length: %d bit\n", keylen * 8);
index 8356a8d..952e990 100644 (file)
@@ -33,9 +33,9 @@
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 #include "src/oui.h"
 
index c785472..650ab0c 100644 (file)
 #include <sys/stat.h>
 #include <sys/param.h>
 
-#include "monitor/mainloop.h"
 #include "monitor/bt.h"
+#include "src/shared/mainloop.h"
 #include "src/shared/util.h"
 #include "src/shared/hci.h"
 
+#define CMD_RESET              0xfc01
+struct cmd_reset {
+       uint8_t  reset_type;
+       uint8_t  patch_enable;
+       uint8_t  otp_ddc_reload;
+       uint8_t  boot_option;
+       uint32_t boot_addr;
+} __attribute__ ((packed));
+
 #define CMD_NO_OPERATION       0xfc02
 
 #define CMD_READ_VERSION       0xfc05
@@ -126,6 +135,11 @@ struct cmd_act_deact_traces {
        uint8_t  rx_trace;
 } __attribute__ ((packed));
 
+#define CMD_TRIGGER_EXCEPTION  0xfc4d
+struct cmd_trigger_exception {
+       uint8_t  type;
+} __attribute__ ((packed));
+
 #define CMD_MEMORY_WRITE       0xfc8e
 
 static struct bt_hci *hci_dev;
@@ -146,7 +160,9 @@ static const char *check_firmware_value = NULL;
 uint8_t manufacturer_mode_reset = 0x00;
 static bool use_manufacturer_mode = false;
 static bool set_traces = false;
+static bool set_exception = false;
 static bool reset_on_exit = false;
+static bool cold_boot = false;
 
 static void reset_complete(const void *data, uint8_t size, void *user_data)
 {
@@ -161,6 +177,25 @@ static void reset_complete(const void *data, uint8_t size, void *user_data)
        mainloop_quit();
 }
 
+static void cold_boot_complete(const void *data, uint8_t size, void *user_data)
+{
+       uint8_t status = *((uint8_t *) data);
+
+       if (status) {
+               fprintf(stderr, "Failed to cold boot (0x%02x)\n", status);
+               mainloop_quit();
+               return;
+       }
+
+       if (reset_on_exit) {
+               bt_hci_send(hci_dev, BT_HCI_CMD_RESET, NULL, 0,
+                                               reset_complete, NULL, NULL);
+               return;
+       }
+
+       mainloop_quit();
+}
+
 static void leave_manufacturer_mode_complete(const void *data, uint8_t size,
                                                        void *user_data)
 {
@@ -286,6 +321,18 @@ static void act_deact_traces(void)
                                        act_deact_traces_complete, NULL, NULL);
 }
 
+static void trigger_exception(void)
+{
+       struct cmd_trigger_exception cmd;
+
+       cmd.type = 0x00;
+
+       bt_hci_send(hci_dev, CMD_TRIGGER_EXCEPTION, &cmd, sizeof(cmd),
+                                                       NULL, NULL, NULL);
+
+       shutdown_device();
+}
+
 static void write_bd_data_complete(const void *data, uint8_t size,
                                                        void *user_data)
 {
@@ -426,6 +473,11 @@ static void enter_manufacturer_mode_complete(const void *data, uint8_t size,
                return;
        }
 
+       if (set_exception) {
+               trigger_exception();
+               return;
+       }
+
        shutdown_device();
 }
 
@@ -601,6 +653,20 @@ static void read_version_complete(const void *data, uint8_t size,
                return;
        }
 
+       if (cold_boot) {
+               struct cmd_reset cmd;
+
+               cmd.reset_type = 0x01;
+               cmd.patch_enable = 0x00;
+               cmd.otp_ddc_reload = 0x01;
+               cmd.boot_option = 0x00;
+               cmd.boot_addr = cpu_to_le32(0x00000000);
+
+               bt_hci_send(hci_dev, CMD_RESET, &cmd, sizeof(cmd),
+                                       cold_boot_complete, NULL, NULL);
+               return;
+       }
+
        if (load_firmware) {
                if (load_firmware_value) {
                        printf("Firmware: %s\n", load_firmware_value);
@@ -733,7 +799,6 @@ static void analyze_firmware(const char *path)
        if (len != st.st_size) {
                fprintf(stderr, "Failed to read complete firmware file\n");
                goto done;
-               return;
        }
 
        if ((size_t) len < sizeof(*css)) {
@@ -767,7 +832,7 @@ static void analyze_firmware(const char *path)
        printf("\n");
 
 
-       if (len != le32_to_cpu(css->size) * 4) {
+       if ((size_t) len != le32_to_cpu(css->size) * 4) {
                fprintf(stderr, "CSS.size does not match file length\n");
                goto done;
        }
@@ -830,6 +895,8 @@ static void usage(void)
                "\t-F, --firmware [file]  Load firmware\n"
                "\t-C, --check <file>     Check firmware image\n"
                "\t-R, --reset            Reset controller\n"
+               "\t-B, --coldboot         Cold boot controller\n"
+               "\t-E, --exception        Trigger exception\n"
                "\t-i, --index <num>      Use specified controller\n"
                "\t-h, --help             Show help options\n");
 }
@@ -841,7 +908,10 @@ static const struct option main_options[] = {
        { "check",    required_argument, NULL, 'C' },
        { "traces",   no_argument,       NULL, 'T' },
        { "reset",    no_argument,       NULL, 'R' },
+       { "coldboot", no_argument,       NULL, 'B' },
+       { "exception",no_argument,       NULL, 'E' },
        { "index",    required_argument, NULL, 'i' },
+       { "raw",      no_argument,       NULL, 'r' },
        { "version",  no_argument,       NULL, 'v' },
        { "help",     no_argument,       NULL, 'h' },
        { }
@@ -850,13 +920,14 @@ static const struct option main_options[] = {
 int main(int argc, char *argv[])
 {
        const char *str;
+       bool use_raw = false;
        sigset_t mask;
        int exit_status;
 
        for (;;) {
                int opt;
 
-               opt = getopt_long(argc, argv, "A::DF::C:TRi:vh",
+               opt = getopt_long(argc, argv, "A::DF::C:TRBEi:rvh",
                                                main_options, NULL);
                if (opt < 0)
                        break;
@@ -881,6 +952,10 @@ int main(int argc, char *argv[])
                        check_firmware_value = optarg;
                        check_firmware = true;
                        break;
+               case 'E':
+                       use_manufacturer_mode = true;
+                       set_exception = true;
+                       break;
                case 'T':
                        use_manufacturer_mode = true;
                        set_traces = true;
@@ -888,6 +963,9 @@ int main(int argc, char *argv[])
                case 'R':
                        reset_on_exit = true;
                        break;
+               case 'B':
+                       cold_boot = true;
+                       break;
                case 'i':
                        if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
                                str = optarg + 3;
@@ -899,6 +977,9 @@ int main(int argc, char *argv[])
                        }
                        hci_index = atoi(str);
                        break;
+               case 'r':
+                       use_raw = true;
+                       break;
                case 'v':
                        printf("%s\n", VERSION);
                        return EXIT_SUCCESS;
@@ -930,10 +1011,18 @@ int main(int argc, char *argv[])
                return EXIT_SUCCESS;
        }
 
-       hci_dev = bt_hci_new_user_channel(hci_index);
-       if (!hci_dev) {
-               fprintf(stderr, "Failed to open HCI user channel\n");
-               return EXIT_FAILURE;
+       if (use_raw) {
+               hci_dev = bt_hci_new_raw_device(hci_index);
+               if (!hci_dev) {
+                       fprintf(stderr, "Failed to open HCI raw device\n");
+                       return EXIT_FAILURE;
+               }
+       } else {
+               hci_dev = bt_hci_new_user_channel(hci_index);
+               if (!hci_dev) {
+                       fprintf(stderr, "Failed to open HCI user channel\n");
+                       return EXIT_FAILURE;
+               }
        }
 
        bt_hci_send(hci_dev, CMD_READ_VERSION, NULL, 0,
index f090e1b..9e19997 100644 (file)
@@ -36,9 +36,9 @@
 #include <readline/readline.h>
 #include <readline/history.h>
 #include <glib.h>
-#include <gdbus.h>
 
-#include <client/display.h>
+#include "gdbus/gdbus.h"
+#include "client/display.h"
 
 /* String display constants */
 #define COLORED_NEW    COLOR_GREEN "NEW" COLOR_OFF
@@ -654,7 +654,6 @@ static void cmd_show(int argc, char *argv[])
        rl_printf("Player %s\n", g_dbus_proxy_get_path(proxy));
 
        print_property(proxy, "Name");
-       print_property(proxy, "Searchable");
        print_property(proxy, "Repeat");
        print_property(proxy, "Equalizer");
        print_property(proxy, "Shuffle");
index bdbbe16..b7948a3 100644 (file)
 #include <sys/ioctl.h>
 #include <poll.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 #include "hciattach.h"
-#include "monitor/mainloop.h"
 #include "monitor/bt.h"
+#include "src/shared/mainloop.h"
 #include "src/shared/timeout.h"
 #include "src/shared/util.h"
 #include "src/shared/hci.h"
index e2e0537..c90f265 100644 (file)
 #include <limits.h>
 #include <errno.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/l2cap.h"
 #include "lib/uuid.h"
 
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
 #include "src/shared/util.h"
 #include "src/shared/att.h"
 #include "src/shared/queue.h"
@@ -64,6 +64,7 @@ static bool verbose = false;
 
 struct client {
        int fd;
+       struct bt_att *att;
        struct gatt_db *db;
        struct bt_gatt_client *gatt;
 };
@@ -74,6 +75,48 @@ static void print_prompt(void)
        fflush(stdout);
 }
 
+static const char *ecode_to_string(uint8_t ecode)
+{
+       switch (ecode) {
+       case BT_ATT_ERROR_INVALID_HANDLE:
+               return "Invalid Handle";
+       case BT_ATT_ERROR_READ_NOT_PERMITTED:
+               return "Read Not Permitted";
+       case BT_ATT_ERROR_WRITE_NOT_PERMITTED:
+               return "Write Not Permitted";
+       case BT_ATT_ERROR_INVALID_PDU:
+               return "Invalid PDU";
+       case BT_ATT_ERROR_AUTHENTICATION:
+               return "Authentication Required";
+       case BT_ATT_ERROR_REQUEST_NOT_SUPPORTED:
+               return "Request Not Supported";
+       case BT_ATT_ERROR_INVALID_OFFSET:
+               return "Invalid Offset";
+       case BT_ATT_ERROR_AUTHORIZATION:
+               return "Authorization Required";
+       case BT_ATT_ERROR_PREPARE_QUEUE_FULL:
+               return "Prepare Write Queue Full";
+       case BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND:
+               return "Attribute Not Found";
+       case BT_ATT_ERROR_ATTRIBUTE_NOT_LONG:
+               return "Attribute Not Long";
+       case BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE:
+               return "Insuficient Encryption Key Size";
+       case BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN:
+               return "Invalid Attribute value len";
+       case BT_ATT_ERROR_UNLIKELY:
+               return "Unlikely Error";
+       case BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION:
+               return "Insufficient Encryption";
+       case BT_ATT_ERROR_UNSUPPORTED_GROUP_TYPE:
+               return "Group type Not Supported";
+       case BT_ATT_ERROR_INSUFFICIENT_RESOURCES:
+               return "Insufficient Resources";
+       default:
+               return "Unknown error type";
+       }
+}
+
 static void att_disconnect_cb(int err, void *user_data)
 {
        printf("Device disconnected: %s\n", strerror(err));
@@ -127,7 +170,6 @@ static void service_removed_cb(struct gatt_db_attribute *attr, void *user_data)
 static struct client *client_create(int fd, uint16_t mtu)
 {
        struct client *cli;
-       struct bt_att *att;
 
        cli = new0(struct client, 1);
        if (!cli) {
@@ -135,24 +177,25 @@ static struct client *client_create(int fd, uint16_t mtu)
                return NULL;
        }
 
-       att = bt_att_new(fd);
-       if (!att) {
+       cli->att = bt_att_new(fd);
+       if (!cli->att) {
                fprintf(stderr, "Failed to initialze ATT transport layer\n");
-               bt_att_unref(att);
+               bt_att_unref(cli->att);
                free(cli);
                return NULL;
        }
 
-       if (!bt_att_set_close_on_unref(att, true)) {
+       if (!bt_att_set_close_on_unref(cli->att, true)) {
                fprintf(stderr, "Failed to set up ATT transport layer\n");
-               bt_att_unref(att);
+               bt_att_unref(cli->att);
                free(cli);
                return NULL;
        }
 
-       if (!bt_att_register_disconnect(att, att_disconnect_cb, NULL, NULL)) {
+       if (!bt_att_register_disconnect(cli->att, att_disconnect_cb, NULL,
+                                                               NULL)) {
                fprintf(stderr, "Failed to set ATT disconnect handler\n");
-               bt_att_unref(att);
+               bt_att_unref(cli->att);
                free(cli);
                return NULL;
        }
@@ -161,16 +204,16 @@ static struct client *client_create(int fd, uint16_t mtu)
        cli->db = gatt_db_new();
        if (!cli->db) {
                fprintf(stderr, "Failed to create GATT database\n");
-               bt_att_unref(att);
+               bt_att_unref(cli->att);
                free(cli);
                return NULL;
        }
 
-       cli->gatt = bt_gatt_client_new(cli->db, att, mtu);
+       cli->gatt = bt_gatt_client_new(cli->db, cli->att, mtu);
        if (!cli->gatt) {
                fprintf(stderr, "Failed to create GATT client\n");
                gatt_db_unref(cli->db);
-               bt_att_unref(att);
+               bt_att_unref(cli->att);
                free(cli);
                return NULL;
        }
@@ -179,7 +222,7 @@ static struct client *client_create(int fd, uint16_t mtu)
                                                                NULL, NULL);
 
        if (verbose) {
-               bt_att_set_debug(att, att_debug_cb, "att: ", NULL);
+               bt_att_set_debug(cli->att, att_debug_cb, "att: ", NULL);
                bt_gatt_client_set_debug(cli->gatt, gatt_debug_cb, "gatt: ",
                                                                        NULL);
        }
@@ -189,7 +232,6 @@ static struct client *client_create(int fd, uint16_t mtu)
                                                                        NULL);
 
        /* bt_gatt_client already holds a reference */
-       bt_att_unref(att);
        gatt_db_unref(cli->db);
 
        return cli;
@@ -198,6 +240,8 @@ static struct client *client_create(int fd, uint16_t mtu)
 static void client_destroy(struct client *cli)
 {
        bt_gatt_client_unref(cli->gatt);
+       bt_att_unref(cli->att);
+       free(cli);
 }
 
 static void print_uuid(const bt_uuid_t *uuid)
@@ -457,6 +501,10 @@ static void cmd_read_multiple(struct client *cli, char *cmd_str)
        }
 
        value = malloc(sizeof(uint16_t) * argc);
+       if (!value) {
+               printf("Failed to construct value\n");
+               return;
+       }
 
        for (i = 0; i < argc; i++) {
                value[i] = strtol(argv[i], &endptr, 0);
@@ -485,7 +533,8 @@ static void read_cb(bool success, uint8_t att_ecode, const uint8_t *value,
        int i;
 
        if (!success) {
-               PRLOG("\nRead request failed: 0x%02x\n", att_ecode);
+               PRLOG("\nRead request failed: %s (0x%02x)\n",
+                               ecode_to_string(att_ecode), att_ecode);
                return;
        }
 
@@ -578,12 +627,14 @@ static void write_value_usage(void)
        printf("Usage: write-value [options] <value_handle> <value>\n"
                "Options:\n"
                "\t-w, --without-response\tWrite without response\n"
+               "\t-s, --signed-write\tSigned write command\n"
                "e.g.:\n"
                "\twrite-value 0x0001 00 01 00\n");
 }
 
 static struct option write_value_options[] = {
        { "without-response",   0, 0, 'w' },
+       { "signed-write",       0, 0, 's' },
        { }
 };
 
@@ -592,7 +643,8 @@ static void write_cb(bool success, uint8_t att_ecode, void *user_data)
        if (success) {
                PRLOG("\nWrite successful\n");
        } else {
-               PRLOG("\nWrite failed: 0x%02x\n", att_ecode);
+               PRLOG("\nWrite failed: %s (0x%02x)\n",
+                               ecode_to_string(att_ecode), att_ecode);
        }
 }
 
@@ -607,6 +659,7 @@ static void cmd_write_value(struct client *cli, char *cmd_str)
        int length;
        uint8_t *value = NULL;
        bool without_response = false;
+       bool signed_write = false;
 
        if (!bt_gatt_client_is_ready(cli->gatt)) {
                printf("GATT client not initialized\n");
@@ -621,12 +674,15 @@ static void cmd_write_value(struct client *cli, char *cmd_str)
 
        optind = 0;
        argv[0] = "write-value";
-       while ((opt = getopt_long(argc, argv, "+w", write_value_options,
+       while ((opt = getopt_long(argc, argv, "+ws", write_value_options,
                                                                NULL)) != -1) {
                switch (opt) {
                case 'w':
                        without_response = true;
                        break;
+               case 's':
+                       signed_write = true;
+                       break;
                default:
                        write_value_usage();
                        return;
@@ -680,7 +736,7 @@ static void cmd_write_value(struct client *cli, char *cmd_str)
 
        if (without_response) {
                if (!bt_gatt_client_write_without_response(cli->gatt, handle,
-                                                       false, value, length)) {
+                                               signed_write, value, length)) {
                        printf("Failed to initiate write without response "
                                                                "procedure\n");
                        goto done;
@@ -722,7 +778,8 @@ static void write_long_cb(bool success, bool reliable_error, uint8_t att_ecode,
        } else if (reliable_error) {
                PRLOG("Reliable write not verified\n");
        } else {
-               PRLOG("Write failed: 0x%02x\n", att_ecode);
+               PRLOG("\nWrite failed: %s (0x%02x)\n",
+                               ecode_to_string(att_ecode), att_ecode);
        }
 }
 
@@ -852,16 +909,15 @@ static void notify_cb(uint16_t value_handle, const uint8_t *value,
        PRLOG("\n");
 }
 
-static void register_notify_cb(unsigned int id, uint16_t att_ecode,
-                                                               void *user_data)
+static void register_notify_cb(uint16_t att_ecode, void *user_data)
 {
-       if (!id) {
+       if (att_ecode) {
                PRLOG("Failed to register notify handler "
                                        "- error code: 0x%02x\n", att_ecode);
                return;
        }
 
-       PRLOG("Registered notify handler with id: %u\n", id);
+       PRLOG("Registered notify handler!");
 }
 
 static void cmd_register_notify(struct client *cli, char *cmd_str)
@@ -869,6 +925,7 @@ static void cmd_register_notify(struct client *cli, char *cmd_str)
        char *argv[2];
        int argc = 0;
        uint16_t value_handle;
+       unsigned int id;
        char *endptr = NULL;
 
        if (!bt_gatt_client_is_ready(cli->gatt)) {
@@ -887,12 +944,15 @@ static void cmd_register_notify(struct client *cli, char *cmd_str)
                return;
        }
 
-       if (!bt_gatt_client_register_notify(cli->gatt, value_handle,
+       id = bt_gatt_client_register_notify(cli->gatt, value_handle,
                                                        register_notify_cb,
-                                                       notify_cb, NULL, NULL))
+                                                       notify_cb, NULL, NULL);
+       if (!id) {
                printf("Failed to register notify handler\n");
+               return;
+       }
 
-       printf("\n");
+       PRLOG("Registering notify handler with id: %u\n", id);
 }
 
 static void unregister_notify_usage(void)
@@ -931,6 +991,125 @@ static void cmd_unregister_notify(struct client *cli, char *cmd_str)
        printf("Unregistered notify handler with id: %u\n", id);
 }
 
+static void set_sec_level_usage(void)
+{
+       printf("Usage: set_sec_level <level>\n"
+               "level: 1-3\n"
+               "e.g.:\n"
+               "\tset-sec-level 2\n");
+}
+
+static void cmd_set_sec_level(struct client *cli, char *cmd_str)
+{
+       char *argvbuf[1];
+       char **argv = argvbuf;
+       int argc = 0;
+       char *endptr = NULL;
+       int level;
+
+       if (!bt_gatt_client_is_ready(cli->gatt)) {
+               printf("GATT client not initialized\n");
+               return;
+       }
+
+       if (!parse_args(cmd_str, 1, argv, &argc)) {
+               printf("Too many arguments\n");
+               set_sec_level_usage();
+               return;
+       }
+
+       if (argc < 1) {
+               set_sec_level_usage();
+               return;
+       }
+
+       level = strtol(argv[0], &endptr, 0);
+       if (!endptr || *endptr != '\0' || level < 1 || level > 3) {
+               printf("Invalid level: %s\n", argv[0]);
+               return;
+       }
+
+       if (!bt_gatt_client_set_sec_level(cli->gatt, level))
+               printf("Could not set sec level\n");
+       else
+               printf("Setting security level %d success\n", level);
+}
+
+static void cmd_get_sec_level(struct client *cli, char *cmd_str)
+{
+       int level;
+
+       if (!bt_gatt_client_is_ready(cli->gatt)) {
+               printf("GATT client not initialized\n");
+               return;
+       }
+
+       level = bt_gatt_client_get_sec_level(cli->gatt);
+       if (level < 0)
+               printf("Could not set sec level\n");
+       else
+               printf("Security level: %u\n", level);
+}
+
+static bool convert_sign_key(char *optarg, uint8_t key[16])
+{
+       int i;
+
+       if (strlen(optarg) != 32) {
+               printf("sign-key length is invalid\n");
+               return false;
+       }
+
+       for (i = 0; i < 16; i++) {
+               if (sscanf(optarg + (i * 2), "%2hhx", &key[i]) != 1)
+                       return false;
+       }
+
+       return true;
+}
+
+static void set_sign_key_usage(void)
+{
+       printf("Usage: set-sign-key [options]\nOptions:\n"
+               "\t -c, --sign-key <csrk>\tCSRK\n"
+               "e.g.:\n"
+               "\tset-sign-key -c D8515948451FEA320DC05A2E88308188\n");
+}
+
+static bool local_counter(uint32_t *sign_cnt, void *user_data)
+{
+       static uint32_t cnt = 0;
+
+       *sign_cnt = cnt++;
+
+       return true;
+}
+
+static void cmd_set_sign_key(struct client *cli, char *cmd_str)
+{
+       char *argv[3];
+       int argc = 0;
+       uint8_t key[16];
+
+       memset(key, 0, 16);
+
+       if (!parse_args(cmd_str, 2, argv, &argc)) {
+               set_sign_key_usage();
+               return;
+       }
+
+       if (argc != 2) {
+               set_sign_key_usage();
+               return;
+       }
+
+       if (!strcmp(argv[0], "-c") || !strcmp(argv[0], "--sign-key")) {
+               if (convert_sign_key(argv[1], key))
+                       bt_att_set_local_key(cli->att, key, local_counter, cli);
+       } else
+               set_sign_key_usage();
+}
+
 static void cmd_help(struct client *cli, char *cmd_str);
 
 typedef void (*command_func_t)(struct client *cli, char *cmd_str);
@@ -955,6 +1134,12 @@ static struct {
                        "\tSubscribe to not/ind from a characteristic" },
        { "unregister-notify", cmd_unregister_notify,
                                                "Unregister a not/ind session"},
+       { "set-sec-level", cmd_set_sec_level,
+                                       "Set security level on le connection"},
+       { "get-sec-level", cmd_get_sec_level,
+                                       "Get security level on le connection"},
+       { "set-sign-key", cmd_set_sign_key,
+                               "\tSet signing key for signed write command"},
        { }
 };
 
index f6ad8c3..b4fbe60 100644 (file)
 #include <unistd.h>
 #include <errno.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/l2cap.h"
 #include "lib/uuid.h"
 
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
 #include "src/shared/util.h"
 #include "src/shared/att.h"
 #include "src/shared/queue.h"
@@ -77,6 +77,7 @@ static bool verbose = false;
 
 struct server {
        int fd;
+       struct bt_att *att;
        struct gatt_db *db;
        struct bt_gatt_server *gatt;
 
@@ -125,7 +126,7 @@ static void gatt_debug_cb(const char *str, void *user_data)
 
 static void gap_device_name_read_cb(struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data)
 {
        struct server *server = user_data;
@@ -152,7 +153,7 @@ done:
 static void gap_device_name_write_cb(struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
                                        const uint8_t *value, size_t len,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data)
 {
        struct server *server = user_data;
@@ -196,7 +197,7 @@ done:
 
 static void gap_device_name_ext_prop_read_cb(struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data)
 {
        uint8_t value[2];
@@ -211,7 +212,7 @@ static void gap_device_name_ext_prop_read_cb(struct gatt_db_attribute *attrib,
 
 static void gatt_service_changed_cb(struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data)
 {
        PRLOG("Service Changed Read called\n");
@@ -221,7 +222,7 @@ static void gatt_service_changed_cb(struct gatt_db_attribute *attrib,
 
 static void gatt_svc_chngd_ccc_read_cb(struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data)
 {
        struct server *server = user_data;
@@ -238,7 +239,7 @@ static void gatt_svc_chngd_ccc_read_cb(struct gatt_db_attribute *attrib,
 static void gatt_svc_chngd_ccc_write_cb(struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
                                        const uint8_t *value, size_t len,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data)
 {
        struct server *server = user_data;
@@ -272,7 +273,7 @@ done:
 
 static void hr_msrmt_ccc_read_cb(struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data)
 {
        struct server *server = user_data;
@@ -326,7 +327,7 @@ static void update_hr_msrmt_simulation(struct server *server)
 static void hr_msrmt_ccc_write_cb(struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
                                        const uint8_t *value, size_t len,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data)
 {
        struct server *server = user_data;
@@ -366,7 +367,7 @@ done:
 static void hr_control_point_write_cb(struct gatt_db_attribute *attrib,
                                        unsigned int id, uint16_t offset,
                                        const uint8_t *value, size_t len,
-                                       uint8_t opcode, bdaddr_t *bdaddr,
+                                       uint8_t opcode, struct bt_att *att,
                                        void *user_data)
 {
        struct server *server = user_data;
@@ -539,7 +540,6 @@ static void populate_db(struct server *server)
 static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
 {
        struct server *server;
-       struct bt_att *att;
        size_t name_len = strlen(test_device_name);
 
        server = new0(struct server, 1);
@@ -548,18 +548,19 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
                return NULL;
        }
 
-       att = bt_att_new(fd);
-       if (!att) {
+       server->att = bt_att_new(fd);
+       if (!server->att) {
                fprintf(stderr, "Failed to initialze ATT transport layer\n");
                goto fail;
        }
 
-       if (!bt_att_set_close_on_unref(att, true)) {
+       if (!bt_att_set_close_on_unref(server->att, true)) {
                fprintf(stderr, "Failed to set up ATT transport layer\n");
                goto fail;
        }
 
-       if (!bt_att_register_disconnect(att, att_disconnect_cb, NULL, NULL)) {
+       if (!bt_att_register_disconnect(server->att, att_disconnect_cb, NULL,
+                                                                       NULL)) {
                fprintf(stderr, "Failed to set ATT disconnect handler\n");
                goto fail;
        }
@@ -581,7 +582,7 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
                goto fail;
        }
 
-       server->gatt = bt_gatt_server_new(server->db, att, mtu);
+       server->gatt = bt_gatt_server_new(server->db, server->att, mtu);
        if (!server->gatt) {
                fprintf(stderr, "Failed to create GATT server\n");
                goto fail;
@@ -590,7 +591,7 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
        server->hr_visible = hr_visible;
 
        if (verbose) {
-               bt_att_set_debug(att, att_debug_cb, "att: ", NULL);
+               bt_att_set_debug(server->att, att_debug_cb, "att: ", NULL);
                bt_gatt_server_set_debug(server->gatt, gatt_debug_cb,
                                                        "server: ", NULL);
        }
@@ -599,7 +600,6 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
        srand(time(NULL));
 
        /* bt_gatt_server already holds a reference */
-       bt_att_unref(att);
        populate_db(server);
 
        return server;
@@ -607,7 +607,7 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
 fail:
        gatt_db_unref(server->db);
        free(server->device_name);
-       bt_att_unref(att);
+       bt_att_unref(server->att);
        free(server);
 
        return NULL;
@@ -631,7 +631,7 @@ static void usage(void)
                "\t-s, --security-level <sec>\tSet security level (low|"
                                                                "medium|high)\n"
                "\t-v, --verbose\t\t\tEnable extra logging\n"
-               "\t-r, --heart-rate\t\tEnable Heart Rate service"
+               "\t-r, --heart-rate\t\tEnable Heart Rate service\n"
                "\t-h, --help\t\t\tDisplay help\n");
 }
 
@@ -972,6 +972,69 @@ static void cmd_services(struct server *server, char *cmd_str)
        gatt_db_foreach_service(server->db, NULL, print_service, server);
 }
 
+static bool convert_sign_key(char *optarg, uint8_t key[16])
+{
+       int i;
+
+       if (strlen(optarg) != 32) {
+               printf("sign-key length is invalid\n");
+               return false;
+       }
+
+       for (i = 0; i < 16; i++) {
+               if (sscanf(optarg + (i * 2), "%2hhx", &key[i]) != 1)
+                       return false;
+       }
+
+       return true;
+}
+
+static void set_sign_key_usage(void)
+{
+       printf("Usage: set-sign-key [options]\nOptions:\n"
+               "\t -c, --sign-key <remote csrk>\tRemote CSRK\n"
+               "e.g.:\n"
+               "\tset-sign-key -c D8515948451FEA320DC05A2E88308188\n");
+}
+
+static bool remote_counter(uint32_t *sign_cnt, void *user_data)
+{
+       static uint32_t cnt = 0;
+
+       if (*sign_cnt < cnt)
+               return false;
+
+       cnt = *sign_cnt;
+
+       return true;
+}
+
+static void cmd_set_sign_key(struct server *server, char *cmd_str)
+{
+       char *argv[3];
+       int argc = 0;
+       uint8_t key[16];
+
+       memset(key, 0, 16);
+
+       if (!parse_args(cmd_str, 2, argv, &argc)) {
+               set_sign_key_usage();
+               return;
+       }
+
+       if (argc != 2) {
+               set_sign_key_usage();
+               return;
+       }
+
+       if (!strcmp(argv[0], "-c") || !strcmp(argv[0], "--sign-key")) {
+               if (convert_sign_key(argv[1], key))
+                       bt_att_set_remote_key(server->att, key, remote_counter,
+                                                                       server);
+       } else
+               set_sign_key_usage();
+}
+
 static void cmd_help(struct server *server, char *cmd_str);
 
 typedef void (*command_func_t)(struct server *server, char *cmd_str);
@@ -985,6 +1048,8 @@ static struct {
        { "notify", cmd_notify, "\tSend handle-value notification" },
        { "heart-rate", cmd_heart_rate, "\tHide/Unhide Heart Rate Service" },
        { "services", cmd_services, "\tEnumerate all services" },
+       { "set-sign-key", cmd_set_sign_key,
+                       "\tSet remote signing key for signed write command"},
        { }
 };
 
index b838c25..fd11ac4 100644 (file)
@@ -35,8 +35,8 @@
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 
-#include "monitor/mainloop.h"
 #include "monitor/bt.h"
+#include "src/shared/mainloop.h"
 #include "src/shared/timeout.h"
 #include "src/shared/util.h"
 #include "src/shared/hci.h"
index 6a87ffd..10e78d5 100644 (file)
@@ -35,7 +35,7 @@
 
 #include <glib.h>
 
-#include <bluetooth/bluetooth.h>
+#include "lib/bluetooth.h"
 
 #include "btio/btio.h"
 
index eac7204..8eff56b 100644 (file)
@@ -24,6 +24,7 @@
 #endif
 
 #include <stdio.h>
+#include <stdarg.h>
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <poll.h>
 #include <getopt.h>
 #include <stdbool.h>
+#include <wordexp.h>
+#include <ctype.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 
 #include "src/uuid-helper.h"
 #include "lib/mgmt.h"
 
-#include "monitor/mainloop.h"
+#include "client/display.h"
+#include "src/shared/mainloop.h"
+#include "src/shared/io.h"
 #include "src/shared/util.h"
 #include "src/shared/mgmt.h"
-#include "src/shared/gap.h"
 
-static bool monitor = false;
+static struct mgmt *mgmt = NULL;
+static uint16_t mgmt_index = MGMT_INDEX_NONE;
+
 static bool discovery = false;
 static bool resolve_names = true;
+static bool interactive = false;
+
+static char *saved_prompt = NULL;
+static int saved_point = 0;
 
-static int pending = 0;
+static struct {
+       uint16_t index;
+       uint16_t req;
+       struct mgmt_addr_info addr;
+} prompt = {
+       .index = MGMT_INDEX_NONE,
+};
+
+static int pending_index = 0;
 
 #ifndef MIN
 #define MIN(x, y) ((x) < (y) ? (x) : (y))
 #endif
 
-static size_t convert_hexstr(const char *hexstr, uint8_t *buf, size_t buflen)
+#define PROMPT_ON      COLOR_BLUE "[mgmt]" COLOR_OFF "# "
+
+static void update_prompt(uint16_t index)
+{
+       char str[32];
+
+       if (index == MGMT_INDEX_NONE)
+               snprintf(str, sizeof(str), "%s# ",
+                                       COLOR_BLUE "[mgmt]" COLOR_OFF);
+       else
+               snprintf(str, sizeof(str),
+                               COLOR_BLUE "[hci%u]" COLOR_OFF "# ", index);
+
+       if (saved_prompt) {
+               free(saved_prompt);
+               saved_prompt = strdup(str);
+               return;
+       }
+
+       rl_set_prompt(str);
+}
+
+static void noninteractive_quit(int status)
+{
+       if (interactive)
+               return;
+
+       if (status == EXIT_SUCCESS)
+               mainloop_exit_success();
+       else
+               mainloop_exit_failure();
+}
+
+#define print(fmt, arg...) do { \
+       if (interactive) \
+               rl_printf(fmt "\n", ## arg); \
+       else \
+               printf(fmt "\n", ## arg); \
+} while (0)
+
+#define error(fmt, arg...) do { \
+       if (interactive) \
+               rl_printf(COLOR_RED fmt "\n" COLOR_OFF, ## arg); \
+       else \
+               fprintf(stderr, fmt "\n", ## arg); \
+} while (0)
+
+static size_t hex2bin(const char *hexstr, uint8_t *buf, size_t buflen)
 {
        size_t i, len;
 
@@ -74,6 +142,17 @@ static size_t convert_hexstr(const char *hexstr, uint8_t *buf, size_t buflen)
        return len;
 }
 
+static size_t bin2hex(const uint8_t *buf, size_t buflen, char *str,
+                                                               size_t strlen)
+{
+       size_t i;
+
+       for (i = 0; i < buflen && i < (strlen / 2); i++)
+               sprintf(str + (i * 2), "%02x", buf[i]);
+
+       return i;
+}
+
 static bool load_identity(uint16_t index, struct mgmt_irk_info *irk)
 {
        char identity_path[PATH_MAX];
@@ -87,7 +166,7 @@ static bool load_identity(uint16_t index, struct mgmt_irk_info *irk)
 
        fp = fopen(identity_path, "r");
        if (!fp) {
-               perror("Failed to open identity file");
+               error("Failed to open identity file: %s", strerror(errno));
                return false;
        }
 
@@ -99,7 +178,7 @@ static bool load_identity(uint16_t index, struct mgmt_irk_info *irk)
                return false;
 
        str2ba(addr, &irk->addr.bdaddr);
-       convert_hexstr(key, irk->val, sizeof(irk->val));
+       hex2bin(key, irk->val, sizeof(irk->val));
 
        free(addr);
        free(key);
@@ -112,7 +191,7 @@ static bool load_identity(uint16_t index, struct mgmt_irk_info *irk)
                irk->addr.type = BDADDR_LE_RANDOM;
                break;
        default:
-               fprintf(stderr, "Invalid address type %u\n", type);
+               error("Invalid address type %u", type);
                return false;
        }
 
@@ -125,41 +204,35 @@ static void controller_error(uint16_t index, uint16_t len,
        const struct mgmt_ev_controller_error *ev = param;
 
        if (len < sizeof(*ev)) {
-               fprintf(stderr,
-                       "Too short (%u bytes) controller error event\n", len);
+               error("Too short (%u bytes) controller error event", len);
                return;
        }
 
-       if (monitor)
-               printf("hci%u error 0x%02x\n", index, ev->error_code);
+       print("hci%u error 0x%02x", index, ev->error_code);
 }
 
 static void index_added(uint16_t index, uint16_t len,
                                const void *param, void *user_data)
 {
-       if (monitor)
-               printf("hci%u added\n", index);
+       print("hci%u added", index);
 }
 
 static void index_removed(uint16_t index, uint16_t len,
                                const void *param, void *user_data)
 {
-       if (monitor)
-               printf("hci%u removed\n", index);
+       print("hci%u removed", index);
 }
 
 static void unconf_index_added(uint16_t index, uint16_t len,
                                const void *param, void *user_data)
 {
-       if (monitor)
-               printf("hci%u added (unconfigured)\n", index);
+       print("hci%u added (unconfigured)", index);
 }
 
 static void unconf_index_removed(uint16_t index, uint16_t len,
                                const void *param, void *user_data)
 {
-       if (monitor)
-               printf("hci%u removed (unconfigured)\n", index);
+       print("hci%u removed (unconfigured)", index);
 }
 
 static const char *options_str[] = {
@@ -167,14 +240,22 @@ static const char *options_str[] = {
                                "public-address",
 };
 
-static void print_options(uint32_t options)
+static const char *options2str(uint32_t options)
 {
+       static char str[256];
        unsigned i;
+       int off;
+
+       off = 0;
+       str[0] = '\0';
 
        for (i = 0; i < NELEM(options_str); i++) {
                if ((options & (1 << i)) != 0)
-                       printf("%s ", options_str[i]);
+                       off += snprintf(str + off, sizeof(str) - off, "%s ",
+                                                       options_str[i]);
        }
+
+       return str;
 }
 
 static void new_config_options(uint16_t index, uint16_t len,
@@ -183,15 +264,11 @@ static void new_config_options(uint16_t index, uint16_t len,
        const uint32_t *ev = param;
 
        if (len < sizeof(*ev)) {
-               fprintf(stderr, "Too short new_config_options event (%u)\n", len);
+               error("Too short new_config_options event (%u)", len);
                return;
        }
 
-       if (monitor) {
-               printf("hci%u new_config_options: ", index);
-               print_options(get_le32(ev));
-               printf("\n");
-       }
+       print("hci%u new_config_options: %s", index, options2str(get_le32(ev)));
 }
 
 static const char *settings_str[] = {
@@ -210,16 +287,25 @@ static const char *settings_str[] = {
                                "debug-keys",
                                "privacy",
                                "configuration",
+                               "static-addr",
 };
 
-static void print_settings(uint32_t settings)
+static const char *settings2str(uint32_t settings)
 {
+       static char str[256];
        unsigned i;
+       int off;
+
+       off = 0;
+       str[0] = '\0';
 
        for (i = 0; i < NELEM(settings_str); i++) {
                if ((settings & (1 << i)) != 0)
-                       printf("%s ", settings_str[i]);
+                       off += snprintf(str + off, sizeof(str) - off, "%s ",
+                                                       settings_str[i]);
        }
+
+       return str;
 }
 
 static void new_settings(uint16_t index, uint16_t len,
@@ -228,15 +314,11 @@ static void new_settings(uint16_t index, uint16_t len,
        const uint32_t *ev = param;
 
        if (len < sizeof(*ev)) {
-               fprintf(stderr, "Too short new_settings event (%u)\n", len);
+               error("Too short new_settings event (%u)", len);
                return;
        }
 
-       if (monitor) {
-               printf("hci%u new_settings: ", index);
-               print_settings(get_le32(ev));
-               printf("\n");
-       }
+       print("hci%u new_settings: %s", index, settings2str(get_le32(ev)));
 }
 
 static void discovering(uint16_t index, uint16_t len, const void *param,
@@ -245,44 +327,36 @@ static void discovering(uint16_t index, uint16_t len, const void *param,
        const struct mgmt_ev_discovering *ev = param;
 
        if (len < sizeof(*ev)) {
-               fprintf(stderr, "Too short (%u bytes) discovering event\n",
-                                                                       len);
+               error("Too short (%u bytes) discovering event", len);
                return;
        }
 
-       if (ev->discovering == 0 && discovery) {
-               mainloop_quit();
-               return;
-       }
+       print("hci%u type %u discovering %s", index, ev->type,
+                                       ev->discovering ? "on" : "off");
 
-       if (monitor)
-               printf("hci%u type %u discovering %s\n", index,
-                               ev->type, ev->discovering ? "on" : "off");
+       if (ev->discovering == 0 && discovery)
+               return noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void new_link_key(uint16_t index, uint16_t len, const void *param,
                                                        void *user_data)
 {
        const struct mgmt_ev_new_link_key *ev = param;
+       char addr[18];
 
        if (len != sizeof(*ev)) {
-               fprintf(stderr, "Invalid new_link_key length (%u bytes)\n",
-                                                                       len);
+               error("Invalid new_link_key length (%u bytes)", len);
                return;
        }
 
-       if (monitor) {
-               char addr[18];
-               ba2str(&ev->key.addr.bdaddr, addr);
-               printf("hci%u new_link_key %s type 0x%02x pin_len %d "
-                               "store_hint %u\n", index, addr, ev->key.type,
-                               ev->key.pin_len, ev->store_hint);
-       }
+       ba2str(&ev->key.addr.bdaddr, addr);
+       print("hci%u new_link_key %s type 0x%02x pin_len %d store_hint %u",
+               index, addr, ev->key.type, ev->key.pin_len, ev->store_hint);
 }
 
 static const char *typestr(uint8_t type)
 {
-       const char *str[] = { "BR/EDR", "LE Public", "LE Random" };
+       static const char *str[] = { "BR/EDR", "LE Public", "LE Random" };
 
        if (type <= BDADDR_LE_RANDOM)
                return str[type];
@@ -295,91 +369,107 @@ static void connected(uint16_t index, uint16_t len, const void *param,
 {
        const struct mgmt_ev_device_connected *ev = param;
        uint16_t eir_len;
+       char addr[18];
 
        if (len < sizeof(*ev)) {
-               fprintf(stderr,
-                       "Invalid connected event length (%u bytes)\n", len);
+               error("Invalid connected event length (%u bytes)", len);
                return;
        }
 
        eir_len = get_le16(&ev->eir_len);
        if (len != sizeof(*ev) + eir_len) {
-               fprintf(stderr, "Invalid connected event length "
-                       "(%u bytes, eir_len %u bytes)\n", len, eir_len);
+               error("Invalid connected event length (%u != eir_len %u)",
+                                                               len, eir_len);
                return;
        }
 
-       if (monitor) {
-               char addr[18];
-               ba2str(&ev->addr.bdaddr, addr);
-               printf("hci%u %s type %s connected eir_len %u\n", index, addr,
+       ba2str(&ev->addr.bdaddr, addr);
+       print("hci%u %s type %s connected eir_len %u", index, addr,
                                        typestr(ev->addr.type), eir_len);
-       }
+}
+
+static void release_prompt(void)
+{
+       if (!interactive)
+               return;
+
+       memset(&prompt, 0, sizeof(prompt));
+       prompt.index = MGMT_INDEX_NONE;
+
+       if (!saved_prompt)
+               return;
+
+       /* This will cause rl_expand_prompt to re-run over the last prompt,
+        * but our prompt doesn't expand anyway.
+        */
+       rl_set_prompt(saved_prompt);
+       rl_replace_line("", 0);
+       rl_point = saved_point;
+       rl_redisplay();
+
+       free(saved_prompt);
+       saved_prompt = NULL;
 }
 
 static void disconnected(uint16_t index, uint16_t len, const void *param,
                                                        void *user_data)
 {
        const struct mgmt_ev_device_disconnected *ev = param;
+       char addr[18];
+       uint8_t reason;
 
        if (len < sizeof(struct mgmt_addr_info)) {
-               fprintf(stderr,
-                       "Invalid disconnected event length (%u bytes)\n", len);
+               error("Invalid disconnected event length (%u bytes)", len);
                return;
        }
 
-       if (monitor) {
-               char addr[18];
-               uint8_t reason;
+       if (!memcmp(&ev->addr, &prompt.addr, sizeof(ev->addr)))
+               release_prompt();
 
-               if (len < sizeof(*ev))
-                       reason = MGMT_DEV_DISCONN_UNKNOWN;
-               else
-                       reason = ev->reason;
+       if (len < sizeof(*ev))
+               reason = MGMT_DEV_DISCONN_UNKNOWN;
+       else
+               reason = ev->reason;
 
-               ba2str(&ev->addr.bdaddr, addr);
-               printf("hci%u %s type %s disconnected with reason %u\n",
-                               index, addr, typestr(ev->addr.type), reason);
-       }
+       ba2str(&ev->addr.bdaddr, addr);
+       print("hci%u %s type %s disconnected with reason %u",
+                       index, addr, typestr(ev->addr.type), reason);
 }
 
 static void conn_failed(uint16_t index, uint16_t len, const void *param,
                                                        void *user_data)
 {
        const struct mgmt_ev_connect_failed *ev = param;
+       char addr[18];
 
        if (len != sizeof(*ev)) {
-               fprintf(stderr,
-                       "Invalid connect_failed event length (%u bytes)\n", len);
+               error("Invalid connect_failed event length (%u bytes)", len);
                return;
        }
 
-       if (monitor) {
-               char addr[18];
-               ba2str(&ev->addr.bdaddr, addr);
-               printf("hci%u %s type %s connect failed (status 0x%02x, %s)\n",
-                               index, addr, typestr(ev->addr.type), ev->status,
-                               mgmt_errstr(ev->status));
-       }
+       ba2str(&ev->addr.bdaddr, addr);
+       print("hci%u %s type %s connect failed (status 0x%02x, %s)",
+                       index, addr, typestr(ev->addr.type), ev->status,
+                       mgmt_errstr(ev->status));
 }
 
 static void auth_failed(uint16_t index, uint16_t len, const void *param,
                                                        void *user_data)
 {
        const struct mgmt_ev_auth_failed *ev = param;
+       char addr[18];
 
        if (len != sizeof(*ev)) {
-               fprintf(stderr,
-                       "Invalid auth_failed event length (%u bytes)\n", len);
+               error("Invalid auth_failed event length (%u bytes)", len);
                return;
        }
 
-       if (monitor) {
-               char addr[18];
-               ba2str(&ev->addr.bdaddr, addr);
-               printf("hci%u %s auth failed with status 0x%02x (%s)\n",
+       if (!memcmp(&ev->addr, &prompt.addr, sizeof(ev->addr)))
+               release_prompt();
+
+       ba2str(&ev->addr.bdaddr, addr);
+       print("hci%u %s auth failed with status 0x%02x (%s)",
                        index, addr, ev->status, mgmt_errstr(ev->status));
-       }
 }
 
 static void local_name_changed(uint16_t index, uint16_t len, const void *param,
@@ -388,13 +478,11 @@ static void local_name_changed(uint16_t index, uint16_t len, const void *param,
        const struct mgmt_ev_local_name_changed *ev = param;
 
        if (len != sizeof(*ev)) {
-               fprintf(stderr,
-                       "Invalid local_name_changed length (%u bytes)\n", len);
+               error("Invalid local_name_changed length (%u bytes)", len);
                return;
        }
 
-       if (monitor)
-               printf("hci%u name changed: %s\n", index, ev->name);
+       print("hci%u name changed: %s", index, ev->name);
 }
 
 static void confirm_name_rsp(uint8_t status, uint16_t len,
@@ -404,25 +492,24 @@ static void confirm_name_rsp(uint8_t status, uint16_t len,
        char addr[18];
 
        if (len == 0 && status != 0) {
-               fprintf(stderr,
-                       "confirm_name failed with status 0x%02x (%s)\n",
-                                       status, mgmt_errstr(status));
+               error("confirm_name failed with status 0x%02x (%s)", status,
+                                                       mgmt_errstr(status));
                return;
        }
 
        if (len != sizeof(*rp)) {
-               fprintf(stderr, "confirm_name rsp length %u instead of %zu\n",
-                       len, sizeof(*rp));
+               error("confirm_name rsp length %u instead of %zu",
+                                                       len, sizeof(*rp));
                return;
        }
 
        ba2str(&rp->addr.bdaddr, addr);
 
        if (status != 0)
-               fprintf(stderr, "confirm_name for %s failed: 0x%02x (%s)\n",
+               error("confirm_name for %s failed: 0x%02x (%s)",
                        addr, status, mgmt_errstr(status));
        else
-               printf("confirm_name succeeded for %s\n", addr);
+               print("confirm_name succeeded for %s", addr);
 }
 
 static char *eir_get_name(const uint8_t *eir, uint16_t eir_len)
@@ -490,8 +577,7 @@ static void device_found(uint16_t index, uint16_t len, const void *param,
        uint32_t flags;
 
        if (len < sizeof(*ev)) {
-               fprintf(stderr,
-                       "Too short device_found length (%u bytes)\n", len);
+               error("Too short device_found length (%u bytes)", len);
                return;
        }
 
@@ -499,28 +585,28 @@ static void device_found(uint16_t index, uint16_t len, const void *param,
 
        eir_len = get_le16(&ev->eir_len);
        if (len != sizeof(*ev) + eir_len) {
-               fprintf(stderr, "dev_found: expected %zu bytes, got %u bytes\n",
+               error("dev_found: expected %zu bytes, got %u bytes",
                                                sizeof(*ev) + eir_len, len);
                return;
        }
 
-       if (monitor || discovery) {
+       if (discovery) {
                char addr[18], *name;
 
                ba2str(&ev->addr.bdaddr, addr);
-               printf("hci%u dev_found: %s type %s rssi %d "
+               print("hci%u dev_found: %s type %s rssi %d "
                        "flags 0x%04x ", index, addr,
                        typestr(ev->addr.type), ev->rssi, flags);
 
                if (ev->addr.type != BDADDR_BREDR)
-                       printf("AD flags 0x%02x ",
+                       print("AD flags 0x%02x ",
                                        eir_get_flags(ev->eir, eir_len));
 
                name = eir_get_name(ev->eir, eir_len);
                if (name)
-                       printf("name %s\n", name);
+                       print("name %s", name);
                else
-                       printf("eir_len %u\n", eir_len);
+                       print("eir_len %u", eir_len);
 
                free(name);
        }
@@ -544,14 +630,12 @@ static void pin_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0) {
-               fprintf(stderr,
-                       "PIN Code reply failed with status 0x%02x (%s)\n",
+               error("PIN Code reply failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-               mainloop_quit();
-               return;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
-       printf("PIN Reply successful\n");
+       print("PIN Reply successful");
 }
 
 static int mgmt_pin_reply(struct mgmt *mgmt, uint16_t index,
@@ -573,14 +657,12 @@ static void pin_neg_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0) {
-               fprintf(stderr,
-                       "PIN Neg reply failed with status 0x%02x (%s)\n",
+               error("PIN Neg reply failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-               mainloop_quit();
-               return;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
-       printf("PIN Negative Reply successful\n");
+       print("PIN Negative Reply successful");
 }
 
 static int mgmt_pin_neg_reply(struct mgmt *mgmt, uint16_t index,
@@ -595,57 +677,16 @@ static int mgmt_pin_neg_reply(struct mgmt *mgmt, uint16_t index,
                                sizeof(cp), &cp, pin_neg_rsp, NULL, NULL);
 }
 
-static void request_pin(uint16_t index, uint16_t len, const void *param,
-                                                       void *user_data)
-{
-       const struct mgmt_ev_pin_code_request *ev = param;
-       struct mgmt *mgmt = user_data;
-       char pin[18];
-       size_t pin_len;
-
-       if (len != sizeof(*ev)) {
-               fprintf(stderr,
-                       "Invalid pin_code request length (%u bytes)\n", len);
-               return;
-       }
-
-       if (monitor) {
-               char addr[18];
-               ba2str(&ev->addr.bdaddr, addr);
-               printf("hci%u %s request PIN\n", index, addr);
-       }
-
-       printf("PIN Request (press enter to reject) >> ");
-       fflush(stdout);
-
-       memset(pin, 0, sizeof(pin));
-
-       if (fgets(pin, sizeof(pin), stdin) == NULL || pin[0] == '\n') {
-               mgmt_pin_neg_reply(mgmt, index, &ev->addr);
-               return;
-       }
-
-       pin_len = strlen(pin);
-       if (pin[pin_len - 1] == '\n') {
-               pin[pin_len - 1] = '\0';
-               pin_len--;
-       }
-
-       mgmt_pin_reply(mgmt, index, &ev->addr, pin, pin_len);
-}
-
 static void confirm_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0) {
-               fprintf(stderr,
-                       "User Confirm reply failed. status 0x%02x (%s)\n",
+               error("User Confirm reply failed. status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-               mainloop_quit();
-               return;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
-       printf("User Confirm Reply successful\n");
+       print("User Confirm Reply successful");
 }
 
 static int mgmt_confirm_reply(struct mgmt *mgmt, uint16_t index,
@@ -664,14 +705,12 @@ static void confirm_neg_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0) {
-               fprintf(stderr,
-                       "Confirm Neg reply failed. status 0x%02x (%s)\n",
+               error("Confirm Neg reply failed. status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-               mainloop_quit();
-               return;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
-       printf("User Confirm Negative Reply successful\n");
+       print("User Confirm Negative Reply successful");
 }
 
 static int mgmt_confirm_neg_reply(struct mgmt *mgmt, uint16_t index,
@@ -686,66 +725,16 @@ static int mgmt_confirm_neg_reply(struct mgmt *mgmt, uint16_t index,
                                sizeof(cp), &cp, confirm_neg_rsp, NULL, NULL);
 }
 
-
-static void user_confirm(uint16_t index, uint16_t len, const void *param,
-                                                       void *user_data)
-{
-       const struct mgmt_ev_user_confirm_request *ev = param;
-       struct mgmt *mgmt = user_data;
-       char rsp[5];
-       size_t rsp_len;
-       uint32_t val;
-       char addr[18];
-
-       if (len != sizeof(*ev)) {
-               fprintf(stderr,
-                       "Invalid user_confirm request length (%u)\n", len);
-               return;
-       }
-
-       ba2str(&ev->addr.bdaddr, addr);
-       val = get_le32(&ev->value);
-
-       if (monitor)
-               printf("hci%u %s User Confirm %06u hint %u\n", index, addr,
-                                                       val, ev->confirm_hint);
-
-       if (ev->confirm_hint)
-               printf("Accept pairing with %s (yes/no) >> ", addr);
-       else
-               printf("Confirm value %06u for %s (yes/no) >> ", val, addr);
-
-       fflush(stdout);
-
-       memset(rsp, 0, sizeof(rsp));
-
-       if (fgets(rsp, sizeof(rsp), stdin) == NULL || rsp[0] == '\n') {
-               mgmt_confirm_neg_reply(mgmt, index, &ev->addr);
-               return;
-       }
-
-       rsp_len = strlen(rsp);
-       if (rsp[rsp_len - 1] == '\n')
-               rsp[rsp_len - 1] = '\0';
-
-       if (rsp[0] == 'y' || rsp[0] == 'Y')
-               mgmt_confirm_reply(mgmt, index, &ev->addr);
-       else
-               mgmt_confirm_neg_reply(mgmt, index, &ev->addr);
-}
-
 static void passkey_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0) {
-               fprintf(stderr,
-                       "User Passkey reply failed. status 0x%02x (%s)\n",
+               error("User Passkey reply failed. status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-               mainloop_quit();
-               return;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
-       printf("User Passkey Reply successful\n");
+       print("User Passkey Reply successful");
 }
 
 static int mgmt_passkey_reply(struct mgmt *mgmt, uint16_t index,
@@ -766,14 +755,12 @@ static void passkey_neg_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0) {
-               fprintf(stderr,
-                       "Passkey Neg reply failed. status 0x%02x (%s)\n",
+               error("Passkey Neg reply failed. status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-               mainloop_quit();
-               return;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
-       printf("User Passkey Negative Reply successful\n");
+       print("User Passkey Negative Reply successful");
 }
 
 static int mgmt_passkey_neg_reply(struct mgmt *mgmt, uint16_t index,
@@ -788,95 +775,214 @@ static int mgmt_passkey_neg_reply(struct mgmt *mgmt, uint16_t index,
                                sizeof(cp), &cp, passkey_neg_rsp, NULL, NULL);
 }
 
+static bool prompt_input(const char *input)
+{
+       size_t len;
 
-static void request_passkey(uint16_t index, uint16_t len, const void *param,
+       if (!prompt.req)
+               return false;
+
+       len = strlen(input);
+
+       switch (prompt.req) {
+       case MGMT_EV_PIN_CODE_REQUEST:
+               if (len)
+                       mgmt_pin_reply(mgmt, prompt.index, &prompt.addr,
+                                                               input, len);
+               else
+                       mgmt_pin_neg_reply(mgmt, prompt.index, &prompt.addr);
+               break;
+       case MGMT_EV_USER_PASSKEY_REQUEST:
+               if (strlen(input) > 0)
+                       mgmt_passkey_reply(mgmt, prompt.index, &prompt.addr,
+                                                               atoi(input));
+               else
+                       mgmt_passkey_neg_reply(mgmt, prompt.index,
+                                                               &prompt.addr);
+               break;
+       case MGMT_EV_USER_CONFIRM_REQUEST:
+               if (input[0] == 'y' || input[0] == 'Y')
+                       mgmt_confirm_reply(mgmt, prompt.index, &prompt.addr);
+               else
+                       mgmt_confirm_neg_reply(mgmt, prompt.index,
+                                                               &prompt.addr);
+               break;
+       }
+
+       release_prompt();
+
+       return true;
+}
+
+static void interactive_prompt(const char *msg)
+{
+       if (saved_prompt)
+               return;
+
+       saved_prompt = strdup(rl_prompt);
+       if (!saved_prompt)
+               return;
+
+       saved_point = rl_point;
+
+       rl_set_prompt("");
+       rl_redisplay();
+
+       rl_set_prompt(msg);
+
+       rl_replace_line("", 0);
+       rl_redisplay();
+}
+
+static size_t get_input(char *buf, size_t buf_len)
+{
+       size_t len;
+
+       if (!fgets(buf, buf_len, stdin))
+               return 0;
+
+       len = strlen(buf);
+
+       /* Remove trailing white-space */
+       while (len && isspace(buf[len - 1]))
+               buf[--len] = '\0';
+
+       return len;
+}
+
+static void ask(uint16_t index, uint16_t req, const struct mgmt_addr_info *addr,
+                                               const char *fmt, ...)
+{
+       char msg[256], buf[18];
+       va_list ap;
+       int off;
+
+       prompt.index = index;
+       prompt.req = req;
+       memcpy(&prompt.addr, addr, sizeof(*addr));
+
+       va_start(ap, fmt);
+       off = vsnprintf(msg, sizeof(msg), fmt, ap);
+       va_end(ap);
+
+       snprintf(msg + off, sizeof(msg) - off, " %s ",
+                                       COLOR_BOLDGRAY ">>" COLOR_OFF);
+
+       if (interactive) {
+               interactive_prompt(msg);
+               va_end(ap);
+               return;
+       }
+
+       printf("%s", msg);
+       fflush(stdout);
+
+       memset(buf, 0, sizeof(buf));
+       get_input(buf, sizeof(buf));
+       prompt_input(buf);
+}
+
+static void request_pin(uint16_t index, uint16_t len, const void *param,
                                                        void *user_data)
 {
-       const struct mgmt_ev_user_passkey_request *ev = param;
-       struct mgmt *mgmt = user_data;
-       char passkey[7];
+       const struct mgmt_ev_pin_code_request *ev = param;
+       char addr[18];
 
        if (len != sizeof(*ev)) {
-               fprintf(stderr,
-                       "Invalid passkey request length (%u bytes)\n", len);
+               error("Invalid pin_code request length (%u bytes)", len);
                return;
        }
 
-       if (monitor) {
-               char addr[18];
-               ba2str(&ev->addr.bdaddr, addr);
-               printf("hci%u %s request passkey\n", index, addr);
-       }
+       ba2str(&ev->addr.bdaddr, addr);
+       print("hci%u %s request PIN", index, addr);
 
-       printf("Passkey Request (press enter to reject) >> ");
-       fflush(stdout);
+       ask(index, MGMT_EV_PIN_CODE_REQUEST, &ev->addr,
+                               "PIN Request (press enter to reject)");
+}
 
-       memset(passkey, 0, sizeof(passkey));
+static void user_confirm(uint16_t index, uint16_t len, const void *param,
+                                                       void *user_data)
+{
+       const struct mgmt_ev_user_confirm_request *ev = param;
+       uint32_t val;
+       char addr[18];
 
-       if (fgets(passkey, sizeof(passkey), stdin) == NULL ||
-                                                       passkey[0] == '\n') {
-               mgmt_passkey_neg_reply(mgmt, index, &ev->addr);
+       if (len != sizeof(*ev)) {
+               error("Invalid user_confirm request length (%u)", len);
                return;
        }
 
-       len = strlen(passkey);
-       if (passkey[len - 1] == '\n') {
-               passkey[len - 1] = '\0';
-               len--;
+       ba2str(&ev->addr.bdaddr, addr);
+       val = get_le32(&ev->value);
+
+       print("hci%u %s User Confirm %06u hint %u", index, addr,
+                                                       val, ev->confirm_hint);
+
+       if (ev->confirm_hint)
+               ask(index, MGMT_EV_USER_CONFIRM_REQUEST, &ev->addr,
+                               "Accept pairing with %s (yes/no)", addr);
+       else
+               ask(index, MGMT_EV_USER_CONFIRM_REQUEST, &ev->addr,
+                       "Confirm value %06u for %s (yes/no)", val, addr);
+}
+
+static void request_passkey(uint16_t index, uint16_t len, const void *param,
+                                                       void *user_data)
+{
+       const struct mgmt_ev_user_passkey_request *ev = param;
+       char addr[18];
+
+       if (len != sizeof(*ev)) {
+               error("Invalid passkey request length (%u bytes)", len);
+               return;
        }
 
-       mgmt_passkey_reply(mgmt, index, &ev->addr, atoi(passkey));
+       ba2str(&ev->addr.bdaddr, addr);
+       print("hci%u %s request passkey", index, addr);
+
+       ask(index, MGMT_EV_USER_PASSKEY_REQUEST, &ev->addr,
+                       "Passkey Request (press enter to reject)");
 }
 
 static void passkey_notify(uint16_t index, uint16_t len, const void *param,
                                                        void *user_data)
 {
        const struct mgmt_ev_passkey_notify *ev = param;
+       char addr[18];
 
        if (len != sizeof(*ev)) {
-               fprintf(stderr,
-                       "Invalid passkey request length (%u bytes)\n", len);
+               error("Invalid passkey request length (%u bytes)", len);
                return;
        }
 
-       if (monitor) {
-               char addr[18];
-               ba2str(&ev->addr.bdaddr, addr);
-               printf("hci%u %s request passkey\n", index, addr);
-       }
+       ba2str(&ev->addr.bdaddr, addr);
+       print("hci%u %s request passkey", index, addr);
 
-       printf("Passkey Notify: %06u (entered %u)\n", get_le32(&ev->passkey),
+       print("Passkey Notify: %06u (entered %u)", get_le32(&ev->passkey),
                                                                ev->entered);
 }
 
-static void cmd_monitor(struct mgmt *mgmt, uint16_t index, int argc,
-                                                               char **argv)
-{
-       printf("Monitoring mgmt events...\n");
-       monitor = true;
-}
-
 static void version_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        const struct mgmt_rp_read_version *rp = param;
 
        if (status != 0) {
-               fprintf(stderr, "Reading mgmt version failed with status"
-                       " 0x%02x (%s)\n", status, mgmt_errstr(status));
+               error("Reading mgmt version failed with status 0x%02x (%s)",
+                                               status, mgmt_errstr(status));
                goto done;
        }
 
        if (len < sizeof(*rp)) {
-               fprintf(stderr, "Too small version reply (%u bytes)\n", len);
+               error("Too small version reply (%u bytes)", len);
                goto done;
        }
 
-       printf("MGMT Version %u, revision %u\n", rp->version,
+       print("MGMT Version %u, revision %u", rp->version,
                                                get_le16(&rp->revision));
 
 done:
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_version(struct mgmt *mgmt, uint16_t index, int argc,
@@ -884,8 +990,8 @@ static void cmd_version(struct mgmt *mgmt, uint16_t index, int argc,
 {
        if (mgmt_send(mgmt, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE,
                                0, NULL, version_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send read_version cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send read_version cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -899,13 +1005,13 @@ static void commands_rsp(uint8_t status, uint16_t len, const void *param,
        int i;
 
        if (status != 0) {
-               fprintf(stderr, "Reading supported commands failed with status"
-                       " 0x%02x (%s)\n", status, mgmt_errstr(status));
+               error("Read Supported Commands failed: status 0x%02x (%s)",
+                                               status, mgmt_errstr(status));
                goto done;
        }
 
        if (len < sizeof(*rp)) {
-               fprintf(stderr, "Too small commands reply (%u bytes)\n", len);
+               error("Too small commands reply (%u bytes)", len);
                goto done;
        }
 
@@ -916,27 +1022,27 @@ static void commands_rsp(uint8_t status, uint16_t len, const void *param,
                                                num_events * sizeof(uint16_t);
 
        if (len < expected_len) {
-               fprintf(stderr, "Too small commands reply (%u != %zu)\n",
+               error("Too small commands reply (%u != %zu)",
                                                        len, expected_len);
                goto done;
        }
 
        opcode = rp->opcodes;
 
-       printf("%u commands:\n", num_commands);
+       print("%u commands:", num_commands);
        for (i = 0; i < num_commands; i++) {
                uint16_t op = get_le16(opcode++);
-               printf("\t%s (0x%04x)\n", mgmt_opstr(op), op);
+               print("\t%s (0x%04x)", mgmt_opstr(op), op);
        }
 
-       printf("%u events:\n", num_events);
+       print("%u events:", num_events);
        for (i = 0; i < num_events; i++) {
                uint16_t ev = get_le16(opcode++);
-               printf("\t%s (0x%04x)\n", mgmt_evstr(ev), ev);
+               print("\t%s (0x%04x)", mgmt_evstr(ev), ev);
        }
 
 done:
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_commands(struct mgmt *mgmt, uint16_t index, int argc,
@@ -944,8 +1050,8 @@ static void cmd_commands(struct mgmt *mgmt, uint16_t index, int argc,
 {
        if (mgmt_send(mgmt, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE,
                                0, NULL, commands_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send read_commands cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send read_commands cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -957,28 +1063,25 @@ static void unconf_index_rsp(uint8_t status, uint16_t len, const void *param,
        unsigned int i;
 
        if (status != 0) {
-               fprintf(stderr,
-                       "Reading index list failed with status 0x%02x (%s)\n",
+               error("Reading index list failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
                goto done;
        }
 
        if (len < sizeof(*rp)) {
-               fprintf(stderr, "Too small index list reply (%u bytes)\n",
-                                                                       len);
+               error("Too small index list reply (%u bytes)", len);
                goto done;
        }
 
        count = get_le16(&rp->num_controllers);
 
        if (len < sizeof(*rp) + count * sizeof(uint16_t)) {
-               fprintf(stderr,
-                       "Index count (%u) doesn't match reply length (%u)\n",
+               error("Index count (%u) doesn't match reply length (%u)",
                                                                count, len);
                goto done;
        }
 
-       printf("Unconfigured index list with %u item%s\n",
+       print("Unconfigured index list with %u item%s",
                                                count, count != 1 ? "s" : "");
 
        for (i = 0; i < count; i++) {
@@ -986,12 +1089,12 @@ static void unconf_index_rsp(uint8_t status, uint16_t len, const void *param,
 
                index = get_le16(&rp->index[i]);
 
-               printf("\thci%u\n", index);
+               print("\thci%u", index);
 
        }
 
 done:
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void config_info_rsp(uint8_t status, uint16_t len, const void *param,
@@ -1001,29 +1104,25 @@ static void config_info_rsp(uint8_t status, uint16_t len, const void *param,
        uint16_t index = PTR_TO_UINT(user_data);
 
        if (status != 0) {
-               fprintf(stderr,
-                       "Reading hci%u config failed with status 0x%02x (%s)\n",
+               error("Reading hci%u config failed with status 0x%02x (%s)",
                                        index, status, mgmt_errstr(status));
                goto done;
        }
 
        if (len < sizeof(*rp)) {
-               fprintf(stderr, "Too small info reply (%u bytes)\n", len);
+               error("Too small info reply (%u bytes)", len);
                goto done;
        }
 
-       printf("hci%u:\tmanufacturer %u\n", index, get_le16(&rp->manufacturer));
-
-       printf("\tsupported options: ");
-       print_options(get_le32(&rp->supported_options));
-       printf("\n");
+       print("hci%u:\tmanufacturer %u", index, get_le16(&rp->manufacturer));
 
-       printf("\tmissing options: ");
-       print_options(get_le32(&rp->missing_options));
-       printf("\n");
+       print("\tsupported options: %s",
+                       options2str(get_le32(&rp->supported_options)));
+       print("\tmissing options: %s",
+                       options2str(get_le32(&rp->missing_options)));
 
 done:
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_config(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
@@ -1034,8 +1133,8 @@ static void cmd_config(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
                if (mgmt_send(mgmt, MGMT_OP_READ_UNCONF_INDEX_LIST,
                                        MGMT_INDEX_NONE, 0, NULL,
                                        unconf_index_rsp, mgmt, NULL) == 0) {
-                       fprintf(stderr, "Unable to send unconf_index_list cmd\n");
-                       exit(EXIT_FAILURE);
+                       error("Unable to send unconf_index_list cmd");
+                       return noninteractive_quit(EXIT_FAILURE);
                }
 
                return;
@@ -1045,8 +1144,8 @@ static void cmd_config(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 
        if (mgmt_send(mgmt, MGMT_OP_READ_CONFIG_INFO, index, 0, NULL,
                                        config_info_rsp, data, NULL) == 0) {
-               fprintf(stderr, "Unable to send read_config_info cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send read_config_info cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -1057,40 +1156,39 @@ static void info_rsp(uint8_t status, uint16_t len, const void *param,
        uint16_t index = PTR_TO_UINT(user_data);
        char addr[18];
 
-       pending--;
+       pending_index--;
 
        if (status != 0) {
-               fprintf(stderr,
-                       "Reading hci%u info failed with status 0x%02x (%s)\n",
+               error("Reading hci%u info failed with status 0x%02x (%s)",
                                        index, status, mgmt_errstr(status));
                goto done;
        }
 
        if (len < sizeof(*rp)) {
-               fprintf(stderr, "Too small info reply (%u bytes)\n", len);
+               error("Too small info reply (%u bytes)", len);
                goto done;
        }
 
        ba2str(&rp->bdaddr, addr);
-       printf("hci%u:\taddr %s version %u manufacturer %u"
-                       " class 0x%02x%02x%02x\n", index,
+       print("hci%u:\taddr %s version %u manufacturer %u"
+                       " class 0x%02x%02x%02x", index,
                        addr, rp->version, get_le16(&rp->manufacturer),
                        rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
 
-       printf("\tsupported settings: ");
-       print_settings(get_le32(&rp->supported_settings));
+       print("\tsupported settings: %s",
+                       settings2str(get_le32(&rp->supported_settings)));
 
-       printf("\n\tcurrent settings: ");
-       print_settings(get_le32(&rp->current_settings));
+       print("\tcurrent settings: %s",
+                       settings2str(get_le32(&rp->current_settings)));
 
-       printf("\n\tname %s\n", rp->name);
-       printf("\tshort name %s\n", rp->short_name);
+       print("\tname %s", rp->name);
+       print("\tshort name %s", rp->short_name);
 
-       if (pending > 0)
+       if (pending_index > 0)
                return;
 
 done:
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void index_rsp(uint8_t status, uint16_t len, const void *param,
@@ -1102,36 +1200,25 @@ static void index_rsp(uint8_t status, uint16_t len, const void *param,
        unsigned int i;
 
        if (status != 0) {
-               fprintf(stderr,
-                       "Reading index list failed with status 0x%02x (%s)\n",
+               error("Reading index list failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-               goto done;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (len < sizeof(*rp)) {
-               fprintf(stderr, "Too small index list reply (%u bytes)\n",
-                                                                       len);
-               goto done;
+               error("Too small index list reply (%u bytes)", len);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        count = get_le16(&rp->num_controllers);
 
        if (len < sizeof(*rp) + count * sizeof(uint16_t)) {
-               fprintf(stderr,
-                       "Index count (%u) doesn't match reply length (%u)\n",
+               error("Index count (%u) doesn't match reply length (%u)",
                                                                count, len);
-               goto done;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
-       if (monitor)
-               printf("Index list with %u item%s\n",
-                                               count, count != 1 ? "s" : "");
-
-       if (count == 0)
-               goto done;
-
-       if (monitor && count > 0)
-               printf("\t");
+       print("Index list with %u item%s", count, count != 1 ? "s" : "");
 
        for (i = 0; i < count; i++) {
                uint16_t index;
@@ -1139,27 +1226,19 @@ static void index_rsp(uint8_t status, uint16_t len, const void *param,
 
                index = get_le16(&rp->index[i]);
 
-               if (monitor)
-                       printf("hci%u ", index);
-
                data = UINT_TO_PTR(index);
 
                if (mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
                                                info_rsp, data, NULL) == 0) {
-                       fprintf(stderr, "Unable to send read_info cmd\n");
-                       goto done;
+                       error("Unable to send read_info cmd");
+                       return noninteractive_quit(EXIT_FAILURE);
                }
 
-               pending++;
+               pending_index++;
        }
 
-       if (monitor && count > 0)
-               printf("\n");
-
-       return;
-
-done:
-       mainloop_quit();
+       if (!count)
+               noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_info(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
@@ -1170,8 +1249,8 @@ static void cmd_info(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
                if (mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST,
                                        MGMT_INDEX_NONE, 0, NULL,
                                        index_rsp, mgmt, NULL) == 0) {
-                       fprintf(stderr, "Unable to send index_list cmd\n");
-                       exit(EXIT_FAILURE);
+                       error("Unable to send index_list cmd");
+                       return noninteractive_quit(EXIT_FAILURE);
                }
 
                return;
@@ -1181,8 +1260,8 @@ static void cmd_info(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 
        if (mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, info_rsp,
                                                        data, NULL) == 0) {
-               fprintf(stderr, "Unable to send read_info cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send read_info cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -1232,24 +1311,22 @@ static void setting_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len,
        const uint32_t *rp = param;
 
        if (status != 0) {
-               fprintf(stderr,
-                       "%s for hci%u failed with status 0x%02x (%s)\n",
+               error("%s for hci%u failed with status 0x%02x (%s)",
                        mgmt_opstr(op), id, status, mgmt_errstr(status));
                goto done;
        }
 
        if (len < sizeof(*rp)) {
-               fprintf(stderr, "Too small %s response (%u bytes)\n",
+               error("Too small %s response (%u bytes)",
                                                        mgmt_opstr(op), len);
                goto done;
        }
 
-       printf("hci%u %s complete, settings: ", id, mgmt_opstr(op));
-       print_settings(get_le32(rp));
-       printf("\n");
+       print("hci%u %s complete, settings: %s", id, mgmt_opstr(op),
+                                               settings2str(get_le32(rp)));
 
 done:
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_setting(struct mgmt *mgmt, uint16_t index, uint16_t op,
@@ -1258,8 +1335,8 @@ static void cmd_setting(struct mgmt *mgmt, uint16_t index, uint16_t op,
        uint8_t val;
 
        if (argc < 2) {
-               printf("Specify \"on\" or \"off\"\n");
-               exit(EXIT_FAILURE);
+               print("Specify \"on\" or \"off\"");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
@@ -1273,8 +1350,8 @@ static void cmd_setting(struct mgmt *mgmt, uint16_t index, uint16_t op,
                index = 0;
 
        if (send_cmd(mgmt, op, index, sizeof(val), &val, setting_rsp) == 0) {
-               fprintf(stderr, "Unable to send %s cmd\n", mgmt_opstr(op));
-               exit(EXIT_FAILURE);
+               error("Unable to send %s cmd", mgmt_opstr(op));
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -1289,8 +1366,8 @@ static void cmd_discov(struct mgmt *mgmt, uint16_t index, int argc,
        struct mgmt_cp_set_discoverable cp;
 
        if (argc < 2) {
-               printf("Usage: btmgmt %s <yes/no/limited> [timeout]\n", argv[0]);
-               exit(EXIT_FAILURE);
+               print("Usage: %s <yes/no/limited> [timeout]", argv[0]);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        memset(&cp, 0, sizeof(cp));
@@ -1312,8 +1389,8 @@ static void cmd_discov(struct mgmt *mgmt, uint16_t index, int argc,
 
        if (send_cmd(mgmt, MGMT_OP_SET_DISCOVERABLE, index, sizeof(cp), &cp,
                                                        setting_rsp) == 0) {
-               fprintf(stderr, "Unable to send set_discoverable cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send set_discoverable cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -1351,8 +1428,8 @@ static void cmd_sc(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
        uint8_t val;
 
        if (argc < 2) {
-               printf("Specify \"on\" or \"off\" or \"only\"\n");
-               exit(EXIT_FAILURE);
+               print("Specify \"on\" or \"off\" or \"only\"");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
@@ -1369,8 +1446,8 @@ static void cmd_sc(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 
        if (send_cmd(mgmt, MGMT_OP_SET_SECURE_CONN, index,
                                        sizeof(val), &val, setting_rsp) == 0) {
-               fprintf(stderr, "Unable to send set_secure_conn cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send set_secure_conn cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -1401,8 +1478,8 @@ static void cmd_privacy(struct mgmt *mgmt, uint16_t index, int argc,
        struct mgmt_cp_set_privacy cp;
 
        if (argc < 2) {
-               printf("Specify \"on\" or \"off\"\n");
-               exit(EXIT_FAILURE);
+               print("Specify \"on\" or \"off\"");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
@@ -1416,25 +1493,24 @@ static void cmd_privacy(struct mgmt *mgmt, uint16_t index, int argc,
                index = 0;
 
        if (argc > 2) {
-               if (convert_hexstr(argv[2], cp.irk,
+               if (hex2bin(argv[2], cp.irk,
                                        sizeof(cp.irk)) != sizeof(cp.irk)) {
-                       fprintf(stderr, "Invalid key format\n");
-                       exit(EXIT_FAILURE);
+                       error("Invalid key format");
+                       return noninteractive_quit(EXIT_FAILURE);
                }
        } else {
                int fd;
 
                fd = open("/dev/urandom", O_RDONLY);
                if (fd < 0) {
-                       fprintf(stderr, "open(/dev/urandom): %s\n",
-                                                       strerror(errno));
-                       exit(EXIT_FAILURE);
+                       error("open(/dev/urandom): %s", strerror(errno));
+                       return noninteractive_quit(EXIT_FAILURE);
                }
 
                if (read(fd, cp.irk, sizeof(cp.irk)) != sizeof(cp.irk)) {
-                       fprintf(stderr, "Reading from urandom failed\n");
+                       error("Reading from urandom failed");
                        close(fd);
-                       exit(EXIT_FAILURE);
+                       return noninteractive_quit(EXIT_FAILURE);
                }
 
                close(fd);
@@ -1442,8 +1518,8 @@ static void cmd_privacy(struct mgmt *mgmt, uint16_t index, int argc,
 
        if (send_cmd(mgmt, MGMT_OP_SET_PRIVACY, index, sizeof(cp), &cp,
                                                        setting_rsp) == 0) {
-               fprintf(stderr, "Unable to send Set Privacy command\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send Set Privacy command");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -1453,21 +1529,20 @@ static void class_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len,
        const struct mgmt_ev_class_of_dev_changed *rp = param;
 
        if (len == 0 && status != 0) {
-               fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
+               error("%s failed, status 0x%02x (%s)",
                                mgmt_opstr(op), status, mgmt_errstr(status));
-               goto done;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (len != sizeof(*rp)) {
-               fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len);
-               goto done;
+               error("Unexpected %s len %u", mgmt_opstr(op), len);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
-       printf("%s succeeded. Class 0x%02x%02x%02x\n", mgmt_opstr(op),
+       print("%s succeeded. Class 0x%02x%02x%02x", mgmt_opstr(op),
                rp->class_of_dev[2], rp->class_of_dev[1], rp->class_of_dev[0]);
 
-done:
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_class(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
@@ -1475,8 +1550,8 @@ static void cmd_class(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
        uint8_t class[2];
 
        if (argc < 3) {
-               printf("Usage: btmgmt %s <major> <minor>\n", argv[0]);
-               exit(EXIT_FAILURE);
+               print("Usage: %s <major> <minor>", argv[0]);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        class[0] = atoi(argv[1]);
@@ -1487,8 +1562,8 @@ static void cmd_class(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 
        if (send_cmd(mgmt, MGMT_OP_SET_DEV_CLASS, index, sizeof(class), class,
                                                        class_rsp) == 0) {
-               fprintf(stderr, "Unable to send set_dev_class cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send set_dev_class cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -1499,33 +1574,30 @@ static void disconnect_rsp(uint8_t status, uint16_t len, const void *param,
        char addr[18];
 
        if (len == 0 && status != 0) {
-               fprintf(stderr, "Disconnect failed with status 0x%02x (%s)\n",
+               error("Disconnect failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-               goto done;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (len != sizeof(*rp)) {
-               fprintf(stderr, "Invalid disconnect response length (%u)\n",
-                                                                       len);
-               goto done;
+               error("Invalid disconnect response length (%u)", len);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        ba2str(&rp->addr.bdaddr, addr);
 
        if (status == 0)
-               printf("%s disconnected\n", addr);
+               print("%s disconnected", addr);
        else
-               fprintf(stderr,
-                       "Disconnecting %s failed with status 0x%02x (%s)\n",
+               error("Disconnecting %s failed with status 0x%02x (%s)",
                                addr, status, mgmt_errstr(status));
 
-done:
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void disconnect_usage(void)
 {
-       printf("Usage: btmgmt disconnect [-t type] <remote address>\n");
+       print("Usage: disconnect [-t type] <remote address>");
 }
 
 static struct option disconnect_options[] = {
@@ -1548,9 +1620,11 @@ static void cmd_disconnect(struct mgmt *mgmt, uint16_t index, int argc,
                        type = strtol(optarg, NULL, 0);
                        break;
                case 'h':
+                       disconnect_usage();
+                       return noninteractive_quit(EXIT_SUCCESS);
                default:
                        disconnect_usage();
-                       exit(EXIT_SUCCESS);
+                       return noninteractive_quit(EXIT_FAILURE);
                }
        }
 
@@ -1560,7 +1634,7 @@ static void cmd_disconnect(struct mgmt *mgmt, uint16_t index, int argc,
 
        if (argc < 1) {
                disconnect_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
@@ -1572,8 +1646,8 @@ static void cmd_disconnect(struct mgmt *mgmt, uint16_t index, int argc,
 
        if (mgmt_send(mgmt, MGMT_OP_DISCONNECT, index, sizeof(cp), &cp,
                                        disconnect_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send disconnect cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send disconnect cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -1584,16 +1658,15 @@ static void con_rsp(uint8_t status, uint16_t len, const void *param,
        uint16_t count, i;
 
        if (len < sizeof(*rp)) {
-               fprintf(stderr, "Too small (%u bytes) get_connections rsp\n",
-                                                                       len);
-               goto done;
+               error("Too small (%u bytes) get_connections rsp", len);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        count = get_le16(&rp->conn_count);
        if (len != sizeof(*rp) + count * sizeof(struct mgmt_addr_info)) {
-               fprintf(stderr, "Invalid get_connections length "
-                                       " (count=%u, len=%u)\n", count, len);
-               goto done;
+               error("Invalid get_connections length (count=%u, len=%u)",
+                                                               count, len);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        for (i = 0; i < count; i++) {
@@ -1601,11 +1674,10 @@ static void con_rsp(uint8_t status, uint16_t len, const void *param,
 
                ba2str(&rp->addr[i].bdaddr, addr);
 
-               printf("%s type %s\n", addr, typestr(rp->addr[i].type));
+               print("%s type %s", addr, typestr(rp->addr[i].type));
        }
 
-done:
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_con(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
@@ -1615,8 +1687,8 @@ static void cmd_con(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 
        if (mgmt_send(mgmt, MGMT_OP_GET_CONNECTIONS, index, 0, NULL,
                                                con_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send get_connections cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send get_connections cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -1624,20 +1696,18 @@ static void find_service_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0) {
-               fprintf(stderr,
-                       "Unable to start service discovery. status 0x%02x (%s)\n",
-                       status, mgmt_errstr(status));
-               mainloop_quit();
-               return;
+               error("Start Service Discovery failed: status 0x%02x (%s)",
+                                               status, mgmt_errstr(status));
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
-       printf("Service discovery started\n");
+       print("Service discovery started");
        discovery = true;
 }
 
 static void find_service_usage(void)
 {
-       printf("Usage: btmgmt find-service [-u UUID] [-r RSSI_Threshold] [-l|-b]\n");
+       print("Usage: find-service [-u UUID] [-r RSSI_Threshold] [-l|-b]");
 }
 
 static struct option find_service_options[] = {
@@ -1678,39 +1748,39 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc,
                index = 0;
 
        type = 0;
-       hci_set_bit(BDADDR_BREDR, &type);
-       hci_set_bit(BDADDR_LE_PUBLIC, &type);
-       hci_set_bit(BDADDR_LE_RANDOM, &type);
+       type |= (1 << BDADDR_BREDR);
+       type |= (1 << BDADDR_LE_PUBLIC);
+       type |= (1 << BDADDR_LE_RANDOM);
        rssi = 127;
        count = 0;
 
        if (argc == 1) {
                find_service_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        while ((opt = getopt_long(argc, argv, "+lbu:r:p:h",
                                        find_service_options, NULL)) != -1) {
                switch (opt) {
                case 'l':
-                       hci_clear_bit(BDADDR_BREDR, &type);
-                       hci_set_bit(BDADDR_LE_PUBLIC, &type);
-                       hci_set_bit(BDADDR_LE_RANDOM, &type);
+                       type &= ~(1 << BDADDR_BREDR);
+                       type |= (1 << BDADDR_LE_PUBLIC);
+                       type |= (1 << BDADDR_LE_RANDOM);
                        break;
                case 'b':
-                       hci_set_bit(BDADDR_BREDR, &type);
-                       hci_clear_bit(BDADDR_LE_PUBLIC, &type);
-                       hci_clear_bit(BDADDR_LE_RANDOM, &type);
+                       type |= (1 << BDADDR_BREDR);
+                       type &= ~(1 << BDADDR_LE_PUBLIC);
+                       type &= ~(1 << BDADDR_LE_RANDOM);
                        break;
                case 'u':
                        if (count == MAX_UUIDS) {
-                               printf("Max %u UUIDs supported\n", MAX_UUIDS);
-                               exit(EXIT_FAILURE);
+                               print("Max %u UUIDs supported", MAX_UUIDS);
+                               return noninteractive_quit(EXIT_FAILURE);
                        }
 
                        if (bt_string2uuid(&uuid, optarg) < 0) {
-                               printf("Invalid UUID: %s\n", optarg);
-                               exit(EXIT_FAILURE);
+                               print("Invalid UUID: %s", optarg);
+                               return noninteractive_quit(EXIT_FAILURE);
                        }
                        cp = (void *) buf;
                        uuid_to_uuid128(&uuid128, &uuid);
@@ -1723,10 +1793,10 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc,
                        break;
                case 'h':
                        find_service_usage();
-                       exit(EXIT_SUCCESS);
+                       return noninteractive_quit(EXIT_SUCCESS);
                default:
                        find_service_usage();
-                       exit(EXIT_FAILURE);
+                       return noninteractive_quit(EXIT_FAILURE);
                }
        }
 
@@ -1736,7 +1806,7 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc,
 
        if (argc > 0) {
                find_service_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        cp = (void *) buf;
@@ -1747,8 +1817,8 @@ static void cmd_find_service(struct mgmt *mgmt, uint16_t index, int argc,
        if (mgmt_send(mgmt, MGMT_OP_START_SERVICE_DISCOVERY, index,
                                sizeof(*cp) + count * 16, cp,
                                find_service_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send start_service_discovery cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send start_service_discovery cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -1756,20 +1826,18 @@ static void find_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0) {
-               fprintf(stderr,
-                       "Unable to start discovery. status 0x%02x (%s)\n",
+               error("Unable to start discovery. status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-               mainloop_quit();
-               return;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
-       printf("Discovery started\n");
+       print("Discovery started");
        discovery = true;
 }
 
 static void find_usage(void)
 {
-       printf("Usage: btmgmt find [-l|-b]>\n");
+       print("Usage: find [-l|-b]>");
 }
 
 static struct option find_options[] = {
@@ -1789,27 +1857,29 @@ static void cmd_find(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
                index = 0;
 
        type = 0;
-       hci_set_bit(BDADDR_BREDR, &type);
-       hci_set_bit(BDADDR_LE_PUBLIC, &type);
-       hci_set_bit(BDADDR_LE_RANDOM, &type);
+       type |= (1 << BDADDR_BREDR);
+       type |= (1 << BDADDR_LE_PUBLIC);
+       type |= (1 << BDADDR_LE_RANDOM);
 
        while ((opt = getopt_long(argc, argv, "+lbh", find_options,
                                                                NULL)) != -1) {
                switch (opt) {
                case 'l':
-                       hci_clear_bit(BDADDR_BREDR, &type);
-                       hci_set_bit(BDADDR_LE_PUBLIC, &type);
-                       hci_set_bit(BDADDR_LE_RANDOM, &type);
+                       type &= ~(1 << BDADDR_BREDR);
+                       type |= (1 << BDADDR_LE_PUBLIC);
+                       type |= (1 << BDADDR_LE_RANDOM);
                        break;
                case 'b':
-                       hci_set_bit(BDADDR_BREDR, &type);
-                       hci_clear_bit(BDADDR_LE_PUBLIC, &type);
-                       hci_clear_bit(BDADDR_LE_RANDOM, &type);
+                       type |= (1 << BDADDR_BREDR);
+                       type &= ~(1 << BDADDR_LE_PUBLIC);
+                       type &= ~(1 << BDADDR_LE_RANDOM);
                        break;
                case 'h':
+                       find_usage();
+                       return noninteractive_quit(EXIT_SUCCESS);
                default:
                        find_usage();
-                       exit(EXIT_SUCCESS);
+                       return noninteractive_quit(EXIT_FAILURE);
                }
        }
 
@@ -1822,8 +1892,8 @@ static void cmd_find(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 
        if (mgmt_send(mgmt, MGMT_OP_START_DISCOVERY, index, sizeof(cp), &cp,
                                                find_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send start_discovery cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send start_discovery cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -1831,11 +1901,10 @@ static void name_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0)
-               fprintf(stderr, "Unable to set local name "
-                                               "with status 0x%02x (%s)\n",
+               error("Unable to set local name with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
 
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_name(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
@@ -1843,8 +1912,8 @@ static void cmd_name(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
        struct mgmt_cp_set_local_name cp;
 
        if (argc < 2) {
-               printf("Usage: btmgmt %s <name> [shortname]\n", argv[0]);
-               exit(EXIT_FAILURE);
+               print("Usage: %s <name> [shortname]", argv[0]);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
@@ -1858,8 +1927,8 @@ static void cmd_name(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 
        if (mgmt_send(mgmt, MGMT_OP_SET_LOCAL_NAME, index, sizeof(cp), &cp,
                                                name_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send set_name cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send set_name cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -1870,35 +1939,34 @@ static void pair_rsp(uint8_t status, uint16_t len, const void *param,
        char addr[18];
 
        if (len == 0 && status != 0) {
-               fprintf(stderr, "Pairing failed with status 0x%02x (%s)\n",
+               error("Pairing failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-               goto done;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (len != sizeof(*rp)) {
-               fprintf(stderr, "Unexpected pair_rsp len %u\n", len);
-               goto done;
+               error("Unexpected pair_rsp len %u", len);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
+       if (!memcmp(&rp->addr, &prompt.addr, sizeof(rp->addr)))
+               release_prompt();
+
        ba2str(&rp->addr.bdaddr, addr);
 
-       if (status != 0) {
-               fprintf(stderr,
-                       "Pairing with %s (%s) failed. status 0x%02x (%s)\n",
+       if (status)
+               error("Pairing with %s (%s) failed. status 0x%02x (%s)",
                        addr, typestr(rp->addr.type), status,
                        mgmt_errstr(status));
-               goto done;
-       }
-
-       printf("Paired with %s (%s)\n", addr, typestr(rp->addr.type));
+       else
+               print("Paired with %s (%s)", addr, typestr(rp->addr.type));
 
-done:
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void pair_usage(void)
 {
-       printf("Usage: btmgmt pair [-c cap] [-t type] <remote address>\n");
+       print("Usage: pair [-c cap] [-t type] <remote address>");
 }
 
 static struct option pair_options[] = {
@@ -1926,9 +1994,11 @@ static void cmd_pair(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
                        type = strtol(optarg, NULL, 0);
                        break;
                case 'h':
+                       pair_usage();
+                       return noninteractive_quit(EXIT_SUCCESS);
                default:
                        pair_usage();
-                       exit(EXIT_SUCCESS);
+                       return noninteractive_quit(EXIT_FAILURE);
                }
        }
 
@@ -1938,7 +2008,7 @@ static void cmd_pair(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 
        if (argc < 1) {
                pair_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
@@ -1950,12 +2020,12 @@ static void cmd_pair(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
        cp.io_cap = cap;
 
        ba2str(&cp.addr.bdaddr, addr);
-       printf("Pairing with %s (%s)\n", addr, typestr(cp.addr.type));
+       print("Pairing with %s (%s)", addr, typestr(cp.addr.type));
 
        if (mgmt_send(mgmt, MGMT_OP_PAIR_DEVICE, index, sizeof(cp), &cp,
                                                pair_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send pair_device cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send pair_device cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -1966,35 +2036,31 @@ static void cancel_pair_rsp(uint8_t status, uint16_t len, const void *param,
        char addr[18];
 
        if (len == 0 && status != 0) {
-               fprintf(stderr, "Cancel Pairing failed with 0x%02x (%s)\n",
+               error("Cancel Pairing failed with 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-               goto done;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (len != sizeof(*rp)) {
-               fprintf(stderr, "Unexpected cancel_pair_rsp len %u\n", len);
-               goto done;
+               error("Unexpected cancel_pair_rsp len %u", len);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        ba2str(&rp->bdaddr, addr);
 
-       if (status != 0) {
-               fprintf(stderr,
-                       "Cancel Pairing with %s (%s) failed. 0x%02x (%s)\n",
+       if (status)
+               error("Cancel Pairing with %s (%s) failed. 0x%02x (%s)",
                        addr, typestr(rp->type), status,
                        mgmt_errstr(status));
-               goto done;
-       }
-
-       printf("Pairing Cancelled with %s\n", addr);
+       else
+               print("Pairing Cancelled with %s", addr);
 
-done:
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cancel_pair_usage(void)
 {
-       printf("Usage: btmgmt cancelpair [-t type] <remote address>\n");
+       print("Usage: cancelpair [-t type] <remote address>");
 }
 
 static struct option cancel_pair_options[] = {
@@ -2017,9 +2083,11 @@ static void cmd_cancel_pair(struct mgmt *mgmt, uint16_t index, int argc,
                        type = strtol(optarg, NULL, 0);
                        break;
                case 'h':
+                       cancel_pair_usage();
+                       return noninteractive_quit(EXIT_SUCCESS);
                default:
                        cancel_pair_usage();
-                       exit(EXIT_SUCCESS);
+                       return noninteractive_quit(EXIT_FAILURE);
                }
        }
 
@@ -2029,7 +2097,7 @@ static void cmd_cancel_pair(struct mgmt *mgmt, uint16_t index, int argc,
 
        if (argc < 1) {
                cancel_pair_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
@@ -2041,8 +2109,8 @@ static void cmd_cancel_pair(struct mgmt *mgmt, uint16_t index, int argc,
 
        if (mgmt_send(mgmt, MGMT_OP_CANCEL_PAIR_DEVICE, index, sizeof(cp), &cp,
                                        cancel_pair_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send cancel_pair_device cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send cancel_pair_device cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -2053,34 +2121,30 @@ static void unpair_rsp(uint8_t status, uint16_t len, const void *param,
        char addr[18];
 
        if (len == 0 && status != 0) {
-               fprintf(stderr, "Unpair device failed. status 0x%02x (%s)\n",
+               error("Unpair device failed. status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-               goto done;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (len != sizeof(*rp)) {
-               fprintf(stderr, "Unexpected unpair_device_rsp len %u\n", len);
-               goto done;
+               error("Unexpected unpair_device_rsp len %u", len);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        ba2str(&rp->addr.bdaddr, addr);
 
-       if (status != 0) {
-               fprintf(stderr,
-                       "Unpairing %s failed. status 0x%02x (%s)\n",
+       if (status)
+               error("Unpairing %s failed. status 0x%02x (%s)",
                                addr, status, mgmt_errstr(status));
-               goto done;
-       }
-
-       printf("%s unpaired\n", addr);
+       else
+               print("%s unpaired", addr);
 
-done:
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void unpair_usage(void)
 {
-       printf("Usage: btmgmt unpair [-t type] <remote address>\n");
+       print("Usage: unpair [-t type] <remote address>");
 }
 
 static struct option unpair_options[] = {
@@ -2103,9 +2167,11 @@ static void cmd_unpair(struct mgmt *mgmt, uint16_t index, int argc,
                        type = strtol(optarg, NULL, 0);
                        break;
                case 'h':
+                       unpair_usage();
+                       return noninteractive_quit(EXIT_SUCCESS);
                default:
                        unpair_usage();
-                       exit(EXIT_SUCCESS);
+                       return noninteractive_quit(EXIT_FAILURE);
                }
        }
 
@@ -2115,7 +2181,7 @@ static void cmd_unpair(struct mgmt *mgmt, uint16_t index, int argc,
 
        if (argc < 1) {
                unpair_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
@@ -2128,8 +2194,8 @@ static void cmd_unpair(struct mgmt *mgmt, uint16_t index, int argc,
 
        if (mgmt_send(mgmt, MGMT_OP_UNPAIR_DEVICE, index, sizeof(cp), &cp,
                                                unpair_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send unpair_device cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send unpair_device cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -2137,12 +2203,12 @@ static void keys_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0)
-               fprintf(stderr, "Load keys failed with status 0x%02x (%s)\n",
+               error("Load keys failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
        else
-               printf("Keys successfully loaded\n");
+               print("Keys successfully loaded");
 
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_keys(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
@@ -2156,8 +2222,8 @@ static void cmd_keys(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 
        if (mgmt_send(mgmt, MGMT_OP_LOAD_LINK_KEYS, index, sizeof(cp), &cp,
                                                keys_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send load_keys cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send load_keys cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -2165,12 +2231,12 @@ static void ltks_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0)
-               fprintf(stderr, "Load keys failed with status 0x%02x (%s)\n",
+               error("Load keys failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
        else
-               printf("Long term keys successfully loaded\n");
+               print("Long term keys successfully loaded");
 
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_ltks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
@@ -2184,8 +2250,8 @@ static void cmd_ltks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 
        if (mgmt_send(mgmt, MGMT_OP_LOAD_LONG_TERM_KEYS, index, sizeof(cp), &cp,
                                                ltks_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send load_ltks cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send load_ltks cmd");
+               return noninteractive_quit(EXIT_SUCCESS);
        }
 }
 
@@ -2193,17 +2259,17 @@ static void irks_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0)
-               fprintf(stderr, "Load IRKs failed with status 0x%02x (%s)\n",
+               error("Load IRKs failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
        else
-               printf("Identity Resolving Keys successfully loaded\n");
+               print("Identity Resolving Keys successfully loaded");
 
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void irks_usage(void)
 {
-       printf("Usage: btmgmt irks [--local]\n");
+       print("Usage: irks [--local]");
 }
 
 static struct option irks_options[] = {
@@ -2232,8 +2298,8 @@ static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
                switch (opt) {
                case 'l':
                        if (count >= MAX_IRKS) {
-                               fprintf(stderr, "Number of IRKs exceeded\n");
-                               exit(EXIT_FAILURE);
+                               error("Number of IRKs exceeded");
+                               return noninteractive_quit(EXIT_FAILURE);
                        }
                        if (strlen(optarg) > 3 &&
                                        strncasecmp(optarg, "hci", 3) == 0)
@@ -2241,17 +2307,17 @@ static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
                        else
                                local_index = atoi(optarg);
                        if (!load_identity(local_index, &cp->irks[count])) {
-                               fprintf(stderr, "Unable to load identity\n");
-                               exit(EXIT_FAILURE);
+                               error("Unable to load identity");
+                               return noninteractive_quit(EXIT_FAILURE);
                        }
                        count++;
                        break;
                case 'h':
                        irks_usage();
-                       exit(EXIT_SUCCESS);
+                       return noninteractive_quit(EXIT_SUCCESS);
                default:
                        irks_usage();
-                       exit(EXIT_FAILURE);
+                       return noninteractive_quit(EXIT_FAILURE);
                }
        }
 
@@ -2261,7 +2327,7 @@ static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 
        if (argc > 0) {
                irks_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        cp->irk_count = cpu_to_le16(count);
@@ -2269,8 +2335,8 @@ static void cmd_irks(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
        if (mgmt_send(mgmt, MGMT_OP_LOAD_IRKS, index,
                                        sizeof(*cp) + count * 23, cp,
                                        irks_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send load_irks cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send load_irks cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -2281,34 +2347,31 @@ static void block_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len,
        char addr[18];
 
        if (len == 0 && status != 0) {
-               fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
+               error("%s failed, status 0x%02x (%s)",
                                mgmt_opstr(op), status, mgmt_errstr(status));
-               goto done;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (len != sizeof(*rp)) {
-               fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len);
-               goto done;
+               error("Unexpected %s len %u", mgmt_opstr(op), len);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        ba2str(&rp->bdaddr, addr);
 
-       if (status != 0) {
-               fprintf(stderr, "%s %s (%s) failed. status 0x%02x (%s)\n",
+       if (status)
+               error("%s %s (%s) failed. status 0x%02x (%s)",
                                mgmt_opstr(op), addr, typestr(rp->type),
                                status, mgmt_errstr(status));
-               goto done;
-       }
-
-       printf("%s %s succeeded\n", mgmt_opstr(op), addr);
+       else
+               print("%s %s succeeded", mgmt_opstr(op), addr);
 
-done:
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void block_usage(void)
 {
-       printf("Usage: btmgmt block [-t type] <remote address>\n");
+       print("Usage: block [-t type] <remote address>");
 }
 
 static struct option block_options[] = {
@@ -2330,9 +2393,11 @@ static void cmd_block(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
                        type = strtol(optarg, NULL, 0);
                        break;
                case 'h':
+                       block_usage();
+                       return noninteractive_quit(EXIT_SUCCESS);
                default:
                        block_usage();
-                       exit(EXIT_SUCCESS);
+                       return noninteractive_quit(EXIT_FAILURE);
                }
        }
 
@@ -2342,7 +2407,7 @@ static void cmd_block(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 
        if (argc < 1) {
                block_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
@@ -2354,14 +2419,14 @@ static void cmd_block(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 
        if (send_cmd(mgmt, MGMT_OP_BLOCK_DEVICE, index, sizeof(cp), &cp,
                                                        block_rsp) == 0) {
-               fprintf(stderr, "Unable to send block_device cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send block_device cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
 static void unblock_usage(void)
 {
-       printf("Usage: btmgmt unblock [-t type] <remote address>\n");
+       print("Usage: unblock [-t type] <remote address>");
 }
 
 static void cmd_unblock(struct mgmt *mgmt, uint16_t index, int argc,
@@ -2378,9 +2443,11 @@ static void cmd_unblock(struct mgmt *mgmt, uint16_t index, int argc,
                        type = strtol(optarg, NULL, 0);
                        break;
                case 'h':
+                       unblock_usage();
+                       return noninteractive_quit(EXIT_SUCCESS);
                default:
                        unblock_usage();
-                       exit(EXIT_SUCCESS);
+                       return noninteractive_quit(EXIT_FAILURE);
                }
        }
 
@@ -2390,7 +2457,7 @@ static void cmd_unblock(struct mgmt *mgmt, uint16_t index, int argc,
 
        if (argc < 1) {
                unblock_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
@@ -2402,8 +2469,8 @@ static void cmd_unblock(struct mgmt *mgmt, uint16_t index, int argc,
 
        if (send_cmd(mgmt, MGMT_OP_UNBLOCK_DEVICE, index, sizeof(cp), &cp,
                                                        block_rsp) == 0) {
-               fprintf(stderr, "Unable to send unblock_device cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send unblock_device cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -2415,16 +2482,16 @@ static void cmd_add_uuid(struct mgmt *mgmt, uint16_t index, int argc,
        uuid_t uuid, uuid128;
 
        if (argc < 3) {
-               printf("UUID and service hint needed\n");
-               exit(EXIT_FAILURE);
+               print("UUID and service hint needed");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
                index = 0;
 
        if (bt_string2uuid(&uuid, argv[1]) < 0) {
-               printf("Invalid UUID: %s\n", argv[1]);
-               exit(EXIT_FAILURE);
+               print("Invalid UUID: %s", argv[1]);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        memset(&cp, 0, sizeof(cp));
@@ -2437,8 +2504,8 @@ static void cmd_add_uuid(struct mgmt *mgmt, uint16_t index, int argc,
 
        if (send_cmd(mgmt, MGMT_OP_ADD_UUID, index, sizeof(cp), &cp,
                                                        class_rsp) == 0) {
-               fprintf(stderr, "Unable to send add_uuid cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send add_uuid cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -2450,16 +2517,16 @@ static void cmd_remove_uuid(struct mgmt *mgmt, uint16_t index, int argc,
        uuid_t uuid, uuid128;
 
        if (argc < 2) {
-               printf("UUID needed\n");
-               exit(EXIT_FAILURE);
+               print("UUID needed");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
                index = 0;
 
        if (bt_string2uuid(&uuid, argv[1]) < 0) {
-               printf("Invalid UUID: %s\n", argv[1]);
-               exit(EXIT_FAILURE);
+               print("Invalid UUID: %s", argv[1]);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        memset(&cp, 0, sizeof(cp));
@@ -2470,8 +2537,8 @@ static void cmd_remove_uuid(struct mgmt *mgmt, uint16_t index, int argc,
 
        if (send_cmd(mgmt, MGMT_OP_REMOVE_UUID, index, sizeof(cp), &cp,
                                                        class_rsp) == 0) {
-               fprintf(stderr, "Unable to send remove_uuid cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send remove_uuid cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -2489,46 +2556,35 @@ static void local_oob_rsp(uint8_t status, uint16_t len, const void *param,
 {
        const struct mgmt_rp_read_local_oob_data *rp = param;
        const struct mgmt_rp_read_local_oob_ext_data *rp_ext = param;
-       int i;
+       char str[33];
 
        if (status != 0) {
-               fprintf(stderr, "Read Local OOB Data failed "
-                                               "with status 0x%02x (%s)\n",
+               error("Read Local OOB Data failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-               goto done;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (len < sizeof(*rp)) {
-               fprintf(stderr, "Too small (%u bytes) read_local_oob rsp\n",
-                                                                       len);
-               goto done;
+               error("Too small (%u bytes) read_local_oob rsp", len);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
-       printf("Hash C from P-192: ");
-       for (i = 0; i < 16; i++)
-               printf("%02x", rp->hash[i]);
-       printf("\n");
+       bin2hex(rp->hash, 16, str, sizeof(str));
+       print("Hash C from P-192: %s", str);
 
-       printf("Randomizer R with P-192: ");
-       for (i = 0; i < 16; i++)
-               printf("%02x", rp->randomizer[i]);
-       printf("\n");
+       bin2hex(rp->randomizer, 16, str, sizeof(str));
+       print("Randomizer R with P-192: %s", str);
 
        if (len < sizeof(*rp_ext))
-               goto done;
+               return noninteractive_quit(EXIT_SUCCESS);
 
-       printf("Hash C from P-256: ");
-       for (i = 0; i < 16; i++)
-               printf("%02x", rp_ext->hash256[i]);
-       printf("\n");
+       bin2hex(rp_ext->hash256, 16, str, sizeof(str));
+       print("Hash C from P-256: %s", str);
 
-       printf("Randomizer R with P-256: ");
-       for (i = 0; i < 16; i++)
-               printf("%02x", rp_ext->randomizer256[i]);
-       printf("\n");
+       bin2hex(rp_ext->randomizer256, 16, str, sizeof(str));
+       print("Randomizer R with P-256: %s", str);
 
-done:
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_local_oob(struct mgmt *mgmt, uint16_t index,
@@ -2539,8 +2595,8 @@ static void cmd_local_oob(struct mgmt *mgmt, uint16_t index,
 
        if (mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_DATA, index, 0, NULL,
                                        local_oob_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send read_local_oob cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send read_local_oob cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -2551,26 +2607,25 @@ static void remote_oob_rsp(uint8_t status, uint16_t len, const void *param,
        char addr[18];
 
        if (status != 0) {
-               fprintf(stderr, "Add Remote OOB Data failed: 0x%02x (%s)\n",
+               error("Add Remote OOB Data failed: 0x%02x (%s)",
                                                status, mgmt_errstr(status));
                return;
        }
 
        if (len < sizeof(*rp)) {
-               fprintf(stderr, "Too small (%u bytes) add_remote_oob rsp\n",
-                                                                       len);
+               error("Too small (%u bytes) add_remote_oob rsp", len);
                return;
        }
 
        ba2str(&rp->bdaddr, addr);
-       printf("Remote OOB data added for %s (%u)\n", addr, rp->type);
+       print("Remote OOB data added for %s (%u)", addr, rp->type);
 }
 
 static void remote_oob_usage(void)
 {
-       printf("Usage: btmgmt remote-oob [-t <addr_type>] "
+       print("Usage: remote-oob [-t <addr_type>] "
                "[-r <rand192>] [-h <hash192>] [-R <rand256>] [-H <hash256>] "
-               "<addr>\n");
+               "<addr>");
 }
 
 static struct option remote_oob_opt[] = {
@@ -2595,20 +2650,20 @@ static void cmd_remote_oob(struct mgmt *mgmt, uint16_t index,
                        cp.addr.type = strtol(optarg, NULL, 0);
                        break;
                case 'r':
-                       convert_hexstr(optarg, cp.rand192, 16);
+                       hex2bin(optarg, cp.rand192, 16);
                        break;
                case 'h':
-                       convert_hexstr(optarg, cp.hash192, 16);
+                       hex2bin(optarg, cp.hash192, 16);
                        break;
                case 'R':
-                       convert_hexstr(optarg, cp.rand256, 16);
+                       hex2bin(optarg, cp.rand256, 16);
                        break;
                case 'H':
-                       convert_hexstr(optarg, cp.hash256, 16);
+                       hex2bin(optarg, cp.hash256, 16);
                        break;
                default:
                        remote_oob_usage();
-                       exit(EXIT_SUCCESS);
+                       return noninteractive_quit(EXIT_FAILURE);
                }
        }
 
@@ -2618,7 +2673,7 @@ static void cmd_remote_oob(struct mgmt *mgmt, uint16_t index,
 
        if (argc < 1) {
                remote_oob_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
@@ -2626,13 +2681,13 @@ static void cmd_remote_oob(struct mgmt *mgmt, uint16_t index,
 
        str2ba(argv[0], &cp.addr.bdaddr);
 
-       printf("Adding OOB data for %s (%s)\n", argv[0], typestr(cp.addr.type));
+       print("Adding OOB data for %s (%s)", argv[0], typestr(cp.addr.type));
 
        if (mgmt_send(mgmt, MGMT_OP_ADD_REMOTE_OOB_DATA, index,
                                sizeof(cp), &cp, remote_oob_rsp,
                                NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send add_remote_oob cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send add_remote_oob cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -2640,19 +2695,18 @@ static void did_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0)
-               fprintf(stderr, "Set Device ID failed "
-                                               "with status 0x%02x (%s)\n",
+               error("Set Device ID failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
        else
-               printf("Device ID successfully set\n");
+               print("Device ID successfully set");
 
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void did_usage(void)
 {
-       printf("Usage: btmgmt did <source>:<vendor>:<product>:<version>\n");
-       printf("       possible source values: bluetooth, usb\n");
+       print("Usage: did <source>:<vendor>:<product>:<version>");
+       print("       possible source values: bluetooth, usb");
 }
 
 static void cmd_did(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
@@ -2663,7 +2717,7 @@ static void cmd_did(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 
        if (argc < 2) {
                did_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        result = sscanf(argv[1], "bluetooth:%4hx:%4hx:%4hx", &vendor, &product,
@@ -2681,7 +2735,7 @@ static void cmd_did(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
        }
 
        did_usage();
-       exit(EXIT_FAILURE);
+       return noninteractive_quit(EXIT_FAILURE);
 
 done:
        if (index == MGMT_INDEX_NONE)
@@ -2694,8 +2748,8 @@ done:
 
        if (mgmt_send(mgmt, MGMT_OP_SET_DEVICE_ID, index, sizeof(cp), &cp,
                                                did_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send set_device_id cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send set_device_id cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -2703,18 +2757,17 @@ static void static_addr_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0)
-               fprintf(stderr, "Set static address failed "
-                                               "with status 0x%02x (%s)\n",
+               error("Set static address failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
        else
-               printf("Static address successfully set\n");
+               print("Static address successfully set");
 
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void static_addr_usage(void)
 {
-       printf("Usage: btmgmt static-addr <address>\n");
+       print("Usage: static-addr <address>");
 }
 
 static void cmd_static_addr(struct mgmt *mgmt, uint16_t index,
@@ -2724,7 +2777,7 @@ static void cmd_static_addr(struct mgmt *mgmt, uint16_t index,
 
        if (argc < 2) {
                static_addr_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
@@ -2734,8 +2787,8 @@ static void cmd_static_addr(struct mgmt *mgmt, uint16_t index,
 
        if (mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index, sizeof(cp), &cp,
                                        static_addr_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send set_static_address cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send set_static_address cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -2745,24 +2798,21 @@ static void options_rsp(uint16_t op, uint16_t id, uint8_t status,
        const uint32_t *rp = param;
 
        if (status != 0) {
-               fprintf(stderr,
-                       "%s for hci%u failed with status 0x%02x (%s)\n",
+               error("%s for hci%u failed with status 0x%02x (%s)",
                        mgmt_opstr(op), id, status, mgmt_errstr(status));
-               goto done;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (len < sizeof(*rp)) {
-               fprintf(stderr, "Too small %s response (%u bytes)\n",
+               error("Too small %s response (%u bytes)",
                                                        mgmt_opstr(op), len);
-               goto done;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
-       printf("hci%u %s complete, options: ", id, mgmt_opstr(op));
-       print_options(get_le32(rp));
-       printf("\n");
+       print("hci%u %s complete, options: %s", id, mgmt_opstr(op),
+                                               options2str(get_le32(rp)));
 
-done:
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_public_addr(struct mgmt *mgmt, uint16_t index,
@@ -2771,8 +2821,8 @@ static void cmd_public_addr(struct mgmt *mgmt, uint16_t index,
        struct mgmt_cp_set_public_address cp;
 
        if (argc < 2) {
-               printf("Usage: btmgmt public-addr <address>\n");
-               exit(EXIT_FAILURE);
+               print("Usage: public-addr <address>");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
@@ -2782,8 +2832,8 @@ static void cmd_public_addr(struct mgmt *mgmt, uint16_t index,
 
        if (send_cmd(mgmt, MGMT_OP_SET_PUBLIC_ADDRESS, index, sizeof(cp), &cp,
                                                        options_rsp) == 0) {
-               fprintf(stderr, "Unable to send Set Public Address cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send Set Public Address cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -2793,8 +2843,8 @@ static void cmd_ext_config(struct mgmt *mgmt, uint16_t index,
        struct mgmt_cp_set_external_config cp;
 
        if (argc < 2) {
-               printf("Specify \"on\" or \"off\"\n");
-               exit(EXIT_FAILURE);
+               print("Specify \"on\" or \"off\"");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
@@ -2809,8 +2859,8 @@ static void cmd_ext_config(struct mgmt *mgmt, uint16_t index,
 
        if (send_cmd(mgmt, MGMT_OP_SET_EXTERNAL_CONFIG, index, sizeof(cp), &cp,
                                                        options_rsp) == 0) {
-               fprintf(stderr, "Unable to send Set External Config cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send Set External Config cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -2826,37 +2876,35 @@ static void conn_info_rsp(uint8_t status, uint16_t len, const void *param,
        const struct mgmt_rp_get_conn_info *rp = param; char addr[18];
 
        if (len == 0 && status != 0) {
-               fprintf(stderr, "Get Conn Info failed, status 0x%02x (%s)\n",
+               error("Get Conn Info failed, status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-               goto done;
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (len < sizeof(*rp)) {
-               fprintf(stderr, "Unexpected Get Conn Info len %u\n", len);
-               goto done;
+               error("Unexpected Get Conn Info len %u", len);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        ba2str(&rp->addr.bdaddr, addr);
 
-       if (status != 0) {
-               fprintf(stderr, "Get Conn Info for %s (%s) failed. status 0x%02x (%s)\n",
+       if (status) {
+               error("Get Conn Info for %s (%s) failed. status 0x%02x (%s)",
                                                addr, typestr(rp->addr.type),
                                                status, mgmt_errstr(status));
-               goto done;
-       }
-
-       printf("Connection Information for %s (%s)\n",
+       } else {
+               print("Connection Information for %s (%s)",
                                                addr, typestr(rp->addr.type));
-       printf("\tRSSI %d\n\tTX power %d\n\tmaximum TX power %d\n",
+               print("\tRSSI %d\tTX power %d\tmaximum TX power %d",
                                rp->rssi, rp->tx_power, rp->max_tx_power);
+       }
 
-done:
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void conn_info_usage(void)
 {
-       printf("Usage: btmgmt conn-info [-t type] <remote address>\n");
+       print("Usage: conn-info [-t type] <remote address>");
 }
 
 static struct option conn_info_options[] = {
@@ -2879,9 +2927,11 @@ static void cmd_conn_info(struct mgmt *mgmt, uint16_t index,
                        type = strtol(optarg, NULL, 0);
                        break;
                case 'h':
+                       conn_info_usage();
+                       return noninteractive_quit(EXIT_SUCCESS);
                default:
                        conn_info_usage();
-                       exit(EXIT_SUCCESS);
+                       return noninteractive_quit(EXIT_FAILURE);
                }
        }
 
@@ -2891,7 +2941,7 @@ static void cmd_conn_info(struct mgmt *mgmt, uint16_t index,
 
        if (argc < 1) {
                conn_info_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
@@ -2903,8 +2953,8 @@ static void cmd_conn_info(struct mgmt *mgmt, uint16_t index,
 
        if (mgmt_send(mgmt, MGMT_OP_GET_CONN_INFO, index, sizeof(cp), &cp,
                                        conn_info_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send get_conn_info cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send get_conn_info cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -2912,18 +2962,17 @@ static void io_cap_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0)
-               fprintf(stderr, "Could not set IO Capability with "
-                                               "status 0x%02x (%s)\n",
+               error("Could not set IO Capability with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
        else
-               printf("IO Capabilities successfully set\n");
+               print("IO Capabilities successfully set");
 
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void io_cap_usage(void)
 {
-       printf("Usage: btmgmt io-cap <cap>\n");
+       print("Usage: io-cap <cap>");
 }
 
 static void cmd_io_cap(struct mgmt *mgmt, uint16_t index,
@@ -2934,7 +2983,7 @@ static void cmd_io_cap(struct mgmt *mgmt, uint16_t index,
 
        if (argc < 2) {
                io_cap_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
@@ -2946,8 +2995,8 @@ static void cmd_io_cap(struct mgmt *mgmt, uint16_t index,
 
        if (mgmt_send(mgmt, MGMT_OP_SET_IO_CAPABILITY, index, sizeof(cp), &cp,
                                        io_cap_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send set-io-cap cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send set-io-cap cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -2955,17 +3004,17 @@ static void scan_params_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0)
-               fprintf(stderr, "Set scan parameters failed with status 0x%02x (%s)\n",
+               error("Set scan parameters failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
        else
-               printf("Scan parameters successfully set\n");
+               print("Scan parameters successfully set");
 
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void scan_params_usage(void)
 {
-       printf("Usage: btmgmt scan-params <interval> <window>\n");
+       print("Usage: scan-params <interval> <window>");
 }
 
 static void cmd_scan_params(struct mgmt *mgmt, uint16_t index,
@@ -2975,7 +3024,7 @@ static void cmd_scan_params(struct mgmt *mgmt, uint16_t index,
 
        if (argc < 3) {
                scan_params_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
@@ -2986,8 +3035,8 @@ static void cmd_scan_params(struct mgmt *mgmt, uint16_t index,
 
        if (mgmt_send(mgmt, MGMT_OP_SET_SCAN_PARAMS, index, sizeof(cp), &cp,
                                        scan_params_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send set_scan_params cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send set_scan_params cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -2997,21 +3046,21 @@ static void clock_info_rsp(uint8_t status, uint16_t len, const void *param,
        const struct mgmt_rp_get_clock_info *rp = param;
 
        if (len < sizeof(*rp)) {
-               fprintf(stderr, "Unexpected Get Clock Info len %u\n", len);
-               exit(EXIT_FAILURE);
+               error("Unexpected Get Clock Info len %u", len);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (status) {
-               fprintf(stderr, "Get Clock Info failed with status 0x%02x (%s)\n",
+               error("Get Clock Info failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
-       printf("Local Clock:   %u\n", le32_to_cpu(rp->local_clock));
-       printf("Piconet Clock: %u\n", le32_to_cpu(rp->piconet_clock));
-       printf("Accurary:      %u\n", le16_to_cpu(rp->accuracy));
+       print("Local Clock:   %u", le32_to_cpu(rp->local_clock));
+       print("Piconet Clock: %u", le32_to_cpu(rp->piconet_clock));
+       print("Accurary:      %u", le16_to_cpu(rp->accuracy));
 
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_clock_info(struct mgmt *mgmt, uint16_t index,
@@ -3029,8 +3078,8 @@ static void cmd_clock_info(struct mgmt *mgmt, uint16_t index,
 
        if (mgmt_send(mgmt, MGMT_OP_GET_CLOCK_INFO, index, sizeof(cp), &cp,
                                        clock_info_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send get_clock_info cmd\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send get_clock_info cmd");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -3038,14 +3087,14 @@ static void add_device_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0)
-               fprintf(stderr, "Add device failed with status 0x%02x (%s)\n",
+               error("Add device failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void add_device_usage(void)
 {
-       printf("Usage: btmgmt add-device [-a action] [-t type] <address>\n");
+       print("Usage: add-device [-a action] [-t type] <address>");
 }
 
 static struct option add_device_options[] = {
@@ -3074,9 +3123,11 @@ static void cmd_add_device(struct mgmt *mgmt, uint16_t index,
                        type = strtol(optarg, NULL, 0);
                        break;
                case 'h':
+                       add_device_usage();
+                       return noninteractive_quit(EXIT_SUCCESS);
                default:
                        add_device_usage();
-                       exit(EXIT_SUCCESS);
+                       return noninteractive_quit(EXIT_FAILURE);
                }
        }
 
@@ -3086,7 +3137,7 @@ static void cmd_add_device(struct mgmt *mgmt, uint16_t index,
 
        if (argc < 1) {
                add_device_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
@@ -3098,12 +3149,12 @@ static void cmd_add_device(struct mgmt *mgmt, uint16_t index,
        cp.action = action;
 
        ba2str(&cp.addr.bdaddr, addr);
-       printf("Adding device with %s (%s)\n", addr, typestr(cp.addr.type));
+       print("Adding device with %s (%s)", addr, typestr(cp.addr.type));
 
        if (mgmt_send(mgmt, MGMT_OP_ADD_DEVICE, index, sizeof(cp), &cp,
                                        add_device_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send add device command\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send add device command");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -3111,14 +3162,14 @@ static void remove_device_rsp(uint8_t status, uint16_t len, const void *param,
                                                        void *user_data)
 {
        if (status != 0)
-               fprintf(stderr, "Remove device failed with status 0x%02x (%s)\n",
+               error("Remove device failed with status 0x%02x (%s)",
                                                status, mgmt_errstr(status));
-       mainloop_quit();
+       noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void del_device_usage(void)
 {
-       printf("Usage: btmgmt del-device [-t type] <address>\n");
+       print("Usage: del-device [-t type] <address>");
 }
 
 static struct option del_device_options[] = {
@@ -3142,9 +3193,11 @@ static void cmd_del_device(struct mgmt *mgmt, uint16_t index,
                        type = strtol(optarg, NULL, 0);
                        break;
                case 'h':
+                       del_device_usage();
+                       return noninteractive_quit(EXIT_SUCCESS);
                default:
                        del_device_usage();
-                       exit(EXIT_SUCCESS);
+                       return noninteractive_quit(EXIT_FAILURE);
                }
        }
 
@@ -3154,7 +3207,7 @@ static void cmd_del_device(struct mgmt *mgmt, uint16_t index,
 
        if (argc < 1) {
                del_device_usage();
-               exit(EXIT_FAILURE);
+               return noninteractive_quit(EXIT_FAILURE);
        }
 
        if (index == MGMT_INDEX_NONE)
@@ -3165,12 +3218,12 @@ static void cmd_del_device(struct mgmt *mgmt, uint16_t index,
        cp.addr.type = type;
 
        ba2str(&cp.addr.bdaddr, addr);
-       printf("Removing device with %s (%s)\n", addr, typestr(cp.addr.type));
+       print("Removing device with %s (%s)", addr, typestr(cp.addr.type));
 
        if (mgmt_send(mgmt, MGMT_OP_REMOVE_DEVICE, index, sizeof(cp), &cp,
                                        remove_device_rsp, NULL, NULL) == 0) {
-               fprintf(stderr, "Unable to send remove device command\n");
-               exit(EXIT_FAILURE);
+               error("Unable to send remove device command");
+               return noninteractive_quit(EXIT_FAILURE);
        }
 }
 
@@ -3183,12 +3236,15 @@ static void cmd_clr_devices(struct mgmt *mgmt, uint16_t index,
        cmd_del_device(mgmt, index, 2, rm_argv);
 }
 
-static struct {
+struct cmd_info {
        char *cmd;
        void (*func)(struct mgmt *mgmt, uint16_t index, int argc, char **argv);
        char *doc;
-} command[] = {
-       { "monitor",    cmd_monitor,    "Monitor events"                },
+       char * (*gen) (const char *text, int state);
+       void (*disp) (char **matches, int num_matches, int max_length);
+};
+
+static struct cmd_info all_cmd[] = {
        { "version",    cmd_version,    "Get the MGMT Version"          },
        { "commands",   cmd_commands,   "List supported commands"       },
        { "config",     cmd_config,     "Show configuration info"       },
@@ -3238,16 +3294,237 @@ static struct {
        { "add-device", cmd_add_device, "Add Device"                    },
        { "del-device", cmd_del_device, "Remove Device"                 },
        { "clr-devices",cmd_clr_devices,"Clear Devices"                 },
-       { }
 };
 
-static void gap_ready(bool status, void *user_data)
+static void cmd_quit(struct mgmt *mgmt, uint16_t index,
+                                               int argc, char **argv)
+{
+       mainloop_exit_success();
+}
+
+static void register_mgmt_callbacks(struct mgmt *mgmt, uint16_t index)
+{
+       mgmt_register(mgmt, MGMT_EV_CONTROLLER_ERROR, index, controller_error,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index, index_added,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_INDEX_REMOVED, index, index_removed,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_NEW_SETTINGS, index, new_settings,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_DISCOVERING, index, discovering,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_NEW_LINK_KEY, index, new_link_key,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_DEVICE_CONNECTED, index, connected,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_DEVICE_DISCONNECTED, index, disconnected,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_CONNECT_FAILED, index, conn_failed,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_AUTH_FAILED, index, auth_failed,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_LOCAL_NAME_CHANGED, index,
+                                       local_name_changed, NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_DEVICE_FOUND, index, device_found,
+                                                               mgmt, NULL);
+       mgmt_register(mgmt, MGMT_EV_PIN_CODE_REQUEST, index, request_pin,
+                                                               mgmt, NULL);
+       mgmt_register(mgmt, MGMT_EV_USER_CONFIRM_REQUEST, index, user_confirm,
+                                                               mgmt, NULL);
+       mgmt_register(mgmt, MGMT_EV_USER_PASSKEY_REQUEST, index,
+                                               request_passkey, mgmt, NULL);
+       mgmt_register(mgmt, MGMT_EV_PASSKEY_NOTIFY, index,
+                                               passkey_notify, mgmt, NULL);
+       mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_ADDED, index,
+                                       unconf_index_added, NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_REMOVED, index,
+                                       unconf_index_removed, NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_NEW_CONFIG_OPTIONS, index,
+                                       new_config_options, NULL, NULL);
+
+}
+
+static void cmd_select(struct mgmt *mgmt, uint16_t index,
+                                               int argc, char **argv)
+{
+       if (argc != 2) {
+               error("Usage: select <index>");
+               return;
+       }
+
+       mgmt_cancel_all(mgmt);
+       mgmt_unregister_all(mgmt);
+
+       if (!strcmp(argv[1], "none") || !strcmp(argv[1], "any") ||
+                                               !strcmp(argv[1], "all"))
+               mgmt_index = MGMT_INDEX_NONE;
+       else if (!strncmp(argv[1], "hci", 3))
+               mgmt_index = atoi(&argv[1][3]);
+       else
+               mgmt_index = atoi(argv[1]);
+
+       register_mgmt_callbacks(mgmt, mgmt_index);
+
+       print("Selected index %u", mgmt_index);
+
+       update_prompt(mgmt_index);
+}
+
+static struct cmd_info interactive_cmd[] = {
+       { "select",     cmd_select,     "Select a different index"      },
+       { "quit",       cmd_quit,       "Exit program"                  },
+       { "exit",       cmd_quit,       "Exit program"                  },
+       { "help",       NULL,           "List supported commands"       },
+};
+
+static char *cmd_generator(const char *text, int state)
+{
+       static size_t i, j, len;
+       const char *cmd;
+
+       if (!state) {
+               i = 0;
+               j = 0;
+               len = strlen(text);
+       }
+
+       while (i < NELEM(all_cmd)) {
+               cmd = all_cmd[i++].cmd;
+
+               if (!strncmp(cmd, text, len))
+                       return strdup(cmd);
+       }
+
+       while (j < NELEM(interactive_cmd)) {
+               cmd = interactive_cmd[j++].cmd;
+
+               if (!strncmp(cmd, text, len))
+                       return strdup(cmd);
+       }
+
+       return NULL;
+}
+
+static char **cmd_completion(const char *text, int start, int end)
+{
+       char **matches = NULL;
+
+       if (start > 0) {
+               unsigned int i;
+
+               for (i = 0; i < NELEM(all_cmd); i++) {
+                       struct cmd_info *c = &all_cmd[i];
+
+                       if (strncmp(c->cmd, rl_line_buffer, start - 1))
+                               continue;
+
+                       if (!c->gen)
+                               continue;
+
+                       rl_completion_display_matches_hook = c->disp;
+                       matches = rl_completion_matches(text, c->gen);
+                       break;
+               }
+       } else {
+               rl_completion_display_matches_hook = NULL;
+               matches = rl_completion_matches(text, cmd_generator);
+       }
+
+       if (!matches)
+               rl_attempted_completion_over = 1;
+
+       return matches;
+}
+
+static struct cmd_info *find_cmd(const char *cmd, struct cmd_info table[],
+                                                       size_t cmd_count)
+{
+       size_t i;
+
+       for (i = 0; i < cmd_count; i++) {
+               if (!strcmp(table[i].cmd, cmd))
+                       return &table[i];
+       }
+
+       return NULL;
+}
+
+static void rl_handler(char *input)
 {
+       struct cmd_info *c;
+       wordexp_t w;
+       char *cmd, **argv;
+       size_t argc, i;
+
+       if (!input) {
+               rl_insert_text("quit");
+               rl_redisplay();
+               rl_crlf();
+               mainloop_quit();
+               return;
+       }
+
+       if (!strlen(input))
+               goto done;
+
+       if (prompt_input(input))
+               goto done;
+
+       add_history(input);
+
+       if (wordexp(input, &w, WRDE_NOCMD))
+               goto done;
+
+       if (w.we_wordc == 0)
+               goto free_we;
+
+       cmd = w.we_wordv[0];
+       argv = w.we_wordv;
+       argc = w.we_wordc;
+
+       c = find_cmd(cmd, all_cmd, NELEM(all_cmd));
+       if (!c && interactive)
+               c = find_cmd(cmd, interactive_cmd, NELEM(interactive_cmd));
+
+       if (c && c->func) {
+               c->func(mgmt, mgmt_index, argc, argv);
+               goto free_we;
+       }
+
+       if (strcmp(cmd, "help")) {
+               print("Invalid command");
+               goto free_we;
+       }
+
+       print("Available commands:");
+
+       for (i = 0; i < NELEM(all_cmd); i++) {
+               c = &all_cmd[i];
+               if (c->doc)
+                       print("  %s %-*s %s", c->cmd,
+                               (int)(25 - strlen(c->cmd)), "", c->doc ? : "");
+       }
+
+       if (!interactive)
+               goto free_we;
+
+       for (i = 0; i < NELEM(interactive_cmd); i++) {
+               c = &interactive_cmd[i];
+               if (c->doc)
+                       print("  %s %-*s %s", c->cmd,
+                               (int)(25 - strlen(c->cmd)), "", c->doc ? : "");
+       }
+
+free_we:
+       wordfree(&w);
+done:
+       free(input);
 }
 
 static void usage(void)
 {
-       int i;
+       unsigned int i;
 
        printf("btmgmt ver %s\n", VERSION);
        printf("Usage:\n"
@@ -3259,8 +3536,8 @@ static void usage(void)
                "\t--help\tDisplay help\n");
 
        printf("Commands:\n");
-       for (i = 0; command[i].cmd; i++)
-               printf("\t%-15s\t%s\n", command[i].cmd, command[i].doc);
+       for (i = 0; i < NELEM(all_cmd); i++)
+               printf("\t%-15s\t%s\n", all_cmd[i].cmd, all_cmd[i].doc);
 
        printf("\n"
                "For more information on the usage of each command use:\n"
@@ -3274,15 +3551,32 @@ static struct option main_options[] = {
        { 0, 0, 0, 0 }
 };
 
+static bool prompt_read(struct io *io, void *user_data)
+{
+       rl_callback_read_char();
+       return true;
+}
+
+static struct io *setup_stdin(void)
+{
+       struct io *io;
+
+       io = io_new(STDIN_FILENO);
+       if (!io)
+               return io;
+
+       io_set_read_handler(io, prompt_read, NULL, NULL);
+
+       return io;
+}
+
 int main(int argc, char *argv[])
 {
-       struct bt_gap *gap;
-       int opt, i;
+       struct io *input;
        uint16_t index = MGMT_INDEX_NONE;
-       struct mgmt *mgmt;
-       int exit_status;
+       int status, opt;
 
-       while ((opt = getopt_long(argc, argv, "+hvi:",
+       while ((opt = getopt_long(argc, argv, "+hi:",
                                                main_options, NULL)) != -1) {
                switch (opt) {
                case 'i':
@@ -3292,9 +3586,6 @@ int main(int argc, char *argv[])
                        else
                                index = atoi(optarg);
                        break;
-               case 'v':
-                       monitor = true;
-                       break;
                case 'h':
                default:
                        usage();
@@ -3306,86 +3597,61 @@ int main(int argc, char *argv[])
        argv += optind;
        optind = 0;
 
-       if (argc < 1) {
-               usage();
-               return 0;
-       }
-
        mainloop_init();
 
-       if (index == MGMT_INDEX_NONE)
-               gap = bt_gap_new_default();
-       else
-               gap = bt_gap_new_index(index);
-
-       bt_gap_set_ready_handler(gap, gap_ready, NULL, NULL);
-
        mgmt = mgmt_new_default();
        if (!mgmt) {
                fprintf(stderr, "Unable to open mgmt_socket\n");
                return EXIT_FAILURE;
        }
 
-       for (i = 0; command[i].cmd; i++) {
-               if (strcmp(command[i].cmd, argv[0]) != 0)
-                       continue;
+       if (argc > 0) {
+               struct cmd_info *c;
+
+               c = find_cmd(argv[0], all_cmd, NELEM(all_cmd));
+               if (!c) {
+                       fprintf(stderr, "Unknown command: %s\n", argv[0]);
+                       mgmt_unref(mgmt);
+                       return EXIT_FAILURE;
+               }
 
-               command[i].func(mgmt, index, argc, argv);
-               break;
+               c->func(mgmt, index, argc, argv);
        }
 
-       if (command[i].cmd == NULL) {
-               fprintf(stderr, "Unknown command: %s\n", argv[0]);
-               mgmt_unref(mgmt);
-               return EXIT_FAILURE;
+       register_mgmt_callbacks(mgmt, index);
+
+       /* Interactive mode */
+       if (!argc)
+               input = setup_stdin();
+       else
+               input = NULL;
+
+       if (input) {
+               interactive = true;
+
+               rl_attempted_completion_function = cmd_completion;
+
+               rl_erase_empty_line = 1;
+               rl_callback_handler_install(NULL, rl_handler);
+
+               update_prompt(index);
+               rl_redisplay();
        }
 
-       mgmt_register(mgmt, MGMT_EV_CONTROLLER_ERROR, index, controller_error,
-                                                               NULL, NULL);
-       mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index, index_added,
-                                                               NULL, NULL);
-       mgmt_register(mgmt, MGMT_EV_INDEX_REMOVED, index, index_removed,
-                                                               NULL, NULL);
-       mgmt_register(mgmt, MGMT_EV_NEW_SETTINGS, index, new_settings,
-                                                               NULL, NULL);
-       mgmt_register(mgmt, MGMT_EV_DISCOVERING, index, discovering,
-                                                               NULL, NULL);
-       mgmt_register(mgmt, MGMT_EV_NEW_LINK_KEY, index, new_link_key,
-                                                               NULL, NULL);
-       mgmt_register(mgmt, MGMT_EV_DEVICE_CONNECTED, index, connected,
-                                                               NULL, NULL);
-       mgmt_register(mgmt, MGMT_EV_DEVICE_DISCONNECTED, index, disconnected,
-                                                               NULL, NULL);
-       mgmt_register(mgmt, MGMT_EV_CONNECT_FAILED, index, conn_failed,
-                                                               NULL, NULL);
-       mgmt_register(mgmt, MGMT_EV_AUTH_FAILED, index, auth_failed,
-                                                               NULL, NULL);
-       mgmt_register(mgmt, MGMT_EV_LOCAL_NAME_CHANGED, index,
-                                       local_name_changed, NULL, NULL);
-       mgmt_register(mgmt, MGMT_EV_DEVICE_FOUND, index, device_found,
-                                                               mgmt, NULL);
-       mgmt_register(mgmt, MGMT_EV_PIN_CODE_REQUEST, index, request_pin,
-                                                               mgmt, NULL);
-       mgmt_register(mgmt, MGMT_EV_USER_CONFIRM_REQUEST, index, user_confirm,
-                                                               mgmt, NULL);
-       mgmt_register(mgmt, MGMT_EV_USER_PASSKEY_REQUEST, index,
-                                               request_passkey, mgmt, NULL);
-       mgmt_register(mgmt, MGMT_EV_PASSKEY_NOTIFY, index,
-                                               passkey_notify, mgmt, NULL);
-       mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_ADDED, index,
-                                       unconf_index_added, NULL, NULL);
-       mgmt_register(mgmt, MGMT_EV_UNCONF_INDEX_REMOVED, index,
-                                       unconf_index_removed, NULL, NULL);
-       mgmt_register(mgmt, MGMT_EV_NEW_CONFIG_OPTIONS, index,
-                                       new_config_options, NULL, NULL);
+       mgmt_index = index;
 
-       exit_status = mainloop_run();
+       status = mainloop_run();
+
+       if (input) {
+               io_destroy(input);
+
+               rl_message("");
+               rl_callback_handler_remove();
+       }
 
        mgmt_cancel_all(mgmt);
        mgmt_unregister_all(mgmt);
        mgmt_unref(mgmt);
 
-       bt_gap_unref(gap);
-
-       return exit_status;
+       return status;
 }
index 3503148..43ccac1 100644 (file)
 #include <arpa/inet.h>
 
 #include "src/shared/util.h"
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
 #include "monitor/bt.h"
 
+#define HCI_BREDR      0x00
+#define HCI_AMP                0x01
+
 #define BTPROTO_HCI    1
 struct sockaddr_hci {
        sa_family_t     hci_family;
@@ -563,6 +566,7 @@ static void usage(void)
                "\t-u, --unix [path]           Use Unix server\n"
                "\t-p, --port <port>           Use specified TCP port\n"
                "\t-i, --index <num>           Use specified controller\n"
+               "\t-a, --amp                   Create AMP controller\n"
                "\t-d, --debug                 Enable debugging output\n"
                "\t-h, --help                  Show help options\n");
 }
@@ -573,6 +577,7 @@ static const struct option main_options[] = {
        { "unix",    optional_argument, NULL, 'u' },
        { "port",    required_argument, NULL, 'p' },
        { "index",   required_argument, NULL, 'i' },
+       { "amp",     no_argument,       NULL, 'a' },
        { "debug",   no_argument,       NULL, 'd' },
        { "version", no_argument,       NULL, 'v' },
        { "help",    no_argument,       NULL, 'h' },
@@ -585,18 +590,22 @@ int main(int argc, char *argv[])
        const char *server_address = NULL;
        const char *unix_path = NULL;
        unsigned short tcp_port = 0xb1ee;       /* 45550 */
+       uint8_t type = HCI_BREDR;
        const char *str;
        sigset_t mask;
 
        for (;;) {
                int opt;
 
-               opt = getopt_long(argc, argv, "c:l::u::p:i:dvh",
+               opt = getopt_long(argc, argv, "ac:l::u::p:i:dvh",
                                                main_options, NULL);
                if (opt < 0)
                        break;
 
                switch (opt) {
+               case 'a':
+                       type = HCI_AMP;
+                       break;
                case 'c':
                        connect_address = optarg;
                        break;
@@ -674,7 +683,7 @@ int main(int argc, char *argv[])
 
                printf("Opening virtual device\n");
 
-               host_fd = open_vhci(0x00);
+               host_fd = open_vhci(type);
                if (host_fd < 0) {
                        close(dev_fd);
                        return EXIT_FAILURE;
index 71191eb..3eb8082 100644 (file)
@@ -230,7 +230,7 @@ next_packet:
                if (flags & 0x01)
                        opcode = BTSNOOP_OPCODE_SCO_RX_PKT;
                else
-                       opcode = BTSNOOP_OPCODE_ACL_TX_PKT;
+                       opcode = BTSNOOP_OPCODE_SCO_TX_PKT;
                break;
        case 0x04:
                opcode = BTSNOOP_OPCODE_EVENT_PKT;
index 3ff9fb1..e60493d 100644 (file)
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-#include <bluetooth/cmtp.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/l2cap.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+#include "lib/cmtp.h"
 
 static volatile sig_atomic_t __io_canceled = 0;
 
index 0231805..95fa7b6 100644 (file)
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/l2cap.h"
 
-#include "monitor/mainloop.h"
+#include "src/shared/mainloop.h"
 
 static bool send_message(const bdaddr_t *src, const bdaddr_t *dst,
                                                        uint16_t psm)
index 36af921..2c09189 100644 (file)
@@ -35,9 +35,9 @@
 #include <sys/mman.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 #include "csr.h"
 
index 6bd37c3..d2e4ab9 100644 (file)
@@ -30,9 +30,9 @@
 #include <string.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 #include "csr.h"
 
index 2a0be91..2aa4042 100644 (file)
@@ -25,7 +25,7 @@
 #include <config.h>
 #endif
 
-#include <gdbus.h>
+#include "gdbus/gdbus.h"
 
 #include "src/shared/tester.h"
 #include "emulator/hciemu.h"
diff --git a/tools/gatt-example b/tools/gatt-example
new file mode 100644 (file)
index 0000000..a6f5cbe
--- /dev/null
@@ -0,0 +1,533 @@
+#!/usr/bin/python
+
+import dbus
+import dbus.exceptions
+import dbus.mainloop.glib
+import dbus.service
+
+import array
+import gobject
+
+from random import randint
+
+mainloop = None
+
+BLUEZ_SERVICE_NAME = 'org.bluez'
+GATT_MANAGER_IFACE = 'org.bluez.GattManager1'
+DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
+DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'
+
+GATT_SERVICE_IFACE = 'org.bluez.GattService1'
+GATT_CHRC_IFACE = 'org.bluez.GattCharacteristic1'
+GATT_DESC_IFACE = 'org.bluez.GattDescriptor1'
+
+class InvalidArgsException(dbus.exceptions.DBusException):
+    _dbus_error_name = 'org.freedesktop.DBus.Error.InvalidArgs'
+
+class NotSupportedException(dbus.exceptions.DBusException):
+    _dbus_error_name = 'org.bluez.Error.NotSupported'
+
+class NotPermittedException(dbus.exceptions.DBusException):
+    _dbus_error_name = 'org.bluez.Error.NotPermitted'
+
+class InvalidValueLengthException(dbus.exceptions.DBusException):
+    _dbus_error_name = 'org.bluez.Error.InvalidValueLength'
+
+class FailedException(dbus.exceptions.DBusException):
+    _dbus_error_name = 'org.bluez.Error.Failed'
+
+
+class Service(dbus.service.Object):
+    PATH_BASE = '/org/bluez/example/service'
+
+    def __init__(self, bus, index, uuid, primary):
+        self.path = self.PATH_BASE + str(index)
+        self.bus = bus
+        self.uuid = uuid
+        self.primary = primary
+        self.characteristics = []
+        dbus.service.Object.__init__(self, bus, self.path)
+
+    def get_properties(self):
+        return {
+                GATT_SERVICE_IFACE: {
+                        'UUID': self.uuid,
+                        'Primary': self.primary,
+                        'Characteristics': dbus.Array(
+                                self.get_characteristic_paths(),
+                                signature='o')
+                }
+        }
+
+    def get_path(self):
+        return dbus.ObjectPath(self.path)
+
+    def add_characteristic(self, characteristic):
+        self.characteristics.append(characteristic)
+
+    def get_characteristic_paths(self):
+        result = []
+        for chrc in self.characteristics:
+            result.append(chrc.get_path())
+        return result
+
+    def get_characteristics(self):
+        return self.characteristics
+
+    @dbus.service.method(DBUS_PROP_IFACE,
+                         in_signature='s',
+                         out_signature='a{sv}')
+    def GetAll(self, interface):
+        if interface != GATT_SERVICE_IFACE:
+            raise InvalidArgsException()
+
+        return self.get_properties[GATT_SERVICE_IFACE]
+
+    @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}')
+    def GetManagedObjects(self):
+        response = {}
+        print 'GetManagedObjects'
+
+        response[self.get_path()] = self.get_properties()
+        chrcs = self.get_characteristics()
+        for chrc in chrcs:
+            response[chrc.get_path()] = chrc.get_properties()
+            descs = chrc.get_descriptors()
+            for desc in descs:
+                response[desc.get_path()] = desc.get_properties()
+
+        return response
+
+
+class Characteristic(dbus.service.Object):
+    def __init__(self, bus, index, uuid, flags, service):
+        self.path = service.path + '/char' + str(index)
+        self.bus = bus
+        self.uuid = uuid
+        self.service = service
+        self.flags = flags
+        self.descriptors = []
+        dbus.service.Object.__init__(self, bus, self.path)
+
+    def get_properties(self):
+        return {
+                GATT_CHRC_IFACE: {
+                        'Service': self.service.get_path(),
+                        'UUID': self.uuid,
+                        'Flags': self.flags,
+                        'Descriptors': dbus.Array(
+                                self.get_descriptor_paths(),
+                                signature='o')
+                }
+        }
+
+    def get_path(self):
+        return dbus.ObjectPath(self.path)
+
+    def add_descriptor(self, descriptor):
+        self.descriptors.append(descriptor)
+
+    def get_descriptor_paths(self):
+        result = []
+        for desc in self.descriptors:
+            result.append(desc.get_path())
+        return result
+
+    def get_descriptors(self):
+        return self.descriptors
+
+    @dbus.service.method(DBUS_PROP_IFACE,
+                         in_signature='s',
+                         out_signature='a{sv}')
+    def GetAll(self, interface):
+        if interface != GATT_CHRC_IFACE:
+            raise InvalidArgsException()
+
+        return self.get_properties[GATT_CHRC_IFACE]
+
+    @dbus.service.method(GATT_CHRC_IFACE, out_signature='ay')
+    def ReadValue(self):
+        print 'Default ReadValue called, returning error'
+        raise NotSupportedException()
+
+    @dbus.service.method(GATT_CHRC_IFACE, in_signature='ay')
+    def WriteValue(self, value):
+        print 'Default WriteValue called, returning error'
+        raise NotSupportedException()
+
+    @dbus.service.method(GATT_CHRC_IFACE)
+    def StartNotify(self):
+        print 'Default StartNotify called, returning error'
+        raise NotSupportedException()
+
+    @dbus.service.method(GATT_CHRC_IFACE)
+    def StopNotify(self):
+        print 'Default StopNotify called, returning error'
+        raise NotSupportedException()
+
+    @dbus.service.signal(DBUS_PROP_IFACE,
+                         signature='sa{sv}as')
+    def PropertiesChanged(self, interface, changed, invalidated):
+        pass
+
+
+class Descriptor(dbus.service.Object):
+    def __init__(self, bus, index, uuid, characteristic):
+        self.path = characteristic.path + '/desc' + str(index)
+        self.bus = bus
+        self.uuid = uuid
+        self.chrc = characteristic
+        dbus.service.Object.__init__(self, bus, self.path)
+
+    def get_properties(self):
+        return {
+                GATT_DESC_IFACE: {
+                        'Characteristic': self.chrc.get_path(),
+                        'UUID': self.uuid,
+                }
+        }
+
+    def get_path(self):
+        return dbus.ObjectPath(self.path)
+
+    @dbus.service.method(DBUS_PROP_IFACE,
+                         in_signature='s',
+                         out_signature='a{sv}')
+    def GetAll(self, interface):
+        if interface != GATT_DESC_IFACE:
+            raise InvalidArgsException()
+
+        return self.get_properties[GATT_CHRC_IFACE]
+
+    @dbus.service.method(GATT_DESC_IFACE, out_signature='ay')
+    def ReadValue(self):
+        print 'Default ReadValue called, returning error'
+        raise NotSupportedException()
+
+    @dbus.service.method(GATT_DESC_IFACE, in_signature='ay')
+    def WriteValue(self, value):
+        print 'Default WriteValue called, returning error'
+        raise NotSupportedException()
+
+
+class HeartRateService(Service):
+    """
+    Fake Heart Rate Service that simulates a fake heart beat and control point
+    behavior.
+
+    """
+    HR_UUID = '0000180d-0000-1000-8000-00805f9b34fb'
+
+    def __init__(self, bus, index):
+        Service.__init__(self, bus, index, self.HR_UUID, True)
+        self.add_characteristic(HeartRateMeasurementChrc(bus, 0, self))
+        self.add_characteristic(BodySensorLocationChrc(bus, 1, self))
+        self.add_characteristic(HeartRateControlPointChrc(bus, 2, self))
+        self.energy_expended = 0
+
+
+class HeartRateMeasurementChrc(Characteristic):
+    HR_MSRMT_UUID = '00002a37-0000-1000-8000-00805f9b34fb'
+
+    def __init__(self, bus, index, service):
+        Characteristic.__init__(
+                self, bus, index,
+                self.HR_MSRMT_UUID,
+                ['notify'],
+                service)
+        self.notifying = False
+        self.hr_ee_count = 0
+
+    def hr_msrmt_cb(self):
+        value = []
+        value.append(dbus.Byte(0x06))
+
+        value.append(dbus.Byte(randint(90, 130)))
+
+        if self.hr_ee_count % 10 == 0:
+            value[0] = dbus.Byte(value[0] | 0x08)
+            value.append(dbus.Byte(self.service.energy_expended & 0xff))
+            value.append(dbus.Byte((self.service.energy_expended >> 8) & 0xff))
+
+        self.service.energy_expended = \
+                min(0xffff, self.service.energy_expended + 1)
+        self.hr_ee_count += 1
+
+        print 'Updating value: ' + repr(value)
+
+        self.PropertiesChanged(GATT_CHRC_IFACE, { 'Value': value }, [])
+
+        return self.notifying
+
+    def _update_hr_msrmt_simulation(self):
+        print 'Update HR Measurement Simulation'
+
+        if not self.notifying:
+            return
+
+        gobject.timeout_add(1000, self.hr_msrmt_cb)
+
+    def StartNotify(self):
+        if self.notifying:
+            print 'Already notifying, nothing to do'
+            return
+
+        self.notifying = True
+        self._update_hr_msrmt_simulation()
+
+    def StopNotify(self):
+        if not self.notifying:
+            print 'Not notifying, nothing to do'
+            return
+
+        self.notifying = False
+        self._update_hr_msrmt_simulation()
+
+
+class BodySensorLocationChrc(Characteristic):
+    BODY_SNSR_LOC_UUID = '00002a38-0000-1000-8000-00805f9b34fb'
+
+    def __init__(self, bus, index, service):
+        Characteristic.__init__(
+                self, bus, index,
+                self.BODY_SNSR_LOC_UUID,
+                ['read'],
+                service)
+
+    def ReadValue(self):
+        # Return 'Chest' as the sensor location.
+        return [ 0x01 ]
+
+class HeartRateControlPointChrc(Characteristic):
+    HR_CTRL_PT_UUID = '00002a39-0000-1000-8000-00805f9b34fb'
+
+    def __init__(self, bus, index, service):
+        Characteristic.__init__(
+                self, bus, index,
+                self.HR_CTRL_PT_UUID,
+                ['write'],
+                service)
+
+    def WriteValue(self, value):
+        print 'Heart Rate Control Point WriteValue called'
+
+        if len(value) != 1:
+            raise InvalidValueLengthException()
+
+        byte = value[0]
+        print 'Control Point value: ' + repr(byte)
+
+        if byte != 1:
+            raise FailedException("0x80")
+
+        print 'Energy Expended field reset!'
+        self.service.energy_expended = 0
+
+
+class BatteryService(Service):
+    """
+    Fake Battery service that emulates a draining battery.
+
+    """
+    BATTERY_UUID = '180f'
+
+    def __init__(self, bus, index):
+        Service.__init__(self, bus, index, self.BATTERY_UUID, True)
+        self.add_characteristic(BatteryLevelCharacteristic(bus, 0, self))
+
+
+class BatteryLevelCharacteristic(Characteristic):
+    """
+    Fake Battery Level characteristic. The battery level is drained by 2 points
+    every 5 seconds.
+
+    """
+    BATTERY_LVL_UUID = '2a19'
+
+    def __init__(self, bus, index, service):
+        Characteristic.__init__(
+                self, bus, index,
+                self.BATTERY_LVL_UUID,
+                ['read', 'notify'],
+                service)
+        self.notifying = False
+        self.battery_lvl = 100
+        gobject.timeout_add(5000, self.drain_battery)
+
+    def notify_battery_level(self):
+        if not self.notifying:
+            return
+        self.PropertiesChanged(
+                GATT_CHRC_IFACE,
+                { 'Value': [dbus.Byte(self.battery_lvl)] }, [])
+
+    def drain_battery(self):
+        if self.battery_lvl > 0:
+            self.battery_lvl -= 2
+            if self.battery_lvl < 0:
+                self.battery_lvl = 0
+        print 'Battery Level drained: ' + repr(self.battery_lvl)
+        self.notify_battery_level()
+        return True
+
+    def ReadValue(self):
+        print 'Battery Level read: ' + repr(self.battery_lvl)
+        return [dbus.Byte(self.battery_lvl)]
+
+    def StartNotify(self):
+        if self.notifying:
+            print 'Already notifying, nothing to do'
+            return
+
+        self.notifying = True
+        self.notify_battery_level()
+
+    def StopNotify(self):
+        if not self.notifying:
+            print 'Not notifying, nothing to do'
+            return
+
+        self.notifying = False
+
+
+class TestService(Service):
+    """
+    Dummy test service that provides characteristics and descriptors that
+    exercise various API functionality.
+
+    """
+    TEST_SVC_UUID = '12345678-1234-5678-1234-56789abcdef0'
+
+    def __init__(self, bus, index):
+        Service.__init__(self, bus, index, self.TEST_SVC_UUID, False)
+        self.add_characteristic(TestCharacteristic(bus, 0, self))
+
+
+class TestCharacteristic(Characteristic):
+    """
+    Dummy test characteristic. Allows writing arbitrary bytes to its value, and
+    contains "extended properties", as well as a test descriptor.
+
+    """
+    TEST_CHRC_UUID = '12345678-1234-5678-1234-56789abcdef1'
+
+    def __init__(self, bus, index, service):
+        Characteristic.__init__(
+                self, bus, index,
+                self.TEST_CHRC_UUID,
+                ['read', 'write', 'writable-auxiliaries'],
+                service)
+        self.value = []
+        self.add_descriptor(TestDescriptor(bus, 0, self))
+        self.add_descriptor(
+                CharacteristicUserDescriptionDescriptor(bus, 1, self))
+
+    def ReadValue(self):
+        print 'TestCharacteristic Read: ' + repr(self.value)
+        return self.value
+
+    def WriteValue(self, value):
+        print 'TestCharacteristic Write: ' + repr(value)
+        self.value = value
+
+
+class TestDescriptor(Descriptor):
+    """
+    Dummy test descriptor. Returns a static value.
+
+    """
+    TEST_DESC_UUID = '12345678-1234-5678-1234-56789abcdef2'
+
+    def __init__(self, bus, index, characteristic):
+        Descriptor.__init__(
+                self, bus, index,
+                self.TEST_DESC_UUID,
+                characteristic)
+
+    def ReadValue(self):
+        return [
+                dbus.Byte('T'), dbus.Byte('e'), dbus.Byte('s'), dbus.Byte('t')
+        ]
+
+
+class CharacteristicUserDescriptionDescriptor(Descriptor):
+    """
+    Writable CUD descriptor.
+
+    """
+    CUD_UUID = '2901'
+
+    def __init__(self, bus, index, characteristic):
+        self.writable = 'writable-auxiliaries' in characteristic.flags
+        self.value = array.array('B', 'This is a characteristic for testing')
+        self.value = self.value.tolist()
+        Descriptor.__init__(
+                self, bus, index,
+                self.CUD_UUID,
+                characteristic)
+
+    def ReadValue(self):
+        return self.value
+
+    def WriteValue(self, value):
+        if not self.writable:
+            raise NotPermittedException()
+        self.value = value
+
+
+def register_service_cb():
+    print 'GATT service registered'
+
+
+def register_service_error_cb(error):
+    print 'Failed to register service: ' + str(error)
+    mainloop.quit()
+
+
+def find_adapter(bus):
+    remote_om = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, '/'),
+                               DBUS_OM_IFACE)
+    objects = remote_om.GetManagedObjects()
+
+    for o, props in objects.iteritems():
+        if props.has_key(GATT_MANAGER_IFACE):
+            return o
+
+    return None
+
+def main():
+    global mainloop
+
+    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+    bus = dbus.SystemBus()
+
+    adapter = find_adapter(bus)
+    if not adapter:
+        print 'GattManager1 interface not found'
+        return
+
+    service_manager = dbus.Interface(
+            bus.get_object(BLUEZ_SERVICE_NAME, adapter),
+            GATT_MANAGER_IFACE)
+
+    hr_service = HeartRateService(bus, 0)
+    bat_service = BatteryService(bus, 1)
+    test_service = TestService(bus, 2)
+
+    mainloop = gobject.MainLoop()
+
+    service_manager.RegisterService(hr_service.get_path(), {},
+                                    reply_handler=register_service_cb,
+                                    error_handler=register_service_error_cb)
+    service_manager.RegisterService(bat_service.get_path(), {},
+                                    reply_handler=register_service_cb,
+                                    error_handler=register_service_error_cb)
+    service_manager.RegisterService(test_service.get_path(), {},
+                                    reply_handler=register_service_cb,
+                                    error_handler=register_service_error_cb)
+
+    mainloop.run()
+
+if __name__ == '__main__':
+    main()
index 6bca404..33e0d6a 100644 (file)
@@ -33,7 +33,8 @@
 
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus/gdbus.h>
+
+#include "gdbus/gdbus.h"
 
 #include "src/error.h"
 
index 3535faa..150c5d0 100644 (file)
@@ -45,9 +45,9 @@
 #include <sys/param.h>
 #include <sys/ioctl.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 #include "hciattach.h"
 
@@ -1315,7 +1315,7 @@ static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
 
        if (tcgetattr(fd, &ti) < 0) {
                perror("Can't get port settings");
-               return -1;
+               goto fail;
        }
 
        cfmakeraw(&ti);
@@ -1331,13 +1331,13 @@ static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
 
        if (tcsetattr(fd, TCSANOW, &ti) < 0) {
                perror("Can't set port settings");
-               return -1;
+               goto fail;
        }
 
        /* Set initial baudrate */
        if (set_speed(fd, &ti, u->init_speed) < 0) {
                perror("Can't set initial baud rate");
-               return -1;
+               goto fail;
        }
 
        tcflush(fd, TCIOFLUSH);
@@ -1358,39 +1358,43 @@ static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
 #endif
 
        if (u->init && u->init(fd, u, &ti) < 0)
-               return -1;
+               goto fail;
 
        tcflush(fd, TCIOFLUSH);
 
        /* Set actual baudrate */
        if (set_speed(fd, &ti, u->speed) < 0) {
                perror("Can't set baud rate");
-               return -1;
+               goto fail;
        }
 
        /* Set TTY to N_HCI line discipline */
        i = N_HCI;
        if (ioctl(fd, TIOCSETD, &i) < 0) {
                perror("Can't set line discipline");
-               return -1;
+               goto fail;
        }
 
        if (flags && ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
                perror("Can't set UART flags");
-               return -1;
+               goto fail;
        }
 
        if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) {
                perror("Can't set device");
-               return -1;
+               goto fail;
        }
 
 #if 0
        if (u->post && u->post(fd, u, &ti) < 0)
-               return -1;
+               goto fail;
 #endif
 
        return fd;
+
+fail:
+       close(fd);
+       return -1;
 }
 
 #endif /* __BROADCOM_PATCH__ */
@@ -1530,7 +1534,7 @@ int main(int argc, char *argv[])
                        dev[0] = 0;
                        if (!strchr(opt, '/'))
                                strcpy(dev, "/dev/");
-                       strncat(dev, opt, PATH_MAX);
+                       strcat(dev, opt);
                        break;
 
                case 1:
index 23208c6..a76b448 100644 (file)
@@ -33,9 +33,9 @@
 #include <sys/param.h>
 #include <sys/ioctl.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 #include "hciattach.h"
 
@@ -840,17 +840,8 @@ static int ath_ps_download(int fd)
                goto download_cmplete;
        }
 
-       /*
-        * It is not necessary that Patch file be available,
-        * continue with PS Operations if patch file is not available.
-        */
-       if (patch_file[0] == '\0')
-               err = 0;
-
        stream = fopen(patch_file, "r");
-       if (!stream)
-               err = 0;
-       else {
+       if(stream) {
                patch_count = ps_patch_download(fd, stream);
                fclose(stream);
 
index 3d36c20..81f38cb 100644 (file)
@@ -36,9 +36,9 @@
 #include <time.h>
 #include <limits.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 #include "hciattach.h"
 
index 749098e..2650dcb 100644 (file)
@@ -35,9 +35,9 @@
 #include <sys/ioctl.h>
 #include <time.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 #include "hciattach.h"
 
index 0e25905..22ac629 100644 (file)
@@ -42,9 +42,9 @@
 #include <sys/ioctl.h>
 #include <sys/uio.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 #include "hciattach.h"
 
index dbb7c47..474545a 100644 (file)
@@ -35,7 +35,7 @@
 #include <dirent.h>
 #include <sys/param.h>
 
-#include <bluetooth/bluetooth.h>
+#include "lib/bluetooth.h"
 
 #include "hciattach.h"
 
index 9099bb4..14053d0 100644 (file)
@@ -37,9 +37,9 @@
 #include <sys/param.h>
 #include <sys/ioctl.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 #include "hciattach.h"
 
index a7c1706..f6ef068 100644 (file)
@@ -41,9 +41,9 @@
 #include <sys/ioctl.h>
 #include <sys/uio.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 #include "hciattach.h"
 
index 8ec1e8a..6397e71 100644 (file)
@@ -39,9 +39,9 @@
 #include <sys/socket.h>
 #include <sys/stat.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 #include "src/textfile.h"
 #include "src/shared/util.h"
@@ -624,6 +624,9 @@ static void cmd_features(int ctl, int hdev, char *opt)
                exit(1);
        }
 
+       if (max_page < 1 && (features[6] & LMP_SIMPLE_PAIR))
+               max_page = 1;
+
        print_dev_hdr(&di);
        printf("\tFeatures%s: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "
                                "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
index 87beac9..b5f818d 100644 (file)
@@ -31,9 +31,9 @@
 #include <getopt.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 static struct option main_options[] = {
        { "device",     1, 0, 'i' },
index 9ad4ce0..18c9033 100644 (file)
 #include <stdio.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
-int main(void)
+int main(int argc, char *argv[])
 {
        uint32_t type_mask;
        uint32_t event_mask[2];
index 85498dc..7d06556 100644 (file)
@@ -203,6 +203,52 @@ The clock can be
 for the local clock or
 .BR 1
 for the piconet clock (which is default).
+.TP
+.BI lescan " [--privacy] [--passive] [--whitelist] [--discovery=g|l] \
+[--duplicates]"
+Start LE scan
+.TP
+.BI leinfo " [--static] [--random] <bdaddr>"
+Get LE remote information
+.TP
+.BI lewladd " [--random] <bdaddr>"
+Add device to LE White List
+.TP
+.BI lewlrm " <bdaddr>"
+Remove device from LE White List
+.TP
+.BI lewlsz
+Read size of LE White List
+.TP
+.BI lewlclr
+Clear LE White List
+.TP
+.BI lerladd " [--local irk] [--peer irk] [--random] <bdaddr>"
+Add device to LE Resolving List
+.TP
+.BI lerlrm " <bdaddr>"
+Remove device from LE Resolving List
+.TP
+.BI lerlclr
+Clear LE Resolving List
+.TP
+.BI lerlsz
+Read size of LE Resolving List
+.TP
+.BI lerlon
+Enable LE Address Resolution
+.TP
+.BI lerloff
+Disable LE Address Resolution
+.TP
+.BI lecc " [--static] [--random] <bdaddr> | [--whitelist]"
+Create a LE Connection
+.TP
+.BI ledc " <handle> [reason]"
+Disconnect a LE Connection
+.TP
+.BI lecup " <handle> <min> <max> <latency> <timeout>"
+LE Connection Update
 .SH AUTHORS
 Written by Maxim Krasnyansky <maxk@qualcomm.com> and Marcel Holtmann <marcel@holtmann.org>
 .PP
index 2c84dc7..02c4ebe 100644 (file)
@@ -40,9 +40,9 @@
 #include <sys/socket.h>
 #include <signal.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
 
 #include "src/oui.h"
 
@@ -967,6 +967,9 @@ static void cmd_info(int dev_id, int argc, char **argv)
                hci_read_remote_ext_features(dd, handle, 0, &max_page,
                                                        features, 20000);
 
+       if (max_page < 1 && (features[6] & LMP_SIMPLE_PAIR))
+               max_page = 1;
+
        printf("\tFeatures%s: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "
                                "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
                (max_page > 0) ? " page 0" : "",
@@ -2404,9 +2407,7 @@ failed:
 
 static int print_advertising_devices(int dd, uint8_t filter_type)
 {
-       unsigned char buf_array[HCI_MAX_EVENT_SIZE+1] = {0};
-       unsigned char *buf = buf_array;
-       unsigned char *ptr = NULL;
+       unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr;
        struct hci_filter nf, of;
        struct sigaction sa;
        socklen_t olen;
@@ -2433,14 +2434,11 @@ static int print_advertising_devices(int dd, uint8_t filter_type)
        sigaction(SIGINT, &sa, NULL);
 
        while (1) {
-               evt_le_meta_event *meta = NULL;
-               le_advertising_info *info = NULL;
-               char addr_array[18];
-               char *addr = addr_array;
-
-               buf[HCI_MAX_EVENT_SIZE] = 0;
+               evt_le_meta_event *meta;
+               le_advertising_info *info;
+               char addr[18];
 
-               while ((len = read(dd, buf, HCI_MAX_EVENT_SIZE)) < 0) {
+               while ((len = read(dd, buf, sizeof(buf))) < 0) {
                        if (errno == EINTR && signal_received == SIGINT) {
                                len = 0;
                                goto done;
@@ -2462,16 +2460,14 @@ static int print_advertising_devices(int dd, uint8_t filter_type)
                /* Ignoring multiple reports */
                info = (le_advertising_info *) (meta->data + 1);
                if (check_report_filter(filter_type, info)) {
-                       char name_array[30];
-                       char *name = name_array;
+                       char name[30];
 
-                       memset(name, 0, 30);
+                       memset(name, 0, sizeof(name));
 
                        ba2str(&info->bdaddr, addr);
                        eir_parse_name(info->data, info->length,
-                                                       name, 29);
+                                                       name, sizeof(name) - 1);
 
-                       name[29] = '\0';
                        printf("%s %s\n", addr, name);
                }
        }
@@ -3300,18 +3296,19 @@ static const char *lecup_help =
        "Usage:\n"
        "\tlecup <handle> <min> <max> <latency> <timeout>\n"
        "\tOptions:\n"
-       "\t    -H, --handle <0xXXXX>  LE connection handle\n"
-       "\t    -m, --min <interval>   Range: 0x0006 to 0x0C80\n"
-       "\t    -M, --max <interval>   Range: 0x0006 to 0x0C80\n"
-       "\t    -l, --latency <range>  Slave latency. Range: 0x0000 to 0x03E8\n"
-       "\t    -t, --timeout  <time>  N * 10ms. Range: 0x000A to 0x0C80\n"
+       "\t    --handle=<0xXXXX>  LE connection handle\n"
+       "\t    --min=<interval>   Range: 0x0006 to 0x0C80\n"
+       "\t    --max=<interval>   Range: 0x0006 to 0x0C80\n"
+       "\t    --latency=<range>  Slave latency. Range: 0x0000 to 0x03E8\n"
+       "\t    --timeout=<time>   N * 10ms. Range: 0x000A to 0x0C80\n"
        "\n\t min/max range: 7.5ms to 4s. Multiply factor: 1.25ms"
        "\n\t timeout range: 100ms to 32.0s. Larger than max interval\n";
 
 static void cmd_lecup(int dev_id, int argc, char **argv)
 {
        uint16_t handle = 0, min, max, latency, timeout;
-       int opt, dd, base;
+       int opt, dd;
+       int options = 0;
 
        /* Aleatory valid values */
        min = 0x0C8;
@@ -3320,31 +3317,38 @@ static void cmd_lecup(int dev_id, int argc, char **argv)
        timeout = 0x0C80;
 
        for_each_opt(opt, lecup_options, NULL) {
-               if (optarg && strncasecmp("0x", optarg, 2) == 0)
-                       base = 16;
-               else
-                       base = 10;
-
                switch (opt) {
                case 'H':
-                       handle = strtoul(optarg, NULL, base);
+                       handle = strtoul(optarg, NULL, 0);
                        break;
                case 'm':
-                       min = strtoul(optarg, NULL, base);
+                       min = strtoul(optarg, NULL, 0);
                        break;
                case 'M':
-                       max = strtoul(optarg, NULL, base);
+                       max = strtoul(optarg, NULL, 0);
                        break;
                case 'l':
-                       latency = strtoul(optarg, NULL, base);
+                       latency = strtoul(optarg, NULL, 0);
                        break;
                case 't':
-                       timeout = strtoul(optarg, NULL, base);
+                       timeout = strtoul(optarg, NULL, 0);
                        break;
                default:
                        printf("%s", lecup_help);
                        return;
                }
+
+               options = 1;
+       }
+
+       if (options == 0) {
+               helper_arg(5, 5, &argc, &argv, lecup_help);
+
+               handle = strtoul(argv[0], NULL, 0);
+               min = strtoul(argv[1], NULL, 0);
+               max = strtoul(argv[2], NULL, 0);
+               latency = strtoul(argv[3], NULL, 0);
+               timeout = strtoul(argv[4], NULL, 0);
        }
 
        if (handle == 0) {
index d9b5d3b..943531c 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2012 Canonical
+ *  Copyright (C) 2012-2013  Intel Corporation
  *
  *
  *  This program is free software; you can redistribute it and/or modify
 #include <config.h>
 #endif
 
-#include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+
+static ssize_t process_record(int fd, const char *line, uint16_t *upper_addr)
+{
+       const char *ptr = line + 1;
+       char str[3];
+       size_t len;
+       uint8_t *buf;
+       uint32_t addr;
+       uint8_t sum = 0;
+       int n = 0;
+
+       if (line[0] != ':') {
+               fprintf(stderr, "Invalid record start code (%c)\n", line[0]);
+               return -EINVAL;
+       }
+
+       len = strlen(line);
+       if (len < 11) {
+               fprintf(stderr, "Record information is too short\n");
+               return -EILSEQ;
+       }
 
-#define RBUF_SIZE      640
+       buf = malloc((len / 2) + 3);
+       if (!buf) {
+               fprintf(stderr, "Failed to allocate memory for record data\n");
+               return -ENOMEM;
+       }
+
+       while (1) {
+               str[0] = *ptr++;
+               str[1] = *ptr++;
+               str[2] = '\0';
+
+               buf[3 + n] = strtol(str, NULL, 16);
+
+               if (*ptr == '\r' || *ptr == '\n')
+                       break;
+
+               sum += buf[3 + n++];
+       }
+
+       sum = 0x100 - (sum & 0xff);
+
+       if (n < 4 || buf[3] + 4 != n) {
+               fprintf(stderr, "Record length is not matching data\n");
+               free(buf);
+               return -EILSEQ;
+       }
+
+       if (buf[3 + n] != sum) {
+               fprintf(stderr, "Checksum mismatch\n");
+               free(buf);
+               return -EILSEQ;
+       }
+
+       switch (buf[6]) {
+       case 0x00:
+               addr = (*upper_addr << 16) + (buf[4] << 8) + buf[5];
+
+               buf[0] = 0x4c;
+               buf[1] = 0xfc;
+               buf[2] = n;
+
+               buf[3] = (addr & 0x000000ff);
+               buf[4] = (addr & 0x0000ff00) >> 8;
+               buf[5] = (addr & 0x00ff0000) >> 16;
+               buf[6] = (addr & 0xff000000) >> 24;
+
+               if (write(fd, buf, n + 3) < 0) {
+                       perror("Failed to write data record");
+                       free(buf);
+                       return -errno;
+               }
+               break;
+       case 0x01:
+               buf[0] = 0x4e;
+               buf[1] = 0xfc;
+               buf[2] = 0x04;
+
+               buf[3] = 0xff;
+               buf[4] = 0xff;
+               buf[5] = 0xff;
+               buf[6] = 0xff;
+
+               if (write(fd, buf, 7) < 0) {
+                       perror("Failed to write end record");
+                       free(buf);
+                       return -errno;
+               }
+               break;
+       case 0x04:
+               *upper_addr = (buf[7] << 8) + buf[8];
+               break;
+       default:
+               fprintf(stderr, "Unsupported record type (%02X)\n", buf[3]);
+               free(buf);
+               return -EILSEQ;
+       }
 
-static unsigned int asc_to_int(char a)
+       free(buf);
+
+       return len;
+}
+
+static void convert_file(const char *input_path, const char *output_path)
 {
-       if (a >= 'A')
-               return (a - 'A') + 10;
-       else
-               return a - '0';
+       uint16_t upper_addr = 0x0000;
+       size_t line_size = 1024;
+       char line_buffer[line_size];
+       char *path;
+       const char *ptr;
+       FILE *fp;
+       struct stat st;
+       off_t cur = 0;
+       int fd;
+
+       if (output_path) {
+               path = strdup(output_path);
+               if (!path) {
+                       perror("Failed to allocate string");
+                       return;
+               }
+       } else {
+               ptr = strrchr(input_path, '.');
+               if (ptr) {
+                       path = malloc(ptr - input_path + 6);
+                       if (!path) {
+                               perror("Failed to allocate string");
+                               return;
+                       }
+                       strncpy(path, input_path, ptr - input_path);
+                       strcpy(path + (ptr - input_path), ".hcd");
+               } else {
+                       if (asprintf(&path, "%s.hcd", input_path) < 0) {
+                               perror("Failed to allocate string");
+                               return;
+                       }
+               }
+       }
+
+       printf("Converting %s to %s\n", input_path, path);
+
+       fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+
+       free(path);
+
+       if (fd < 0) {
+               perror("Failed to create output file");
+               return;
+       }
+
+       if (stat(input_path, &st) < 0) {
+               fprintf(stderr, "Failed get file size\n");
+               close(fd);
+               return;
+       }
+
+       if (st.st_size == 0) {
+               fprintf(stderr, "Empty file\n");
+               close(fd);
+               return;
+       }
+
+       fp = fopen(input_path, "r");
+       if (!fp) {
+               fprintf(stderr, "Failed to open input file\n");
+               close(fd);
+               return;
+       }
+
+       while (1) {
+               char *str;
+               ssize_t len;
+
+               str = fgets(line_buffer, line_size - 1, fp);
+               if (!str)
+                       break;
+
+               len = process_record(fd, str, &upper_addr);
+               if (len < 0)
+                       goto done;
+
+               cur += len;
+       }
+
+       if (cur != st.st_size) {
+               fprintf(stderr, "Data length does not match file length\n");
+               goto done;
+       }
+
+done:
+       fclose(fp);
+
+       close(fd);
 }
 
-static unsigned int hex_to_int(const char *h)
+struct ver_data {
+       uint16_t num;
+       char name[20];
+       char major[4];
+       char minor[4];
+       char build[4];
+       struct ver_data *next;
+};
+
+static struct ver_data *ver_list = NULL;
+
+static void ver_parse_file(const char *pathname)
 {
-       return asc_to_int(*h) * 0x10 + asc_to_int(*(h + 1));
+       struct ver_data *ver, *tmp, *prev;
+       char dummy1[5], dummy2[5];
+
+       if (strlen(pathname) < 7)
+               return;
+
+       if (strncmp(pathname, "BCM", 3))
+               return;
+
+       ver = malloc(sizeof(*ver));
+       if (!ver)
+               return;
+
+       memset(ver, 0, sizeof(*ver));
+
+       if (sscanf(pathname, "%[A-Z0-9]_%3c.%3c.%3c.%4c.%4c.hex",
+                                       ver->name, ver->major, ver->minor,
+                                       ver->build, dummy1, dummy2) != 6) {
+               printf("\t/* failed to parse %s */\n", pathname);
+               free(ver);
+               return;
+       }
+
+       ver->num = atoi(ver->build) + (atoi(ver->minor) << 8) +
+                                               (atoi(ver->major) << 13);
+
+       if (!ver_list) {
+               ver_list = ver;
+               return;
+       }
+
+       for (tmp = ver_list, prev = NULL; tmp; prev = tmp, tmp = tmp->next) {
+               if (ver->num == tmp->num) {
+                       free(ver);
+                       return;
+               }
+
+               if (ver->num < tmp->num) {
+                       if (prev) {
+                               prev->next = ver;
+                               ver->next = tmp;
+                       } else {
+                               ver->next = ver_list;
+                               ver_list = ver;
+                       }
+                       return;
+               }
+       }
+
+       prev->next = ver;
 }
 
-static unsigned int lhex_to_int(const char *h)
+static void ver_parse_entry(const char *pathname)
 {
-       return hex_to_int(h) * 0x100 + hex_to_int(h + 2);
+       struct stat st;
+       int fd;
+
+       fd = open(pathname, O_RDONLY);
+       if (fd < 0) {
+               printf("\t/* failed to open %s */\n", pathname);
+               return;
+       }
+
+       if (fstat(fd, &st) < 0) {
+               printf("\t/* failed to stat %s */\n", pathname);
+               goto done;
+       }
+
+       if (S_ISREG(st.st_mode)) {
+               ver_parse_file(basename(pathname));
+               goto done;
+       }
+
+       if (S_ISDIR(st.st_mode)) {
+               DIR *dir;
+
+               dir = fdopendir(fd);
+               if (!dir)
+                       goto done;
+
+               while (1) {
+                       struct dirent *d;
+
+                       d = readdir(dir);
+                       if (!d)
+                               break;
+
+                       if (d->d_type == DT_REG)
+                               ver_parse_file(d->d_name);
+               }
+
+               closedir(dir);
+       }
+
+done:
+       close(fd);
 }
 
-static int check_sum(const char *str, int len)
+static void ver_print_table(int argc, char *argv[])
 {
-       unsigned int sum, cal;
-       int i;
-       sum = hex_to_int(str + len - 2);
-       for (cal = 0, i = 1; i < len - 2; i += 2)
-               cal += hex_to_int(str + i);
-       cal = 0x100 - (cal & 0xFF);
-       return sum == cal;
+       struct ver_data *ver;
+
+       printf("static const struct {\n");
+       printf("\tuint16_t ver;\n");
+       printf("\tconst char *str\n");
+       printf("} table[] = {\n");
+
+       if (argc > 0) {
+               int i;
+
+               for (i = 0; i < argc; i++)
+                       ver_parse_entry(argv[i]);
+       } else
+               ver_parse_entry(".");
+
+       for (ver = ver_list; ver; ) {
+               struct ver_data *tmp = ver;
+
+               printf("\t{ 0x%4.4x, \"%s\"\t},\t/* %s.%s.%s */\n",
+                                       ver->num, ver->name,
+                                       ver->major, ver->minor, ver->build);
+
+               ver = ver->next;
+               free(tmp);
+       }
+
+       printf("        { }\n");
+       printf("};\n");
 }
 
-static int check_hex_line(const char *str, unsigned int len)
+static void usage(void)
 {
-       if ((str[0] != ':') || (len < 11) || !check_sum(str, len) ||
-                       (hex_to_int(str + 1) * 2 + 11 != len))
-               return 0;
-       return 1;
+       printf("Broadcom Bluetooth firmware converter\n"
+               "Usage:\n");
+       printf("\thex2hcd [options] <file>\n");
+       printf("Options:\n"
+               "\t-o, --output <file>    Provide firmware output file\n"
+               "\t-h, --help             Show help options\n");
 }
 
+static const struct option main_options[] = {
+       { "table",   no_argument,       NULL, 'T' },
+       { "output",  required_argument, NULL, 'o' },
+       { "version", no_argument,       NULL, 'v' },
+       { "help",    no_argument,       NULL, 'h' },
+       { }
+};
+
 int main(int argc, char *argv[])
 {
-       unsigned int i, addr = 0;
-       FILE *ifp, *ofp;
-       char *rbuf;
-       ssize_t len;
-       size_t buflen;
-
-       if (argc != 3) {
-               printf("Usage: %s <input hex file> <output file>\n", argv[0]);
-               return 0;
-       }
-
-       ifp = fopen(argv[1], "r");
-       ofp = fopen(argv[2], "w");
-       if ((ifp == NULL) || (ofp == NULL)) {
-               puts("failed to open file.");
-               return -EIO;
-       }
-
-       rbuf = NULL;
-       while ((len = getline(&rbuf, &buflen, ifp)) > 0) {
-               int type;
-               char obuf[7];
-               unsigned int dest_addr;
-               while ((rbuf[len - 1] == '\r') || (rbuf[len - 1] == '\n'))
-                       len--;
-               printf("%d, %s\n", (int)len, rbuf);
-               if (!check_hex_line(rbuf, len))
+       const char *output_path = NULL;
+       bool print_table = false;
+       int i;
+
+       for (;;) {
+               int opt;
+
+               opt = getopt_long(argc, argv, "To:vh", main_options, NULL);
+               if (opt < 0)
                        break;
-               type = hex_to_int(rbuf + 7);
-               switch (type) {
-                       case 4:
-                               addr = lhex_to_int(rbuf + 9) * 0x10000;
-                               printf("bump addr to 0x%08X\n", addr);
-                               break;
-                       case 0:
-                               dest_addr = addr + lhex_to_int(rbuf + 3);
-                               obuf[0] = 0x4c;
-                               obuf[1] = 0xfc;
-                               obuf[2] = hex_to_int(rbuf + 1) + 4;
-                               obuf[3] = dest_addr;
-                               obuf[4] = dest_addr >> 8;
-                               obuf[5] = dest_addr >> 16;
-                               obuf[6] = dest_addr >> 24;
-                               if (fwrite(obuf, 7, 1, ofp) != 1)
-                                       goto output_err;
-                               for (i = 0; i < hex_to_int(rbuf + 1); i++) {
-                                       obuf[0] = hex_to_int(rbuf + 9 + i * 2);
-                                       if (fwrite(obuf, 1, 1, ofp) != 1)
-                                               goto output_err;
-                               }
-                               break;
-                       case 1:
-                               if (fwrite("\x4e\xfc\x04\xff\xff\xff\xff", 7, 1, ofp) != 1)
-                                       goto output_err;
-                               goto end;
-                       default:
-                               return -EINVAL;
+
+               switch (opt) {
+               case 'T':
+                       print_table = true;
+                       break;
+               case 'o':
+                       output_path = optarg;
+                       break;
+               case 'v':
+                       printf("%s\n", VERSION);
+                       return EXIT_SUCCESS;
+               case 'h':
+                       usage();
+                       return EXIT_SUCCESS;
+               default:
+                       return EXIT_FAILURE;
                }
        }
 
-       puts("hex file formatting error");
-       return -EINVAL;
+       if (print_table) {
+               ver_print_table(argc - optind, argv + optind);
+               return EXIT_SUCCESS;
+       }
 
-output_err:
-       puts("error on writing output file");
-       return -EIO;
+       if (argc - optind < 1) {
+               fprintf(stderr, "No input firmware files provided\n");
+               return EXIT_FAILURE;
+       }
 
-end:
-       return 0;
-}
+       if (output_path && argc - optind > 1) {
+               fprintf(stderr, "Only single input firmware supported\n");
+               return EXIT_FAILURE;
+       }
+
+       for (i = optind; i < argc; i++)
+               convert_file(argv[i], output_path);
 
+       return EXIT_SUCCESS;
+}
index 8c5d520..c6876a3 100644 (file)
@@ -32,7 +32,7 @@ mode and back.
 .B --mode= [hid, hci]
 Sets the mode to switch the device into
 .TP
-.B --method= [csr, logitech-hid, dell]
+.B --method= [csr, csr2, logitech-hid, dell]
 Which vendor method to use for switching the device.
 .TP
 .B --devpath=
index a183bfa..8f060f2 100644 (file)
@@ -59,7 +59,7 @@ struct usbfs_ctrltransfer {
        uint16_t wIndex;
        uint16_t wLength;
        uint32_t timeout;       /* in milliseconds */
-       void *data;             /* pointer to data */
+       const void *data;       /* pointer to data */
 };
 
 
@@ -77,7 +77,7 @@ struct usbfs_disconnect{
 
 static int control_message(int fd, int requesttype, int request,
                                        int value, int index,
-                                       char *bytes, int size, int timeout)
+                                       const uint8_t *bytes, int size, int timeout)
 {
        struct usbfs_ctrltransfer transfer;
 
@@ -119,6 +119,52 @@ static int usb_switch_csr(int fd, enum mode mode)
        return err;
 }
 
+static int usb_switch_csr2(int fd, enum mode mode)
+{
+       int err = 0;
+       struct usbfs_disconnect disconnect;
+       const uint8_t report[] = {
+               0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+
+       switch (mode) {
+       case HCI:
+               /* send report as is */
+               disconnect.interface = 0;
+               disconnect.flags = USBFS_DISCONNECT_EXCEPT_DRIVER;
+               strcpy(disconnect.driver, "usbfs");
+
+               if (ioctl(fd, USBFS_IOCTL_DISCONNECT, &disconnect) < 0) {
+                       fprintf(stderr, "Can't claim interface: %s (%d)\n",
+                               strerror(errno), errno);
+                       return -1;
+               }
+
+               /* Set_report request with
+                * report id: 0x01, report type: feature (0x03)
+                * on interface 0
+                */
+               err = control_message(fd,
+                                     USB_ENDPOINT_OUT | USB_TYPE_CLASS |
+                                     USB_RECIP_INTERFACE,
+                                     USB_REQ_SET_CONFIGURATION,
+                                     0x01 | (0x03 << 8),
+                                     0, report, sizeof(report), 5000);
+               /* unable to detect whether the previous state
+                * already was HCI (EALREADY)
+                */
+               break;
+       case HID:
+               /* currently unknown how to switch to HID */
+               fprintf(stderr,
+                       "csr2: Switching to hid mode is not implemented\n");
+               err = -1;
+               break;
+       }
+
+       return err;
+}
+
 static int hid_logitech_send_report(int fd, const char *buf, size_t size)
 {
        struct hiddev_report_info rinfo;
@@ -180,7 +226,7 @@ out:
 
 static int usb_switch_dell(int fd, enum mode mode)
 {
-       char report[] = { 0x7f, 0x00, 0x00, 0x00 };
+       uint8_t report[] = { 0x7f, 0x00, 0x00, 0x00 };
        struct usbfs_disconnect disconnect;
        int err;
 
@@ -258,7 +304,7 @@ static void usage(const char *error)
        printf("Usage: hid2hci [options]\n"
                "  --mode=       mode to switch to [hid|hci] (default hci)\n"
                "  --devpath=    sys device path\n"
-               "  --method=     method to use to switch [csr|logitech-hid|dell]\n"
+               "  --method=     method to use to switch [csr|csr2|logitech-hid|dell]\n"
                "  --help\n\n");
 }
 
@@ -311,6 +357,9 @@ int main(int argc, char *argv[])
                        if (!strcmp(optarg, "csr")) {
                                method = METHOD_CSR;
                                usb_switch = usb_switch_csr;
+                       } else if (!strcmp(optarg, "csr2")) {
+                               method = METHOD_CSR;
+                               usb_switch = usb_switch_csr2;
                        } else if (!strcmp(optarg, "logitech-hid")) {
                                method = METHOD_LOGITECH_HID;
                        } else if (!strcmp(optarg, "dell")) {
index 3b712e1..8a42dce 100644 (file)
@@ -27,7 +27,7 @@
 
 #include <stdio.h>
 
-#include <bluetooth/bluetooth.h>
+#include "lib/bluetooth.h"
 
 static const struct {
        uint16_t vendor;
index 28967de..9d48e66 100644 (file)
@@ -36,8 +36,8 @@
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 
-#include "monitor/mainloop.h"
 #include "monitor/bt.h"
+#include "src/shared/mainloop.h"
 #include "src/shared/timeout.h"
 #include "src/shared/util.h"
 #include "src/shared/hci.h"
index cf0fa38..7f03591 100644 (file)
@@ -82,6 +82,9 @@ struct l2cap_data {
        const void *pin;
        uint8_t client_pin_len;
        const void *client_pin;
+
+       bool addr_type_avail;
+       uint8_t addr_type;
 };
 
 static void mgmt_debug(const char *str, void *user_data)
@@ -441,6 +444,12 @@ static const struct l2cap_data le_client_connect_reject_test_1 = {
        .expect_err = ECONNREFUSED,
 };
 
+static const struct l2cap_data le_client_connect_reject_test_2 = {
+       .client_psm = 0x0080,
+       .addr_type_avail = true,
+       .addr_type = BDADDR_LE_PUBLIC,
+};
+
 static const struct l2cap_data le_client_connect_nval_psm_test = {
        .client_psm = 0x0080,
        .expect_err = ECONNREFUSED,
@@ -943,6 +952,7 @@ failed:
 static int create_l2cap_sock(struct test_data *data, uint16_t psm,
                                                uint16_t cid, int sec_level)
 {
+       const struct l2cap_data *l2data = data->test_data;
        const uint8_t *master_bdaddr;
        struct sockaddr_l2 addr;
        int sk, err;
@@ -968,7 +978,10 @@ static int create_l2cap_sock(struct test_data *data, uint16_t psm,
        addr.l2_psm = htobs(psm);
        addr.l2_cid = htobs(cid);
        bacpy(&addr.l2_bdaddr, (void *) master_bdaddr);
-       if (data->hciemu_type == HCIEMU_TYPE_LE)
+
+       if (l2data && l2data->addr_type_avail)
+               addr.l2_bdaddr_type = l2data->addr_type;
+       else if (data->hciemu_type == HCIEMU_TYPE_LE)
                addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;
        else
                addr.l2_bdaddr_type = BDADDR_BREDR;
@@ -1003,6 +1016,7 @@ static int create_l2cap_sock(struct test_data *data, uint16_t psm,
 static int connect_l2cap_sock(struct test_data *data, int sk, uint16_t psm,
                                                                uint16_t cid)
 {
+       const struct l2cap_data *l2data = data->test_data;
        const uint8_t *client_bdaddr;
        struct sockaddr_l2 addr;
        int err;
@@ -1018,7 +1032,10 @@ static int connect_l2cap_sock(struct test_data *data, int sk, uint16_t psm,
        bacpy(&addr.l2_bdaddr, (void *) client_bdaddr);
        addr.l2_psm = htobs(psm);
        addr.l2_cid = htobs(cid);
-       if (data->hciemu_type == HCIEMU_TYPE_LE)
+
+       if (l2data && l2data->addr_type_avail)
+               addr.l2_bdaddr_type = l2data->addr_type;
+       else if (data->hciemu_type == HCIEMU_TYPE_LE)
                addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;
        else
                addr.l2_bdaddr_type = BDADDR_BREDR;
@@ -1084,6 +1101,27 @@ static void test_connect(const void *test_data)
        tester_print("Connect in progress");
 }
 
+static void test_connect_reject(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       const struct l2cap_data *l2data = data->test_data;
+       int sk;
+
+       sk = create_l2cap_sock(data, 0, l2data->cid, l2data->sec_level);
+       if (sk < 0) {
+               tester_test_failed();
+               return;
+       }
+
+       if (connect_l2cap_sock(data, sk, l2data->client_psm,
+                                                       l2data->cid) < 0)
+               tester_test_passed();
+       else
+               tester_test_failed();
+
+       close(sk);
+}
+
 static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond,
                                                        gpointer user_data)
 {
@@ -1396,6 +1434,9 @@ int main(int argc, char *argv[])
        test_l2cap_le("L2CAP LE Client - Command Reject",
                                        &le_client_connect_reject_test_1,
                                        setup_powered_client, test_connect);
+       test_l2cap_bredr("L2CAP LE Client - Connection Reject",
+                               &le_client_connect_reject_test_2,
+                               setup_powered_client, test_connect_reject);
        test_l2cap_le("L2CAP LE Client - Invalid PSM",
                                        &le_client_connect_nval_psm_test,
                                        setup_powered_client, test_connect);
index 3dd437e..fa97fe3 100644 (file)
 #include <poll.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/l2cap.h"
 
 /* Defaults */
 static bdaddr_t bdaddr;
index a0636b9..83c5cbd 100644 (file)
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/l2cap.h"
 
 #include "src/shared/util.h"
 
index 42734eb..3092873 100644 (file)
 #include <getopt.h>
 #include <unistd.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-
 #include <glib.h>
 
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+
 #include "btio/btio.h"
 #include "lib/l2cap.h"
 #include "profiles/health/mcap.h"
@@ -71,20 +71,27 @@ static gboolean no_close = FALSE;
 
 #define REQ_CLOCK_ACC 0x1400
 
-static void mdl_connected_cb(struct mcap_mdl *mdl, void *data)
+static void mdl_close(struct mcap_mdl *mdl)
 {
        int fd = -1;
 
        printf("%s\n", __func__);
 
-       if (mdl_disconnect && mdl_disconnect_timeout >= 0) {
+       if (mdl_disconnect_timeout >= 0)
                sleep(mdl_disconnect_timeout);
 
-               fd = mcap_mdl_get_fd(mdl);
+       fd = mcap_mdl_get_fd(mdl);
 
-               if (fd > 0)
-                       close(fd);
-       }
+       if (fd > 0)
+               close(fd);
+}
+
+static void mdl_connected_cb(struct mcap_mdl *mdl, void *data)
+{
+       printf("%s\n", __func__);
+
+       if (mdl_disconnect)
+               mdl_close(mdl);
 }
 
 static void mdl_closed_cb(struct mcap_mdl *mdl, void *data)
@@ -94,7 +101,13 @@ static void mdl_closed_cb(struct mcap_mdl *mdl, void *data)
        if (mcl_disconnect && mcl_disconnect_timeout >= 0) {
                sleep(mcl_disconnect_timeout);
 
+               printf("Closing MCAP communication link\n");
                mcap_close_mcl(mcl, TRUE);
+
+               if (no_close)
+                       return;
+
+               g_main_loop_quit(mloop);
        }
 }
 
@@ -102,6 +115,10 @@ static void mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
 {
        /* TODO */
        printf("%s\n", __func__);
+
+       /* Disconnecting MDL latency timeout */
+       if (mdl_disconnect_timeout >= 0)
+               sleep(mdl_disconnect_timeout);
 }
 
 static void mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
@@ -152,7 +169,7 @@ static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
 static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
 {
        /* TODO */
-       printf("MCL disconnected\n");
+       printf("%s\n", __func__);
 
        if (no_close)
                return;
@@ -163,14 +180,19 @@ static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
 static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
 {
        /* TODO */
-       printf("MCL uncached unsupported\n");
+       printf("%s\n", __func__);
 }
 
 static void connect_mdl_cb(struct mcap_mdl *mdl, GError *gerr, gpointer data)
 {
        mdlid = mcap_mdl_get_mdlid(mdl);
 
-       printf("MDL %d connected\n", mdlid);
+       printf("%s\n", __func__);
+
+       if (mdlid == MCAP_MDLID_RESERVED)
+               printf("MCAP mdlid is reserved");
+       else
+               printf("MDL %d connected\n", mdlid);
 }
 
 static void create_mdl_cb(struct mcap_mdl *mcap_mdl, uint8_t type, GError *gerr,
@@ -178,6 +200,8 @@ static void create_mdl_cb(struct mcap_mdl *mcap_mdl, uint8_t type, GError *gerr,
 {
        GError *err = NULL;
 
+       printf("%s\n", __func__);
+
        if (gerr) {
                printf("MDL error: %s\n", gerr->message);
 
@@ -234,6 +258,7 @@ static void trigger_mdl_action(int mode)
        }
 
        if (mode == MODE_CONNECT) {
+               printf("Creating MCAP Data End Point\n");
                mcap_create_mdl(mcl, 1, 0, create_mdl_cb, NULL, NULL, &gerr);
                if (gerr) {
                        printf("Could not connect MDL: %s\n", gerr->message);
@@ -286,6 +311,7 @@ static void create_mcl_cb(struct mcap_mcl *mcap_mcl, GError *err, gpointer data)
        mcl = mcap_mcl_ref(mcap_mcl);
        trigger_mdl_action(data_mode);
 }
+
 static void usage(void)
 {
        printf("mcaptest - MCAP testing ver %s\n", VERSION);
@@ -293,10 +319,12 @@ static void usage(void)
                "\tmcaptest <control_mode> <data_mode> [options]\n");
        printf("Control Link Mode:\n"
                "\t-c connect <dst_addr>\n"
+               "\t-b close control link after closing data link\n"
                "\t-e <timeout> disconnect MCL and quit after MDL is closed\n"
                "\t-g send clock sync capability request if MCL connected\n");
        printf("Data Link Mode:\n"
                "\t-d connect\n"
+               "\t-a close data link immediately after being connected"
                "\t-f <timeout> disconnect MDL after it's connected\n"
                "\t-u send \'Unavailable\' on first MDL connection request\n");
        printf("Options:\n"
@@ -313,6 +341,8 @@ static struct option main_options[] = {
        { "disconnect_cl",      1, 0, 'e' },
        { "synccap_req",        0, 0, 'g' },
        { "connect_dl",         0, 0, 'd' },
+       { "disconnect_da",      0, 0, 'a' },
+       { "disconnect_ca",      0, 0, 'b' },
        { "disconnect_dl",      1, 0, 'f' },
        { "unavailable_dl",     0, 0, 'u' },
        { "no exit mcl dis/err",0, 0, 'n' },
@@ -320,6 +350,7 @@ static struct option main_options[] = {
        { "data_ch",            1, 0, 'D' },
        { 0, 0, 0, 0 }
 };
+
 int main(int argc, char *argv[])
 {
        GError *err = NULL;
@@ -337,7 +368,7 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
-       while ((opt = getopt_long(argc, argv, "+i:c:C:D:e:f:dghun",
+       while ((opt = getopt_long(argc, argv, "+i:c:C:D:e:f:dghunab",
                                                main_options, NULL)) != EOF) {
                switch (opt) {
                case 'i':
@@ -359,14 +390,22 @@ int main(int argc, char *argv[])
 
                        break;
 
-               case 'e':
+               case 'a':
+                       mdl_disconnect = TRUE;
+
+                       break;
+
+               case 'b':
                        mcl_disconnect = TRUE;
+
+                       break;
+
+               case 'e':
                        mcl_disconnect_timeout = atoi(optarg);
 
                        break;
 
                case 'f':
-                       mdl_disconnect = TRUE;
                        mdl_disconnect_timeout = atoi(optarg);
 
                        break;
index 790426a..e5fb889 100644 (file)
@@ -56,6 +56,7 @@ struct test_data {
        unsigned int mgmt_settings_id;
        unsigned int mgmt_alt_settings_id;
        unsigned int mgmt_alt_ev_id;
+       unsigned int mgmt_discov_ev_id;
        uint8_t mgmt_version;
        uint16_t mgmt_revision;
        uint16_t mgmt_index;
@@ -310,7 +311,7 @@ static void test_condition_complete(struct test_data *data)
                user->test_data = data; \
                user->expected_version = 0x08; \
                user->expected_manufacturer = 0x003f; \
-               user->expected_supported_settings = 0x00003fff; \
+               user->expected_supported_settings = 0x0000bfff; \
                user->initial_settings = 0x00000080; \
                user->unmet_conditions = 0; \
                tester_add_full(name, data, \
@@ -348,7 +349,7 @@ static void test_condition_complete(struct test_data *data)
                user->test_data = data; \
                user->expected_version = 0x08; \
                user->expected_manufacturer = 0x003f; \
-               user->expected_supported_settings = 0x00003e1b; \
+               user->expected_supported_settings = 0x0000be1b; \
                user->initial_settings = 0x00000200; \
                user->unmet_conditions = 0; \
                tester_add_full(name, data, \
@@ -406,6 +407,8 @@ struct generic_data {
        bool client_enable_sc;
        bool expect_sc_key;
        bool force_power_off;
+       bool addr_type_avail;
+       uint8_t addr_type;
 };
 
 static const char dummy_data[] = { 0x00 };
@@ -2395,7 +2398,10 @@ static const void *pair_device_send_param_func(uint16_t *len)
        static uint8_t param[8];
 
        memcpy(param, hciemu_get_client_bdaddr(data->hciemu), 6);
-       if (data->hciemu_type == HCIEMU_TYPE_LE)
+
+       if (test->addr_type_avail)
+               param[6] = test->addr_type;
+       else if (data->hciemu_type == HCIEMU_TYPE_LE)
                param[6] = 0x01; /* Address type */
        else
                param[6] = 0x00; /* Address type */
@@ -2409,10 +2415,14 @@ static const void *pair_device_send_param_func(uint16_t *len)
 static const void *pair_device_expect_param_func(uint16_t *len)
 {
        struct test_data *data = tester_get_data();
+       const struct generic_data *test = data->test_data;
        static uint8_t param[7];
 
        memcpy(param, hciemu_get_client_bdaddr(data->hciemu), 6);
-       if (data->hciemu_type == HCIEMU_TYPE_LE)
+
+       if (test->addr_type_avail)
+               param[6] = test->addr_type;
+       else if (data->hciemu_type == HCIEMU_TYPE_LE)
                param[6] = 0x01; /* Address type */
        else
                param[6] = 0x00; /* Address type */
@@ -2501,6 +2511,52 @@ static const void *client_bdaddr_param_func(uint8_t *len)
        return bdaddr;
 }
 
+static const struct generic_data pair_device_not_supported_test_1 = {
+       .setup_settings = settings_powered_bondable,
+       .send_opcode = MGMT_OP_PAIR_DEVICE,
+       .send_func = pair_device_send_param_func,
+       .expect_status = MGMT_STATUS_NOT_SUPPORTED,
+       .expect_func = pair_device_expect_param_func,
+       .addr_type_avail = true,
+       .addr_type = BDADDR_BREDR,
+};
+
+static const struct generic_data pair_device_not_supported_test_2 = {
+       .setup_settings = settings_powered_bondable,
+       .send_opcode = MGMT_OP_PAIR_DEVICE,
+       .send_func = pair_device_send_param_func,
+       .expect_status = MGMT_STATUS_NOT_SUPPORTED,
+       .expect_func = pair_device_expect_param_func,
+       .addr_type_avail = true,
+       .addr_type = BDADDR_LE_PUBLIC,
+};
+
+static uint16_t settings_powered_bondable_le[] = { MGMT_OP_SET_LE,
+                                                       MGMT_OP_SET_BONDABLE,
+                                                       MGMT_OP_SET_POWERED,
+                                                       0 };
+
+static const struct generic_data pair_device_reject_transport_not_enabled_1 = {
+       .setup_settings = settings_powered_bondable_le,
+       .setup_nobredr = true,
+       .send_opcode = MGMT_OP_PAIR_DEVICE,
+       .send_func = pair_device_send_param_func,
+       .expect_status = MGMT_STATUS_REJECTED,
+       .expect_func = pair_device_expect_param_func,
+       .addr_type_avail = true,
+       .addr_type = BDADDR_BREDR,
+};
+
+static const struct generic_data pair_device_reject_transport_not_enabled_2 = {
+       .setup_settings = settings_powered_bondable,
+       .send_opcode = MGMT_OP_PAIR_DEVICE,
+       .send_func = pair_device_send_param_func,
+       .expect_status = MGMT_STATUS_REJECTED,
+       .expect_func = pair_device_expect_param_func,
+       .addr_type_avail = true,
+       .addr_type = BDADDR_LE_PUBLIC,
+};
+
 static const struct generic_data pair_device_reject_test_1 = {
        .setup_settings = settings_powered_bondable,
        .send_opcode = MGMT_OP_PAIR_DEVICE,
@@ -2833,6 +2889,25 @@ static const struct generic_data pair_device_smp_bredr_test_1 = {
        .client_io_cap = 0x03, /* NoInputNoOutput */
 };
 
+static const struct generic_data pair_device_smp_bredr_test_2 = {
+       .setup_settings = settings_powered_sc_bondable_le_ssp,
+       .client_enable_ssp = true,
+       .client_enable_le = true,
+       .client_enable_sc = true,
+       .expect_sc_key = true,
+       .send_opcode = MGMT_OP_PAIR_DEVICE,
+       .send_func = pair_device_send_param_func,
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_func = pair_device_expect_param_func,
+       .expect_alt_ev =  MGMT_EV_NEW_LONG_TERM_KEY,
+       .expect_alt_ev_len = sizeof(struct mgmt_ev_new_long_term_key),
+       .verify_alt_ev_func = verify_ltk,
+       .expect_hci_command = BT_HCI_CMD_USER_CONFIRM_REQUEST_REPLY,
+       .expect_hci_func = client_bdaddr_param_func,
+       .io_cap = 0x01, /* DisplayYesNo */
+       .client_io_cap = 0x01, /* DisplayYesNo */
+};
+
 static const struct generic_data pair_device_le_reject_test_1 = {
        .setup_settings = settings_powered_bondable,
        .io_cap = 0x02, /* KeyboardOnly */
@@ -3021,6 +3096,44 @@ static const struct generic_data pairing_acceptor_ssp_4 = {
        .client_auth_req = 0x02, /* Dedicated Bonding - No MITM */
 };
 
+static uint16_t settings_powered_sc_bondable_connectable_le_ssp[] = {
+                                               MGMT_OP_SET_BONDABLE,
+                                               MGMT_OP_SET_CONNECTABLE,
+                                               MGMT_OP_SET_LE,
+                                               MGMT_OP_SET_SSP,
+                                               MGMT_OP_SET_SECURE_CONN,
+                                               MGMT_OP_SET_POWERED,
+                                               0 };
+
+static const struct generic_data pairing_acceptor_smp_bredr_1 = {
+       .setup_settings = settings_powered_sc_bondable_connectable_le_ssp,
+       .client_enable_ssp = true,
+       .client_enable_le = true,
+       .client_enable_sc = true,
+       .expect_sc_key = true,
+       .expect_alt_ev =  MGMT_EV_NEW_LONG_TERM_KEY,
+       .expect_alt_ev_len = sizeof(struct mgmt_ev_new_long_term_key),
+       .verify_alt_ev_func = verify_ltk,
+       .just_works = true,
+       .io_cap = 0x03, /* NoInputNoOutput */
+       .client_io_cap = 0x03, /* No InputNoOutput */
+       .client_auth_req = 0x00, /* No Bonding - No MITM */
+};
+
+static const struct generic_data pairing_acceptor_smp_bredr_2 = {
+       .setup_settings = settings_powered_sc_bondable_connectable_le_ssp,
+       .client_enable_ssp = true,
+       .client_enable_le = true,
+       .client_enable_sc = true,
+       .expect_sc_key = true,
+       .expect_alt_ev =  MGMT_EV_NEW_LONG_TERM_KEY,
+       .expect_alt_ev_len = sizeof(struct mgmt_ev_new_long_term_key),
+       .verify_alt_ev_func = verify_ltk,
+       .io_cap = 0x01, /* DisplayYesNo */
+       .client_io_cap = 0x01, /* DisplayYesNo */
+       .client_auth_req = 0x02, /* Dedicated Bonding - No MITM */
+};
+
 static uint16_t settings_powered_bondable_connectable_advertising[] = {
                                        MGMT_OP_SET_BONDABLE,
                                        MGMT_OP_SET_CONNECTABLE,
@@ -3160,12 +3273,27 @@ static const struct generic_data unblock_device_invalid_param_test_1 = {
 
 static const char set_static_addr_valid_param[] = {
                        0x11, 0x22, 0x33, 0x44, 0x55, 0xc0 };
+static const char set_static_addr_settings[] = { 0x00, 0x82, 0x00, 0x00 };
 
 static const struct generic_data set_static_addr_success_test = {
        .send_opcode = MGMT_OP_SET_STATIC_ADDRESS,
        .send_param = set_static_addr_valid_param,
        .send_len = sizeof(set_static_addr_valid_param),
        .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_static_addr_settings,
+       .expect_len = sizeof(set_static_addr_settings),
+       .expect_settings_set = MGMT_SETTING_STATIC_ADDRESS,
+};
+
+static const char set_static_addr_settings_dual[] = { 0x80, 0x00, 0x00, 0x00 };
+
+static const struct generic_data set_static_addr_success_test_2 = {
+       .send_opcode = MGMT_OP_SET_STATIC_ADDRESS,
+       .send_param = set_static_addr_valid_param,
+       .send_len = sizeof(set_static_addr_valid_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_static_addr_settings_dual,
+       .expect_len = sizeof(set_static_addr_settings_dual),
 };
 
 static const struct generic_data set_static_addr_failure_test = {
@@ -3176,6 +3304,14 @@ static const struct generic_data set_static_addr_failure_test = {
        .expect_status = MGMT_STATUS_REJECTED,
 };
 
+static const struct generic_data set_static_addr_failure_test_2 = {
+       .setup_settings = settings_powered,
+       .send_opcode = MGMT_OP_SET_STATIC_ADDRESS,
+       .send_param = set_static_addr_valid_param,
+       .send_len = sizeof(set_static_addr_valid_param),
+       .expect_status = MGMT_STATUS_NOT_SUPPORTED,
+};
+
 static const char set_scan_params_valid_param[] = { 0x60, 0x00, 0x30, 0x00 };
 
 static const struct generic_data set_scan_params_success_test = {
@@ -3706,10 +3842,9 @@ static void discovering_event(uint16_t index, uint16_t length,
                                        const void *param, void *user_data)
 {
        struct test_data *data = tester_get_data();
-       unsigned int id = PTR_TO_UINT(user_data);
        const struct mgmt_ev_discovering *ev = param;
 
-       mgmt_unregister(data->mgmt, id);
+       mgmt_unregister(data->mgmt, data->mgmt_discov_ev_id);
 
        if (length != sizeof(*ev)) {
                tester_warn("Incorrect discovering event length");
@@ -3743,10 +3878,11 @@ static void setup_start_discovery(const void *test_data)
        const struct generic_data *test = data->test_data;
        const void *send_param = test->setup_send_param;
        uint16_t send_len = test->setup_send_len;
-       unsigned int id = 0;
+       unsigned int id;
 
        id = mgmt_register(data->mgmt, MGMT_EV_DISCOVERING, data->mgmt_index,
-                          discovering_event, UINT_TO_PTR(id), NULL);
+                          discovering_event, NULL, NULL);
+       data->mgmt_discov_ev_id = id;
 
        mgmt_send(data->mgmt, test->setup_send_opcode, data->mgmt_index,
                                send_len, send_param, setup_discovery_callback,
@@ -5006,6 +5142,18 @@ int main(int argc, char *argv[])
        test_bredrle("Pair Device - Power off 1",
                                &pair_device_power_off_test_1,
                                NULL, test_command_generic);
+       test_le("Pair Device - Incorrect transport reject 1",
+                               &pair_device_not_supported_test_1,
+                               NULL, test_command_generic);
+       test_bredr("Pair Device - Incorrect transport reject 2",
+                               &pair_device_not_supported_test_2,
+                               NULL, test_command_generic);
+       test_bredrle("Pair Device - Reject on not enabled transport 1",
+                               &pair_device_reject_transport_not_enabled_1,
+                               NULL, test_command_generic);
+       test_bredrle("Pair Device - Reject on not enabled transport 2",
+                               &pair_device_reject_transport_not_enabled_2,
+                               NULL, test_command_generic);
        test_bredrle("Pair Device - Invalid Parameters 1",
                                &pair_device_invalid_param_test_1,
                                NULL, test_command_generic);
@@ -5060,9 +5208,12 @@ int main(int argc, char *argv[])
        test_bredrle("Pair Device - SSP Non-bondable 1",
                                &pair_device_ssp_nonbondable_1,
                                NULL, test_command_generic);
-       test_bredrle("Pair Device - SMP over BR/EDR Just-Works Success 1",
+       test_bredrle("Pair Device - SMP over BR/EDR Success 1",
                                &pair_device_smp_bredr_test_1,
                                NULL, test_command_generic);
+       test_bredrle("Pair Device - SMP over BR/EDR Success 2",
+                               &pair_device_smp_bredr_test_2,
+                               NULL, test_command_generic);
        test_le("Pair Device - LE Success 1",
                                &pair_device_le_success_test_1,
                                NULL, test_command_generic);
@@ -5109,6 +5260,12 @@ int main(int argc, char *argv[])
        test_bredrle("Pairing Acceptor - SSP 4",
                                &pairing_acceptor_ssp_4, setup_pairing_acceptor,
                                test_pairing_acceptor);
+       test_bredrle("Pairing Acceptor - SMP over BR/EDR 1",
+                               &pairing_acceptor_smp_bredr_1,
+                               setup_pairing_acceptor, test_pairing_acceptor);
+       test_bredrle("Pairing Acceptor - SMP over BR/EDR 2",
+                               &pairing_acceptor_smp_bredr_2,
+                               setup_pairing_acceptor, test_pairing_acceptor);
        test_le("Pairing Acceptor - LE 1",
                                &pairing_acceptor_le_1, setup_pairing_acceptor,
                                test_pairing_acceptor);
@@ -5147,12 +5304,18 @@ int main(int argc, char *argv[])
                                &unblock_device_invalid_param_test_1,
                                NULL, test_command_generic);
 
-       test_bredrle("Set Static Address - Success",
+       test_le("Set Static Address - Success 1",
                                &set_static_addr_success_test,
                                NULL, test_command_generic);
-       test_bredrle("Set Static Address - Failure",
+       test_bredrle("Set Static Address - Success 2",
+                               &set_static_addr_success_test_2,
+                               NULL, test_command_generic);
+       test_bredrle("Set Static Address - Failure 1",
                                &set_static_addr_failure_test,
                                NULL, test_command_generic);
+       test_bredr("Set Static Address - Failure 2",
+                               &set_static_addr_failure_test_2,
+                               NULL, test_command_generic);
 
        test_bredrle("Set Scan Parameters - Success",
                                &set_scan_params_success_test,
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
deleted file mode 100755 (executable)
index c94330c..0000000
+++ /dev/null
@@ -1,2593 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <getopt.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include <dbus/dbus.h>
-#include <glib.h>
-#include <gdbus/gdbus.h>
-
-#define BLUEZ_BUS_NAME "org.bluez"
-#define BLUEZ_PATH "/org/bluez"
-#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
-#define BLUEZ_MEDIA_INTERFACE "org.bluez.Media1"
-#define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
-#define BLUEZ_MEDIA_FOLDER_INTERFACE "org.bluez.MediaFolder1"
-#define BLUEZ_MEDIA_ITEM_INTERFACE "org.bluez.MediaItem1"
-#define BLUEZ_MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport1"
-#define MPRIS_BUS_NAME "org.mpris.MediaPlayer2."
-#define MPRIS_INTERFACE "org.mpris.MediaPlayer2"
-#define MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
-#define MPRIS_TRACKLIST_INTERFACE "org.mpris.MediaPlayer2.TrackList"
-#define MPRIS_PLAYLISTS_INTERFACE "org.mpris.MediaPlayer2.Playlists"
-#define MPRIS_PLAYER_PATH "/org/mpris/MediaPlayer2"
-#define ERROR_INTERFACE "org.mpris.MediaPlayer2.Error"
-
-static GMainLoop *main_loop;
-static GDBusProxy *adapter = NULL;
-static DBusConnection *sys = NULL;
-static DBusConnection *session = NULL;
-static GDBusClient *client = NULL;
-static GSList *players = NULL;
-static GSList *transports = NULL;
-
-static gboolean option_version = FALSE;
-static gboolean option_export = FALSE;
-
-struct tracklist {
-       GDBusProxy *proxy;
-       GSList *items;
-};
-
-struct player {
-       char *bus_name;
-       DBusConnection *conn;
-       GDBusProxy *proxy;
-       GDBusProxy *folder;
-       GDBusProxy *device;
-       GDBusProxy *transport;
-       GDBusProxy *playlist;
-       struct tracklist *tracklist;
-};
-
-typedef int (* parse_metadata_func) (DBusMessageIter *iter, const char *key,
-                                               DBusMessageIter *metadata);
-
-static void dict_append_entry(DBusMessageIter *dict, const char *key, int type,
-                                                               void *val);
-
-static void sig_term(int sig)
-{
-       g_main_loop_quit(main_loop);
-}
-
-static DBusMessage *get_all(DBusConnection *conn, const char *name)
-{
-       DBusMessage *msg, *reply;
-       DBusError err;
-       const char *iface = MPRIS_PLAYER_INTERFACE;
-
-       msg = dbus_message_new_method_call(name, MPRIS_PLAYER_PATH,
-                                       DBUS_INTERFACE_PROPERTIES, "GetAll");
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               return NULL;
-       }
-
-       dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface,
-                                       DBUS_TYPE_INVALID);
-
-       dbus_error_init(&err);
-
-       reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
-
-       dbus_message_unref(msg);
-
-       if (!reply) {
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               return NULL;
-       }
-
-       return reply;
-}
-
-static void append_variant(DBusMessageIter *iter, int type, void *val)
-{
-       DBusMessageIter value;
-       char sig[2] = { type, '\0' };
-
-       dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
-
-       dbus_message_iter_append_basic(&value, type, val);
-
-       dbus_message_iter_close_container(iter, &value);
-}
-
-static void append_array_variant(DBusMessageIter *iter, int type, void *val,
-                                                       int n_elements)
-{
-       DBusMessageIter variant, array;
-       char type_sig[2] = { type, '\0' };
-       char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' };
-
-       dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
-                                               array_sig, &variant);
-
-       dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
-                                               type_sig, &array);
-
-       if (dbus_type_is_fixed(type) == TRUE) {
-               dbus_message_iter_append_fixed_array(&array, type, val,
-                                                       n_elements);
-       } else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
-               const char ***str_array = val;
-               int i;
-
-               for (i = 0; i < n_elements; i++)
-                       dbus_message_iter_append_basic(&array, type,
-                                                       &((*str_array)[i]));
-       }
-
-       dbus_message_iter_close_container(&variant, &array);
-
-       dbus_message_iter_close_container(iter, &variant);
-}
-
-static void dict_append_array(DBusMessageIter *dict, const char *key, int type,
-                       void *val, int n_elements)
-{
-       DBusMessageIter entry;
-
-       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
-                                               NULL, &entry);
-
-       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
-
-       append_array_variant(&entry, type, val, n_elements);
-
-       dbus_message_iter_close_container(dict, &entry);
-}
-
-static void append_basic(DBusMessageIter *base, DBusMessageIter *iter,
-                                                               int type)
-{
-       const void *value;
-
-       dbus_message_iter_get_basic(iter, &value);
-       dbus_message_iter_append_basic(base, type, &value);
-}
-
-static void append_iter(DBusMessageIter *base, DBusMessageIter *iter);
-static void append_container(DBusMessageIter *base, DBusMessageIter *iter,
-                                                               int type)
-{
-       DBusMessageIter iter_sub, base_sub;
-       char *sig;
-
-       dbus_message_iter_recurse(iter, &iter_sub);
-
-       switch (type) {
-       case DBUS_TYPE_ARRAY:
-       case DBUS_TYPE_VARIANT:
-               sig = dbus_message_iter_get_signature(&iter_sub);
-               break;
-       default:
-               sig = NULL;
-               break;
-       }
-
-       dbus_message_iter_open_container(base, type, sig, &base_sub);
-
-       if (sig != NULL)
-               dbus_free(sig);
-
-       append_iter(&base_sub, &iter_sub);
-
-       dbus_message_iter_close_container(base, &base_sub);
-}
-
-static void append_iter(DBusMessageIter *base, DBusMessageIter *iter)
-{
-       int type;
-
-       while ((type = dbus_message_iter_get_arg_type(iter)) !=
-                                                       DBUS_TYPE_INVALID) {
-               if (dbus_type_is_basic(type))
-                       append_basic(base, iter, type);
-               else if (dbus_type_is_container(type))
-                       append_container(base, iter, type);
-
-               dbus_message_iter_next(iter);
-       }
-}
-
-static void dict_append_iter(DBusMessageIter *dict, const char *key,
-                                               DBusMessageIter *iter)
-{
-       DBusMessageIter entry;
-
-       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
-                                               NULL, &entry);
-
-       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
-
-       append_iter(&entry, iter);
-
-       dbus_message_iter_close_container(dict, &entry);
-}
-
-static int parse_metadata_entry(DBusMessageIter *entry, const char *key,
-                                               DBusMessageIter *metadata)
-{
-       if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
-               return -EINVAL;
-
-       dict_append_iter(metadata, key, entry);
-
-       return 0;
-}
-
-static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata,
-                                               parse_metadata_func func)
-{
-       DBusMessageIter dict;
-       int ctype;
-
-       ctype = dbus_message_iter_get_arg_type(args);
-       if (ctype != DBUS_TYPE_ARRAY)
-               return -EINVAL;
-
-       dbus_message_iter_recurse(args, &dict);
-
-       while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
-                                                       DBUS_TYPE_INVALID) {
-               DBusMessageIter entry;
-               const char *key;
-
-               if (ctype != DBUS_TYPE_DICT_ENTRY)
-                       return -EINVAL;
-
-               dbus_message_iter_recurse(&dict, &entry);
-               if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
-                       return -EINVAL;
-
-               dbus_message_iter_get_basic(&entry, &key);
-               dbus_message_iter_next(&entry);
-
-               if (func(&entry, key, metadata) < 0)
-                       return -EINVAL;
-
-               dbus_message_iter_next(&dict);
-       }
-
-       return 0;
-}
-
-static void append_metadata(DBusMessageIter *iter, DBusMessageIter *dict,
-                                               parse_metadata_func func)
-{
-       DBusMessageIter value, metadata;
-
-       dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
-                                                               &value);
-
-       dbus_message_iter_open_container(&value, 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, &metadata);
-
-       parse_metadata(dict, &metadata, func);
-
-       dbus_message_iter_close_container(&value, &metadata);
-       dbus_message_iter_close_container(iter, &value);
-}
-
-static void dict_append_entry(DBusMessageIter *dict, const char *key, int type,
-                                                               void *val)
-{
-       DBusMessageIter entry;
-
-       if (type == DBUS_TYPE_STRING) {
-               const char *str = *((const char **) val);
-               if (str == NULL)
-                       return;
-       }
-
-       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
-                                                       NULL, &entry);
-
-       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
-
-       if (strcasecmp(key, "Metadata") == 0)
-               append_metadata(&entry, val, parse_metadata_entry);
-       else
-               append_variant(&entry, type, val);
-
-       dbus_message_iter_close_container(dict, &entry);
-}
-
-static char *sender2path(const char *sender)
-{
-       char *path;
-
-       path = g_strconcat("/", sender, NULL);
-       return g_strdelimit(path, ":.", '_');
-}
-
-static void copy_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusMessage *msg = user_data;
-       DBusMessage *reply = dbus_pending_call_steal_reply(call);
-       DBusMessage *copy;
-       DBusMessageIter args, iter;
-
-       copy = dbus_message_new_method_return(msg);
-       if (copy == NULL) {
-               dbus_message_unref(reply);
-               return;
-       }
-
-       dbus_message_iter_init_append(copy, &iter);
-
-       if (!dbus_message_iter_init(reply, &args))
-               goto done;
-
-       append_iter(&iter, &args);
-
-       dbus_connection_send(sys, copy, NULL);
-
-done:
-       dbus_message_unref(copy);
-       dbus_message_unref(reply);
-}
-
-static DBusHandlerResult player_message(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       char *owner = data;
-       DBusMessage *copy;
-       DBusMessageIter args, iter;
-       DBusPendingCall *call;
-
-       dbus_message_iter_init(msg, &args);
-
-       copy = dbus_message_new_method_call(owner,
-                                       MPRIS_PLAYER_PATH,
-                                       dbus_message_get_interface(msg),
-                                       dbus_message_get_member(msg));
-       if (copy == NULL)
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-       dbus_message_iter_init_append(copy, &iter);
-       append_iter(&iter, &args);
-
-       if (!dbus_connection_send_with_reply(session, copy, &call, -1))
-               goto done;
-
-       dbus_message_ref(msg);
-       dbus_pending_call_set_notify(call, copy_reply, msg, NULL);
-       dbus_pending_call_unref(call);
-
-done:
-       dbus_message_unref(copy);
-
-       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static struct player *find_player_by_bus_name(const char *name)
-{
-       GSList *l;
-
-       for (l = players; l; l = l->next) {
-               struct player *player = l->data;
-
-               if (strcmp(player->bus_name, name) == 0)
-                       return player;
-       }
-
-       return NULL;
-}
-
-static const DBusObjectPathVTable player_table = {
-       .message_function = player_message,
-};
-
-static void add_player(DBusConnection *conn, const char *name,
-                                                       const char *sender)
-{
-       DBusMessage *reply = NULL;
-       DBusMessage *msg;
-       DBusMessageIter iter, args;
-       DBusError err;
-       char *path, *owner;
-       struct player *player;
-
-       if (!adapter)
-               return;
-
-       player = find_player_by_bus_name(name);
-       if (player == NULL) {
-               reply = get_all(conn, name);
-               if (reply == NULL)
-                       return;
-               dbus_message_iter_init(reply, &args);
-       }
-
-       msg = dbus_message_new_method_call(BLUEZ_BUS_NAME,
-                                       g_dbus_proxy_get_path(adapter),
-                                       BLUEZ_MEDIA_INTERFACE,
-                                       "RegisterPlayer");
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               return;
-       }
-
-       path = sender2path(sender);
-       dbus_connection_get_object_path_data(sys, path, (void **) &owner);
-
-       if (owner != NULL)
-               goto done;
-
-       dbus_message_iter_init_append(msg, &iter);
-
-       dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
-
-       if (player != NULL) {
-               if (!g_dbus_get_properties(player->conn,
-                                               MPRIS_PLAYER_PATH,
-                                               MPRIS_PLAYER_INTERFACE,
-                                               &iter))
-                       goto done;
-       } else {
-               append_iter(&iter, &args);
-               dbus_message_unref(reply);
-       }
-
-       dbus_error_init(&err);
-
-       owner = strdup(sender);
-
-       if (!dbus_connection_register_object_path(sys, path, &player_table,
-                                                               owner)) {
-               fprintf(stderr, "Can't register object path for player\n");
-               free(owner);
-               goto done;
-       }
-
-       reply = dbus_connection_send_with_reply_and_block(sys, msg, -1, &err);
-       if (!reply) {
-               fprintf(stderr, "Can't register player\n");
-               free(owner);
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-       }
-
-done:
-       if (reply)
-               dbus_message_unref(reply);
-       dbus_message_unref(msg);
-       g_free(path);
-}
-
-static void remove_player(DBusConnection *conn, const char *sender)
-{
-       DBusMessage *msg;
-       char *path, *owner;
-
-       if (!adapter)
-               return;
-
-       path = sender2path(sender);
-       dbus_connection_get_object_path_data(sys, path, (void **) &owner);
-
-       if (owner == NULL) {
-               g_free(path);
-               return;
-       }
-
-       msg = dbus_message_new_method_call(BLUEZ_BUS_NAME,
-                                       g_dbus_proxy_get_path(adapter),
-                                       BLUEZ_MEDIA_INTERFACE,
-                                       "UnregisterPlayer");
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               g_free(path);
-               return;
-       }
-
-       dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &path,
-                                       DBUS_TYPE_INVALID);
-
-       dbus_connection_send(sys, msg, NULL);
-
-       dbus_connection_unregister_object_path(sys, path);
-
-       dbus_message_unref(msg);
-       g_free(path);
-       g_free(owner);
-}
-
-static gboolean player_signal(DBusConnection *conn, DBusMessage *msg,
-                                                               void *user_data)
-{
-       DBusMessage *signal;
-       DBusMessageIter iter, args;
-       char *path, *owner;
-
-       dbus_message_iter_init(msg, &iter);
-
-       path = sender2path(dbus_message_get_sender(msg));
-       dbus_connection_get_object_path_data(sys, path, (void **) &owner);
-
-       if (owner == NULL)
-               goto done;
-
-       signal = dbus_message_new_signal(path, dbus_message_get_interface(msg),
-                                               dbus_message_get_member(msg));
-       if (signal == NULL) {
-               fprintf(stderr, "Unable to allocate new %s.%s signal",
-                                               dbus_message_get_interface(msg),
-                                               dbus_message_get_member(msg));
-               goto done;
-       }
-
-       dbus_message_iter_init_append(signal, &args);
-
-       append_iter(&args, &iter);
-
-       dbus_connection_send(sys, signal, NULL);
-       dbus_message_unref(signal);
-
-done:
-       g_free(path);
-
-       return TRUE;
-}
-
-static gboolean name_owner_changed(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       const char *name, *old, *new;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_STRING, &name,
-                                       DBUS_TYPE_STRING, &old,
-                                       DBUS_TYPE_STRING, &new,
-                                       DBUS_TYPE_INVALID)) {
-               fprintf(stderr, "Invalid arguments for NameOwnerChanged signal");
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-       }
-
-       if (!g_str_has_prefix(name, "org.mpris"))
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-       if (*new == '\0') {
-               printf("player %s at %s disappear\n", name, old);
-               remove_player(conn, old);
-       } else if (option_export || find_player_by_bus_name(name) == NULL) {
-               printf("player %s at %s found\n", name, new);
-               add_player(conn, name, new);
-       }
-
-       return TRUE;
-}
-
-static char *get_name_owner(DBusConnection *conn, const char *name)
-{
-       DBusMessage *msg, *reply;
-       DBusError err;
-       char *owner;
-
-       msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
-                                       DBUS_INTERFACE_DBUS, "GetNameOwner");
-
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               return NULL;
-       }
-
-       dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
-                                                       DBUS_TYPE_INVALID);
-
-       dbus_error_init(&err);
-
-       reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
-
-       dbus_message_unref(msg);
-
-       if (!reply) {
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               return NULL;
-       }
-
-       if (!dbus_message_get_args(reply, NULL,
-                                       DBUS_TYPE_STRING, &owner,
-                                       DBUS_TYPE_INVALID)) {
-               dbus_message_unref(reply);
-               return NULL;
-       }
-
-       owner = g_strdup(owner);
-
-       dbus_message_unref(reply);
-
-       dbus_connection_flush(conn);
-
-       return owner;
-}
-
-static void parse_list_names(DBusConnection *conn, DBusMessageIter *args)
-{
-       DBusMessageIter array;
-       int ctype;
-
-       ctype = dbus_message_iter_get_arg_type(args);
-       if (ctype != DBUS_TYPE_ARRAY)
-               return;
-
-       dbus_message_iter_recurse(args, &array);
-
-       while ((ctype = dbus_message_iter_get_arg_type(&array)) !=
-                                                       DBUS_TYPE_INVALID) {
-               const char *name;
-               char *owner;
-
-               if (ctype != DBUS_TYPE_STRING)
-                       goto next;
-
-               dbus_message_iter_get_basic(&array, &name);
-
-               if (!g_str_has_prefix(name, "org.mpris"))
-                       goto next;
-
-               owner = get_name_owner(conn, name);
-
-               if (owner == NULL)
-                       goto next;
-
-               printf("player %s at %s found\n", name, owner);
-
-               add_player(conn, name, owner);
-
-               g_free(owner);
-next:
-               dbus_message_iter_next(&array);
-       }
-}
-
-static void list_names(DBusConnection *conn)
-{
-       DBusMessage *msg, *reply;
-       DBusMessageIter iter;
-       DBusError err;
-
-       msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
-                                       DBUS_INTERFACE_DBUS, "ListNames");
-
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               return;
-       }
-
-       dbus_error_init(&err);
-
-       reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
-
-       dbus_message_unref(msg);
-
-       if (!reply) {
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               return;
-       }
-
-       dbus_message_iter_init(reply, &iter);
-
-       parse_list_names(conn, &iter);
-
-       dbus_message_unref(reply);
-
-       dbus_connection_flush(conn);
-}
-
-static void usage(void)
-{
-       printf("Bluetooth mpris-player ver %s\n\n", VERSION);
-
-       printf("Usage:\n");
-}
-
-static GOptionEntry options[] = {
-       { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
-                               "Show version information and exit" },
-       { "export", 'e', 0, G_OPTION_ARG_NONE, &option_export,
-                               "Export remote players" },
-       { NULL },
-};
-
-static void connect_handler(DBusConnection *connection, void *user_data)
-{
-       printf("org.bluez appeared\n");
-}
-
-static void disconnect_handler(DBusConnection *connection, void *user_data)
-{
-       printf("org.bluez disappeared\n");
-}
-
-static void unregister_tracklist(struct player *player)
-{
-       struct tracklist *tracklist = player->tracklist;
-
-       g_slist_free(tracklist->items);
-       g_dbus_proxy_unref(tracklist->proxy);
-       g_free(tracklist);
-       player->tracklist = NULL;
-}
-
-static void player_free(void *data)
-{
-       struct player *player = data;
-
-       if (player->tracklist != NULL)
-               unregister_tracklist(player);
-
-       if (player->conn) {
-               dbus_connection_close(player->conn);
-               dbus_connection_unref(player->conn);
-       }
-
-       g_dbus_proxy_unref(player->device);
-       g_dbus_proxy_unref(player->proxy);
-
-       if (player->transport)
-               g_dbus_proxy_unref(player->transport);
-
-       if (player->playlist)
-               g_dbus_proxy_unref(player->playlist);
-
-       g_free(player->bus_name);
-       g_free(player);
-}
-
-struct pending_call {
-       struct player *player;
-       DBusMessage *msg;
-};
-
-static void pending_call_free(void *data)
-{
-       struct pending_call *p = data;
-
-       if (p->msg)
-               dbus_message_unref(p->msg);
-
-       g_free(p);
-}
-
-static void player_reply(DBusMessage *message, void *user_data)
-{
-       struct pending_call *p = user_data;
-       struct player *player = p->player;
-       DBusMessage *msg = p->msg;
-       DBusMessage *reply;
-       DBusError err;
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, message)) {
-               fprintf(stderr, "error: %s", err.name);
-               reply = g_dbus_create_error(msg, err.name, "%s", err.message);
-               dbus_error_free(&err);
-       } else
-               reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-
-       g_dbus_send_message(player->conn, reply);
-}
-
-static void player_control(struct player *player, DBusMessage *msg,
-                                                       const char *name)
-{
-       struct pending_call *p;
-
-       p = g_new0(struct pending_call, 1);
-       p->player = player;
-       p->msg = dbus_message_ref(msg);
-
-       g_dbus_proxy_method_call(player->proxy, name, NULL, player_reply,
-                                               p, pending_call_free);
-}
-
-static const char *status_to_playback(const char *status)
-{
-       if (strcasecmp(status, "playing") == 0)
-               return "Playing";
-       else if (strcasecmp(status, "paused") == 0)
-               return "Paused";
-       else
-               return "Stopped";
-}
-
-static const char *player_get_status(struct player *player)
-{
-       const char *status;
-       DBusMessageIter value;
-
-       if (g_dbus_proxy_get_property(player->proxy, "Status", &value)) {
-               dbus_message_iter_get_basic(&value, &status);
-               return status_to_playback(status);
-       }
-
-       if (player->transport == NULL)
-               goto done;
-
-       if (!g_dbus_proxy_get_property(player->transport, "State", &value))
-               goto done;
-
-       dbus_message_iter_get_basic(&value, &status);
-
-       if (strcasecmp(status, "active") == 0)
-               return "Playing";
-
-done:
-       return "Stopped";
-}
-
-static DBusMessage *player_toggle(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct player *player = data;
-       const char *status;
-
-       status = player_get_status(player);
-
-       if (strcasecmp(status, "Playing") == 0)
-               player_control(player, msg, "Pause");
-       else
-               player_control(player, msg, "Play");
-
-       return NULL;
-}
-
-static DBusMessage *player_play(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct player *player = data;
-
-       player_control(player, msg, "Play");
-
-       return NULL;
-}
-
-static DBusMessage *player_pause(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct player *player = data;
-
-       player_control(player, msg, "Pause");
-
-       return NULL;
-}
-
-static DBusMessage *player_stop(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct player *player = data;
-
-       player_control(player, msg, "Stop");
-
-       return NULL;
-}
-
-static DBusMessage *player_next(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct player *player = data;
-
-       player_control(player, msg, "Next");
-
-       return NULL;
-}
-
-static DBusMessage *player_previous(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct player *player = data;
-
-       player_control(player, msg, "Previous");
-
-       return NULL;
-}
-
-static gboolean status_exists(const GDBusPropertyTable *property, void *data)
-{
-       struct player *player = data;
-
-       return player_get_status(player) != NULL;
-}
-
-static gboolean get_status(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *data)
-{
-       struct player *player = data;
-       const char *status;
-
-       status = player_get_status(player);
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
-
-       return TRUE;
-}
-
-static gboolean repeat_exists(const GDBusPropertyTable *property, void *data)
-{
-       DBusMessageIter iter;
-       struct player *player = data;
-
-       return g_dbus_proxy_get_property(player->proxy, "Repeat", &iter);
-}
-
-static const char *repeat_to_loopstatus(const char *value)
-{
-       if (strcasecmp(value, "off") == 0)
-               return "None";
-       else if (strcasecmp(value, "singletrack") == 0)
-               return "Track";
-       else if (strcasecmp(value, "alltracks") == 0)
-               return "Playlist";
-
-       return NULL;
-}
-
-static gboolean get_repeat(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *data)
-{
-       struct player *player = data;
-       DBusMessageIter value;
-       const char *status;
-
-       if (!g_dbus_proxy_get_property(player->proxy, "Repeat", &value))
-               return FALSE;
-
-       dbus_message_iter_get_basic(&value, &status);
-
-       status = repeat_to_loopstatus(status);
-       if (status == NULL)
-               return FALSE;
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
-
-       return TRUE;
-}
-
-static const char *loopstatus_to_repeat(const char *value)
-{
-       if (strcasecmp(value, "None") == 0)
-               return "off";
-       else if (strcasecmp(value, "Track") == 0)
-               return "singletrack";
-       else if (strcasecmp(value, "Playlist") == 0)
-               return "alltracks";
-
-       return NULL;
-}
-
-static void property_result(const DBusError *err, void *user_data)
-{
-       GDBusPendingPropertySet id = GPOINTER_TO_UINT(user_data);
-
-       if (!dbus_error_is_set(err))
-               return g_dbus_pending_property_success(id);
-
-       g_dbus_pending_property_error(id, err->name, err->message);
-}
-
-static void set_repeat(const GDBusPropertyTable *property,
-                       DBusMessageIter *iter, GDBusPendingPropertySet id,
-                       void *data)
-{
-       struct player *player = data;
-       const char *value;
-
-       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
-               g_dbus_pending_property_error(id,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "Invalid arguments in method call");
-               return;
-       }
-
-       dbus_message_iter_get_basic(iter, &value);
-
-       value = loopstatus_to_repeat(value);
-       if (value == NULL) {
-               g_dbus_pending_property_error(id,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "Invalid arguments in method call");
-               return;
-       }
-
-       g_dbus_proxy_set_property_basic(player->proxy, "Repeat",
-                                       DBUS_TYPE_STRING, &value,
-                                       property_result, GUINT_TO_POINTER(id),
-                                       NULL);
-}
-
-static gboolean get_double(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *data)
-{
-       double value = 1.0;
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &value);
-
-       return TRUE;
-}
-
-static gboolean shuffle_exists(const GDBusPropertyTable *property, void *data)
-{
-       DBusMessageIter iter;
-       struct player *player = data;
-
-       return g_dbus_proxy_get_property(player->proxy, "Shuffle", &iter);
-}
-
-static gboolean get_shuffle(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *data)
-{
-       struct player *player = data;
-       DBusMessageIter value;
-       const char *string;
-       dbus_bool_t shuffle;
-
-       if (!g_dbus_proxy_get_property(player->proxy, "Shuffle", &value))
-               return FALSE;
-
-       dbus_message_iter_get_basic(&value, &string);
-
-       shuffle = strcmp(string, "off") != 0;
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &shuffle);
-
-       return TRUE;
-}
-
-static void set_shuffle(const GDBusPropertyTable *property,
-                       DBusMessageIter *iter, GDBusPendingPropertySet id,
-                       void *data)
-{
-       struct player *player = data;
-       dbus_bool_t shuffle;
-       const char *value;
-
-       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN) {
-               g_dbus_pending_property_error(id,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "Invalid arguments in method call");
-               return;
-       }
-
-       dbus_message_iter_get_basic(iter, &shuffle);
-       value = shuffle ? "alltracks" : "off";
-
-       g_dbus_proxy_set_property_basic(player->proxy, "Shuffle",
-                                       DBUS_TYPE_STRING, &value,
-                                       property_result, GUINT_TO_POINTER(id),
-                                       NULL);
-}
-
-static gboolean position_exists(const GDBusPropertyTable *property, void *data)
-{
-       DBusMessageIter iter;
-       struct player *player = data;
-
-       return g_dbus_proxy_get_property(player->proxy, "Position", &iter);
-}
-
-static gboolean get_position(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *data)
-{
-       struct player *player = data;
-       DBusMessageIter var;
-       uint32_t position;
-       int64_t value;
-
-       if (!g_dbus_proxy_get_property(player->proxy, "Position", &var))
-               return FALSE;
-
-       dbus_message_iter_get_basic(&var, &position);
-
-       value = position * 1000;
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_INT64, &value);
-
-       return TRUE;
-}
-
-static gboolean track_exists(const GDBusPropertyTable *property, void *data)
-{
-       DBusMessageIter iter;
-       struct player *player = data;
-
-       return g_dbus_proxy_get_property(player->proxy, "Track", &iter);
-}
-
-static gboolean parse_string_metadata(DBusMessageIter *iter, const char *key,
-                                               DBusMessageIter *metadata)
-{
-       const char *value;
-
-       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
-               return FALSE;
-
-       dbus_message_iter_get_basic(iter, &value);
-
-       dict_append_entry(metadata, key, DBUS_TYPE_STRING, &value);
-
-       return TRUE;
-}
-
-static gboolean parse_array_metadata(DBusMessageIter *iter, const char *key,
-                                               DBusMessageIter *metadata)
-{
-       char **value;
-
-       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
-               return FALSE;
-
-       value = dbus_malloc0(sizeof(char *));
-
-       dbus_message_iter_get_basic(iter, &(value[0]));
-
-       dict_append_array(metadata, key, DBUS_TYPE_STRING, &value, 1);
-
-       dbus_free(value);
-
-       return TRUE;
-}
-
-static gboolean parse_int64_metadata(DBusMessageIter *iter, const char *key,
-                                               DBusMessageIter *metadata)
-{
-       uint32_t duration;
-       int64_t value;
-
-       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
-               return FALSE;
-
-       dbus_message_iter_get_basic(iter, &duration);
-
-       value = duration * 1000;
-
-       dict_append_entry(metadata, key, DBUS_TYPE_INT64, &value);
-
-       return TRUE;
-}
-
-static gboolean parse_int32_metadata(DBusMessageIter *iter, const char *key,
-                                               DBusMessageIter *metadata)
-{
-       uint32_t value;
-
-       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
-               return FALSE;
-
-       dbus_message_iter_get_basic(iter, &value);
-
-       dict_append_entry(metadata, key, DBUS_TYPE_INT32, &value);
-
-       return TRUE;
-}
-
-static gboolean parse_path_metadata(DBusMessageIter *iter, const char *key,
-                                               DBusMessageIter *metadata)
-{
-       const char *value;
-
-       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_OBJECT_PATH)
-               return FALSE;
-
-       dbus_message_iter_get_basic(iter, &value);
-
-       dict_append_entry(metadata, key, DBUS_TYPE_OBJECT_PATH, &value);
-
-       return TRUE;
-}
-
-static int parse_track_entry(DBusMessageIter *entry, const char *key,
-                                               DBusMessageIter *metadata)
-{
-       DBusMessageIter var;
-
-       if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
-               return -EINVAL;
-
-       dbus_message_iter_recurse(entry, &var);
-
-       if (strcasecmp(key, "Title") == 0) {
-               if (!parse_string_metadata(&var, "xesam:title", metadata))
-                       return -EINVAL;
-       } else if (strcasecmp(key, "Artist") == 0) {
-               if (!parse_array_metadata(&var, "xesam:artist", metadata))
-                       return -EINVAL;
-       } else if (strcasecmp(key, "Album") == 0) {
-               if (!parse_string_metadata(&var, "xesam:album", metadata))
-                       return -EINVAL;
-       } else if (strcasecmp(key, "Genre") == 0) {
-               if (!parse_array_metadata(&var, "xesam:genre", metadata))
-                       return -EINVAL;
-       } else if (strcasecmp(key, "Duration") == 0) {
-               if (!parse_int64_metadata(&var, "mpris:length", metadata))
-                       return -EINVAL;
-       } else if (strcasecmp(key, "TrackNumber") == 0) {
-               if (!parse_int32_metadata(&var, "xesam:trackNumber", metadata))
-                       return -EINVAL;
-       } else if (strcasecmp(key, "Item") == 0) {
-               if (!parse_path_metadata(&var, "mpris:trackid", metadata))
-                       return -EINVAL;
-       }
-
-       return 0;
-}
-
-static gboolean get_track(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *data)
-{
-       struct player *player = data;
-       DBusMessageIter var, metadata;
-
-       if (!g_dbus_proxy_get_property(player->proxy, "Track", &var))
-               return FALSE;
-
-       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, &metadata);
-
-       parse_metadata(&var, &metadata, parse_track_entry);
-
-       dbus_message_iter_close_container(iter, &metadata);
-
-       return TRUE;
-}
-
-static gboolean get_enable(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *data)
-{
-       dbus_bool_t value = TRUE;
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
-
-       return TRUE;
-}
-
-
-static gboolean get_volume(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *data)
-{
-       struct player *player = data;
-       double value = 0.0;
-       uint16_t volume;
-       DBusMessageIter var;
-
-       if (player->transport == NULL)
-               goto done;
-
-       if (!g_dbus_proxy_get_property(player->transport, "Volume", &var))
-               goto done;
-
-       dbus_message_iter_get_basic(&var, &volume);
-
-       value = (double) volume / 127;
-
-done:
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &value);
-
-       return TRUE;
-}
-
-static const GDBusMethodTable player_methods[] = {
-       { GDBUS_ASYNC_METHOD("PlayPause", NULL, NULL, player_toggle) },
-       { GDBUS_ASYNC_METHOD("Play", NULL, NULL, player_play) },
-       { GDBUS_ASYNC_METHOD("Pause", NULL, NULL, player_pause) },
-       { GDBUS_ASYNC_METHOD("Stop", NULL, NULL, player_stop) },
-       { GDBUS_ASYNC_METHOD("Next", NULL, NULL, player_next) },
-       { GDBUS_ASYNC_METHOD("Previous", NULL, NULL, player_previous) },
-       { }
-};
-
-static const GDBusSignalTable player_signals[] = {
-       { GDBUS_SIGNAL("Seeked", GDBUS_ARGS({"Position", "x"})) },
-       { }
-};
-
-static const GDBusPropertyTable player_properties[] = {
-       { "PlaybackStatus", "s", get_status, NULL, status_exists },
-       { "LoopStatus", "s", get_repeat, set_repeat, repeat_exists },
-       { "Rate", "d", get_double, NULL, NULL },
-       { "MinimumRate", "d", get_double, NULL, NULL },
-       { "MaximumRate", "d", get_double, NULL, NULL },
-       { "Shuffle", "b", get_shuffle, set_shuffle, shuffle_exists },
-       { "Position", "x", get_position, NULL, position_exists },
-       { "Metadata", "a{sv}", get_track, NULL, track_exists },
-       { "Volume", "d", get_volume, NULL, NULL },
-       { "CanGoNext", "b", get_enable, NULL, NULL },
-       { "CanGoPrevious", "b", get_enable, NULL, NULL },
-       { "CanPlay", "b", get_enable, NULL, NULL },
-       { "CanPause", "b", get_enable, NULL, NULL },
-       { "CanSeek", "b", get_enable, NULL, NULL },
-       { "CanControl", "b", get_enable, NULL, NULL },
-       { }
-};
-
-static gboolean get_disable(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *data)
-{
-       dbus_bool_t value = FALSE;
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
-
-       return TRUE;
-}
-
-static gboolean get_name(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *data)
-{
-       struct player *player = data;
-       DBusMessageIter var;
-       const char *alias;
-       char *name;
-
-       if (!g_dbus_proxy_get_property(player->device, "Alias", &var))
-               return FALSE;
-
-       dbus_message_iter_get_basic(&var, &alias);
-
-       if (g_dbus_proxy_get_property(player->proxy, "Name", &var)) {
-               dbus_message_iter_get_basic(&var, &name);
-               name = g_strconcat(alias, " ", name, NULL);
-       } else
-               name = g_strdup(alias);
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &name);
-
-       g_free(name);
-
-       return TRUE;
-}
-
-static const GDBusMethodTable mpris_methods[] = {
-       { }
-};
-
-static gboolean get_tracklist(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *data)
-{
-       struct player *player = data;
-       dbus_bool_t value;
-
-       value = player->tracklist != NULL ? TRUE : FALSE;
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
-
-       return TRUE;
-}
-
-static const GDBusPropertyTable mpris_properties[] = {
-       { "CanQuit", "b", get_disable, NULL, NULL },
-       { "Fullscreen", "b", get_disable, NULL, NULL },
-       { "CanSetFullscreen", "b", get_disable, NULL, NULL },
-       { "CanRaise", "b", get_disable, NULL, NULL },
-       { "HasTrackList", "b", get_tracklist, NULL, NULL },
-       { "Identity", "s", get_name, NULL, NULL },
-       { }
-};
-
-static GDBusProxy *find_item(struct player *player, const char *path)
-{
-       struct tracklist *tracklist = player->tracklist;
-       GSList *l;
-
-       for (l = tracklist->items; l; l = l->next) {
-               GDBusProxy *proxy = l->data;
-               const char *p = g_dbus_proxy_get_path(proxy);
-
-               if (g_str_equal(path, p))
-                       return proxy;
-       }
-
-       return NULL;
-}
-
-static void append_item_metadata(void *data, void *user_data)
-{
-       GDBusProxy *item = data;
-       DBusMessageIter *iter = user_data;
-       DBusMessageIter var, metadata;
-       const char *path = g_dbus_proxy_get_path(item);
-
-       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, &metadata);
-
-       dict_append_entry(&metadata, "mpris:trackid", DBUS_TYPE_OBJECT_PATH,
-                                                                       &path);
-
-       if (g_dbus_proxy_get_property(item, "Metadata", &var))
-               parse_metadata(&var, &metadata, parse_track_entry);
-
-       dbus_message_iter_close_container(iter, &metadata);
-
-       return;
-}
-
-static DBusMessage *tracklist_get_metadata(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       struct player *player = data;
-       DBusMessage *reply;
-       DBusMessageIter args, array;
-       GSList *l = NULL;
-
-       dbus_message_iter_init(msg, &args);
-
-       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
-               return g_dbus_create_error(msg,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "Invalid Arguments");
-
-       dbus_message_iter_recurse(&args, &array);
-
-       while (dbus_message_iter_get_arg_type(&array) ==
-                                               DBUS_TYPE_OBJECT_PATH) {
-               const char *path;
-               GDBusProxy *item;
-
-               dbus_message_iter_get_basic(&array, &path);
-
-               item = find_item(player, path);
-               if (item == NULL)
-                       return g_dbus_create_error(msg,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "Invalid Arguments");
-
-               l = g_slist_append(l, item);
-
-               dbus_message_iter_next(&array);
-       }
-
-       reply = dbus_message_new_method_return(msg);
-
-       dbus_message_iter_init_append(reply, &args);
-
-       dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY,
-                                       DBUS_TYPE_ARRAY_AS_STRING
-                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                                       DBUS_TYPE_STRING_AS_STRING
-                                       DBUS_TYPE_VARIANT_AS_STRING
-                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
-                                       &array);
-
-       g_slist_foreach(l, append_item_metadata, &array);
-
-       dbus_message_iter_close_container(&args, &array);
-
-       return reply;
-}
-
-static void item_play_reply(DBusMessage *message, void *user_data)
-{
-       struct pending_call *p = user_data;
-       struct player *player = p->player;
-       DBusMessage *msg = p->msg;
-       DBusMessage *reply;
-       DBusError err;
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, message)) {
-               fprintf(stderr, "error: %s", err.name);
-               reply = g_dbus_create_error(msg, err.name, "%s", err.message);
-               dbus_error_free(&err);
-       } else
-               reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-
-       g_dbus_send_message(player->conn, reply);
-}
-
-static void item_play(struct player *player, DBusMessage *msg,
-                                                       GDBusProxy *item)
-{
-       struct pending_call *p;
-
-       p = g_new0(struct pending_call, 1);
-       p->player = player;
-       p->msg = dbus_message_ref(msg);
-
-       g_dbus_proxy_method_call(item, "Play", NULL, item_play_reply,
-                                               p, pending_call_free);
-}
-
-static DBusMessage *tracklist_goto(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       struct player *player = data;
-       GDBusProxy *item;
-       const char *path;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_OBJECT_PATH, &path,
-                                       DBUS_TYPE_INVALID))
-               return g_dbus_create_error(msg,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "Invalid arguments");
-
-       item = find_item(player, path);
-       if (item == NULL)
-               return g_dbus_create_error(msg,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "Invalid arguments");
-
-       item_play(player, msg, item);
-
-       return NULL;
-}
-
-static DBusMessage *tracklist_add_track(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       return g_dbus_create_error(msg, ERROR_INTERFACE ".NotImplemented",
-                                       "Not implemented");
-}
-
-static DBusMessage *tracklist_remove_track(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       return g_dbus_create_error(msg, ERROR_INTERFACE ".NotImplemented",
-                                       "Not implemented");
-}
-
-static const GDBusMethodTable tracklist_methods[] = {
-       { GDBUS_METHOD("GetTracksMetadata",
-                       GDBUS_ARGS({ "tracks", "ao" }),
-                       GDBUS_ARGS({ "metadata", "aa{sv}" }),
-                       tracklist_get_metadata) },
-       { GDBUS_METHOD("AddTrack",
-                       GDBUS_ARGS({ "uri", "s" }, { "after", "o" },
-                                               { "current", "b" }),
-                       NULL,
-                       tracklist_add_track) },
-       { GDBUS_METHOD("RemoveTrack",
-                       GDBUS_ARGS({ "track", "o" }), NULL,
-                       tracklist_remove_track) },
-       { GDBUS_ASYNC_METHOD("GoTo",
-                       GDBUS_ARGS({ "track", "o" }), NULL,
-                       tracklist_goto) },
-       { },
-};
-
-static const GDBusSignalTable tracklist_signals[] = {
-       { GDBUS_SIGNAL("TrackAdded", GDBUS_ARGS({"metadata", "a{sv}"},
-                                               {"after", "o"})) },
-       { GDBUS_SIGNAL("TrackRemoved", GDBUS_ARGS({"track", "o"})) },
-       { GDBUS_SIGNAL("TrackMetadataChanged", GDBUS_ARGS({"track", "o"},
-                                               {"metadata", "a{sv}"})) },
-       { }
-};
-
-static gboolean tracklist_exists(const GDBusPropertyTable *property, void *data)
-{
-       struct player *player = data;
-
-       return player->tracklist != NULL;
-}
-
-static void append_path(gpointer data, gpointer user_data)
-{
-       GDBusProxy *proxy = data;
-       DBusMessageIter *iter = user_data;
-       const char *path = g_dbus_proxy_get_path(proxy);
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
-}
-
-static gboolean get_tracks(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *data)
-{
-       struct player *player = data;
-       struct tracklist *tracklist = player->tracklist;
-       DBusMessageIter value;
-
-       if (tracklist == NULL)
-               return FALSE;
-
-       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
-                                       DBUS_TYPE_OBJECT_PATH_AS_STRING,
-                                       &value);
-       g_slist_foreach(player->tracklist->items, append_path, &value);
-       dbus_message_iter_close_container(iter, &value);
-
-       return TRUE;
-}
-
-static const GDBusPropertyTable tracklist_properties[] = {
-       { "Tracks", "ao", get_tracks, NULL, tracklist_exists },
-       { "CanEditTracks", "b", get_disable, NULL, NULL },
-       { }
-};
-
-static void list_items_setup(DBusMessageIter *iter, void *user_data)
-{
-       DBusMessageIter dict;
-
-       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);
-       dbus_message_iter_close_container(iter, &dict);
-}
-
-static void change_folder_reply(DBusMessage *message, void *user_data)
-{
-       struct player *player = user_data;
-       struct tracklist *tracklist = player->tracklist;
-       DBusError err;
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, message)) {
-               fprintf(stderr, "error: %s", err.name);
-               return;
-       }
-
-       g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
-                                               MPRIS_PLAYLISTS_INTERFACE,
-                                               "ActivePlaylist");
-
-       g_dbus_proxy_method_call(tracklist->proxy, "ListItems",
-                                       list_items_setup, NULL, NULL, NULL);
-}
-
-static void change_folder_setup(DBusMessageIter *iter, void *user_data)
-{
-       struct player *player = user_data;
-       const char *path;
-
-       path = g_dbus_proxy_get_path(player->playlist);
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
-}
-
-static DBusMessage *playlist_activate(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       struct player *player = data;
-       struct tracklist *tracklist = player->tracklist;
-       const char *path;
-
-       if (player->playlist == NULL || tracklist == NULL)
-               return g_dbus_create_error(msg,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "Invalid Arguments");
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_OBJECT_PATH, &path,
-                                       DBUS_TYPE_INVALID))
-               return g_dbus_create_error(msg,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "Invalid Arguments");
-
-       if (!g_str_equal(path, g_dbus_proxy_get_path(player->playlist)))
-               return g_dbus_create_error(msg,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "Invalid Arguments");
-
-       g_dbus_proxy_method_call(tracklist->proxy, "ChangeFolder",
-                               change_folder_setup, change_folder_reply,
-                               player, NULL);
-
-       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-}
-
-static DBusMessage *playlist_get(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct player *player = data;
-       uint32_t index, count;
-       const char *order;
-       dbus_bool_t reverse;
-       DBusMessage *reply;
-       DBusMessageIter iter, entry, value, name;
-       const char *string, *path;
-       const char *empty = "";
-
-       if (player->playlist == NULL)
-               return g_dbus_create_error(msg,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "Invalid Arguments");
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_UINT32, &index,
-                                       DBUS_TYPE_UINT32, &count,
-                                       DBUS_TYPE_STRING, &order,
-                                       DBUS_TYPE_BOOLEAN, &reverse,
-                                       DBUS_TYPE_INVALID))
-               return g_dbus_create_error(msg,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "Invalid Arguments");
-
-       path = g_dbus_proxy_get_path(player->playlist);
-
-       reply = dbus_message_new_method_return(msg);
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(oss)",
-                                                               &entry);
-       dbus_message_iter_open_container(&entry, DBUS_TYPE_STRUCT, NULL,
-                                                               &value);
-       dbus_message_iter_append_basic(&value, DBUS_TYPE_OBJECT_PATH, &path);
-       if (g_dbus_proxy_get_property(player->playlist, "Name", &name)) {
-               dbus_message_iter_get_basic(&name, &string);
-               dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING,
-                                                               &string);
-       } else {
-               dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING,
-                                                               &path);
-       }
-       dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &empty);
-       dbus_message_iter_close_container(&entry, &value);
-       dbus_message_iter_close_container(&iter, &entry);
-
-       return reply;
-}
-
-static const GDBusMethodTable playlist_methods[] = {
-       { GDBUS_METHOD("ActivatePlaylist",
-                       GDBUS_ARGS({ "playlist", "o" }), NULL,
-                       playlist_activate) },
-       { GDBUS_METHOD("GetPlaylists",
-                       GDBUS_ARGS({ "index", "u" }, { "maxcount", "u"},
-                                       { "order", "s" }, { "reverse", "b" }),
-                       GDBUS_ARGS({ "playlists", "a(oss)"}),
-                       playlist_get) },
-       { },
-};
-
-static gboolean playlist_exists(const GDBusPropertyTable *property, void *data)
-{
-       struct player *player = data;
-
-       return player->playlist != NULL;
-}
-
-static gboolean get_playlist_count(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *data)
-{
-       struct player *player = data;
-       uint32_t count = 1;
-
-       if (player->playlist == NULL)
-               return FALSE;
-
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &count);
-
-       return TRUE;
-}
-
-static gboolean get_orderings(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *data)
-{
-       DBusMessageIter value;
-       const char *order = "User";
-
-       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
-                                       DBUS_TYPE_OBJECT_PATH_AS_STRING,
-                                       &value);
-       dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &order);
-       dbus_message_iter_close_container(iter, &value);
-
-       return TRUE;
-}
-
-static gboolean get_active_playlist(const GDBusPropertyTable *property,
-                                       DBusMessageIter *iter, void *data)
-{
-       struct player *player = data;
-       DBusMessageIter value, entry;
-       dbus_bool_t enabled = TRUE;
-       const char *path, *empty = "";
-
-       if (player->playlist == NULL)
-               return FALSE;
-
-       path = g_dbus_proxy_get_path(player->playlist);
-
-       dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
-                                                       NULL, &value);
-       dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &enabled);
-       dbus_message_iter_open_container(&value, DBUS_TYPE_STRUCT, NULL,
-                                                               &entry);
-       dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH, &path);
-       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &path);
-       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &empty);
-       dbus_message_iter_close_container(&value, &entry);
-       dbus_message_iter_close_container(iter, &value);
-
-       return TRUE;
-}
-
-static const GDBusPropertyTable playlist_properties[] = {
-       { "PlaylistCount", "u", get_playlist_count, NULL, playlist_exists },
-       { "Orderings", "as", get_orderings, NULL, NULL },
-       { "ActivePlaylist", "(b(oss))", get_active_playlist, NULL,
-                                                       playlist_exists },
-       { }
-};
-
-#define a_z "abcdefghijklmnopqrstuvwxyz"
-#define A_Z "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-#define _0_9 "_0123456789"
-
-static char *mpris_busname(char *name)
-{
-       if (g_ascii_isdigit(name[0]))
-               return g_strconcat(MPRIS_BUS_NAME, "bt_",
-                               g_strcanon(name, A_Z a_z _0_9, '_'), NULL);
-       else
-               return g_strconcat(MPRIS_BUS_NAME,
-                               g_strcanon(name, A_Z a_z _0_9, '_'), NULL);
-}
-
-static GDBusProxy *find_transport_by_path(const char *path)
-{
-       GSList *l;
-
-       for (l = transports; l; l = l->next) {
-               GDBusProxy *transport = l->data;
-               DBusMessageIter iter;
-               const char *value;
-
-               if (!g_dbus_proxy_get_property(transport, "Device", &iter))
-                       continue;
-
-               dbus_message_iter_get_basic(&iter, &value);
-
-               if (strcmp(path, value) == 0)
-                       return transport;
-       }
-
-       return NULL;
-}
-
-static struct player *find_player(GDBusProxy *proxy)
-{
-       GSList *l;
-
-       for (l = players; l; l = l->next) {
-               struct player *player = l->data;
-               const char *path, *p;
-
-               if (player->proxy == proxy)
-                       return player;
-
-               path = g_dbus_proxy_get_path(proxy);
-               p = g_dbus_proxy_get_path(player->proxy);
-               if (g_str_equal(path, p))
-                       return player;
-       }
-
-       return NULL;
-}
-
-static void register_tracklist(GDBusProxy *proxy)
-{
-       struct player *player;
-       struct tracklist *tracklist;
-
-       player = find_player(proxy);
-       if (player == NULL)
-               return;
-
-       if (player->tracklist != NULL)
-               return;
-
-       tracklist = g_new0(struct tracklist, 1);
-       tracklist->proxy = g_dbus_proxy_ref(proxy);
-
-       player->tracklist = tracklist;
-
-       g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
-                                               MPRIS_INTERFACE,
-                                               "HasTrackList");
-
-       if (player->playlist == NULL)
-               return;
-
-       g_dbus_proxy_method_call(player->tracklist->proxy, "ChangeFolder",
-                               change_folder_setup, change_folder_reply,
-                               player, NULL);
-}
-
-static void register_player(GDBusProxy *proxy)
-{
-       struct player *player;
-       DBusMessageIter iter;
-       const char *path, *alias, *name;
-       char *busname;
-       GDBusProxy *device, *transport;
-
-       if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
-               return;
-
-       dbus_message_iter_get_basic(&iter, &path);
-
-       device = g_dbus_proxy_new(client, path, "org.bluez.Device1");
-       if (device == NULL)
-               return;
-
-       if (!g_dbus_proxy_get_property(device, "Alias", &iter))
-               return;
-
-       dbus_message_iter_get_basic(&iter, &alias);
-
-       if (g_dbus_proxy_get_property(proxy, "Name", &iter)) {
-               dbus_message_iter_get_basic(&iter, &name);
-               busname = g_strconcat(alias, " ", name, NULL);
-       } else
-               busname = g_strdup(alias);
-
-       player = g_new0(struct player, 1);
-       player->bus_name = mpris_busname(busname);
-       player->proxy = g_dbus_proxy_ref(proxy);
-       player->device = device;
-
-       g_free(busname);
-
-       players = g_slist_prepend(players, player);
-
-       printf("Player %s created\n", player->bus_name);
-
-       player->conn = g_dbus_setup_private(DBUS_BUS_SESSION, player->bus_name,
-                                                                       NULL);
-       if (!session) {
-               fprintf(stderr, "Could not register bus name %s",
-                                                       player->bus_name);
-               goto fail;
-       }
-
-       if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
-                                               MPRIS_INTERFACE,
-                                               mpris_methods,
-                                               NULL,
-                                               mpris_properties,
-                                               player, NULL)) {
-               fprintf(stderr, "Could not register interface %s",
-                                               MPRIS_INTERFACE);
-               goto fail;
-       }
-
-       if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
-                                               MPRIS_PLAYER_INTERFACE,
-                                               player_methods,
-                                               player_signals,
-                                               player_properties,
-                                               player, player_free)) {
-               fprintf(stderr, "Could not register interface %s",
-                                               MPRIS_PLAYER_INTERFACE);
-               goto fail;
-       }
-
-       if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
-                                               MPRIS_TRACKLIST_INTERFACE,
-                                               tracklist_methods,
-                                               tracklist_signals,
-                                               tracklist_properties,
-                                               player, NULL)) {
-               fprintf(stderr, "Could not register interface %s",
-                                               MPRIS_TRACKLIST_INTERFACE);
-               goto fail;
-       }
-
-       if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
-                                               MPRIS_PLAYLISTS_INTERFACE,
-                                               playlist_methods,
-                                               NULL,
-                                               playlist_properties,
-                                               player, NULL)) {
-               fprintf(stderr, "Could not register interface %s",
-                                               MPRIS_PLAYLISTS_INTERFACE);
-               goto fail;
-       }
-
-       transport = find_transport_by_path(path);
-       if (transport)
-               player->transport = g_dbus_proxy_ref(transport);
-
-       return;
-
-fail:
-       players = g_slist_remove(players, player);
-       player_free(player);
-}
-
-static struct player *find_player_by_device(const char *device)
-{
-       GSList *l;
-
-       for (l = players; l; l = l->next) {
-               struct player *player = l->data;
-               const char *path = g_dbus_proxy_get_path(player->device);
-
-               if (g_strcmp0(device, path) == 0)
-                       return player;
-       }
-
-       return NULL;
-}
-
-static void register_transport(GDBusProxy *proxy)
-{
-       struct player *player;
-       DBusMessageIter iter;
-       const char *path;
-
-       if (g_slist_find(transports, proxy) != NULL)
-               return;
-
-       if (!g_dbus_proxy_get_property(proxy, "Volume", &iter))
-               return;
-
-       if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
-               return;
-
-       dbus_message_iter_get_basic(&iter, &path);
-
-       transports = g_slist_append(transports, proxy);
-
-       player = find_player_by_device(path);
-       if (player == NULL || player->transport != NULL)
-               return;
-
-       player->transport = g_dbus_proxy_ref(proxy);
-}
-
-static struct player *find_player_by_item(const char *item)
-{
-       GSList *l;
-
-       for (l = players; l; l = l->next) {
-               struct player *player = l->data;
-               const char *path = g_dbus_proxy_get_path(player->proxy);
-
-               if (g_str_has_prefix(item, path))
-                       return player;
-       }
-
-       return NULL;
-}
-
-static void register_playlist(struct player *player, GDBusProxy *proxy)
-{
-       const char *path;
-       DBusMessageIter iter;
-
-       if (!g_dbus_proxy_get_property(player->proxy, "Playlist", &iter))
-               return;
-
-       dbus_message_iter_get_basic(&iter, &path);
-
-       if (!g_str_equal(path, g_dbus_proxy_get_path(proxy)))
-               return;
-
-       player->playlist = g_dbus_proxy_ref(proxy);
-
-       g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
-                                               MPRIS_PLAYLISTS_INTERFACE,
-                                               "PlaylistCount");
-
-       if (player->tracklist == NULL)
-               return;
-
-       g_dbus_proxy_method_call(player->tracklist->proxy, "ChangeFolder",
-                               change_folder_setup, change_folder_reply,
-                               player, NULL);
-}
-
-static void register_item(struct player *player, GDBusProxy *proxy)
-{
-       struct tracklist *tracklist;
-       const char *path, *playlist;
-       DBusMessage *signal;
-       DBusMessageIter iter, args, metadata;
-       GSList *l;
-       GDBusProxy *after;
-
-       if (player->playlist == NULL) {
-               register_playlist(player, proxy);
-               return;
-       }
-
-       tracklist = player->tracklist;
-       if (tracklist == NULL)
-               return;
-
-       path = g_dbus_proxy_get_path(proxy);
-       playlist = g_dbus_proxy_get_path(player->playlist);
-       if (!g_str_has_prefix(path, playlist))
-               return;
-
-       l = g_slist_last(tracklist->items);
-       tracklist->items = g_slist_append(tracklist->items, proxy);
-
-       g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
-                                               MPRIS_TRACKLIST_INTERFACE,
-                                               "Tracks");
-
-       if (l == NULL)
-               return;
-
-       signal = dbus_message_new_signal(MPRIS_PLAYER_PATH,
-                                       MPRIS_TRACKLIST_INTERFACE,
-                                       "TrackAdded");
-       if (!signal) {
-               fprintf(stderr, "Unable to allocate new %s.TrackAdded signal",
-                                               MPRIS_TRACKLIST_INTERFACE);
-               return;
-       }
-
-       dbus_message_iter_init_append(signal, &args);
-
-       if (!g_dbus_proxy_get_property(proxy, "Metadata", &iter)) {
-               dbus_message_unref(signal);
-               return;
-       }
-
-       dbus_message_iter_open_container(&args, 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, &metadata);
-
-       parse_metadata(&iter, &metadata, parse_track_entry);
-
-       dbus_message_iter_close_container(&args, &metadata);
-
-       after = l->data;
-       path = g_dbus_proxy_get_path(after);
-       dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &path);
-
-       g_dbus_send_message(player->conn, signal);
-}
-
-static void proxy_added(GDBusProxy *proxy, void *user_data)
-{
-       const char *interface;
-       const char *path;
-
-       interface = g_dbus_proxy_get_interface(proxy);
-       path = g_dbus_proxy_get_path(proxy);
-
-       if (!strcmp(interface, BLUEZ_ADAPTER_INTERFACE)) {
-               if (adapter != NULL)
-                       return;
-
-               printf("Bluetooth Adapter %s found\n", path);
-               adapter = proxy;
-               list_names(session);
-       } else if (!strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE)) {
-               printf("Bluetooth Player %s found\n", path);
-               register_player(proxy);
-       } else if (!strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE)) {
-               printf("Bluetooth Transport %s found\n", path);
-               register_transport(proxy);
-       } else if (!strcmp(interface, BLUEZ_MEDIA_FOLDER_INTERFACE)) {
-               printf("Bluetooth Folder %s found\n", path);
-               register_tracklist(proxy);
-       } else if (!strcmp(interface, BLUEZ_MEDIA_ITEM_INTERFACE)) {
-               struct player *player;
-
-               player = find_player_by_item(path);
-               if (player == NULL)
-                       return;
-
-               printf("Bluetooth Item %s found\n", path);
-               register_item(player, proxy);
-       }
-}
-
-static void unregister_player(struct player *player)
-{
-       players = g_slist_remove(players, player);
-
-       if (player->tracklist != NULL) {
-               g_dbus_unregister_interface(player->conn, MPRIS_PLAYER_PATH,
-                                               MPRIS_PLAYLISTS_INTERFACE);
-               g_dbus_unregister_interface(player->conn, MPRIS_PLAYER_PATH,
-                                               MPRIS_TRACKLIST_INTERFACE);
-       }
-
-       g_dbus_unregister_interface(player->conn, MPRIS_PLAYER_PATH,
-                                               MPRIS_INTERFACE);
-
-       g_dbus_unregister_interface(player->conn, MPRIS_PLAYER_PATH,
-                                               MPRIS_PLAYER_INTERFACE);
-}
-
-static struct player *find_player_by_transport(GDBusProxy *proxy)
-{
-       GSList *l;
-
-       for (l = players; l; l = l->next) {
-               struct player *player = l->data;
-
-               if (player->transport == proxy)
-                       return player;
-       }
-
-       return NULL;
-}
-
-static void unregister_transport(GDBusProxy *proxy)
-{
-       struct player *player;
-
-       if (g_slist_find(transports, proxy) == NULL)
-               return;
-
-       transports = g_slist_remove(transports, proxy);
-
-       player = find_player_by_transport(proxy);
-       if (player == NULL)
-               return;
-
-       g_dbus_proxy_unref(player->transport);
-       player->transport = NULL;
-}
-
-static void unregister_item(struct player *player, GDBusProxy *proxy)
-{
-       struct tracklist *tracklist = player->tracklist;
-       const char *path;
-
-       if (tracklist == NULL)
-               return;
-
-       if (g_slist_find(tracklist->items, proxy) == NULL)
-               return;
-
-       path = g_dbus_proxy_get_path(proxy);
-
-       tracklist->items = g_slist_remove(tracklist->items, proxy);
-
-       g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
-                                               MPRIS_TRACKLIST_INTERFACE,
-                                               "Tracks");
-
-       g_dbus_emit_signal(player->conn, MPRIS_PLAYER_PATH,
-                               MPRIS_TRACKLIST_INTERFACE, "TrackRemoved",
-                               DBUS_TYPE_OBJECT_PATH, &path,
-                               DBUS_TYPE_INVALID);
-}
-
-static void remove_players(DBusConnection *conn)
-{
-       char **paths;
-       int i;
-
-       dbus_connection_list_registered(conn, "/", &paths);
-
-       for (i = 0; paths[i]; i++) {
-               char *path;
-               void *data;
-
-               path = g_strdup_printf("/%s", paths[i]);
-               dbus_connection_get_object_path_data(sys, path, &data);
-               dbus_connection_unregister_object_path(sys, path);
-
-               g_free(path);
-               g_free(data);
-       }
-
-       dbus_free_string_array(paths);
-}
-
-static void proxy_removed(GDBusProxy *proxy, void *user_data)
-{
-       const char *interface;
-       const char *path;
-
-       if (adapter == NULL)
-               return;
-
-       interface = g_dbus_proxy_get_interface(proxy);
-       path = g_dbus_proxy_get_path(proxy);
-
-       if (strcmp(interface, BLUEZ_ADAPTER_INTERFACE) == 0) {
-               if (adapter != proxy)
-                       return;
-               printf("Bluetooth Adapter %s removed\n", path);
-               adapter = NULL;
-               remove_players(sys);
-       } else if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) == 0) {
-               struct player *player;
-
-               player = find_player(proxy);
-               if (player == NULL)
-                       return;
-
-               printf("Bluetooth Player %s removed\n", path);
-               unregister_player(player);
-       } else if (strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE) == 0) {
-               printf("Bluetooth Transport %s removed\n", path);
-               unregister_transport(proxy);
-       } else if (strcmp(interface, BLUEZ_MEDIA_ITEM_INTERFACE) == 0) {
-               struct player *player;
-
-               player = find_player_by_item(path);
-               if (player == NULL)
-                       return;
-
-               printf("Bluetooth Item %s removed\n", path);
-               unregister_item(player, proxy);
-       }
-}
-
-static const char *property_to_mpris(const char *property)
-{
-       if (strcasecmp(property, "Repeat") == 0)
-               return "LoopStatus";
-       else if (strcasecmp(property, "Shuffle") == 0)
-               return "Shuffle";
-       else if (strcasecmp(property, "Status") == 0)
-               return "PlaybackStatus";
-       else if (strcasecmp(property, "Position") == 0)
-               return "Position";
-       else if (strcasecmp(property, "Track") == 0)
-               return "Metadata";
-
-       return NULL;
-}
-
-static void player_property_changed(GDBusProxy *proxy, const char *name,
-                                       DBusMessageIter *iter, void *user_data)
-{
-       struct player *player;
-       const char *property;
-       uint32_t position;
-       uint64_t value;
-
-       player = find_player(proxy);
-       if (player == NULL)
-               return;
-
-       property = property_to_mpris(name);
-       if (property == NULL)
-               return;
-
-       g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
-                                               MPRIS_PLAYER_INTERFACE,
-                                               property);
-
-       if (strcasecmp(name, "Position") != 0)
-               return;
-
-       dbus_message_iter_get_basic(iter, &position);
-
-       value = position * 1000;
-
-       g_dbus_emit_signal(player->conn, MPRIS_PLAYER_PATH,
-                                       MPRIS_PLAYER_INTERFACE, "Seeked",
-                                       DBUS_TYPE_INT64, &value,
-                                       DBUS_TYPE_INVALID);
-}
-
-static void transport_property_changed(GDBusProxy *proxy, const char *name,
-                                       DBusMessageIter *iter, void *user_data)
-{
-       struct player *player;
-       DBusMessageIter var;
-       const char *path;
-
-       if (strcasecmp(name, "Volume") != 0 && strcasecmp(name, "State") != 0)
-               return;
-
-       if (!g_dbus_proxy_get_property(proxy, "Device", &var))
-               return;
-
-       dbus_message_iter_get_basic(&var, &path);
-
-       player = find_player_by_device(path);
-       if (player == NULL)
-               return;
-
-       if (strcasecmp(name, "State") == 0) {
-               if (!g_dbus_proxy_get_property(player->proxy, "Status", &var))
-                       g_dbus_emit_property_changed(player->conn,
-                                               MPRIS_PLAYER_PATH,
-                                               MPRIS_PLAYER_INTERFACE,
-                                               "PlaybackStatus");
-               return;
-       }
-
-       g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
-                                               MPRIS_PLAYER_INTERFACE,
-                                               name);
-}
-
-static void item_property_changed(GDBusProxy *proxy, const char *name,
-                                       DBusMessageIter *iter, void *user_data)
-{
-       struct player *player;
-       DBusMessage *signal;
-       DBusMessageIter args;
-       const char *path;
-
-       path = g_dbus_proxy_get_path(proxy);
-
-       player = find_player_by_item(path);
-       if (player == NULL)
-               return;
-
-       if (strcasecmp(name, "Metadata") != 0)
-               return;
-
-       signal = dbus_message_new_signal(MPRIS_PLAYER_PATH,
-                                       MPRIS_TRACKLIST_INTERFACE,
-                                       "TrackMetadataChanged");
-       if (!signal) {
-               fprintf(stderr, "Unable to allocate new %s.TrackAdded signal",
-                                               MPRIS_TRACKLIST_INTERFACE);
-               return;
-       }
-
-       dbus_message_iter_init_append(signal, &args);
-
-       dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &path);
-
-       append_iter(&args, iter);
-
-       g_dbus_send_message(player->conn, signal);
-}
-
-static void property_changed(GDBusProxy *proxy, const char *name,
-                                       DBusMessageIter *iter, void *user_data)
-{
-       const char *interface;
-
-       interface = g_dbus_proxy_get_interface(proxy);
-
-       if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) == 0)
-               return player_property_changed(proxy, name, iter, user_data);
-
-       if (strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE) == 0)
-               return transport_property_changed(proxy, name, iter,
-                                                               user_data);
-
-       if (strcmp(interface, BLUEZ_MEDIA_ITEM_INTERFACE) == 0)
-               return item_property_changed(proxy, name, iter, user_data);
-}
-
-int main(int argc, char *argv[])
-{
-       GOptionContext *context;
-       GError *error = NULL;
-       guint owner_watch, properties_watch, signal_watch;
-       struct sigaction sa;
-
-       context = g_option_context_new(NULL);
-       g_option_context_add_main_entries(context, options, NULL);
-
-       if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
-               if (error != NULL) {
-                       g_printerr("%s\n", error->message);
-                       g_error_free(error);
-               } else
-                       g_printerr("An unknown error occurred\n");
-               exit(1);
-       }
-
-       g_option_context_free(context);
-
-       if (option_version == TRUE) {
-               usage();
-               exit(0);
-       }
-
-       main_loop = g_main_loop_new(NULL, FALSE);
-
-       sys = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
-       if (!sys) {
-               fprintf(stderr, "Can't get on system bus");
-               exit(1);
-       }
-
-       session = g_dbus_setup_bus(DBUS_BUS_SESSION, NULL, NULL);
-       if (!session) {
-               fprintf(stderr, "Can't get on session bus");
-               exit(1);
-       }
-
-       owner_watch = g_dbus_add_signal_watch(session, NULL, NULL,
-                                               DBUS_INTERFACE_DBUS,
-                                               "NameOwnerChanged",
-                                               name_owner_changed,
-                                               NULL, NULL);
-
-       properties_watch = g_dbus_add_properties_watch(session, NULL, NULL,
-                                                       MPRIS_PLAYER_INTERFACE,
-                                                       player_signal,
-                                                       NULL, NULL);
-
-       signal_watch = g_dbus_add_signal_watch(session, NULL, NULL,
-                                                       MPRIS_PLAYER_INTERFACE,
-                                                       NULL, player_signal,
-                                                       NULL, NULL);
-
-       memset(&sa, 0, sizeof(sa));
-       sa.sa_flags   = SA_NOCLDSTOP;
-       sa.sa_handler = sig_term;
-       sigaction(SIGTERM, &sa, NULL);
-       sigaction(SIGINT,  &sa, NULL);
-
-       client = g_dbus_client_new(sys, BLUEZ_BUS_NAME, BLUEZ_PATH);
-
-       g_dbus_client_set_connect_watch(client, connect_handler, NULL);
-       g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
-
-       g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
-                                               property_changed, NULL);
-
-       g_main_loop_run(main_loop);
-
-       g_dbus_remove_watch(session, owner_watch);
-       g_dbus_remove_watch(session, properties_watch);
-       g_dbus_remove_watch(session, signal_watch);
-
-       g_dbus_client_unref(client);
-
-       dbus_connection_unref(session);
-       dbus_connection_unref(sys);
-
-       g_main_loop_unref(main_loop);
-
-       return 0;
-}
index 397f064..693055e 100644 (file)
@@ -36,7 +36,8 @@
 
 #include <dbus/dbus.h>
 #include <glib.h>
-#include <gdbus/gdbus.h>
+
+#include "gdbus/gdbus.h"
 
 #define BLUEZ_BUS_NAME "org.bluez"
 #define BLUEZ_PATH "/org/bluez"
index 4716a8c..4f931f6 100644 (file)
@@ -36,7 +36,7 @@
 #include <readline/readline.h>
 #include <readline/history.h>
 
-#include <gobex/gobex.h>
+#include "gobex/gobex.h"
 #include "btio/btio.h"
 
 static GMainLoop *main_loop = NULL;
index 3fed6dc..a16c46f 100644 (file)
@@ -33,7 +33,7 @@
 #include <string.h>
 #include <errno.h>
 
-#include <gobex/gobex.h>
+#include "gobex/gobex.h"
 #include "btio/btio.h"
 
 static GMainLoop *main_loop = NULL;
index 512a145..4faff6b 100644 (file)
 #include <signal.h>
 #include <sys/signalfd.h>
 #include <inttypes.h>
+#include <wordexp.h>
 
 #include <readline/readline.h>
 #include <readline/history.h>
 #include <glib.h>
-#include <gdbus.h>
 
-#include <client/display.h>
+#include "gdbus/gdbus.h"
+#include "client/display.h"
 
 /* String display constants */
 #define COLORED_NEW    COLOR_GREEN "NEW" COLOR_OFF
@@ -1232,7 +1233,6 @@ static void list_messages_reply(DBusMessage *message, void *user_data)
 {
        DBusError error;
        DBusMessageIter iter, array;
-       int ctype;
 
        dbus_error_init(&error);
 
@@ -1249,8 +1249,8 @@ static void list_messages_reply(DBusMessage *message, void *user_data)
 
        dbus_message_iter_recurse(&iter, &array);
 
-       while ((ctype = dbus_message_iter_get_arg_type(&array)) ==
-                                                       DBUS_TYPE_DICT_ENTRY) {
+       while ((dbus_message_iter_get_arg_type(&array)) ==
+                                               DBUS_TYPE_DICT_ENTRY) {
                DBusMessageIter entry;
                const char *obj;
 
@@ -2030,8 +2030,9 @@ static char **cmd_completion(const char *text, int start, int end)
 
 static void rl_handler(char *input)
 {
+       wordexp_t w;
        int argc;
-       char **argv = NULL;
+       char **argv;
        int i;
 
        if (!input) {
@@ -2045,18 +2046,16 @@ static void rl_handler(char *input)
        if (!strlen(input))
                goto done;
 
-       g_strstrip(input);
        add_history(input);
 
-       argv = g_strsplit(input, " ", -1);
-       if (argv == NULL)
+       if (wordexp(input, &w, WRDE_NOCMD))
                goto done;
 
-       for (argc = 0; argv[argc];)
-               argc++;
+       if (w.we_wordc == 0)
+               goto free_we;
 
-       if (argc == 0)
-               goto done;
+       argv = w.we_wordv;
+       argc = w.we_wordc;
 
        for (i = 0; cmd_table[i].cmd; i++) {
                if (strcmp(argv[0], cmd_table[i].cmd))
@@ -2064,13 +2063,13 @@ static void rl_handler(char *input)
 
                if (cmd_table[i].func) {
                        cmd_table[i].func(argc, argv);
-                       goto done;
+                       goto free_we;
                }
        }
 
        if (strcmp(argv[0], "help")) {
                printf("Invalid command\n");
-               goto done;
+               goto free_we;
        }
 
        printf("Available commands:\n");
@@ -2083,8 +2082,9 @@ static void rl_handler(char *input)
                                        cmd_table[i].desc ? : "");
        }
 
+free_we:
+       wordfree(&w);
 done:
-       g_strfreev(argv);
        free(input);
 }
 
diff --git a/tools/oobtest.c b/tools/oobtest.c
new file mode 100644 (file)
index 0000000..9cc6c16
--- /dev/null
@@ -0,0 +1,800 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <getopt.h>
+
+#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
+
+#include "src/shared/mainloop.h"
+#include "src/shared/util.h"
+#include "src/shared/mgmt.h"
+
+static bool use_bredr = false;
+static bool use_le = false;
+static bool use_sc = false;
+static bool use_sconly = false;
+static bool use_legacy = false;
+static bool use_random = false;
+static bool use_debug = false;
+static bool use_cross = false;
+static bool provide_p192 = false;
+static bool provide_p256 = false;
+
+static struct mgmt *mgmt;
+static uint16_t index1 = MGMT_INDEX_NONE;
+static uint16_t index2 = MGMT_INDEX_NONE;
+static bdaddr_t bdaddr1;
+static bdaddr_t bdaddr2;
+
+static void pin_code_request_event(uint16_t index, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_pin_code_request *ev = param;
+       struct mgmt_cp_pin_code_reply cp;
+       char str[18];
+
+       ba2str(&ev->addr.bdaddr, str);
+
+       printf("[Index %u]\n", index);
+       printf("  Pin code request: %s\n", str);
+
+       memset(&cp, 0, sizeof(cp));
+       memcpy(&cp.addr, &ev->addr, sizeof(cp.addr));
+       cp.pin_len = 4;
+       memset(cp.pin_code, '0', 4);
+
+       mgmt_reply(mgmt, MGMT_OP_PIN_CODE_REPLY, index, sizeof(cp), &cp,
+                                                       NULL, NULL, NULL);
+}
+
+static void new_link_key_event(uint16_t index, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_new_link_key *ev = param;
+       const char *type;
+       char str[18];
+       int i;
+
+       ba2str(&ev->key.addr.bdaddr, str);
+
+       switch (ev->key.type) {
+       case 0x00:
+               type = "Legacy";
+               break;
+       case 0x01:
+               type = "Local Unit";
+               break;
+       case 0x02:
+               type = "Remote Unit";
+               break;
+       case 0x03:
+               type = "Debug";
+               break;
+       case 0x04:
+               type = "Unauthenticated, P-192";
+               break;
+       case 0x05:
+               type = "Authenticated, P-192";
+               break;
+       case 0x06:
+               type = "Changed";
+               break;
+       case 0x07:
+               type = "Unauthenticated, P-256";
+               break;
+       case 0x08:
+               type = "Authenticated, P-256";
+               break;
+       default:
+               type = "<unknown>";
+               break;
+       }
+
+       printf("[Index %u]\n", index);
+       printf("  New link key: %s\n", str);
+       printf("  Type: %s (%u)\n", type, ev->key.type);
+       printf("  Key: ");
+       for (i = 0; i < 16; i++)
+               printf("%02x", ev->key.val[i]);
+       printf("\n");
+}
+
+static void new_long_term_key_event(uint16_t index, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_new_long_term_key *ev = param;
+       const char *type;
+       char str[18];
+       int i;
+
+       ba2str(&ev->key.addr.bdaddr, str);
+
+       switch (ev->key.type) {
+       case 0x00:
+               if (ev->key.master)
+                       type = "Unauthenticated, Master";
+               else
+                       type = "Unauthenticated, Slave";
+               break;
+       case 0x01:
+               if (ev->key.master)
+                       type = "Authenticated, Master";
+               else
+                       type = "Authenticated, Slave";
+               break;
+       case 0x02:
+               type = "Unauthenticated, P-256";
+               break;
+       case 0x03:
+               type = "Authenticated, P-256";
+               break;
+       case 0x04:
+               type = "Debug";
+               break;
+       default:
+               type = "<unknown>";
+               break;
+       }
+
+       printf("[Index %u]\n", index);
+       printf("  New long term key: %s\n", str);
+       printf("  Type: %s (%u)\n", type, ev->key.type);
+       printf("  Key: ");
+       for (i = 0; i < 16; i++)
+               printf("%02x", ev->key.val[i]);
+       printf("\n");
+}
+
+static void pair_device_complete(uint8_t status, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       uint16_t index = PTR_TO_UINT(user_data);
+
+       if (status) {
+               fprintf(stderr, "Pair device from index %u failed: %s\n",
+                                               index, mgmt_errstr(status));
+       }
+
+       mainloop_quit();
+}
+
+static void pair_device(uint16_t index, const bdaddr_t *bdaddr)
+{
+       struct mgmt_cp_pair_device cp;
+       char str[18];
+
+       ba2str(bdaddr, str);
+
+       printf("[Index %u]\n", index);
+       printf("  Starting pairing: %s\n", str);
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       if (use_bredr)
+               cp.addr.type = BDADDR_BREDR;
+       else if (use_random)
+               cp.addr.type = BDADDR_LE_RANDOM;
+       else
+               cp.addr.type = BDADDR_LE_PUBLIC;
+       cp.io_cap = 0x03;
+
+       mgmt_send(mgmt, MGMT_OP_PAIR_DEVICE, index, sizeof(cp), &cp,
+                                               pair_device_complete,
+                                               UINT_TO_PTR(index), NULL);
+}
+
+static void add_remote_oob_data_complete(uint8_t status, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_addr_info *rp = param;
+       uint16_t index = PTR_TO_UINT(user_data);
+       char str[18];
+
+       if (status) {
+               fprintf(stderr, "Adding OOB data for index %u failed: %s\n",
+                                               index, mgmt_errstr(status));
+       }
+
+       ba2str(&rp->bdaddr, str);
+
+       printf("[Index %u]\n", index);
+       printf("  Remote data added: %s\n", str);
+
+       if (index == index1) {
+               uint8_t val = 0x01;
+
+               mgmt_send(mgmt, MGMT_OP_SET_CONNECTABLE, index2, 1, &val,
+                                                       NULL, NULL, NULL);
+
+               if (use_le)
+                       mgmt_send(mgmt, MGMT_OP_SET_ADVERTISING, index2,
+                                               1, &val, NULL, NULL, NULL);
+
+               pair_device(index1, &bdaddr2);
+       }
+}
+
+static void add_remote_oob_data(uint16_t index, const bdaddr_t *bdaddr,
+                               const uint8_t *hash192, const uint8_t *rand192,
+                               const uint8_t *hash256, const uint8_t *rand256)
+{
+       struct mgmt_cp_add_remote_oob_data cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       if (use_bredr)
+               cp.addr.type = BDADDR_BREDR;
+       else if (use_random)
+               cp.addr.type = BDADDR_LE_RANDOM;
+       else
+               cp.addr.type = BDADDR_LE_PUBLIC;
+       if (hash192 && rand192) {
+               memcpy(cp.hash192, hash192, 16);
+               memcpy(cp.rand192, rand192, 16);
+       } else {
+               memset(cp.hash192, 0, 16);
+               memset(cp.rand192, 0, 16);
+       }
+       if (hash256 && rand256) {
+               memcpy(cp.hash256, hash256, 16);
+               memcpy(cp.rand256, rand256, 16);
+       } else {
+               memset(cp.hash256, 0, 16);
+               memset(cp.rand256, 0, 16);
+       }
+
+       mgmt_send(mgmt, MGMT_OP_ADD_REMOTE_OOB_DATA, index, sizeof(cp), &cp,
+                                               add_remote_oob_data_complete,
+                                               UINT_TO_PTR(index), NULL);
+}
+
+static void read_oob_data_complete(uint8_t status, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_read_local_oob_ext_data *rp = param;
+       uint16_t index = PTR_TO_UINT(user_data);
+       const uint8_t *hash192, *rand192, *hash256, *rand256;
+       int i;
+
+       if (status) {
+               fprintf(stderr, "Reading OOB data for index %u failed: %s\n",
+                                               index, mgmt_errstr(status));
+               mainloop_quit();
+               return;
+       }
+
+       printf("[Index %u]\n", index);
+
+       if (provide_p192) {
+               hash192 = rp->hash192;
+               rand192 = rp->randomizer192;
+       } else {
+               hash192 = NULL;
+               rand192 = NULL;
+       }
+
+       printf("  Hash C from P-192: ");
+       for (i = 0; i < 16; i++)
+               printf("%02x", rp->hash192[i]);
+       printf("\n");
+
+       printf("  Randomizer R with P-192: ");
+       for (i = 0; i < 16; i++)
+               printf("%02x", rp->randomizer192[i]);
+       printf("\n");
+
+       if (len < sizeof(*rp)) {
+               hash256 = NULL;
+               rand256 = NULL;
+               goto done;
+       }
+
+       if (provide_p256) {
+               hash256 = rp->hash256;
+               rand256 = rp->randomizer256;
+       } else {
+               hash256 = NULL;
+               rand256 = NULL;
+       }
+
+       printf("  Hash C from P-256: ");
+       for (i = 0; i < 16; i++)
+               printf("%02x", rp->hash256[i]);
+       printf("\n");
+
+       printf("  Randomizer R with P-256: ");
+       for (i = 0; i < 16; i++)
+               printf("%02x", rp->randomizer256[i]);
+       printf("\n");
+
+done:
+       if (index == index1)
+               add_remote_oob_data(index2, &bdaddr1,
+                                       hash192, rand192, hash256, rand256);
+       else if (index == index2)
+               add_remote_oob_data(index1, &bdaddr2,
+                                       hash192, rand192, hash256, rand256);
+}
+
+static void set_powered_complete(uint8_t status, uint16_t len,
+                                       const void *param, void *user_data)
+{
+       uint16_t index = PTR_TO_UINT(user_data);
+       uint32_t settings;
+       uint8_t val;
+
+       if (status) {
+               fprintf(stderr, "Powering on for index %u failed: %s\n",
+                                               index, mgmt_errstr(status));
+               mainloop_quit();
+               return;
+       }
+
+       settings = get_le32(param);
+
+       if (!(settings & MGMT_SETTING_POWERED)) {
+               fprintf(stderr, "Controller is not powered\n");
+               mainloop_quit();
+               return;
+       }
+
+       if (use_debug) {
+               if (index == index1) {
+                       val = 0x02;
+                       mgmt_send(mgmt, MGMT_OP_SET_DEBUG_KEYS, index, 1, &val,
+                                                       NULL, NULL, NULL);
+               } else if (index == index2) {
+                       val = 0x01;
+                       mgmt_send(mgmt, MGMT_OP_SET_DEBUG_KEYS, index, 1, &val,
+                                                       NULL, NULL, NULL);
+               }
+       }
+
+       if (use_bredr && (provide_p192 || provide_p256)) {
+               mgmt_send(mgmt, MGMT_OP_READ_LOCAL_OOB_DATA, index, 0, NULL,
+                                               read_oob_data_complete,
+                                               UINT_TO_PTR(index), NULL);
+       } else {
+               if (index == index1)
+                       add_remote_oob_data(index2, &bdaddr1,
+                                               NULL, NULL, NULL, NULL);
+               else if (index == index2)
+                       add_remote_oob_data(index1, &bdaddr2,
+                                               NULL, NULL, NULL, NULL);
+       }
+}
+
+static void clear_link_keys(uint16_t index)
+{
+       struct mgmt_cp_load_link_keys cp;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.debug_keys = 0x00;
+       cp.key_count = cpu_to_le16(0);
+
+       mgmt_send(mgmt, MGMT_OP_LOAD_LINK_KEYS, index,
+                                       sizeof(cp), &cp, NULL, NULL, NULL);
+}
+
+static void clear_long_term_keys(uint16_t index)
+{
+       struct mgmt_cp_load_long_term_keys cp;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.key_count = cpu_to_le16(0);
+
+       mgmt_send(mgmt, MGMT_OP_LOAD_LONG_TERM_KEYS, index,
+                                       sizeof(cp), &cp, NULL, NULL, NULL);
+}
+
+static void clear_remote_oob_data(uint16_t index)
+{
+       struct mgmt_cp_remove_remote_oob_data cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, BDADDR_ANY);
+       cp.addr.type = BDADDR_BREDR;
+
+       mgmt_send(mgmt, MGMT_OP_REMOVE_REMOTE_OOB_DATA, index,
+                                       sizeof(cp), &cp, NULL, NULL, NULL);
+}
+
+static void read_info(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
+{
+       const struct mgmt_rp_read_info *rp = param;
+       uint16_t index = PTR_TO_UINT(user_data);
+       uint32_t supported_settings;
+       uint8_t val;
+       char str[18];
+
+       if (status) {
+               fprintf(stderr, "Reading info for index %u failed: %s\n",
+                                               index, mgmt_errstr(status));
+               mainloop_quit();
+               return;
+       }
+
+       ba2str(&rp->bdaddr, str);
+
+       printf("[Index %u]\n", index);
+       printf("  Address: %s\n", str);
+
+       if (index == index1)
+               bacpy(&bdaddr1, &rp->bdaddr);
+       else if (index == index2)
+               bacpy(&bdaddr2, &rp->bdaddr);
+
+       supported_settings = le32_to_cpu(rp->supported_settings);
+
+       if (use_bredr && !(supported_settings & MGMT_SETTING_BREDR)) {
+               fprintf(stderr, "BR/EDR support missing\n");
+               mainloop_quit();
+               return;
+       }
+
+       if (!use_legacy && !(supported_settings & MGMT_SETTING_SSP)) {
+               fprintf(stderr, "Secure Simple Pairing support missing\n");
+               mainloop_quit();
+               return;
+       }
+
+       if (use_le && !(supported_settings & MGMT_SETTING_LE)) {
+               fprintf(stderr, "Low Energy support missing\n");
+               mainloop_quit();
+               return;
+       }
+
+       if (use_sc && !(supported_settings & MGMT_SETTING_SECURE_CONN)) {
+               fprintf(stderr, "Secure Connections support missing\n");
+               mainloop_quit();
+               return;
+       }
+
+       if (use_sconly && !(supported_settings & MGMT_SETTING_SECURE_CONN)) {
+               fprintf(stderr, "Secure Connections Only support missing\n");
+               mainloop_quit();
+               return;
+       }
+
+       if (use_debug && !(supported_settings & MGMT_SETTING_DEBUG_KEYS)) {
+               fprintf(stderr, "Debug keys support missing\n");
+               mainloop_quit();
+               return;
+       }
+
+       if (use_cross && (!(supported_settings & MGMT_SETTING_BREDR) ||
+                               !(supported_settings & MGMT_SETTING_LE))) {
+               fprintf(stderr, "Dual-mode support is support missing\n");
+               mainloop_quit();
+               return;
+       }
+
+       mgmt_register(mgmt, MGMT_EV_PIN_CODE_REQUEST, index,
+                                               pin_code_request_event,
+                                               UINT_TO_PTR(index), NULL);
+
+       mgmt_register(mgmt, MGMT_EV_NEW_LINK_KEY, index,
+                                               new_link_key_event,
+                                               UINT_TO_PTR(index), NULL);
+
+       mgmt_register(mgmt, MGMT_EV_NEW_LONG_TERM_KEY, index,
+                                               new_long_term_key_event,
+                                               UINT_TO_PTR(index), NULL);
+
+       val = 0x00;
+       mgmt_send(mgmt, MGMT_OP_SET_POWERED, index, 1, &val,
+                                               NULL, NULL, NULL);
+
+       clear_link_keys(index);
+       clear_long_term_keys(index);
+       clear_remote_oob_data(index);
+
+       if (use_bredr) {
+               val = 0x01;
+               mgmt_send(mgmt, MGMT_OP_SET_BREDR, index, 1, &val,
+                                                       NULL, NULL, NULL);
+
+               val = use_cross ? 0x01 : 0x00;
+               mgmt_send(mgmt, MGMT_OP_SET_LE, index, 1, &val,
+                                                       NULL, NULL, NULL);
+
+               val = use_legacy ? 0x00 : 0x01;
+               mgmt_send(mgmt, MGMT_OP_SET_SSP, index, 1, &val,
+                                                       NULL, NULL, NULL);
+       } else if (use_le) {
+               val = 0x01;
+               mgmt_send(mgmt, MGMT_OP_SET_LE, index, 1, &val,
+                                                       NULL, NULL, NULL);
+
+               val = use_cross ? 0x01 : 0x00;
+               mgmt_send(mgmt, MGMT_OP_SET_BREDR, index, 1, &val,
+                                                       NULL, NULL, NULL);
+       } else {
+               fprintf(stderr, "Invalid transport for pairing\n");
+               mainloop_quit();
+               return;
+       }
+
+       if (use_random) {
+               bdaddr_t bdaddr;
+
+               str2ba("c0:00:aa:bb:00:00", &bdaddr);
+               bdaddr.b[0] = index;
+
+               mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index,
+                                               6, &bdaddr, NULL, NULL, NULL);
+
+               if (index == index1)
+                       bacpy(&bdaddr1, &bdaddr);
+               else if (index == index2)
+                       bacpy(&bdaddr2, &bdaddr);
+       } else {
+               bdaddr_t bdaddr;
+
+               bacpy(&bdaddr, BDADDR_ANY);
+
+               mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index,
+                                               6, &bdaddr, NULL, NULL, NULL);
+       }
+
+       if (use_sc) {
+               val = 0x01;
+               mgmt_send(mgmt, MGMT_OP_SET_SECURE_CONN, index, 1, &val,
+                                                       NULL, NULL, NULL);
+       } else if (use_sconly) {
+               val = 0x02;
+               mgmt_send(mgmt, MGMT_OP_SET_SECURE_CONN, index, 1, &val,
+                                                       NULL, NULL, NULL);
+       } else {
+               val = 0x00;
+               mgmt_send(mgmt, MGMT_OP_SET_SECURE_CONN, index, 1, &val,
+                                                       NULL, NULL, NULL);
+       }
+
+       val = 0x00;
+       mgmt_send(mgmt, MGMT_OP_SET_DEBUG_KEYS, index, 1, &val,
+                                               NULL, NULL, NULL);
+
+       val = 0x01;
+       mgmt_send(mgmt, MGMT_OP_SET_BONDABLE, index, 1, &val,
+                                               NULL, NULL, NULL);
+
+       val = 0x01;
+       mgmt_send(mgmt, MGMT_OP_SET_POWERED, index, 1, &val,
+                                               set_powered_complete,
+                                               UINT_TO_PTR(index), NULL);
+}
+
+static void read_index_list(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
+{
+       const struct mgmt_rp_read_index_list *rp = param;
+       uint16_t count;
+       int i;
+
+       if (status) {
+               fprintf(stderr, "Reading index list failed: %s\n",
+                                               mgmt_errstr(status));
+               mainloop_quit();
+               return;
+       }
+
+       count = le16_to_cpu(rp->num_controllers);
+
+       if (count < 2) {
+               fprintf(stderr, "At least 2 controllers are required\n");
+               mainloop_quit();
+               return;
+       }
+
+       for (i = 0; i < count; i++) {
+               uint16_t index = cpu_to_le16(rp->index[i]);
+
+               if (index < index1)
+                       index1 = index;
+       }
+
+       for (i = 0; i < count; i++) {
+               uint16_t index = cpu_to_le16(rp->index[i]);
+
+               if (index < index2 && index > index1)
+                       index2 = index;
+       }
+
+       printf("Selecting index %u for initiator\n", index1);
+       printf("Selecting index %u for acceptor\n", index2);
+
+       mgmt_send(mgmt, MGMT_OP_READ_INFO, index1, 0, NULL,
+                               read_info, UINT_TO_PTR(index1), NULL);
+       mgmt_send(mgmt, MGMT_OP_READ_INFO, index2, 0, NULL,
+                               read_info, UINT_TO_PTR(index2), NULL);
+}
+
+static void signal_callback(int signum, void *user_data)
+{
+       switch (signum) {
+       case SIGINT:
+       case SIGTERM:
+               mainloop_quit();
+               break;
+       }
+}
+
+static void usage(void)
+{
+       printf("oobtest - Out-of-band pairing testing\n"
+               "Usage:\n");
+       printf("\toobtest [options]\n");
+       printf("options:\n"
+               "\t-B, --bredr            Use BR/EDR transport\n"
+               "\t-L, --le               Use LE transport\n"
+               "\t-S, --sc               Use Secure Connections\n"
+               "\t-O, --sconly           Use Secure Connections Only\n"
+               "\t-P, --legacy           Use Legacy Pairing\n"
+               "\t-R, --random           Use Static random address\n"
+               "\t-D, --debug            Use Pairing debug keys\n"
+               "\t-C, --cross            Use cross-transport pairing\n"
+               "\t-1, --p192             Provide P-192 OOB data\n"
+               "\t-2, --p256             Provide P-256 OOB data\n"
+               "\t-h, --help             Show help options\n");
+}
+
+static const struct option main_options[] = {
+       { "bredr",   no_argument,       NULL, 'B' },
+       { "le",      no_argument,       NULL, 'L' },
+       { "sc",      no_argument,       NULL, 'S' },
+       { "sconly",  no_argument,       NULL, 'O' },
+       { "legacy",  no_argument,       NULL, 'P' },
+       { "random",  no_argument,       NULL, 'R' },
+       { "static",  no_argument,       NULL, 'R' },
+       { "debug",   no_argument,       NULL, 'D' },
+       { "cross",   no_argument,       NULL, 'C' },
+       { "dual",    no_argument,       NULL, 'C' },
+       { "p192",    no_argument,       NULL, '1' },
+       { "p256",    no_argument,       NULL, '2' },
+       { "version", no_argument,       NULL, 'v' },
+       { "help",    no_argument,       NULL, 'h' },
+       { }
+};
+
+int main(int argc ,char *argv[])
+{
+       sigset_t mask;
+       int exit_status;
+
+       for (;;) {
+               int opt;
+
+               opt = getopt_long(argc, argv, "BLSOPRDC12vh",
+                                               main_options, NULL);
+               if (opt < 0)
+                       break;
+
+               switch (opt) {
+               case 'B':
+                       use_bredr = true;
+                       break;
+               case 'L':
+                       use_le = true;
+                       break;
+               case 'S':
+                       use_sc = true;
+                       break;
+               case 'O':
+                       use_sconly = true;
+                       break;
+               case 'P':
+                       use_legacy = true;
+                       break;
+               case 'R':
+                       use_random = true;
+                       break;
+               case 'D':
+                       use_debug = true;
+                       break;
+               case 'C':
+                       use_cross = true;
+                       break;
+               case '1':
+                       provide_p192 = true;
+                       break;
+               case '2':
+                       provide_p256 = true;
+                       break;
+               case 'v':
+                       printf("%s\n", VERSION);
+                       return EXIT_SUCCESS;
+               case 'h':
+                       usage();
+                       return EXIT_SUCCESS;
+               default:
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (argc - optind > 0) {
+               fprintf(stderr, "Invalid command line parameters\n");
+               return EXIT_FAILURE;
+       }
+
+       if (use_bredr == use_le) {
+               fprintf(stderr, "Specify either --bredr or --le\n");
+               return EXIT_FAILURE;
+       }
+
+       if (use_legacy && !use_bredr) {
+               fprintf(stderr, "Specify --legacy with --bredr\n");
+               return EXIT_FAILURE;
+       }
+
+       if (use_random && !use_le) {
+               fprintf(stderr, "Specify --random with --le\n");
+               return EXIT_FAILURE;
+       }
+
+       if (use_random && use_cross) {
+               fprintf(stderr, "Only --random or --cross can be used\n");
+               return EXIT_FAILURE;
+       }
+
+       if (use_sc && use_sconly) {
+               fprintf(stderr, "Only --sc or --sconly can be used\n");
+               return EXIT_FAILURE;
+       }
+
+       mainloop_init();
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+       sigaddset(&mask, SIGTERM);
+
+       mainloop_set_signal(&mask, signal_callback, NULL, NULL);
+
+       mgmt = mgmt_new_default();
+       if (!mgmt) {
+               fprintf(stderr, "Failed to open management socket\n");
+               return EXIT_FAILURE;
+       }
+
+       if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST,
+                                       MGMT_INDEX_NONE, 0, NULL,
+                                       read_index_list, NULL, NULL)) {
+               fprintf(stderr, "Failed to read index list\n");
+               exit_status = EXIT_FAILURE;
+               goto done;
+       }
+
+       exit_status = mainloop_run();
+
+done:
+       mgmt_unref(mgmt);
+
+       return exit_status;
+}
index cd52cb5..0918eee 100644 (file)
@@ -127,7 +127,7 @@ static char *event_str[EVENT_NUM + 1] = {
        "AMP Status Change",
 };
 
-#define LE_EV_NUM 5
+#define LE_EV_NUM 11
 static char *ev_le_meta_str[LE_EV_NUM + 1] = {
        "Unknown",
        "LE Connection Complete",
@@ -135,6 +135,12 @@ static char *ev_le_meta_str[LE_EV_NUM + 1] = {
        "LE Connection Update Complete",
        "LE Read Remote Used Features Complete",
        "LE Long Term Key Request",
+       "LE Remote Connection Parameter Request",
+       "LE Data Length Change",
+       "LE Read Local P-256 Public Key Complete",
+       "LE Generate DHKey Complete",
+       "LE Enhanced Connection Complete",
+       "LE Direct Advertising Report",
 };
 
 #define CMD_LINKCTL_NUM 60
@@ -446,9 +452,9 @@ static char *error_code_str[ERROR_CODE_NUM + 1] = {
        "SCO Offset Rejected",
        "SCO Interval Rejected",
        "SCO Air Mode Rejected",
-       "Invalid LMP Parameters",
+       "Invalid LMP Parameters / Invalid LL Parameters",
        "Unspecified Error",
-       "Unsupported LMP Parameter Value",
+       "Unsupported LMP Parameter Value / Unsupported LL Parameter Value",
        "Role Change Not Allowed",
        "LMP Response Timeout",
        "LMP Error Transaction Collision",
@@ -475,7 +481,7 @@ static char *error_code_str[ERROR_CODE_NUM + 1] = {
        "Host Busy - Pairing",
        "Connection Rejected due to No Suitable Channel Found",
        "Controller Busy",
-       "Unacceptable Connection Interval",
+       "Unacceptable Connection Parameters",
        "Directed Advertising Timeout",
        "Connection Terminated Due to MIC Failure",
        "Connection Failed to be Established",
@@ -3667,7 +3673,11 @@ static inline void le_meta_ev_dump(int level, struct frame *frm)
        frm->len -= EVT_LE_META_EVENT_SIZE;
 
        p_indent(level, frm);
-       printf("%s\n", ev_le_meta_str[subevent]);
+
+       if (subevent <= LE_EV_NUM)
+               printf("%s\n", ev_le_meta_str[subevent]);
+       else
+               printf("%s\n", ev_le_meta_str[0]);
 
        switch (mevt->subevent) {
        case EVT_LE_CONN_COMPLETE:
index 11ae37f..bdc1eb5 100644 (file)
 #include <sys/socket.h>
 #include <sys/stat.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/rfcomm.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
 
 #include "src/shared/util.h"
 
index ba324be..55b6ac6 100644 (file)
@@ -409,20 +409,20 @@ static gboolean client_received_data(GIOChannel *io, GIOCondition cond,
                                                        gpointer user_data)
 {
        struct test_data *data = tester_get_data();
-       const struct rfcomm_client_data *client_data = data->test_data;
+       const struct rfcomm_client_data *cli = data->test_data;
        int sk;
        ssize_t ret;
        char buf[248];
 
        sk = g_io_channel_unix_get_fd(io);
 
-       ret = read(sk, buf, client_data->data_len);
-       if (client_data->data_len != ret) {
+       ret = read(sk, buf, cli->data_len);
+       if (cli->data_len != ret) {
                tester_test_failed();
                return false;
        }
 
-       if (memcmp(client_data->read_data, buf, client_data->data_len))
+       if (memcmp(cli->read_data, buf, cli->data_len))
                tester_test_failed();
        else
                tester_test_passed();
@@ -431,13 +431,15 @@ static gboolean client_received_data(GIOChannel *io, GIOCondition cond,
 }
 
 static gboolean rc_connect_cb(GIOChannel *io, GIOCondition cond,
-               gpointer user_data)
+                                                       gpointer user_data)
 {
        struct test_data *data = tester_get_data();
-       const struct rfcomm_client_data *client_data = data->test_data;
+       const struct rfcomm_client_data *cli = data->test_data;
        socklen_t len = sizeof(int);
        int sk, err, sk_err;
 
+       tester_print("Connected");
+
        data->io_id = 0;
 
        sk = g_io_channel_unix_get_fd(io);
@@ -447,27 +449,30 @@ static gboolean rc_connect_cb(GIOChannel *io, GIOCondition cond,
        else
                err = -sk_err;
 
-       if (client_data->expected_connect_err &&
-                               err == client_data->expected_connect_err) {
+       if (cli->expected_connect_err && err == cli->expected_connect_err) {
                tester_test_passed();
                return false;
        }
 
-       if (client_data->send_data) {
+       if (cli->send_data) {
                ssize_t ret;
 
-               ret = write(sk, client_data->send_data, client_data->data_len);
-               if (client_data->data_len != ret)
+               tester_print("Writing %u bytes of data", cli->data_len);
+
+               ret = write(sk, cli->send_data, cli->data_len);
+               if (cli->data_len != ret) {
+                       tester_warn("Failed to write %u bytes: %s (%d)",
+                                       cli->data_len, strerror(errno), errno);
                        tester_test_failed();
+               }
 
                return false;
-       } else if (client_data->read_data) {
+       } else if (cli->read_data) {
                g_io_add_watch(io, G_IO_IN, client_received_data, NULL);
                bthost_send_rfcomm_data(hciemu_client_get_host(data->hciemu),
                                                data->conn_handle,
-                                               client_data->client_channel,
-                                               client_data->read_data,
-                                               client_data->data_len);
+                                               cli->client_channel,
+                                               cli->read_data, cli->data_len);
                return false;
        }
 
@@ -483,15 +488,17 @@ static void client_hook_func(const void *data, uint16_t len,
                                                        void *user_data)
 {
        struct test_data *test_data = tester_get_data();
-       const struct rfcomm_client_data *client_data = test_data->test_data;
+       const struct rfcomm_client_data *cli = test_data->test_data;
        ssize_t ret;
 
-       if (client_data->data_len != len) {
+       tester_print("bthost received %u bytes of data", len);
+
+       if (cli->data_len != len) {
                tester_test_failed();
                return;
        }
 
-       ret = memcmp(client_data->send_data, data, len);
+       ret = memcmp(cli->send_data, data, len);
        if (ret)
                tester_test_failed();
        else
@@ -502,15 +509,15 @@ static void server_hook_func(const void *data, uint16_t len,
                                                        void *user_data)
 {
        struct test_data *test_data = tester_get_data();
-       const struct rfcomm_server_data *server_data = test_data->test_data;
+       const struct rfcomm_server_data *srv = test_data->test_data;
        ssize_t ret;
 
-       if (server_data->data_len != len) {
+       if (srv->data_len != len) {
                tester_test_failed();
                return;
        }
 
-       ret = memcmp(server_data->send_data, data, len);
+       ret = memcmp(srv->send_data, data, len);
        if (ret)
                tester_test_failed();
        else
@@ -521,14 +528,14 @@ static void rfcomm_connect_cb(uint16_t handle, uint16_t cid,
                                                void *user_data, bool status)
 {
        struct test_data *data = tester_get_data();
-       const struct rfcomm_client_data *client_data = data->test_data;
+       const struct rfcomm_client_data *cli = data->test_data;
        struct bthost *bthost = hciemu_client_get_host(data->hciemu);
 
-       if (client_data->send_data)
+       if (cli->send_data)
                bthost_add_rfcomm_chan_hook(bthost, handle,
-                                               client_data->client_channel,
+                                               cli->client_channel,
                                                client_hook_func, NULL);
-       else if (client_data->read_data)
+       else if (cli->read_data)
                data->conn_handle = handle;
 }
 
@@ -536,13 +543,13 @@ static void test_connect(const void *test_data)
 {
        struct test_data *data = tester_get_data();
        struct bthost *bthost = hciemu_client_get_host(data->hciemu);
-       const struct rfcomm_client_data *client_data = data->test_data;
+       const struct rfcomm_client_data *cli = data->test_data;
        const uint8_t *client_addr, *master_addr;
        GIOChannel *io;
        int sk;
 
        bthost_add_l2cap_server(bthost, 0x0003, NULL, NULL);
-       bthost_add_rfcomm_server(bthost, client_data->server_channel,
+       bthost_add_rfcomm_server(bthost, cli->server_channel,
                                                rfcomm_connect_cb, NULL);
 
        master_addr = hciemu_get_master_bdaddr(data->hciemu);
@@ -551,7 +558,7 @@ static void test_connect(const void *test_data)
        sk = create_rfcomm_sock((bdaddr_t *) master_addr, 0);
 
        if (connect_rfcomm_sock(sk, (const bdaddr_t *) client_addr,
-                                       client_data->client_channel) < 0) {
+                                       cli->client_channel) < 0) {
                close(sk);
                tester_test_failed();
                return;
@@ -571,20 +578,20 @@ static gboolean server_received_data(GIOChannel *io, GIOCondition cond,
                                                        gpointer user_data)
 {
        struct test_data *data = tester_get_data();
-       const struct rfcomm_server_data *server_data = data->test_data;
+       const struct rfcomm_server_data *srv = data->test_data;
        char buf[1024];
        ssize_t ret;
        int sk;
 
        sk = g_io_channel_unix_get_fd(io);
 
-       ret = read(sk, buf, server_data->data_len);
-       if (ret != server_data->data_len) {
+       ret = read(sk, buf, srv->data_len);
+       if (ret != srv->data_len) {
                tester_test_failed();
                return false;
        }
 
-       if (memcmp(buf, server_data->read_data, server_data->data_len))
+       if (memcmp(buf, srv->read_data, srv->data_len))
                tester_test_failed();
        else
                tester_test_passed();
@@ -596,7 +603,7 @@ static gboolean rfcomm_listen_cb(GIOChannel *io, GIOCondition cond,
                                                        gpointer user_data)
 {
        struct test_data *data = tester_get_data();
-       const struct rfcomm_server_data *server_data = data->test_data;
+       const struct rfcomm_server_data *srv = data->test_data;
        int sk, new_sk;
 
        data->io_id = 0;
@@ -609,17 +616,16 @@ static gboolean rfcomm_listen_cb(GIOChannel *io, GIOCondition cond,
                return false;
        }
 
-       if (server_data->send_data) {
+       if (srv->send_data) {
                ssize_t ret;
 
-               ret = write(new_sk, server_data->send_data,
-                                                       server_data->data_len);
-               if (ret != server_data->data_len)
+               ret = write(new_sk, srv->send_data, srv->data_len);
+               if (ret != srv->data_len)
                        tester_test_failed();
 
                close(new_sk);
                return false;
-       } else if (server_data->read_data) {
+       } else if (srv->read_data) {
                GIOChannel *new_io;
 
                new_io = g_io_channel_unix_new(new_sk);
@@ -643,21 +649,20 @@ static void connection_cb(uint16_t handle, uint16_t cid, void *user_data,
                                                                bool status)
 {
        struct test_data *data = tester_get_data();
-       const struct rfcomm_server_data *server_data = data->test_data;
+       const struct rfcomm_server_data *srv = data->test_data;
        struct bthost *bthost = hciemu_client_get_host(data->hciemu);
 
-       if (server_data->read_data) {
+       if (srv->read_data) {
                data->conn_handle = handle;
                bthost_send_rfcomm_data(bthost, data->conn_handle,
-                                               server_data->client_channel,
-                                               server_data->read_data,
-                                               server_data->data_len);
+                                               srv->client_channel,
+                                               srv->read_data, srv->data_len);
                return;
-       } else if (server_data->data_len) {
+       } else if (srv->data_len) {
                return;
        }
 
-       if (server_data->expected_status == status)
+       if (srv->expected_status == status)
                tester_test_passed();
        else
                tester_test_failed();
@@ -666,21 +671,20 @@ static void connection_cb(uint16_t handle, uint16_t cid, void *user_data,
 static void client_new_conn(uint16_t handle, void *user_data)
 {
        struct test_data *data = tester_get_data();
-       const struct rfcomm_server_data *server_data = data->test_data;
+       const struct rfcomm_server_data *srv = data->test_data;
        struct bthost *bthost;
 
        bthost = hciemu_client_get_host(data->hciemu);
-       bthost_add_rfcomm_chan_hook(bthost, handle,
-                                               server_data->client_channel,
+       bthost_add_rfcomm_chan_hook(bthost, handle, srv->client_channel,
                                                server_hook_func, NULL);
-       bthost_connect_rfcomm(bthost, handle, server_data->client_channel,
+       bthost_connect_rfcomm(bthost, handle, srv->client_channel,
                                                connection_cb, NULL);
 }
 
 static void test_server(const void *test_data)
 {
        struct test_data *data = tester_get_data();
-       const struct rfcomm_server_data *server_data = data->test_data;
+       const struct rfcomm_server_data *srv = data->test_data;
        const uint8_t *master_addr;
        struct bthost *bthost;
        GIOChannel *io;
@@ -688,8 +692,7 @@ static void test_server(const void *test_data)
 
        master_addr = hciemu_get_master_bdaddr(data->hciemu);
 
-       sk = create_rfcomm_sock((bdaddr_t *) master_addr,
-                                               server_data->server_channel);
+       sk = create_rfcomm_sock((bdaddr_t *) master_addr, srv->server_channel);
        if (sk < 0) {
                tester_test_failed();
                return;
index 659bbec..809c240 100644 (file)
 #include <sys/socket.h>
 #include <sys/wait.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/rfcomm.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/rfcomm.h"
 
 static int rfcomm_raw_tty = 0;
 static int auth = 0;
index d033ae0..596e403 100644 (file)
@@ -37,8 +37,8 @@
 #include <sys/time.h>
 #include <sys/socket.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sco.h>
+#include "lib/bluetooth.h"
+#include "lib/sco.h"
 
 #include "src/shared/util.h"
 
index 1fef800..891d388 100644 (file)
 #include <string.h>
 #include <getopt.h>
 #include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
 #include <netinet/in.h>
 
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+
 #include "src/sdp-xml.h"
 
 #ifndef APPLE_AGENT_SVCLASS_ID
old mode 100755 (executable)
new mode 100644 (file)
index 8fe5ce3..805f08d 100644 (file)
 #include <glib.h>
 
 #include "src/shared/util.h"
+#include "src/shared/queue.h"
 #include "src/log.h"
 #include "android/avdtp.h"
 
+#define MAX_SEID 0x3E
+
 struct test_pdu {
        bool valid;
        bool fragmented;
@@ -85,6 +88,7 @@ struct context {
        struct avdtp *session;
        struct avdtp_local_sep *sep;
        struct avdtp_stream *stream;
+       struct queue *lseps;
        guint source;
        guint process;
        int fd;
@@ -229,7 +233,11 @@ static struct context *context_new(uint16_t version, uint16_t imtu,
        err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
        g_assert(err == 0);
 
-       context->session = avdtp_new(sv[0], imtu, omtu, version);
+       context->lseps = queue_new();
+       g_assert(context->lseps);
+
+       context->session = avdtp_new(sv[0], imtu, omtu, version,
+                                                               context->lseps);
        g_assert(context->session != NULL);
 
        channel = g_io_channel_unix_new(sv[1]);
@@ -256,10 +264,16 @@ static struct context *create_context(uint16_t version, gconstpointer data)
        return context_new(version, 672, 672, data);
 }
 
-static void execute_context(struct context *context)
+static void unregister_sep(void *data)
 {
-       g_main_loop_run(context->main_loop);
+       struct avdtp_local_sep *sep = data;
 
+       /* Removed from the queue by caller */
+       avdtp_unregister_sep(NULL, sep);
+}
+
+static void destroy_context(struct context *context)
+{
        if (context->source > 0)
                g_source_remove(context->source);
        avdtp_unref(context->session);
@@ -267,9 +281,18 @@ static void execute_context(struct context *context)
        g_main_loop_unref(context->main_loop);
 
        test_free(context->data);
+       queue_destroy(context->lseps, unregister_sep);
+
        g_free(context);
 }
 
+static void execute_context(struct context *context)
+{
+       g_main_loop_run(context->main_loop);
+
+       destroy_context(context);
+}
+
 static gboolean sep_getcap_ind(struct avdtp *session,
                                        struct avdtp_local_sep *sep,
                                        GSList **caps, uint8_t *err,
@@ -501,15 +524,15 @@ static void test_server(gconstpointer data)
        struct context *context = create_context(0x0100, data);
        struct avdtp_local_sep *sep;
 
-       sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE, AVDTP_MEDIA_TYPE_AUDIO,
+       sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SOURCE,
+                                       AVDTP_MEDIA_TYPE_AUDIO,
                                        0x00, FALSE, &sep_ind, &sep_cfm,
                                        context);
+       g_assert(sep);
 
        g_idle_add(send_pdu, context);
 
        execute_context(context);
-
-       avdtp_unregister_sep(sep);
 }
 
 static void test_server_1_3(gconstpointer data)
@@ -517,14 +540,14 @@ static void test_server_1_3(gconstpointer data)
        struct context *context = create_context(0x0103, data);
        struct avdtp_local_sep *sep;
 
-       sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE, AVDTP_MEDIA_TYPE_AUDIO,
+       sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SOURCE,
+                                       AVDTP_MEDIA_TYPE_AUDIO,
                                        0x00, TRUE, &sep_ind, NULL, context);
+       g_assert(sep);
 
        g_idle_add(send_pdu, context);
 
        execute_context(context);
-
-       avdtp_unregister_sep(sep);
 }
 
 static void test_server_1_3_sink(gconstpointer data)
@@ -532,14 +555,14 @@ static void test_server_1_3_sink(gconstpointer data)
        struct context *context = create_context(0x0103, data);
        struct avdtp_local_sep *sep;
 
-       sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
+       sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SINK,
+                                       AVDTP_MEDIA_TYPE_AUDIO,
                                        0x00, TRUE, &sep_ind, NULL, context);
+       g_assert(sep);
 
        g_idle_add(send_pdu, context);
 
        execute_context(context);
-
-       avdtp_unregister_sep(sep);
 }
 
 static void test_server_0_sep(gconstpointer data)
@@ -551,6 +574,64 @@ static void test_server_0_sep(gconstpointer data)
        execute_context(context);
 }
 
+static void test_server_seid(gconstpointer data)
+{
+       struct context *context = create_context(0x0103, data);
+       struct avdtp_local_sep *sep;
+       unsigned int i;
+
+       for (i = 0; i < sizeof(int) * 8; i++) {
+               sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SINK,
+                                               AVDTP_MEDIA_TYPE_AUDIO,
+                                               0x00, TRUE, &sep_ind, NULL,
+                                               context);
+               g_assert(sep);
+       }
+
+       /* Now add (MAX_SEID + 1) SEP -> it shall fail */
+       sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SINK,
+                                               AVDTP_MEDIA_TYPE_AUDIO,
+                                               0x00, TRUE, &sep_ind, NULL,
+                                               context);
+       g_assert(!sep);
+
+       destroy_context(context);
+}
+
+static void test_server_seid_duplicate(gconstpointer data)
+{
+       struct context *context = create_context(0x0103, data);
+       struct avdtp_local_sep *sep;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SINK,
+                                               AVDTP_MEDIA_TYPE_AUDIO,
+                                               0x00, TRUE, &sep_ind, NULL,
+                                               context);
+               g_assert(sep);
+       }
+
+       /* Remove 1st element */
+       sep = queue_peek_head(context->lseps);
+       g_assert(sep);
+
+       avdtp_unregister_sep(context->lseps, sep);
+
+       /* Now register new element */
+       sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SINK,
+                                               AVDTP_MEDIA_TYPE_AUDIO,
+                                               0x00, TRUE, &sep_ind, NULL,
+                                               context);
+       g_assert(sep);
+
+       /* Check SEID ids with DISCOVER */
+
+       g_idle_add(send_pdu, context);
+
+       execute_context(context);
+}
+
 static gboolean sep_getcap_ind_frg(struct avdtp *session,
                                        struct avdtp_local_sep *sep,
                                        GSList **caps, uint8_t *err,
@@ -596,15 +677,15 @@ static void test_server_frg(gconstpointer data)
        struct context *context = context_new(0x0100, 48, 48, data);
        struct avdtp_local_sep *sep;
 
-       sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE, AVDTP_MEDIA_TYPE_AUDIO,
+       sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SOURCE,
+                                               AVDTP_MEDIA_TYPE_AUDIO,
                                                0x00, TRUE, &sep_ind_frg,
                                                NULL, context);
+       g_assert(sep);
 
        g_idle_add(send_pdu, context);
 
        execute_context(context);
-
-       avdtp_unregister_sep(sep);
 }
 
 static void discover_cb(struct avdtp *session, GSList *seps,
@@ -679,16 +760,15 @@ static void test_client(gconstpointer data)
        struct context *context = create_context(0x0100, data);
        struct avdtp_local_sep *sep;
 
-       sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
-                                       0x00, FALSE, NULL, &sep_cfm,
-                                       context);
+       sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SINK,
+                                       AVDTP_MEDIA_TYPE_AUDIO,
+                                       0x00, FALSE, NULL, &sep_cfm, context);
+
        context->sep = sep;
 
        avdtp_discover(context->session, discover_cb, context);
 
        execute_context(context);
-
-       avdtp_unregister_sep(sep);
 }
 
 static void test_client_1_3(gconstpointer data)
@@ -696,16 +776,15 @@ static void test_client_1_3(gconstpointer data)
        struct context *context = create_context(0x0103, data);
        struct avdtp_local_sep *sep;
 
-       sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
-                                       0x00, TRUE, NULL, &sep_cfm,
-                                       context);
+       sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SINK,
+                                       AVDTP_MEDIA_TYPE_AUDIO,
+                                       0x00, TRUE, NULL, &sep_cfm, context);
+
        context->sep = sep;
 
        avdtp_discover(context->session, discover_cb, context);
 
        execute_context(context);
-
-       avdtp_unregister_sep(sep);
 }
 
 static void test_client_frg(gconstpointer data)
@@ -713,16 +792,15 @@ static void test_client_frg(gconstpointer data)
        struct context *context = context_new(0x0100, 48, 48, data);
        struct avdtp_local_sep *sep;
 
-       sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
-                                       0x00, TRUE, NULL, &sep_cfm,
-                                       context);
+       sep = avdtp_register_sep(context->lseps, AVDTP_SEP_TYPE_SINK,
+                                       AVDTP_MEDIA_TYPE_AUDIO,
+                                       0x00, TRUE, NULL, &sep_cfm, context);
+
        context->sep = sep;
 
        avdtp_discover(context->session, discover_cb, context);
 
        execute_context(context);
-
-       avdtp_unregister_sep(sep);
 }
 
 int main(int argc, char *argv[])
@@ -738,6 +816,11 @@ int main(int argc, char *argv[])
         * To verify that the following procedures are implemented according to
         * their specification in AVDTP.
         */
+       define_test("/TP/SIG/SMG/BV-06-C-SEID-1", test_server_seid,
+                       raw_pdu(0x00));
+       define_test("/TP/SIG/SMG/BV-06-C-SEID-2", test_server_seid_duplicate,
+                       raw_pdu(0x00, 0x01),
+                       raw_pdu(0x02, 0x01, 0x08, 0x08, 0x04, 0x08));
        define_test("/TP/SIG/SMG/BV-05-C", test_client,
                        raw_pdu(0x00, 0x01));
        define_test("/TP/SIG/SMG/BV-06-C", test_server,
index 919a83b..043634b 100644 (file)
@@ -29,9 +29,9 @@
 
 #include <glib.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/sdp.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/sdp.h"
 
 #include "src/eir.h"
 
index 5f5ad1b..2edcacb 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <glib.h>
 
+#include "lib/bluetooth.h"
 #include "lib/uuid.h"
 #include "src/shared/util.h"
 #include "src/shared/att.h"
@@ -43,6 +44,7 @@
 #include "src/shared/gatt-db.h"
 #include "src/shared/gatt-server.h"
 #include "src/shared/gatt-client.h"
+#include "src/shared/tester.h"
 
 struct test_pdu {
        bool valid;
@@ -66,7 +68,6 @@ struct test_data {
 };
 
 struct context {
-       GMainLoop *main_loop;
        struct bt_gatt_client *client;
        struct bt_gatt_server *server;
        struct bt_att *att;
@@ -77,6 +78,7 @@ struct context {
        int fd;
        unsigned int pdu_offset;
        const struct test_data *data;
+       struct bt_gatt_request *req;
 };
 
 #define data(args...) ((const unsigned char[]) { args })
@@ -102,7 +104,7 @@ struct context {
                data.source_db = db;                                    \
                data.pdu_list = g_malloc(sizeof(pdus));                 \
                memcpy(data.pdu_list, pdus, sizeof(pdus));              \
-               g_test_add_data_func(name, &data, function);            \
+               tester_add(name, &data, NULL, function, NULL);          \
        } while (0)
 
 #define define_test_att(name, function, bt_uuid, test_step, args...)   \
@@ -140,7 +142,7 @@ struct context {
                raw_pdu(0x04, 0x04, 0x00, 0x04, 0x00),                  \
                raw_pdu(0x05, 0x01, 0x04, 0x00, 0x01, 0x29),            \
                raw_pdu(0x08, 0x05, 0x00, 0x08, 0x00, 0x03, 0x28),      \
-               raw_pdu(0x09, 0x07, 0x06, 0x00, 0x02, 0x07, 0x00, 0x29, \
+               raw_pdu(0x09, 0x07, 0x06, 0x00, 0x0a, 0x07, 0x00, 0x29, \
                                0x2a),                                  \
                raw_pdu(0x08, 0x07, 0x00, 0x08, 0x00, 0x03, 0x28),      \
                raw_pdu(0x01, 0x08, 0x07, 0x00, 0x0a),                  \
@@ -149,14 +151,82 @@ struct context {
 
 #define PRIMARY_DISC_SMALL_DB                                          \
                raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),      \
-               raw_pdu(0x11, 0x06, 0x10, 0xF0, 0x15, 0xF0, 0x00, 0x18, \
+               raw_pdu(0x11, 0x06, 0x10, 0xF0, 0x17, 0xF0, 0x00, 0x18, \
                                0xFF, 0xFF, 0xFF, 0xFF, 0x0a, 0x18)
 
+#define PRIMARY_DISC_LARGE_DB_1                                                \
+               raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),      \
+               raw_pdu(0x11, 0x06, 0x10, 0x00, 0x13, 0x00, 0x01, 0x18, \
+                       0x20, 0x00, 0x29, 0x00, 0x0A, 0xA0,             \
+                       0x30, 0x00, 0x32, 0x00, 0x0B, 0xA0),            \
+               raw_pdu(0x10, 0x33, 0x00, 0xff, 0xff, 0x00, 0x28),      \
+               raw_pdu(0x11, 0x06, 0x40, 0x00, 0x46, 0x00, 0x00, 0x18, \
+                       0x50, 0x00, 0x52, 0x00, 0x0B, 0xA0,             \
+                       0x60, 0x00, 0x6B, 0x00, 0x0B, 0xA0),            \
+               raw_pdu(0x10, 0x6C, 0x00, 0xff, 0xff, 0x00, 0x28),      \
+               raw_pdu(0x11, 0x06, 0x70, 0x00, 0x76, 0x00, 0x0B, 0xA0, \
+                       0x80, 0x00, 0x85, 0x00, 0x0B, 0xA0),            \
+               raw_pdu(0x10, 0x86, 0x00, 0xff, 0xff, 0x00, 0x28),      \
+               raw_pdu(0x11, 0x14, 0x90, 0x00, 0x96, 0x00,             \
+                       0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, \
+                       0x00, 0x00, 0x00, 0x00, 0x0C, 0xA0, 0x00, 0x00),\
+               raw_pdu(0x10, 0x97, 0x00, 0xff, 0xff, 0x00, 0x28),      \
+               raw_pdu(0x11, 0x06, 0xa0, 0x00, 0xb1, 0x00, 0x0f, 0xa0),\
+               raw_pdu(0x10, 0xb2, 0x00, 0xff, 0xff, 0x00, 0x28),      \
+               raw_pdu(0x11, 0x14, 0xC0, 0x00, 0xDD, 0x00,             \
+                       0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, \
+                       0x00, 0x00, 0x00, 0x00, 0x0C, 0xA0, 0x00, 0x00),\
+               raw_pdu(0x10, 0xde, 0x00, 0xff, 0xff, 0x00, 0x28),      \
+               raw_pdu(0x01, 0x10, 0xde, 0x00, 0x0a)
+
 #define SECONDARY_DISC_SMALL_DB                                                \
                raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28),      \
-               raw_pdu(0x11, 0x06, 0x01, 0x00, 0x0F, 0x00, 0x0a, 0x18),\
-               raw_pdu(0x10, 0x10, 0x00, 0xff, 0xff, 0x01, 0x28),      \
-               raw_pdu(0x01, 0x10, 0x10, 0x00, 0x0a)
+               raw_pdu(0x11, 0x06, 0x01, 0x00, 0x10, 0x00, 0x0a, 0x18),\
+               raw_pdu(0x10, 0x11, 0x00, 0xff, 0xff, 0x01, 0x28),      \
+               raw_pdu(0x01, 0x10, 0x11, 0x00, 0x0a)
+
+#define INCLUDE_DISC_SMALL_DB                                          \
+               raw_pdu(0x08, 0x10, 0xf0, 0x17, 0xf0, 0x02, 0x28),      \
+               raw_pdu(0x09, 0x08, 0x11, 0xf0, 0x01, 0x00, 0x0f, 0x00, \
+                       0x0a, 0x18),                                    \
+               raw_pdu(0x08, 0x12, 0xf0, 0x17, 0xf0, 0x02, 0x28),      \
+               raw_pdu(0x01, 0x08, 0x12, 0xf0, 0x0a),                  \
+               raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x02, 0x28),      \
+               raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a)
+
+#define CHARACTERISTIC_DISC_SMALL_DB                                   \
+               raw_pdu(0x08, 0x10, 0xf0, 0x17, 0xf0, 0x03, 0x28),      \
+               raw_pdu(0x09, 0x07, 0x12, 0xf0, 0x02, 0x13, 0xf0, 0x00, \
+                       0x2a),                                          \
+               raw_pdu(0x08, 0x13, 0xf0, 0x17, 0xf0, 0x03, 0x28),      \
+               raw_pdu(0x09, 0x15, 0x14, 0xf0, 0x02, 0x15, 0xf0, 0xef, \
+                       0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, 0x00, \
+                       0x00, 0x00, 0x00, 0x09, 0xB0, 0x00, 0x00),      \
+               raw_pdu(0x08, 0x15, 0xf0, 0x17, 0xf0, 0x03, 0x28),      \
+               raw_pdu(0x09, 0x07, 0x16, 0xf0, 0x02, 0x17, 0xf0, 0x01, \
+                       0x2a),                                          \
+               raw_pdu(0x08, 0x17, 0xf0, 0x17, 0xf0, 0x03, 0x28),      \
+               raw_pdu(0x01, 0x08, 0x17, 0xf0, 0x0a),                  \
+               raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),      \
+               raw_pdu(0x09, 0x07, 0x02, 0x00, 0x32, 0x03, 0x00, 0x29, \
+                       0x2a),                                          \
+               raw_pdu(0x08, 0x03, 0x00, 0x10, 0x00, 0x03, 0x28),      \
+               raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a)
+
+#define DESCRIPTOR_DISC_SMALL_DB                                       \
+               raw_pdu(0x04, 0x04, 0x00, 0x10, 0x00),                  \
+               raw_pdu(0x05, 0x01, 0x04, 0x00, 0x02, 0x29, 0x05, 0x00, \
+                       0x01, 0x29),                                    \
+               raw_pdu(0x04, 0x06, 0x00, 0x10, 0x00),                  \
+               raw_pdu(0x01, 0x04, 0x06, 0x00, 0x0a)
+
+#define SMALL_DB_DISCOVERY_PDUS                                                \
+               PRIMARY_DISC_SMALL_DB,                                  \
+               SECONDARY_DISC_SMALL_DB,                                \
+               INCLUDE_DISC_SMALL_DB,                                  \
+               CHARACTERISTIC_DISC_SMALL_DB,                           \
+               DESCRIPTOR_DISC_SMALL_DB
+
 
 #define SERVER_MTU_EXCHANGE_PDU raw_pdu(0x02, 0x17, 0x00)
 
@@ -182,13 +252,6 @@ static bt_uuid_t uuid_char_128 = {
                        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
 };
 
-static void test_debug(const char *str, void *user_data)
-{
-       const char *prefix = user_data;
-
-       g_print("%s%s\n", prefix, str);
-}
-
 static void test_free(gconstpointer user_data)
 {
        const struct test_data *data = user_data;
@@ -197,18 +260,64 @@ static void test_free(gconstpointer user_data)
        g_free(data->pdu_list);
 }
 
+typedef void (*test_step_t)(struct context *context);
+
+struct test_step {
+       test_step_t func;
+       test_step_t post_func;
+       uint16_t handle;
+       uint16_t end_handle;
+       uint8_t uuid[16];
+       uint8_t expected_att_ecode;
+       const uint8_t *value;
+       uint16_t length;
+};
+
+static void destroy_context(struct context *context)
+{
+       if (context->source > 0)
+               g_source_remove(context->source);
+
+       if (context->req)
+               bt_gatt_request_unref(context->req);
+
+       bt_gatt_client_unref(context->client);
+       bt_gatt_server_unref(context->server);
+       gatt_db_unref(context->client_db);
+       gatt_db_unref(context->server_db);
+
+       if (context->att)
+               bt_att_unref(context->att);
+
+       test_free(context->data);
+       g_free(context);
+}
+
 static gboolean context_quit(gpointer user_data)
 {
        struct context *context = user_data;
+       const struct test_step *step = context->data->step;
 
        if (context->process > 0)
                g_source_remove(context->process);
 
-       g_main_loop_quit(context->main_loop);
+       if (step && step->post_func)
+               step->post_func(context);
+
+       destroy_context(context);
+
+       tester_test_passed();
 
        return FALSE;
 }
 
+static void test_debug(const char *str, void *user_data)
+{
+       const char *prefix = user_data;
+
+       tester_debug("%s%s", prefix, str);
+}
+
 static gboolean send_pdu(gpointer user_data)
 {
        struct context *context = user_data;
@@ -219,12 +328,19 @@ static gboolean send_pdu(gpointer user_data)
 
        len = write(context->fd, pdu->data, pdu->size);
 
-       if (g_test_verbose())
-               util_hexdump('<', pdu->data, len, test_debug, "GATT: ");
+       util_hexdump('<', pdu->data, len, test_debug, "GATT: ");
 
        g_assert_cmpint(len, ==, pdu->size);
 
        context->process = 0;
+
+       pdu = &context->data->pdu_list[context->pdu_offset];
+       if (pdu->valid && (pdu->size == 0)) {
+               test_debug("(no action expected)", "GATT: ");
+               context->pdu_offset++;
+               return send_pdu(context);
+       }
+
        return FALSE;
 }
 
@@ -243,6 +359,7 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
                                                        gpointer user_data)
 {
        struct context *context = user_data;
+       const struct test_step *step = context->data->step;
        const struct test_pdu *pdu;
        unsigned char buf[512];
        ssize_t len;
@@ -262,13 +379,23 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
 
        g_assert(len > 0);
 
-       if (g_test_verbose())
-               util_hexdump('>', buf, len, test_debug, "GATT: ");
+       util_hexdump('>', buf, len, test_debug, "GATT: ");
 
        g_assert_cmpint(len, ==, pdu->size);
 
        g_assert(memcmp(buf, pdu->data, pdu->size) == 0);
 
+       /* Empty client PDU means to trigger something out-of-band. */
+       pdu = &context->data->pdu_list[context->pdu_offset];
+
+       if (pdu->valid && (pdu->size == 0)) {
+               context->pdu_offset++;
+               test_debug("triggering server action", "Empty client pdu: ");
+               g_assert(step && step->func);
+               step->func(context);
+               return TRUE;
+       }
+
        context_process(context);
 
        return TRUE;
@@ -278,21 +405,9 @@ static void print_debug(const char *str, void *user_data)
 {
        const char *prefix = user_data;
 
-       g_print("%s%s\n", prefix, str);
+       tester_debug("%s%s", prefix, str);
 }
 
-typedef void (*test_step_t)(struct context *context);
-
-struct test_step {
-       test_step_t func;
-       uint16_t handle;
-       uint16_t end_handle;
-       uint8_t uuid[16];
-       uint8_t expected_att_ecode;
-       const uint8_t *value;
-       uint16_t length;
-};
-
 struct db_attribute_test_data {
        struct gatt_db_attribute *match;
        bool found;
@@ -467,24 +582,16 @@ static struct context *create_context(uint16_t mtu, gconstpointer data)
        const struct test_data *test_data = data;
        GIOChannel *channel;
        int err, sv[2];
-       struct bt_att *att;
-
-       context->main_loop = g_main_loop_new(NULL, FALSE);
-       g_assert(context->main_loop);
 
        err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
        g_assert(err == 0);
 
-       att = bt_att_new(sv[0]);
-       g_assert(att);
+       context->att = bt_att_new(sv[0]);
+       g_assert(context->att);
 
        switch (test_data->context_type) {
        case ATT:
-               context->att = att;
-
-               if (g_test_verbose())
-                       bt_att_set_debug(context->att, print_debug, "bt_att:",
-                                                                       NULL);
+               bt_att_set_debug(context->att, print_debug, "bt_att:", NULL);
 
                bt_gatt_exchange_mtu(context->att, mtu, NULL, NULL, NULL);
                break;
@@ -492,31 +599,26 @@ static struct context *create_context(uint16_t mtu, gconstpointer data)
                context->server_db = gatt_db_ref(test_data->source_db);
                g_assert(context->server_db);
 
-               context->server = bt_gatt_server_new(context->server_db, att,
-                                                                       mtu);
+               context->server = bt_gatt_server_new(context->server_db,
+                                                       context->att, mtu);
                g_assert(context->server);
 
-               if (g_test_verbose())
-                       bt_gatt_server_set_debug(context->server, print_debug,
+               bt_gatt_server_set_debug(context->server, print_debug,
                                                "bt_gatt_server:", NULL);
-               bt_att_unref(att);
                break;
        case CLIENT:
                context->client_db = gatt_db_new();
                g_assert(context->client_db);
 
-               context->client = bt_gatt_client_new(context->client_db, att,
-                                                                       mtu);
+               context->client = bt_gatt_client_new(context->client_db,
+                                                       context->att, mtu);
                g_assert(context->client);
 
-               if (g_test_verbose())
-                       bt_gatt_client_set_debug(context->client, print_debug,
+               bt_gatt_client_set_debug(context->client, print_debug,
                                                "bt_gatt_client:", NULL);
 
                bt_gatt_client_set_ready_handler(context->client,
                                                client_ready_cb, context, NULL);
-
-               bt_att_unref(att);
                break;
        default:
                break;
@@ -547,37 +649,14 @@ static void generic_search_cb(bool success, uint8_t att_ecode,
 {
        struct context *context = user_data;
 
+       bt_gatt_request_unref(context->req);
+       context->req = NULL;
+
        g_assert(success);
 
        context_quit(context);
 }
 
-static void destroy_context(struct context *context)
-{
-       if (context->source > 0)
-               g_source_remove(context->source);
-
-       bt_gatt_client_unref(context->client);
-       bt_gatt_server_unref(context->server);
-       gatt_db_unref(context->client_db);
-       gatt_db_unref(context->server_db);
-
-       if (context->att)
-               bt_att_unref(context->att);
-
-       g_main_loop_unref(context->main_loop);
-
-       test_free(context->data);
-       g_free(context);
-}
-
-static void execute_context(struct context *context)
-{
-       g_main_loop_run(context->main_loop);
-
-       destroy_context(context);
-}
-
 static void test_read_cb(bool success, uint8_t att_ecode,
                                        const uint8_t *value, uint16_t length,
                                        void *user_data)
@@ -603,9 +682,9 @@ static void test_read(struct context *context)
                                                test_read_cb, context, NULL));
 }
 
-const uint8_t read_data_1[] = {0x01, 0x02, 0x03};
+static const uint8_t read_data_1[] = {0x01, 0x02, 0x03};
 
-const struct test_step test_read_1 = {
+static const struct test_step test_read_1 = {
        .handle = 0x0003,
        .func = test_read,
        .expected_att_ecode = 0,
@@ -613,244 +692,835 @@ const struct test_step test_read_1 = {
        .length = 0x03
 };
 
-const struct test_step test_read_2 = {
+static const struct test_step test_read_2 = {
        .handle = 0x0000,
        .func = test_read,
        .expected_att_ecode = 0x01,
 };
 
-const struct test_step test_read_3 = {
+static const struct test_step test_read_3 = {
        .handle = 0x0003,
        .func = test_read,
        .expected_att_ecode = 0x02,
 };
 
-const struct test_step test_read_4 = {
+static const struct test_step test_read_4 = {
        .handle = 0x0003,
        .func = test_read,
        .expected_att_ecode = 0x08,
 };
 
-static void att_write_cb(struct gatt_db_attribute *att, int err,
-                                                               void *user_data)
-{
-       g_assert(!err);
-}
-
-static struct gatt_db_attribute *add_char_with_value(struct gatt_db *db,
-                                       struct gatt_db_attribute *service_att,
-                                       bt_uuid_t *uuid,
-                                       uint32_t att_permissions,
-                                       uint8_t char_properties,
-                                       const void *value, size_t len)
-{
-       struct gatt_db_attribute *attrib;
-
-       attrib = gatt_db_service_add_characteristic(service_att, uuid,
-                                                               att_permissions,
-                                                               char_properties,
-                                                               NULL, NULL,
-                                                               NULL);
+static const struct test_step test_read_5 = {
+       .handle = 0x0003,
+       .func = test_read,
+       .expected_att_ecode = 0x05,
+};
 
-       gatt_db_attribute_write(attrib, 0, value, len, 0x00, NULL, att_write_cb,
-                                                                       NULL);
+static const struct test_step test_read_6 = {
+       .handle = 0x0003,
+       .func = test_read,
+       .expected_att_ecode = 0x0c,
+};
 
-       return attrib;
-}
+static const struct test_step test_read_7 = {
+       .handle = 0x0004,
+       .func = test_read,
+       .expected_att_ecode = 0x00,
+       .value = read_data_1,
+       .length = 0x03
+};
 
-static struct gatt_db_attribute *add_ccc(struct gatt_db_attribute *chrc_att,
-                                                               bool writable)
-{
-       struct gatt_db_attribute *desc_att;
-       bt_uuid_t uuid;
-       uint32_t permissions = BT_ATT_PERM_READ;
-       uint16_t tmp;
+static const struct test_step test_read_8 = {
+       .handle = 0x0004,
+       .func = test_read,
+       .expected_att_ecode = 0x02,
+};
 
-       if (writable)
-               permissions |= BT_ATT_PERM_WRITE;
+static const struct test_step test_read_9 = {
+       .handle = 0x0004,
+       .func = test_read,
+       .expected_att_ecode = 0x08,
+};
 
-       bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
-       desc_att = gatt_db_service_add_descriptor(chrc_att, &uuid, permissions,
-                                                       NULL, NULL, NULL);
+static const struct test_step test_read_10 = {
+       .handle = 0x0004,
+       .func = test_read,
+       .expected_att_ecode = 0x05,
+};
 
-       tmp = 0x0000;
-       gatt_db_attribute_write(desc_att, 0, (uint8_t *)&tmp, sizeof(uint16_t),
-                                               0x00, NULL, att_write_cb, NULL);
+static const struct test_step test_read_11 = {
+       .handle = 0x0004,
+       .func = test_read,
+       .expected_att_ecode = 0x0c,
+};
 
-       return desc_att;
-}
+static const struct test_step test_read_12 = {
+       .handle = 0x0003,
+       .func = test_read,
+       .expected_att_ecode = 0x80,
+};
 
-static struct gatt_db_attribute *
-add_user_description(struct gatt_db_attribute *chrc_att, const char *desc,
-                                                               bool writable)
+static void test_write_cb(bool success, uint8_t att_ecode, void *user_data)
 {
-       struct gatt_db_attribute *desc_att;
-       bt_uuid_t uuid;
-       uint32_t permissions = BT_ATT_PERM_READ;
-
-       if (writable)
-               permissions |= BT_ATT_PERM_WRITE;
-
-       bt_uuid16_create(&uuid, GATT_CHARAC_USER_DESC_UUID);
-       desc_att = gatt_db_service_add_descriptor(chrc_att, &uuid, permissions,
-                                                       NULL, NULL, NULL);
+       struct context *context = user_data;
+       const struct test_step *step = context->data->step;
 
-       gatt_db_attribute_write(desc_att, 0, (uint8_t *)desc, strlen(desc),
-                                               0x00, NULL, att_write_cb, NULL);
+       g_assert(att_ecode == step->expected_att_ecode);
 
-       return desc_att;
+       context_quit(context);
 }
 
-
-typedef struct gatt_db_attribute (*add_service_func) (struct gatt_db *db,
-                                                       uint16_t handle,
-                                                       bool primary,
-                                                       uint16_t extra_handles);
-
-static struct gatt_db_attribute *
-add_device_information_service(struct gatt_db *db, uint16_t handle,
-                                       bool primary, uint16_t extra_handles)
+static void test_write(struct context *context)
 {
-       bt_uuid_t uuid;
-       struct gatt_db_attribute *serv_att;
-
-       bt_string_to_uuid(&uuid, DEVICE_INFORMATION_UUID);
-       serv_att = gatt_db_insert_service(db, handle, &uuid, primary,
-                                                       1 + extra_handles);
+       const struct test_step *step = context->data->step;
 
-       return serv_att;
+       g_assert(bt_gatt_client_write_value(context->client, step->handle,
+                               step->value, step->length, test_write_cb,
+                               context, NULL));
 }
 
-static struct gatt_db_attribute *add_gap(struct gatt_db *db, uint16_t handle,
-                                                       bool primary,
-                                                       uint16_t extra_handles)
-{
-       bt_uuid_t uuid;
-       struct gatt_db_attribute *serv_att;
-
-       bt_string_to_uuid(&uuid, GAP_UUID);
-       serv_att = gatt_db_insert_service(db, handle, &uuid, primary,
-                                                       1 + extra_handles);
+static const uint8_t write_data_1[] = {0x01, 0x02, 0x03};
 
-       return serv_att;
-}
+static const struct test_step test_write_1 = {
+       .handle = 0x0007,
+       .func = test_write,
+       .expected_att_ecode = 0,
+       .value = write_data_1,
+       .length = 0x03
+};
 
-static struct gatt_db *make_service_data_1_db(void)
-{
-       struct gatt_db *db = gatt_db_new();
-       struct gatt_db_attribute *serv_att, *chrc_att;
-       bt_uuid_t uuid;
+static const struct test_step test_write_2 = {
+       .handle = 0x0000,
+       .func = test_write,
+       .expected_att_ecode = 0x01,
+       .value = write_data_1,
+       .length = 0x03
+};
 
-       bt_uuid16_create(&uuid, 0x1801);
-       serv_att = gatt_db_insert_service(db, 0x0001, &uuid, true, 4);
+static const struct test_step test_write_3 = {
+       .handle = 0x0007,
+       .func = test_write,
+       .expected_att_ecode = 0x03,
+       .value = write_data_1,
+       .length = 0x03
+};
 
-       bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME);
-       chrc_att = add_char_with_value(db, serv_att, &uuid, BT_ATT_PERM_READ,
-                                       BT_GATT_CHRC_PROP_READ, "BlueZ", 5);
+static const struct test_step test_write_4 = {
+       .handle = 0x0007,
+       .func = test_write,
+       .expected_att_ecode = 0x08,
+       .value = write_data_1,
+       .length = 0x03
+};
 
-       add_user_description(chrc_att, "Device Name", false);
+static const struct test_step test_write_5 = {
+       .handle = 0x0007,
+       .func = test_write,
+       .expected_att_ecode = 0x05,
+       .value = write_data_1,
+       .length = 0x03
+};
 
-       gatt_db_service_set_active(serv_att, true);
+static const struct test_step test_write_6 = {
+       .handle = 0x0007,
+       .func = test_write,
+       .expected_att_ecode = 0x0c,
+       .value = write_data_1,
+       .length = 0x03
+};
 
-       bt_uuid16_create(&uuid, 0x180d);
-       serv_att = gatt_db_insert_service(db, 0x0005, &uuid, true, 4);
+static const struct test_step test_write_7 = {
+       .handle = 0x0008,
+       .func = test_write,
+       .expected_att_ecode = 0,
+       .value = write_data_1,
+       .length = 0x03
+};
 
-       bt_uuid16_create(&uuid, GATT_CHARAC_MANUFACTURER_NAME_STRING);
-       chrc_att = gatt_db_service_add_characteristic(serv_att, &uuid,
-                                                       BT_ATT_PERM_READ,
-                                                       BT_GATT_CHRC_PROP_READ,
-                                                       NULL, NULL, NULL);
+static const struct test_step test_write_8 = {
+       .handle = 0x0000,
+       .func = test_write,
+       .expected_att_ecode = 0x01,
+       .value = write_data_1,
+       .length = 0x03
+};
 
-       add_user_description(chrc_att, "Manufacturer Name", false);
+static const struct test_step test_write_9 = {
+       .handle = 0x0008,
+       .func = test_write,
+       .expected_att_ecode = 0x03,
+       .value = write_data_1,
+       .length = 0x03
+};
 
-       gatt_db_service_set_active(serv_att, true);
+static const struct test_step test_write_10 = {
+       .handle = 0x0008,
+       .func = test_write,
+       .expected_att_ecode = 0x08,
+       .value = write_data_1,
+       .length = 0x03
+};
 
-       return db;
-}
+static const struct test_step test_write_11 = {
+       .handle = 0x0008,
+       .func = test_write,
+       .expected_att_ecode = 0x05,
+       .value = write_data_1,
+       .length = 0x03
+};
 
-/*
- * Defined Test database 1:
- * Tiny database fits into a single minimum sized-pdu.
- * Satisfies:
- * 3. At least one primary seervice at the MAX handle
- * For each / all databases:
- * X 7. at least one service uuid with multiple instances
- * X 8. Some simple services, some with included services
- * X 9. an instance where handle of included service comes before the including
- * service
- * X 11. Simple characteristics (no desc) and complex characteristics
- *       (multiple descriptors)
- * X 12. Instances of complex chars with 16-bit and 128-bit uuids
- * (although not in scrambled order)
- */
+static const struct test_step test_write_12 = {
+       .handle = 0x0008,
+       .func = test_write,
+       .expected_att_ecode = 0x0c,
+       .value = write_data_1,
+       .length = 0x03
+};
 
-static struct gatt_db *make_test_spec_small_db(void)
+static void test_write_without_response(struct context *context)
 {
-       struct gatt_db *db;
-       struct gatt_db_attribute *serv_att, *dis_att;
-       bt_uuid_t uuid;
-       const char *manuf_device_string = "BlueZ";
-       const char *device_name_string = "BlueZ Unit Tester";
-       const char *user_desc_manuf_name = "Manufacturer Name";
-       uint16_t u16_value;
-       uint8_t u8_value;
-
-       db = gatt_db_new();
+       const struct test_step *step = context->data->step;
 
-       dis_att = add_device_information_service(db, 0x0001, false, 15);
+       g_assert(bt_gatt_client_write_without_response(context->client,
+                                                       step->handle,
+                                                       false, step->value,
+                                                       step->length));
+}
 
-       bt_uuid16_create(&uuid, GATT_CHARAC_MANUFACTURER_NAME_STRING);
-       add_char_with_value(db, dis_att, &uuid, BT_ATT_PERM_READ,
-                                               BT_GATT_CHRC_PROP_READ,
-                                               manuf_device_string,
-                                               strlen(manuf_device_string));
-       add_ccc(dis_att, false);
-       add_user_description(dis_att, user_desc_manuf_name, false);
+static const struct test_step test_write_without_response_1 = {
+       .handle = 0x0007,
+       .func = test_write_without_response,
+       .expected_att_ecode = 0,
+       .value = write_data_1,
+       .length = 0x03
+};
 
-       gatt_db_service_set_active(dis_att, true);
+static bool local_counter(uint32_t *sign_cnt, void *user_data)
+{
+       static uint32_t cnt = 0;
 
-       serv_att = add_gap(db, 0xF010, true, 5);
+       *sign_cnt = cnt++;
 
-       gatt_db_service_add_included(serv_att, dis_att);
+       return true;
+}
 
-       bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME);
-       add_char_with_value(db, serv_att, &uuid, BT_ATT_PERM_READ,
-                                               BT_GATT_CHRC_PROP_READ,
-                                               device_name_string,
-                                               strlen(device_name_string));
+static void test_signed_write(struct context *context)
+{
+       const struct test_step *step = context->data->step;
+       uint8_t key[16] = {0xD8, 0x51, 0x59, 0x48, 0x45, 0x1F, 0xEA, 0x32, 0x0D,
+                               0xC0, 0x5A, 0x2E, 0x88, 0x30, 0x81, 0x88 };
 
-       bt_string_to_uuid(&uuid, "0000B009-0000-0000-0123-456789abcdef");
-       u8_value = 0x09;
-       add_char_with_value(db, serv_att, &uuid, BT_ATT_PERM_READ,
-                                               BT_GATT_CHRC_PROP_READ,
-                                               &u8_value, sizeof(uint8_t));
+       g_assert(bt_att_set_local_key(context->att, key, local_counter,
+                                                               context));
 
-       gatt_db_service_set_active(serv_att, true);
+       g_assert(bt_gatt_client_write_without_response(context->client,
+                                                       step->handle,
+                                                       true, step->value,
+                                                       step->length));
+}
 
-       u16_value = 0x0000; /* "Unknown" Appearance */
-       bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE);
-       add_char_with_value(db, serv_att, &uuid, BT_ATT_PERM_READ,
-                                       BT_GATT_CHRC_PROP_READ, &u16_value,
-                                       sizeof(uint16_t));
+static const struct test_step test_signed_write_1 = {
+       .handle = 0x0007,
+       .func = test_signed_write,
+       .expected_att_ecode = 0,
+       .value = write_data_1,
+       .length = 0x03
+};
 
+static void test_signed_write_seclevel(struct context *context)
+{
+       const struct test_step *step = context->data->step;
+       uint8_t key[16] = {0xD8, 0x51, 0x59, 0x48, 0x45, 0x1F, 0xEA, 0x32, 0x0D,
+                               0xC0, 0x5A, 0x2E, 0x88, 0x30, 0x81, 0x88 };
 
-       serv_att = add_device_information_service(db, 0xFFFF, true, 0);
+       g_assert(bt_att_set_local_key(context->att, key, local_counter,
+                                                               context));
 
-       gatt_db_service_set_active(serv_att, true);
+       g_assert(bt_att_set_sec_level(context->att, BT_SECURITY_MEDIUM));
 
-       return db;
+       g_assert(bt_gatt_client_write_without_response(context->client,
+                                                       step->handle,
+                                                       true, step->value,
+                                                       step->length));
 }
 
-static void test_client(gconstpointer data)
-{
-       struct context *context = create_context(512, data);
+static const struct test_step test_signed_write_seclevel_1 = {
+       .handle = 0x0007,
+       .func = test_signed_write_seclevel,
+       .expected_att_ecode = 0,
+       .value = write_data_1,
+       .length = 0x03
+};
 
-       execute_context(context);
+static void att_write_cb(struct gatt_db_attribute *att, int err,
+                                                               void *user_data)
+{
+       g_assert(!err);
 }
 
-static void test_server(gconstpointer data)
+static struct gatt_db_attribute *add_char_with_value(struct gatt_db *db,
+                                       struct gatt_db_attribute *service_att,
+                                       bt_uuid_t *uuid,
+                                       uint32_t att_permissions,
+                                       uint8_t char_properties,
+                                       const void *value, size_t len)
 {
-       struct context *context = create_context(512, data);
+       struct gatt_db_attribute *attrib;
+
+       attrib = gatt_db_service_add_characteristic(service_att, uuid,
+                                                               att_permissions,
+                                                               char_properties,
+                                                               NULL, NULL,
+                                                               NULL);
+
+       g_assert(attrib != NULL);
+
+       gatt_db_attribute_write(attrib, 0, value, len, 0x00, NULL,
+                                                       att_write_cb, NULL);
+
+       return attrib;
+}
+
+static struct gatt_db_attribute *
+add_desc_with_value(struct gatt_db_attribute *att, bt_uuid_t *uuid,
+                               uint32_t att_perms, const uint8_t *value,
+                               size_t len)
+{
+       struct gatt_db_attribute *desc_att;
+
+       desc_att = gatt_db_service_add_descriptor(att, uuid, att_perms, NULL,
+                                                               NULL, NULL);
+
+       gatt_db_attribute_write(desc_att, 0, value, len, 0x00, NULL,
+                                                       att_write_cb, NULL);
+
+       return desc_att;
+}
+
+enum gatt_type {
+       PRIMARY,
+       SECONDARY,
+       INCLUDE,
+       CHARACTERISTIC,
+       DESCRIPTOR
+};
+
+struct att_handle_spec {
+       uint16_t handle;
+       const char *uuid;
+       enum gatt_type type;
+       uint8_t char_properties;
+       uint32_t att_permissions;
+       const uint8_t *value;
+       size_t len;
+       bool valid;
+};
+
+#define PRIMARY_SERVICE(start_handle, srv_uuid, num_handles)   \
+       {                                                       \
+               .valid = true,                                  \
+               .handle = start_handle,                         \
+               .type = PRIMARY,                                \
+               .uuid = srv_uuid,                               \
+               .len = num_handles,                             \
+       }
+
+#define SECONDARY_SERVICE(start_handle, srv_uuid, num_handles) \
+       {                                                       \
+               .valid = true,                                  \
+               .handle = start_handle,                         \
+               .type = SECONDARY,                              \
+               .uuid = srv_uuid,                               \
+               .len = num_handles,                             \
+       }
+
+#define INCLUDE(include_handle)                                \
+       {                                               \
+               .valid = true,                          \
+               .type = INCLUDE,                        \
+               .handle = include_handle,               \
+       }
+
+#define STR(x) #x
+
+#define CHARACTERISTIC(chr_uuid, permissions, properties, bytes...)    \
+       {                                                               \
+               .valid = true,                                          \
+               .type = CHARACTERISTIC,                                 \
+               .uuid = STR(chr_uuid),                                  \
+               .att_permissions = permissions,                         \
+               .char_properties = properties,                          \
+               .value = data(bytes),                                   \
+               .len = sizeof(data(bytes)),                             \
+       }
+
+#define CHARACTERISTIC_STR(chr_uuid, permissions, properties, string)  \
+               {                                                       \
+               .valid = true,                                          \
+               .type = CHARACTERISTIC,                                 \
+               .uuid = STR(chr_uuid),                                  \
+               .att_permissions = permissions,                         \
+               .char_properties = properties,                          \
+               .value = (uint8_t *)string,                             \
+               .len = strlen(string),                                  \
+       }
+
+#define DESCRIPTOR(desc_uuid, permissions, bytes...)   \
+       {                                               \
+               .valid = true,                          \
+               .type = DESCRIPTOR,                     \
+               .uuid = STR(desc_uuid),                 \
+               .att_permissions = permissions,         \
+               .value = data(bytes),                   \
+               .len = sizeof(data(bytes)),             \
+       }
+
+#define DESCRIPTOR_STR(desc_uuid, permissions, string) \
+       {                                               \
+               .valid = true,                          \
+               .type = DESCRIPTOR,                     \
+               .uuid = STR(desc_uuid),                 \
+               .att_permissions = permissions,         \
+               .value = (uint8_t *)string,             \
+               .len = strlen(string),                  \
+       }
+
+
+static struct gatt_db *make_db(const struct att_handle_spec *spec)
+{
+       struct gatt_db *db = gatt_db_new();
+       struct gatt_db_attribute *att, *include_att;
+       bt_uuid_t uuid;
+
+       att = include_att = NULL;
+
+       for (; spec->valid; spec++) {
+               switch (spec->type) {
+               case PRIMARY:
+               case SECONDARY:
+                       bt_string_to_uuid(&uuid, spec->uuid);
+
+                       if (att)
+                               gatt_db_service_set_active(att, true);
+
+                       att = gatt_db_insert_service(db, spec->handle, &uuid,
+                                       spec->type == PRIMARY, spec->len);
+                       break;
+
+               case INCLUDE:
+                       include_att = gatt_db_get_attribute(db, spec->handle);
+
+                       gatt_db_service_add_included(att, include_att);
+                       break;
+
+               case CHARACTERISTIC:
+                       bt_string_to_uuid(&uuid, spec->uuid);
+
+                       add_char_with_value(db, att, &uuid,
+                                                       spec->att_permissions,
+                                                       spec->char_properties,
+                                                       spec->value, spec->len);
+
+                       break;
+
+               case DESCRIPTOR:
+                       bt_string_to_uuid(&uuid, spec->uuid);
+
+                       add_desc_with_value(att, &uuid, spec->att_permissions,
+                                                       spec->value, spec->len);
+
+                       break;
+               };
+       }
+
+       if (att)
+               gatt_db_service_set_active(att, true);
+
+       return db;
+}
+
+static struct gatt_db *make_service_data_1_db(void)
+{
+       const struct att_handle_spec specs[] = {
+               PRIMARY_SERVICE(0x0001, GATT_UUID, 4),
+               CHARACTERISTIC_STR(GATT_CHARAC_DEVICE_NAME, BT_ATT_PERM_READ,
+                                       BT_GATT_CHRC_PROP_READ, "BlueZ"),
+               DESCRIPTOR_STR(GATT_CHARAC_USER_DESC_UUID, BT_ATT_PERM_READ,
+                                                               "Device Name"),
+               PRIMARY_SERVICE(0x0005, HEART_RATE_UUID, 4),
+               CHARACTERISTIC_STR(GATT_CHARAC_MANUFACTURER_NAME_STRING,
+                                               BT_ATT_PERM_READ,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_WRITE, ""),
+               DESCRIPTOR_STR(GATT_CHARAC_USER_DESC_UUID, BT_ATT_PERM_READ,
+                                                       "Manufacturer Name"),
+               { }
+       };
+
+       return make_db(specs);
+}
+
+/*
+ * Defined Test database 1:
+ * Tiny database fits into a single minimum sized-pdu.
+ * Satisfies requirements:
+ * 3. At least one primary service at the MAX handle
+ * 7. at least one service uuid with multiple instances
+ * 8. Some simple services, some with included services
+ * 9. an instance where handle of included service comes before the including
+ * service
+ * 11. Simple characteristics (no desc) and complex characteristics
+ *     (multiple descriptors)
+ * 12. Instances of complex chars with 16-bit and 128-bit uuids
+ *     (although not in scrambled order)
+ */
+
+static struct gatt_db *make_test_spec_small_db(void)
+{
+       const struct att_handle_spec specs[] = {
+               SECONDARY_SERVICE(0x0001, DEVICE_INFORMATION_UUID, 16),
+               CHARACTERISTIC_STR(GATT_CHARAC_MANUFACTURER_NAME_STRING,
+                                               BT_ATT_PERM_READ |
+                                               BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_NOTIFY |
+                                               BT_GATT_CHRC_PROP_INDICATE,
+                                               "BlueZ"),
+               DESCRIPTOR(GATT_CLIENT_CHARAC_CFG_UUID, BT_ATT_PERM_READ |
+                                               BT_ATT_PERM_WRITE, 0x00, 0x00),
+               DESCRIPTOR_STR(GATT_CHARAC_USER_DESC_UUID, BT_ATT_PERM_READ,
+                                                       "Manufacturer Name"),
+               PRIMARY_SERVICE(0xF010, GAP_UUID, 8),
+               INCLUDE(0x0001),
+               CHARACTERISTIC_STR(GATT_CHARAC_DEVICE_NAME, BT_ATT_PERM_READ,
+                                                       BT_GATT_CHRC_PROP_READ,
+                                                       "BlueZ Unit Tester"),
+               CHARACTERISTIC(0000B009-0000-0000-0123-456789abcdef,
+                                               BT_ATT_PERM_READ,
+                                               BT_GATT_CHRC_PROP_READ, 0x09),
+               CHARACTERISTIC(GATT_CHARAC_APPEARANCE, BT_ATT_PERM_READ,
+                                       BT_GATT_CHRC_PROP_READ, 0x00, 0x00),
+               PRIMARY_SERVICE(0xFFFF, DEVICE_INFORMATION_UUID, 1),
+               { }
+       };
+
+       return make_db(specs);
+}
+
+/*
+ * Defined Test database 2:
+ * Large Database with 128-bit services at the end
+ * Satisfies requirements:
+ * 4. at least one primary service without any include or characteristic
+ *    at the max handle.
+ * 6. at least one secondary service
+ * 7. at least one each of 16-bit and 128-bit UUID with multiple instances
+ * 8. some simple services, some some with included services
+ * 9. one instance where an included service comes before the including
+ * 10. one or more services with both 16-bit and 128-bit service UUIDs
+ * 11. simple and complex characteristics
+ * 12. complex chars with 16-bit and 128-bit uuids
+ */
+
+#define STRING_512BYTES "11111222223333344444555556666677777888889999900000" \
+                       "11111222223333344444555556666677777888889999900000" \
+                       "11111222223333344444555556666677777888889999900000" \
+                       "11111222223333344444555556666677777888889999900000" \
+                       "11111222223333344444555556666677777888889999900000" \
+                       "11111222223333344444555556666677777888889999900000" \
+                       "11111222223333344444555556666677777888889999900000" \
+                       "11111222223333344444555556666677777888889999900000" \
+                       "11111222223333344444555556666677777888889999900000" \
+                       "11111222223333344444555556666677777888889999900000" \
+                       "111112222233"
+
+static struct gatt_db *make_test_spec_large_db_1(void)
+{
+       const struct att_handle_spec specs[] = {
+               PRIMARY_SERVICE(0x0080, "a00b", 6),
+               CHARACTERISTIC(0xb008, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                       BT_GATT_CHRC_PROP_READ |
+                                       BT_GATT_CHRC_PROP_WRITE,
+                                       0x08),
+               DESCRIPTOR(0xb015, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE, 0x01),
+               DESCRIPTOR(0xb016, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE, 0x02),
+               DESCRIPTOR(0xb017, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE |
+                                               BT_ATT_PERM_ENCRYPT, 0x03),
+
+               SECONDARY_SERVICE(0x0001, "a00d", 6),
+               INCLUDE(0x0080),
+               CHARACTERISTIC(0xb00c, BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ,
+                                                                       0x0C),
+               CHARACTERISTIC(0000b00b-0000-0000-0123-456789abcdef,
+                               BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ, 0x0B),
+
+               PRIMARY_SERVICE(0x0010, GATT_UUID, 4),
+               CHARACTERISTIC(GATT_CHARAC_SERVICE_CHANGED, BT_ATT_PERM_READ,
+                                               BT_GATT_CHRC_PROP_INDICATE,
+                                               0x01, 0x00, 0xFF, 0xFF),
+               DESCRIPTOR(GATT_CLIENT_CHARAC_CFG_UUID,
+                                       BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                       0x00, 0x00),
+
+               PRIMARY_SERVICE(0x0020, "a00a", 10),
+               INCLUDE(0x0001),
+               CHARACTERISTIC(0xb001, BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ,
+                                                                       0x01),
+               CHARACTERISTIC_STR(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_WRITE,
+                                               STRING_512BYTES),
+               CHARACTERISTIC_STR(0xb002, BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_WRITE,
+                                               "1111122222333334444455555"
+                                               "6666677777888889999900000"),
+               CHARACTERISTIC(0xb003, BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_WRITE, 0x03),
+
+               PRIMARY_SERVICE(0x0030, "a00b", 3),
+               CHARACTERISTIC(0xb007, BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_WRITE, 0x07),
+
+               PRIMARY_SERVICE(0x0040, GAP_UUID, 7),
+               CHARACTERISTIC_STR(GATT_CHARAC_DEVICE_NAME, BT_ATT_PERM_READ,
+                                       BT_GATT_CHRC_PROP_READ,
+                                       "Test Database"),
+               CHARACTERISTIC(GATT_CHARAC_APPEARANCE, BT_ATT_PERM_READ,
+                                               BT_GATT_CHRC_PROP_READ, 17),
+               CHARACTERISTIC(GATT_CHARAC_PERIPHERAL_PREF_CONN,
+                               BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ,
+                               0x64, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x07, 0xD0),
+
+               PRIMARY_SERVICE(0x0050, "a00b", 3),
+               CHARACTERISTIC(0xb006, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                       BT_GATT_CHRC_PROP_READ |
+                                       BT_GATT_CHRC_PROP_WRITE |
+                                       BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP |
+                                       BT_GATT_CHRC_PROP_NOTIFY |
+                                       BT_GATT_CHRC_PROP_INDICATE, 0x06),
+
+               PRIMARY_SERVICE(0x0060, "a00b", 12),
+               CHARACTERISTIC(0xb004, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                       BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_WRITE, 0x04),
+               CHARACTERISTIC(0xb004, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                       BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_WRITE, 0x04),
+               DESCRIPTOR(GATT_SERVER_CHARAC_CFG_UUID,
+                                       BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                       0x00, 0x00),
+               CHARACTERISTIC(0xb004, 0, 0, 0x04),
+               DESCRIPTOR(0xb012, 0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                               0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+                               0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33,
+                               0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11,
+                               0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
+                               0x00, 0x11, 0x22, 0x33),
+               CHARACTERISTIC(0xb004, BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ,
+                                                                       0x04),
+               DESCRIPTOR(0xb012, BT_ATT_PERM_READ, 0x11, 0x22, 0x33, 0x44,
+                               0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22,
+                               0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+                               0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                               0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
+                               0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33),
+
+               PRIMARY_SERVICE(0x0070, "a00b", 7),
+               CHARACTERISTIC(0xb005, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_WRITE |
+                                               BT_GATT_CHRC_PROP_EXT_PROP,
+                                               0x05),
+               DESCRIPTOR(GATT_CHARAC_EXT_PROPER_UUID, BT_ATT_PERM_READ, 0x03,
+                                                                       0x00),
+               DESCRIPTOR_STR(GATT_CHARAC_USER_DESC_UUID,
+                                       BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
+               DESCRIPTOR(GATT_CHARAC_FMT_UUID, 0x04, 0x00, 0x01, 0x30, 0x01,
+                                                               0x11, 0x31),
+               DESCRIPTOR(0000d5d4-0000-0000-0123-456789abcdef,
+                                                       BT_ATT_PERM_READ, 0x44),
+
+               /* 0x0080 service defined earlier, included in 0x0001 */
+
+               PRIMARY_SERVICE(0x0090, "0000a00c-0000-0000-0123-456789abcdef",
+                                                                       7),
+               INCLUDE(0x0001),
+               CHARACTERISTIC(0000b009-0000-0000-0123-456789abcdef,
+                                       BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                       BT_GATT_CHRC_PROP_READ |
+                                       BT_GATT_CHRC_PROP_WRITE |
+                                       BT_GATT_CHRC_PROP_EXT_PROP, 0x09),
+               DESCRIPTOR(GATT_CHARAC_EXT_PROPER_UUID, BT_ATT_PERM_READ, 0x01,
+                                                                       0x00),
+               DESCRIPTOR(0000d9d2-0000-0000-0123-456789abcdef,
+                               BT_ATT_PERM_READ | BT_ATT_PERM_WRITE, 0x22),
+               DESCRIPTOR(0000d9d3-0000-0000-0123-456789abcdef,
+                                               BT_ATT_PERM_WRITE, 0x33),
+
+               PRIMARY_SERVICE(0x00a0, "a00f", 18),
+               CHARACTERISTIC_STR(0xb00e, BT_ATT_PERM_READ,
+                                       BT_GATT_CHRC_PROP_READ, "Length is "),
+               DESCRIPTOR(GATT_CHARAC_FMT_UUID, BT_ATT_PERM_READ, 0x19, 0x00,
+                                               0x00, 0x30, 0x01, 0x00, 0x00),
+               CHARACTERISTIC(0xb00f, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_WRITE, 0x65),
+               DESCRIPTOR(GATT_CHARAC_FMT_UUID, BT_ATT_PERM_READ, 0x04, 0x00,
+                                               0x01, 0x27, 0x01, 0x01, 0x00),
+               CHARACTERISTIC(0xb006, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_WRITE,
+                                               0x34, 0x12),
+               DESCRIPTOR(GATT_CHARAC_FMT_UUID, BT_ATT_PERM_READ, 0x06, 0x00,
+                                               0x10, 0x27, 0x01, 0x02, 0x00),
+               CHARACTERISTIC(0xb007, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_WRITE,
+                                               0x04, 0x03, 0x02, 0x01),
+               DESCRIPTOR(GATT_CHARAC_FMT_UUID, BT_ATT_PERM_READ, 0x08, 0x00,
+                                               0x17, 0x27, 0x01, 0x03, 0x00),
+               CHARACTERISTIC(0xb010, BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ,
+                                       0x65, 0x34, 0x12, 0x04, 0x03, 0x02,
+                                       0x01),
+               DESCRIPTOR(GATT_CHARAC_AGREG_FMT_UUID, BT_ATT_PERM_READ, 0xA6,
+                                               0x00, 0xa9, 0x00, 0xac, 0x00),
+               CHARACTERISTIC(0xb011, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_AUTH, 0x012),
+
+               PRIMARY_SERVICE(0x00C0, "0000a00c-0000-0000-0123-456789abcdef",
+                                                                       30),
+               CHARACTERISTIC(0xb00a, BT_ATT_PERM_READ, BT_GATT_CHRC_PROP_READ,
+                                                                       0x0A),
+               CHARACTERISTIC_STR(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_WRITE,
+                                               "111112222233333444445"),
+               DESCRIPTOR(0xb012, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                               0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                               0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11),
+               CHARACTERISTIC_STR(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_WRITE,
+                                               "2222233333444445555566"),
+               DESCRIPTOR(0xb013, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                               0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                               0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11,
+                               0x22),
+               CHARACTERISTIC_STR(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_WRITE,
+                                               "33333444445555566666777"),
+               DESCRIPTOR(0xb014, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                               0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                               0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11,
+                               0x22, 0x33),
+               CHARACTERISTIC(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_WRITE,
+                                               0x11, 0x22, 0x33, 0x44, 0x55,
+                                               0x66, 0x77, 0x88, 0x99, 0x00,
+                                               0x11, 0x22, 0x33, 0x44, 0x55,
+                                               0x66, 0x77, 0x88, 0x99, 0x00,
+                                               0x11, 0x22, 0x33, 0x44, 0x55,
+                                               0x66, 0x77, 0x88, 0x99, 0x00,
+                                               0x11, 0x22, 0x33, 0x44, 0x55,
+                                               0x66, 0x77, 0x88, 0x99, 0x00,
+                                               0x11, 0x22, 0x33),
+               DESCRIPTOR(0xb012, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                               0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                               0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
+                               0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
+                               0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11, 0x22,
+                               0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+                               0x11, 0x22, 0x33),
+               CHARACTERISTIC(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_WRITE,
+                                               0x11, 0x22, 0x33, 0x44, 0x55,
+                                               0x66, 0x77, 0x88, 0x99, 0x00,
+                                               0x11, 0x22, 0x33, 0x44, 0x55,
+                                               0x66, 0x77, 0x88, 0x99, 0x00,
+                                               0x11, 0x22, 0x33, 0x44, 0x55,
+                                               0x66, 0x77, 0x88, 0x99, 0x00,
+                                               0x11, 0x22, 0x33, 0x44, 0x55,
+                                               0x66, 0x77, 0x88, 0x99, 0x00,
+                                               0x11, 0x22, 0x33, 0x44),
+               DESCRIPTOR(0xb013, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                               0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                               0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
+                               0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
+                               0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11, 0x22,
+                               0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+                               0x11, 0x22, 0x33, 0x44),
+               CHARACTERISTIC(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_WRITE,
+                                               0x11, 0x22, 0x33, 0x44, 0x55,
+                                               0x66, 0x77, 0x88, 0x99, 0x00,
+                                               0x11, 0x22, 0x33, 0x44, 0x55,
+                                               0x66, 0x77, 0x88, 0x99, 0x00,
+                                               0x11, 0x22, 0x33, 0x44, 0x55,
+                                               0x66, 0x77, 0x88, 0x99, 0x00,
+                                               0x11, 0x22, 0x33, 0x44, 0x55,
+                                               0x66, 0x77, 0x88, 0x99, 0x00,
+                                               0x11, 0x22, 0x33, 0x44, 0x55),
+               DESCRIPTOR(0xb014, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                               0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                               0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
+                               0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
+                               0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11, 0x22,
+                               0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+                               0x11, 0x22, 0x33, 0x44, 0x55),
+               CHARACTERISTIC_STR(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_WRITE,
+                                               "1111122222333334444455555"
+                                               "666667777788888999"),
+               DESCRIPTOR(0xb012, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                               0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                               0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
+                               0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
+                               0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11, 0x22,
+                               0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+                               0x11, 0x22, 0x33),
+               CHARACTERISTIC_STR(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_WRITE,
+                                               "2222233333444445555566666"
+                                               "7777788888999990000"),
+               DESCRIPTOR(0xb013, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                               0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                               0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
+                               0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
+                               0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11, 0x22,
+                               0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+                               0x11, 0x22, 0x33, 0x44),
+               CHARACTERISTIC_STR(0xb002, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                                               BT_GATT_CHRC_PROP_READ |
+                                               BT_GATT_CHRC_PROP_WRITE,
+                                               "3333344444555556666677777"
+                                               "88888999990000011111"),
+               DESCRIPTOR(0xb014, BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+                               0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                               0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
+                               0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
+                               0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x11, 0x22,
+                               0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+                               0x11, 0x22, 0x33, 0x44, 0x55),
+               { }
+       };
+
+       return make_db(specs);
+}
+
+static void test_client(gconstpointer data)
+{
+       create_context(512, data);
+}
+
+static void test_server(gconstpointer data)
+{
+       struct context *context = create_context(512, data);
        ssize_t len;
        const struct test_pdu pdu = SERVER_MTU_EXCHANGE_PDU;
 
@@ -858,10 +1528,7 @@ static void test_server(gconstpointer data)
 
        g_assert_cmpint(len, ==, pdu.size);
 
-       if (g_test_verbose())
-               util_hexdump('<', pdu.data, len, test_debug, "GATT: ");
-
-       execute_context(context);
+       util_hexdump('<', pdu.data, len, test_debug, "GATT: ");
 }
 
 static void test_search_primary(gconstpointer data)
@@ -869,47 +1536,45 @@ static void test_search_primary(gconstpointer data)
        struct context *context = create_context(512, data);
        const struct test_data *test_data = data;
 
-       bt_gatt_discover_all_primary_services(context->att, test_data->uuid,
+       context->req = bt_gatt_discover_all_primary_services(context->att,
+                                                       test_data->uuid,
                                                        generic_search_cb,
                                                        context, NULL);
-
-       execute_context(context);
 }
 
 static void test_search_included(gconstpointer data)
 {
        struct context *context = create_context(512, data);
 
-       bt_gatt_discover_included_services(context->att, 0x0001, 0xffff,
+       context->req = bt_gatt_discover_included_services(context->att,
+                                                       0x0001, 0xffff,
                                                        generic_search_cb,
                                                        context, NULL);
-
-       execute_context(context);
 }
 
 static void test_search_chars(gconstpointer data)
 {
        struct context *context = create_context(512, data);
 
-       g_assert(bt_gatt_discover_characteristics(context->att, 0x0010, 0x0020,
+       context->req = bt_gatt_discover_characteristics(context->att,
+                                                       0x0010, 0x0020,
                                                        generic_search_cb,
-                                                       context, NULL));
-
-       execute_context(context);
+                                                       context, NULL);
+       g_assert(context->req);
 }
 
 static void test_search_descs(gconstpointer data)
 {
        struct context *context = create_context(512, data);
 
-       g_assert(bt_gatt_discover_descriptors(context->att, 0x0013, 0x0016,
+       context->req = bt_gatt_discover_descriptors(context->att,
+                                                       0x0013, 0x0016,
                                                        generic_search_cb,
-                                                       context, NULL));
-
-       execute_context(context);
+                                                       context, NULL);
+       g_assert(context->req);
 }
 
-const struct test_step test_read_by_type_1 = {
+static const struct test_step test_read_by_type_1 = {
        .handle = 0x0001,
        .end_handle = 0xffff,
        .expected_att_ecode = 0x0a,
@@ -917,31 +1582,31 @@ const struct test_step test_read_by_type_1 = {
        .length = 0x03
 };
 
-const struct test_step test_read_by_type_2 = {
+static const struct test_step test_read_by_type_2 = {
        .handle = 0x0001,
        .end_handle = 0xffff,
        .expected_att_ecode = 0x02,
 };
 
-const struct test_step test_read_by_type_3 = {
+static const struct test_step test_read_by_type_3 = {
        .handle = 0x0001,
        .end_handle = 0xffff,
        .expected_att_ecode = 0x0a,
 };
 
-const struct test_step test_read_by_type_4 = {
+static const struct test_step test_read_by_type_4 = {
        .handle = 0x0001,
        .end_handle = 0xffff,
        .expected_att_ecode = 0x08,
 };
 
-const struct test_step test_read_by_type_5 = {
+static const struct test_step test_read_by_type_5 = {
        .handle = 0x0001,
        .end_handle = 0xffff,
        .expected_att_ecode = 0x05,
 };
 
-const struct test_step test_read_by_type_6 = {
+static const struct test_step test_read_by_type_6 = {
        .handle = 0x0001,
        .end_handle = 0xffff,
        .expected_att_ecode = 0x0c,
@@ -954,10 +1619,10 @@ static void multiple_read_cb(bool success, uint8_t att_ecode,
        struct context *context = user_data;
        const struct test_step *step = context->data->step;
 
-       g_assert(att_ecode == step->expected_att_ecode);
+       g_assert_cmpint(att_ecode, ==, step->expected_att_ecode);
 
        if (success) {
-               g_assert(length == step->length);
+               g_assert_cmpint(length, ==, step->length);
                g_assert(memcmp(value, step->value, length) == 0);
        }
 
@@ -977,7 +1642,7 @@ static void test_multiple_read(struct context *context)
                                                NULL));
 }
 
-const struct test_step test_multiple_read_1 = {
+static const struct test_step test_multiple_read_1 = {
        .handle = 0x0003,
        .end_handle = 0x0007,
        .func = test_multiple_read,
@@ -985,35 +1650,35 @@ const struct test_step test_multiple_read_1 = {
        .length = 0x03
 };
 
-const struct test_step test_multiple_read_2 = {
+static const struct test_step test_multiple_read_2 = {
        .handle = 0x0003,
        .end_handle = 0x0007,
        .func = test_multiple_read,
        .expected_att_ecode = 0x02
 };
 
-const struct test_step test_multiple_read_3 = {
+static const struct test_step test_multiple_read_3 = {
        .handle = 0x0003,
        .end_handle = 0x0007,
        .func = test_multiple_read,
        .expected_att_ecode = 0x01
 };
 
-const struct test_step test_multiple_read_4 = {
+static const struct test_step test_multiple_read_4 = {
        .handle = 0x0003,
        .end_handle = 0x0007,
        .func = test_multiple_read,
        .expected_att_ecode = 0x08
 };
 
-const struct test_step test_multiple_read_5 = {
+static const struct test_step test_multiple_read_5 = {
        .handle = 0x0003,
        .end_handle = 0x0007,
        .func = test_multiple_read,
        .expected_att_ecode = 0x05
 };
 
-const struct test_step test_multiple_read_6 = {
+static const struct test_step test_multiple_read_6 = {
        .handle = 0x0003,
        .end_handle = 0x0007,
        .func = test_multiple_read,
@@ -1056,18 +1721,245 @@ static void test_read_by_type(gconstpointer data)
        g_assert(bt_gatt_read_by_type(context->att, step->handle,
                                        step->end_handle, test_data->uuid,
                                        read_by_type_cb, context, NULL));
+}
+
+static void test_long_read(struct context *context)
+{
+       const struct test_step *step = context->data->step;
+
+       g_assert(bt_gatt_client_read_long_value(context->client, step->handle,
+                                               0, multiple_read_cb, context,
+                                               NULL));
+}
+
+static const struct test_step test_long_read_1 = {
+       .handle = 0x0003,
+       .func = test_long_read,
+       .expected_att_ecode = 0,
+       .value = read_data_1,
+       .length = 0x03
+};
+
+/* The maximum length of an attribute value shall be 512 octets. */
+static const uint8_t long_data_2[512] = { [0 ... 511] = 0xff };
+
+static const struct test_step test_long_read_2 = {
+       .handle = 0x0003,
+       .func = test_long_read,
+       .expected_att_ecode = 0,
+       .value = long_data_2,
+       .length = sizeof(long_data_2)
+};
+
+static const struct test_step test_long_read_3 = {
+       .handle = 0x0003,
+       .func = test_long_read,
+       .expected_att_ecode = 0x02
+};
+
+static const struct test_step test_long_read_4 = {
+       .handle = 0x0003,
+       .func = test_long_read,
+       .expected_att_ecode = 0x07
+};
+
+static const struct test_step test_long_read_5 = {
+       .handle = 0x0000,
+       .func = test_long_read,
+       .expected_att_ecode = 0x01
+};
+
+static const struct test_step test_long_read_6 = {
+       .handle = 0x0003,
+       .func = test_long_read,
+       .expected_att_ecode = 0x08
+};
+
+static const struct test_step test_long_read_7 = {
+       .handle = 0x0003,
+       .func = test_long_read,
+       .expected_att_ecode = 0x05
+};
+
+static const struct test_step test_long_read_8 = {
+       .handle = 0x0003,
+       .func = test_long_read,
+       .expected_att_ecode = 0x0c
+};
+
+/* Descriptor test data's */
+
+static const struct test_step test_long_read_9 = {
+       .handle = 0x0004,
+       .func = test_long_read,
+       .expected_att_ecode = 0,
+       .value = read_data_1,
+       .length = 0x03
+};
+
+static const struct test_step test_long_read_10 = {
+       .handle = 0x0004,
+       .func = test_long_read,
+       .expected_att_ecode = 0,
+       .value = long_data_2,
+       .length = sizeof(long_data_2)
+};
+
+static const struct test_step test_long_read_11 = {
+       .handle = 0x0004,
+       .func = test_long_read,
+       .expected_att_ecode = 0x02
+};
+
+static const struct test_step test_long_read_12 = {
+       .handle = 0x0004,
+       .func = test_long_read,
+       .expected_att_ecode = 0x07
+};
 
-       execute_context(context);
+static const struct test_step test_long_read_13 = {
+       .handle = 0x0004,
+       .func = test_long_read,
+       .expected_att_ecode = 0x08
+};
+
+static const struct test_step test_long_read_14 = {
+       .handle = 0x0004,
+       .func = test_long_read,
+       .expected_att_ecode = 0x05
+};
+
+static const struct test_step test_long_read_15 = {
+       .handle = 0x0004,
+       .func = test_long_read,
+       .expected_att_ecode = 0x0c
+};
+
+static void notification_cb(uint16_t value_handle, const uint8_t *value,
+                                       uint16_t length, void *user_data)
+{
+       struct context *context = user_data;
+       const struct test_step *step = context->data->step;
+
+       if (value_handle == step->handle) {
+               g_assert_cmpint(length, ==, step->length);
+
+               g_assert(memcmp(value, step->value, length) == 0);
+
+               context_quit(context);
+       }
+}
+
+static void notification_register_cb(uint16_t att_ecode, void *user_data)
+{
+       g_assert(!att_ecode);
+}
+
+static void test_notification(struct context *context)
+{
+       const struct test_step *step = context->data->step;
+
+       g_assert(bt_gatt_client_register_notify(context->client, step->handle,
+                                               notification_register_cb,
+                                               notification_cb, context,
+                                               NULL));
+}
+
+static const struct test_step test_notification_1 = {
+       .handle = 0x0003,
+       .func = test_notification,
+       .value = read_data_1,
+       .length = 0x03,
+};
+
+static void test_server_notification(struct context *context)
+{
+       const struct test_step *step = context->data->step;
+
+       bt_gatt_server_send_notification(context->server, step->handle,
+                                               step->value, step->length);
 }
 
+static const struct test_step test_notification_server_1 = {
+       .handle = 0x0003,
+       .func = test_server_notification,
+       .value = read_data_1,
+       .length = 0x03,
+};
+
+static uint8_t indication_received;
+
+static void test_indication_cb(void *user_data)
+{
+       struct context *context = user_data;
+
+       indication_received = 1;
+
+       context_quit(context);
+}
+
+static void test_server_indication_confirm(struct context *context)
+{
+       g_assert(indication_received == 1);
+}
+
+static void indication_cb(uint16_t value_handle, const uint8_t *value,
+                                       uint16_t length, void *user_data)
+{
+       struct context *context = user_data;
+       const struct test_step *step = context->data->step;
+
+       if (value_handle == step->handle) {
+               g_assert_cmpint(length, ==, step->length);
+
+               g_assert(memcmp(value, step->value, length) == 0);
+       }
+}
+
+static void test_indication(struct context *context)
+{
+       const struct test_step *step = context->data->step;
+
+       g_assert(bt_gatt_client_register_notify(context->client, step->handle,
+                                               notification_register_cb,
+                                               indication_cb, context,
+                                               NULL));
+}
+
+static const struct test_step test_indication_1 = {
+       .handle = 0x0003,
+       .func = test_indication,
+       .value = read_data_1,
+       .length = 0x03,
+};
+
+static void test_server_indication(struct context *context)
+{
+       const struct test_step *step = context->data->step;
+
+       bt_gatt_server_send_indication(context->server, step->handle,
+                                               step->value, step->length,
+                                               test_indication_cb,
+                                               context, NULL);
+}
+
+static const struct test_step test_indication_server_1 = {
+       .handle = 0x0003,
+       .func = test_server_indication,
+       .post_func = test_server_indication_confirm,
+       .value = read_data_1,
+       .length = 0x03,
+};
+
 int main(int argc, char *argv[])
 {
-       struct gatt_db *service_db_1, *ts_small_db;
+       struct gatt_db *service_db_1, *ts_small_db, *ts_large_db_1;
 
-       g_test_init(&argc, &argv, NULL);
+       tester_init(&argc, &argv);
 
        service_db_1 = make_service_data_1_db();
        ts_small_db = make_test_spec_small_db();
+       ts_large_db_1 = make_test_spec_large_db_1();
 
        /*
         * Server Configuration
@@ -1123,6 +2015,11 @@ int main(int argc, char *argv[])
                        raw_pdu(0x03, 0x00, 0x02),
                        PRIMARY_DISC_SMALL_DB);
 
+       define_test_server("/TP/GAD/SR/BV-01-C-large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       PRIMARY_DISC_LARGE_DB_1);
+
        define_test_att("/TP/GAD/CL/BV-02-C-1", test_search_primary, &uuid_16,
                        NULL,
                        MTU_EXCHANGE_CLIENT_PDUS,
@@ -1145,7 +2042,64 @@ int main(int argc, char *argv[])
                                        0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00,
                                        0x80, 0x00, 0x10, 0x00, 0x00, 0x0d,
                                        0x18, 0x00, 0x00),
-                       raw_pdu(0x01, 0x06, 0x08, 0x00, 0x0a));
+                       raw_pdu(0x01, 0x06, 0x18, 0x00, 0x0a));
+
+       define_test_server("/TP/GAD/SR/BV-02-C/exists-16/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x00,
+                               0x18),
+                       raw_pdu(0x07, 0x10, 0xf0, 0x17, 0xf0),
+                       raw_pdu(0x06, 0x18, 0xf0, 0xff, 0xff, 0x00, 0x28, 0x00,
+                               0x18),
+                       raw_pdu(0x01, 0x06, 0x18, 0xf0, 0x0a));
+
+       define_test_server("/TP/GAD/SR/BV-02-C/exists-16/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x0b,
+                               0xa0),
+                       raw_pdu(0x07, 0x30, 0x00, 0x32, 0x00, 0x50, 0x00, 0x52,
+                               0x00, 0x60, 0x00, 0x6b, 0x00, 0x70, 0x00, 0x76,
+                               0x00, 0x80, 0x00, 0x85, 0x00),
+                       raw_pdu(0x06, 0x86, 0x00, 0xff, 0xff, 0x00, 0x28, 0x0b,
+                               0xa0),
+                       raw_pdu(0x01, 0x06, 0x86, 0x00, 0x0a));
+
+       define_test_server("/TP/GAD/SR/BV-02-C/missing-16/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x01,
+                               0x18),
+                       raw_pdu(0x01, 0x06, 0x01, 0x00, 0x0a));
+
+       define_test_server("/TP/GAD/SR/BV-02-C/missing-16/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x0f,
+                               0xf0),
+                       raw_pdu(0x01, 0x06, 0x01, 0x00, 0x0a));
+
+       define_test_server("/TP/GAD/SR/BV-02-C/exists-128/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0xef,
+                               0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, 0x00,
+                               0x00, 0x00, 0x00, 0x0c, 0xa0, 0x00, 0x00),
+                       raw_pdu(0x07, 0x90, 0x00, 0x96, 0x00, 0xc0, 0x00, 0xdd,
+                               0x00),
+                       raw_pdu(0x06, 0xde, 0x00, 0xff, 0xff, 0x00, 0x28, 0xef,
+                               0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, 0x00,
+                               0x00, 0x00, 0x00, 0x0c, 0xa0, 0x00, 0x00),
+                       raw_pdu(0x01, 0x06, 0xde, 0x00, 0x0a));
+
+       define_test_server("/TP/GAD/SR/BV-02-C/missing-128/large-1",
+                       test_server, ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0xff,
+                               0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, 0x00,
+                               0x00, 0x00, 0x00, 0x0c, 0xa0, 0x00, 0x00),
+                       raw_pdu(0x01, 0x06, 0x01, 0x00, 0x0a));
 
        define_test_att("/TP/GAD/CL/BV-03-C", test_search_included, NULL,
                        NULL,
@@ -1170,11 +2124,86 @@ int main(int argc, char *argv[])
                        raw_pdu(0x08, 0x06, 0x00, 0xff, 0xff, 0x02, 0x28),
                        raw_pdu(0x01, 0x08, 0x06, 0x00, 0x0a));
 
+       define_test_server("/TP/GAD/SR/BV-03-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x02, 0x28),
+                       raw_pdu(0x09, 0x08, 0x11, 0xf0, 0x01, 0x00, 0x10, 0x00,
+                                       0x0a, 0x18),
+                       raw_pdu(0x08, 0x12, 0xf0, 0xff, 0xff, 0x02, 0x28),
+                       raw_pdu(0x01, 0x08, 0x12, 0xf0, 0x0a));
+
+       define_test_server("/TP/GAD/SR/BV-03-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x02, 0x28),
+                       raw_pdu(0x09, 0x08, 0x02, 0x00, 0x80, 0x00, 0x85, 0x00,
+                               0x0b, 0xa0, 0x21, 0x00, 0x01, 0x00, 0x06, 0x00,
+                               0x0d, 0xa0),
+                       raw_pdu(0x08, 0x22, 0x00, 0xff, 0xff, 0x02, 0x28),
+                       raw_pdu(0x09, 0x08, 0x91, 0x00, 0x01, 0x00, 0x06, 0x00,
+                               0x0d, 0xa0),
+                       raw_pdu(0x08, 0x92, 0x00, 0xff, 0xff, 0x02, 0x28),
+                       raw_pdu(0x01, 0x08, 0x92, 0x00, 0x0a));
+
        define_test_att("/TP/GAD/CL/BV-04-C", test_search_chars, NULL,
                        NULL,
                        MTU_EXCHANGE_CLIENT_PDUS,
                        raw_pdu(0x08, 0x10, 0x00, 0x20, 0x00, 0x03, 0x28),
-                       raw_pdu(0x09, 0x07, 0x11, 0x00, 02, 0x12, 0x00, 0x25,
+                       raw_pdu(0x09, 0x07, 0x11, 0x00, 0x02, 0x12, 0x00, 0x25,
+                                       0x2a),
+                       raw_pdu(0x08, 0x12, 0x00, 0x20, 0x00, 0x03, 0x28),
+                       raw_pdu(0x09, 0x15, 0x13, 0x00, 0x02, 0x14, 0x00, 0x85,
+                                       0x00, 0xef, 0xcd, 0xab, 0x89, 0x67,
+                                       0x45, 0x23, 0x01, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00),
+                       raw_pdu(0x08, 0x14, 0x00, 0x20, 0x00, 0x03, 0x28),
+                       raw_pdu(0x01, 0x08, 0x12, 0x00, 0x0a));
+
+       define_test_server("/TP/GAD/SR/BV-04-C/small/1", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x08, 0x10, 0xf0, 0x17, 0xf0, 0x03, 0x28),
+                       raw_pdu(0x09, 0x07, 0x12, 0xf0, 0x02, 0x13, 0xf0, 0x00,
+                                       0x2a),
+                       raw_pdu(0x08, 0x13, 0xf0, 0x17, 0xf0, 0x03, 0x28),
+                       raw_pdu(0x09, 0x15, 0x14, 0xf0, 0x02, 0x15, 0xf0, 0xef,
+                                       0xcd, 0xab, 0x89, 0x67, 0x45, 0x23,
+                                       0x01, 0x00, 0x00, 0x00, 0x00, 0x09,
+                                       0xb0, 0x00, 0x00),
+                       raw_pdu(0x08, 0x15, 0xf0, 0x17, 0xf0, 0x03, 0x28),
+                       raw_pdu(0x09, 0x07, 0x16, 0xf0, 0x02, 0x17, 0xf0, 0x01,
+                                       0x2a),
+                       raw_pdu(0x08, 0x17, 0xf0, 0x17, 0xf0, 0x03, 0x28),
+                       raw_pdu(0x01, 0x08, 0x17, 0xf0, 0x0a));
+
+       define_test_server("/TP/GAD/SR/BV-04-C/small/2", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x08, 0x01, 0x00, 0x0f, 0x00, 0x03, 0x28),
+                       raw_pdu(0x09, 0x07, 0x02, 0x00, 0x32, 0x03, 0x00, 0x29,
+                                       0x2a),
+                       raw_pdu(0x08, 0x03, 0x00, 0x0f, 0x00, 0x03, 0x28),
+                       raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a));
+
+       define_test_server("/TP/GAD/SR/BV-04-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x08, 0x20, 0x00, 0x29, 0x00, 0x03, 0x28),
+                       raw_pdu(0x09, 0x07, 0x22, 0x00, 0x02, 0x23, 0x00, 0x01,
+                               0xb0, 0x24, 0x00, 0x0a, 0x25, 0x00, 0x02, 0xb0,
+                               0x26, 0x00, 0x08, 0x27, 0x00, 0x02, 0xb0),
+                       raw_pdu(0x08, 0x27, 0x00, 0x29, 0x00, 0x03, 0x28),
+                       raw_pdu(0x09, 0x07, 0x28, 0x00, 0x08, 0x29, 0x00, 0x03,
+                               0xb0),
+                       raw_pdu(0x08, 0x29, 0x00, 0x29, 0x00, 0x03, 0x28),
+                       raw_pdu(0x01, 0x08, 0x29, 0x00, 0x0a));
+
+       define_test_att("/TP/GAD/CL/BV-05-C", test_search_chars, NULL,
+                       NULL,
+                       MTU_EXCHANGE_CLIENT_PDUS,
+                       raw_pdu(0x08, 0x10, 0x00, 0x20, 0x00, 0x03, 0x28),
+                       raw_pdu(0x09, 0x07, 0x11, 0x00, 0x02, 0x12, 0x00, 0x25,
                                        0x2a),
                        raw_pdu(0x08, 0x12, 0x00, 0x20, 0x00, 0x03, 0x28),
                        raw_pdu(0x09, 0x15, 0x13, 0x00, 0x02, 0x14, 0x00, 0x85,
@@ -1184,6 +2213,45 @@ int main(int argc, char *argv[])
                        raw_pdu(0x08, 0x14, 0x00, 0x20, 0x00, 0x03, 0x28),
                        raw_pdu(0x01, 0x08, 0x12, 0x00, 0x0a));
 
+       define_test_server("/TP/GAD/SR/BV-05-C/small/1", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x08, 0x10, 0xf0, 0x17, 0xf0, 0x03, 0x28),
+                       raw_pdu(0x09, 0x07, 0x12, 0xf0, 0x02, 0x13, 0xf0, 0x00,
+                                       0x2a),
+                       raw_pdu(0x08, 0x13, 0xf0, 0x17, 0xf0, 0x03, 0x28),
+                       raw_pdu(0x09, 0x15, 0x14, 0xf0, 0x02, 0x15, 0xf0, 0xef,
+                                       0xcd, 0xab, 0x89, 0x67, 0x45, 0x23,
+                                       0x01, 0x00, 0x00, 0x00, 0x00, 0x09,
+                                       0xb0, 0x00, 0x00),
+                       raw_pdu(0x08, 0x15, 0xf0, 0x17, 0xf0, 0x03, 0x28),
+                       raw_pdu(0x09, 0x07, 0x16, 0xf0, 0x02, 0x17, 0xf0, 0x01,
+                                       0x2a),
+                       raw_pdu(0x08, 0x17, 0xf0, 0x17, 0xf0, 0x03, 0x28),
+                       raw_pdu(0x01, 0x08, 0x17, 0xf0, 0x0a));
+
+       define_test_server("/TP/GAD/SR/BV-05-C/small/2", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x08, 0x01, 0x00, 0x0f, 0x00, 0x03, 0x28),
+                       raw_pdu(0x09, 0x07, 0x02, 0x00, 0x32, 0x03, 0x00, 0x29,
+                                       0x2a),
+                       raw_pdu(0x08, 0x03, 0x00, 0x0f, 0x00, 0x03, 0x28),
+                       raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a));
+
+       define_test_server("/TP/GAD/SR/BV-05-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x08, 0x20, 0x00, 0x29, 0x00, 0x03, 0x28),
+                       raw_pdu(0x09, 0x07, 0x22, 0x00, 0x02, 0x23, 0x00, 0x01,
+                               0xb0, 0x24, 0x00, 0x0a, 0x25, 0x00, 0x02, 0xb0,
+                               0x26, 0x00, 0x08, 0x27, 0x00, 0x02, 0xb0),
+                       raw_pdu(0x08, 0x27, 0x00, 0x29, 0x00, 0x03, 0x28),
+                       raw_pdu(0x09, 0x07, 0x28, 0x00, 0x08, 0x29, 0x00, 0x03,
+                               0xb0),
+                       raw_pdu(0x08, 0x29, 0x00, 0x29, 0x00, 0x03, 0x28),
+                       raw_pdu(0x01, 0x08, 0x29, 0x00, 0x0a));
+
        define_test_att("/TP/GAD/CL/BV-06-C", test_search_descs, NULL, NULL,
                        MTU_EXCHANGE_CLIENT_PDUS,
                        raw_pdu(0x04, 0x13, 0x00, 0x16, 0x00),
@@ -1193,6 +2261,24 @@ int main(int argc, char *argv[])
                        raw_pdu(0x05, 0x01, 0x15, 0x00, 0x04, 0x29, 0x16, 0x00,
                                        0x05, 0x29));
 
+       define_test_server("/TP/GAD/SR/BV-06-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x04, 0x04, 0x00, 0x05, 0x00),
+                       raw_pdu(0x05, 0x01, 0x04, 0x00, 0x02, 0x29, 0x05, 0x00,
+                                       0x01, 0x29));
+
+       define_test_server("/TP/GAD/SR/BV-06-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x04, 0x73, 0x00, 0x76, 0x00),
+                       raw_pdu(0x05, 0x01, 0x73, 0x00, 0x00, 0x29, 0x74, 0x00,
+                               0x01, 0x29, 0x75, 0x00, 0x04, 0x29),
+                       raw_pdu(0x04, 0x76, 0x00, 0x76, 0x00),
+                       raw_pdu(0x05, 0x02, 0x76, 0x00, 0xef, 0xcd, 0xab, 0x89,
+                               0x67, 0x45, 0x23, 0x01, 0x00, 0x00, 0x00, 0x00,
+                               0xd4, 0xd5, 0x00, 0x00));
+
        define_test_client("/TP/GAR/CL/BV-01-C", test_client, service_db_1,
                        &test_read_1,
                        SERVICE_DATA_1_PDUS,
@@ -1217,6 +2303,48 @@ int main(int argc, char *argv[])
                        raw_pdu(0x0a, 0x03, 0x00),
                        raw_pdu(0x01, 0x0a, 0x03, 0x00, 0x08));
 
+       define_test_client("/TP/GAR/CL/BI-04-C", test_client, service_db_1,
+                       &test_read_5,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0a, 0x03, 0x00),
+                       raw_pdu(0x01, 0x0a, 0x03, 0x00, 0x05));
+
+       define_test_client("/TP/GAR/CL/BI-05-C", test_client, service_db_1,
+                       &test_read_6,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0a, 0x03, 0x00),
+                       raw_pdu(0x01, 0x0a, 0x03, 0x00, 0x0c));
+
+       define_test_server("/TP/GAR/SR/BV-01-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0a, 0x03, 0x00),
+                       raw_pdu(0x0b, 0x42, 0x6c, 0x75, 0x65, 0x5a));
+
+       define_test_server("/TP/GAR/SR/BV-01-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0a, 0xc4, 0x00),
+                       raw_pdu(0x0b, '1', '1', '1', '1', '1', '2', '2', '2',
+                               '2', '2', '3', '3', '3', '3', '3', '4', '4',
+                               '4', '4', '4', '5'),
+                       raw_pdu(0x0a, 0xca, 0x00),
+                       raw_pdu(0x0b, '3', '3', '3', '3', '3', '4', '4', '4',
+                               '4', '4', '5', '5', '5', '5', '5', '6', '6',
+                               '6', '6', '6', '7', '7'));
+
+       define_test_server("/TP/GAR/SR/BI-02-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0a, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0a, 0x00, 0x00, 0x01));
+
+       define_test_server("/TP/GAR/SR/BI-02-C/large", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0a, 0x0f, 0xf0),
+                       raw_pdu(0x01, 0x0a, 0x0f, 0xf0, 0x01));
+
        define_test_att("/TP/GAR/CL/BV-03-C-1", test_read_by_type,
                        &uuid_char_16, &test_read_by_type_1,
                        raw_pdu(0x02, 0x00, 0x02),
@@ -1271,12 +2399,264 @@ int main(int argc, char *argv[])
                        raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x0d, 0x2a),
                        raw_pdu(0x01, 0x08, 0x0b, 0x00, 0x0c));
 
+       define_test_server("/TP/GAR/SR/BV-03-C/small", test_server, ts_small_db,
+                       NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x08, 0x01, 0x00, 0xFF, 0xFF, 0xef, 0xcd, 0xab,
+                                       0x89, 0x67, 0x45, 0x23, 0x01, 0x00,
+                                       0x00, 0x00, 0x00, 0x09, 0xB0, 0x00,
+                                       0x00),
+                       raw_pdu(0x09, 0x03, 0x15, 0xF0, 0x09),
+                       raw_pdu(0x08, 0x01, 0x00, 0xFF, 0xFF, 0x01, 0x2a),
+                       raw_pdu(0x09, 0x04, 0x17, 0xF0, 0x00, 0x00));
+
+       define_test_server("/TP/GAR/SR/BV-03-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x08, 0x01, 0x00, 0xFF, 0xFF, 0xef, 0xcd, 0xab,
+                                       0x89, 0x67, 0x45, 0x23, 0x01, 0x00,
+                                       0x00, 0x00, 0x00, 0xd4, 0xd5, 0x00,
+                                       0x00),
+                       raw_pdu(0x09, 0x03, 0x76, 0x00, 0x44),
+                       raw_pdu(0x08, 0x01, 0x00, 0xFF, 0xFF, 0x02, 0xB0),
+                       raw_pdu(0x09, 0x15, 0x25, 0x00, '1', '1', '1', '1', '1',
+                               '2', '2', '2', '2', '2', '3', '3', '3', '3',
+                               '3', '4', '4', '4', '4'));
+
+       define_test_server("/TP/GAR/SR/BI-06-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x08, 0x01, 0x00, 0xFF, 0xFF, 0x07, 0xB0),
+                       raw_pdu(0x01, 0x08, 0x32, 0x00, 0x02));
+
+       define_test_server("/TP/GAR/SR/BI-07-C/small", test_server, ts_small_db,
+                       NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x08, 0x01, 0x00, 0xFF, 0xFF, 0xF0, 0x0F),
+                       raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a));
+
+       define_test_server("/TP/GAR/SR/BI-07-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x08, 0x01, 0x00, 0xFF, 0xFF, 0xF0, 0x0F),
+                       raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a));
+
+       define_test_server("/TP/GAR/SR/BI-08-C/small", test_server, ts_small_db,
+                       NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x08, 0x02, 0x00, 0x01, 0x00, 0x00, 0x28),
+                       raw_pdu(0x01, 0x08, 0x02, 0x00, 0x01));
+
+       define_test_server("/TP/GAR/SR/BI-08-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x08, 0x02, 0x00, 0x01, 0x00, 0x00, 0x28),
+                       raw_pdu(0x01, 0x08, 0x02, 0x00, 0x01));
+
+       define_test_server("/TP/GAR/SR/BV-04-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0C, 0xD3, 0x00, 0x00, 0x00),
+                       raw_pdu(0x0D, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                               0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+                               0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22),
+                       raw_pdu(0x0C, 0xD3, 0x00, 0x16, 0x00),
+                       raw_pdu(0x0D, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
+                               0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                               0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44),
+                       raw_pdu(0x0C, 0xD3, 0x00, 0x2C, 0x00),
+                       raw_pdu(0x0D, 0x55),
+                       raw_pdu(0x0C, 0xD3, 0x00, 0x2D, 0x00),
+                       raw_pdu(0x0D));
+
+       define_test_server("/TP/GAR/SR/BI-12-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0C, 0x27, 0x00, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0C, 0x27, 0x00, 0x02));
+
+       define_test_server("/TP/GAR/SR/BI-13-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0C, 0x13, 0xF0, 0xF0, 0x00),
+                       raw_pdu(0x01, 0x0C, 0x13, 0xF0, 0x07));
+
+       define_test_server("/TP/GAR/SR/BI-13-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0C, 0xD3, 0x00, 0xF0, 0x00),
+                       raw_pdu(0x01, 0x0C, 0xD3, 0x00, 0x07));
+
+       define_test_server("/TP/GAR/SR/BI-14-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0C, 0xF0, 0x0F, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0C, 0xF0, 0x0F, 0x01));
+
+       define_test_server("/TP/GAR/SR/BI-14-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0C, 0xF0, 0x0F, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0C, 0xF0, 0x0F, 0x01));
+
+       define_test_client("/TP/GAR/CL/BV-04-C", test_client, service_db_1,
+                       &test_long_read_1,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0c, 0x03, 0x00, 0x00, 0x00),
+                       raw_pdu(0x0b, 0x01, 0x02, 0x03));
+
+       define_test_client("/TP/GAR/CL/BV-04-C/512B", test_client, service_db_1,
+                       &test_long_read_2,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0c, 0x03, 0x00, 0x00, 0x00),
+                       raw_pdu(0x0d, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff),
+                       raw_pdu(0x0c, 0x03, 0x00, 0xff, 0x01),
+                       raw_pdu(0x0d, 0xff));
+
        define_test_client("/TP/GAR/CL/BV-05-C", test_client, service_db_1,
                        &test_multiple_read_1,
                        SERVICE_DATA_1_PDUS,
                        raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
                        raw_pdu(0x0f, 0x01, 0x02, 0x03));
 
+       define_test_client("/TP/GAR/CL/BI-12-C", test_client, service_db_1,
+                       &test_long_read_3,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0c, 0x03, 0x00, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0c, 0x03, 0x00, 0x02));
+
+       define_test_client("/TP/GAR/CL/BI-13-C", test_client, service_db_1,
+                       &test_long_read_4,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0c, 0x03, 0x00, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0c, 0x03, 0x00, 0x07));
+
+       define_test_client("/TP/GAR/CL/BI-14-C", test_client, service_db_1,
+                       &test_long_read_5,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0c, 0x00, 0x00, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0c, 0x00, 0x00, 0x01));
+
+       define_test_client("/TP/GAR/CL/BI-15-C", test_client, service_db_1,
+                       &test_long_read_6,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0c, 0x03, 0x00, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0c, 0x03, 0x00, 0x08));
+
+       define_test_client("/TP/GAR/CL/BI-16-C", test_client, service_db_1,
+                       &test_long_read_7,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0c, 0x03, 0x00, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0c, 0x03, 0x00, 0x05));
+
+       define_test_client("/TP/GAR/CL/BI-17-C", test_client, service_db_1,
+                       &test_long_read_8,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0c, 0x03, 0x00, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0c, 0x03, 0x00, 0x0c));
+
        define_test_client("/TP/GAR/CL/BI-18-C", test_client, service_db_1,
                        &test_multiple_read_2,
                        SERVICE_DATA_1_PDUS,
@@ -1301,11 +2681,495 @@ int main(int argc, char *argv[])
                        raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
                        raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x05));
 
-       define_test_client("/TP/GAR/CL/BI-21-C", test_client, service_db_1,
+       define_test_client("/TP/GAR/CL/BI-22-C", test_client, service_db_1,
                        &test_multiple_read_6,
                        SERVICE_DATA_1_PDUS,
                        raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
                        raw_pdu(0x01, 0x0e, 0x03, 0x00, 0x0c));
 
-       return g_test_run();
+       define_test_server("/TP/GAR/SR/BV-05-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0e, 0x15, 0xF0, 0x03, 0x00),
+                       raw_pdu(0x0f, 0x09, 'B', 'l', 'u', 'e', 'Z'));
+
+       define_test_server("/TP/GAR/SR/BV-05-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0e, 0x44, 0x00, 0x06, 0x00, 0xC4, 0x00),
+                       raw_pdu(0x0f, 0x11, 0x0B, '1', '1', '1', '1', '1', '2',
+                               '2', '2', '2', '2', '3', '3', '3', '3', '3',
+                               '4', '4', '4', '4', '4'));
+
+       define_test_server("/TP/GAR/SR/BI-18-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0e, 0x44, 0x00, 0x06, 0x00, 0x27, 0x00),
+                       raw_pdu(0x01, 0x0e, 0x27, 0x00, 0x02));
+
+       define_test_server("/TP/GAR/SR/BI-19-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0e, 0x15, 0xF0, 0xF0, 0x0F),
+                       raw_pdu(0x01, 0x0e, 0xF0, 0x0F, 0x01));
+
+       define_test_server("/TP/GAR/SR/BI-19-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0e, 0x44, 0x00, 0xF0, 0x0F),
+                       raw_pdu(0x01, 0x0e, 0xF0, 0x0F, 0x01));
+
+       define_test_server("/TP/GAR/SR/BV-06-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0A, 0x05, 0x00),
+                       raw_pdu(0x0B, 'M', 'a', 'n', 'u', 'f', 'a', 'c', 't',
+                               'u', 'r', 'e', 'r', ' ', 'N', 'a', 'm', 'e'));
+
+       define_test_server("/TP/GAR/SR/BV-06-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0A, 0xD4, 0x00),
+                       raw_pdu(0x0B, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                               0x88, 0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90,
+                               0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34));
+
+       define_test_server("/TP/GAR/SR/BI-23-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0A, 0x96, 0x00),
+                       raw_pdu(0x01, 0x0A, 0x96, 0x00, 0x02));
+
+       define_test_server("/TP/GAR/SR/BI-24-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0A, 0xF0, 0x0F),
+                       raw_pdu(0x01, 0x0A, 0xF0, 0x0F, 0x01));
+
+       define_test_server("/TP/GAR/SR/BI-24-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0A, 0xF0, 0x0F),
+                       raw_pdu(0x01, 0x0A, 0xF0, 0x0F, 0x01));
+
+       define_test_server("/TP/GAR/SR/BV-07-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0C, 0xD1, 0x00, 0x00, 0x00),
+                       raw_pdu(0x0D, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                               0x88, 0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90,
+                               0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34),
+                       raw_pdu(0x0C, 0xD1, 0x00, 0x16, 0x00),
+                       raw_pdu(0x0D, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
+                               0x90, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                               0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44),
+                       raw_pdu(0x0C, 0xD1, 0x00, 0x2C, 0x00),
+                       raw_pdu(0x0D));
+
+       define_test_server("/TP/GAR/SR/BV-08-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0C, 0xCE, 0x00, 0x00, 0x00),
+                       raw_pdu(0x0D, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                               0x88, 0x99, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90,
+                               0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34),
+                       raw_pdu(0x0C, 0xCE, 0x00, 0x16, 0x00),
+                       raw_pdu(0x0D, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
+                               0x90, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                               0x88, 0x99, 0x00, 0x11, 0x22, 0x33),
+                       raw_pdu(0x0C, 0xCE, 0x00, 0x2B, 0x00),
+                       raw_pdu(0x0D));
+
+       define_test_server("/TP/GAR/SR/BI-28-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0C, 0x96, 0x00, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0C, 0x96, 0x00, 0x02));
+
+       define_test_server("/TP/GAR/SR/BI-29-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0C, 0x05, 0x00, 0xF0, 0x00),
+                       raw_pdu(0x01, 0x0C, 0x05, 0x00, 0x07));
+
+       define_test_server("/TP/GAR/SR/BI-29-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0C, 0xCE, 0x00, 0xF0, 0x00),
+                       raw_pdu(0x01, 0x0C, 0xCE, 0x00, 0x07));
+
+       define_test_server("/TP/GAR/SR/BI-30-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0C, 0xF0, 0x0F, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0C, 0xF0, 0x0F, 0x01));
+
+       define_test_server("/TP/GAR/SR/BI-30-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x0C, 0xF0, 0x0F, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0C, 0xF0, 0x0F, 0x01));
+
+       define_test_client("/TP/GAN/CL/BV-01-C", test_client, ts_small_db,
+                       &test_notification_1,
+                       MTU_EXCHANGE_CLIENT_PDUS,
+                       SMALL_DB_DISCOVERY_PDUS,
+                       raw_pdu(0x12, 0x04, 0x00, 0x03, 0x00),
+                       raw_pdu(0x13),
+                       raw_pdu(),
+                       raw_pdu(0x1B, 0x03, 0x00, 0x01, 0x02, 0x03));
+
+       define_test_server("/TP/GAN/SR/BV-01-C", test_server, ts_small_db,
+                       &test_notification_server_1,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x12, 0x04, 0x00, 0x01, 0x00),
+                       raw_pdu(0x13),
+                       raw_pdu(),
+                       raw_pdu(0x1B, 0x03, 0x00, 0x01, 0x02, 0x03));
+
+       define_test_server("/TP/GAI/SR/BV-01-C", test_server, ts_small_db,
+                       &test_indication_server_1,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x12, 0x04, 0x00, 0x02, 0x00),
+                       raw_pdu(0x13),
+                       raw_pdu(),
+                       raw_pdu(0x1D, 0x03, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x1E));
+
+       define_test_client("/TP/GAI/CL/BV-01-C", test_client, ts_small_db,
+                       &test_indication_1,
+                       MTU_EXCHANGE_CLIENT_PDUS,
+                       SMALL_DB_DISCOVERY_PDUS,
+                       raw_pdu(0x12, 0x04, 0x00, 0x03, 0x00),
+                       raw_pdu(0x13),
+                       raw_pdu(),
+                       raw_pdu(0x1D, 0x03, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x1E));
+
+       define_test_client("/TP/GAR/CL/BV-06-C", test_client, service_db_1,
+                       &test_read_7,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0a, 0x04, 0x00),
+                       raw_pdu(0x0b, 0x01, 0x02, 0x03));
+
+       define_test_client("/TP/GAR/CL/BI-23-C", test_client, service_db_1,
+                       &test_read_8,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0a, 0x04, 0x00),
+                       raw_pdu(0x01, 0x0a, 0x04, 0x00, 0x02));
+
+       define_test_client("/TP/GAR/CL/BI-24-C", test_client, service_db_1,
+                       &test_read_2,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0a, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0a, 0x00, 0x00, 0x01));
+
+       define_test_client("/TP/GAR/CL/BI-25-C", test_client, service_db_1,
+                       &test_read_9,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0a, 0x04, 0x00),
+                       raw_pdu(0x01, 0x0a, 0x04, 0x00, 0x08));
+
+       define_test_client("/TP/GAR/CL/BI-26-C", test_client, service_db_1,
+                       &test_read_10,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0a, 0x04, 0x00),
+                       raw_pdu(0x01, 0x0a, 0x04, 0x00, 0x05));
+
+       define_test_client("/TP/GAR/CL/BI-27-C", test_client, service_db_1,
+                       &test_read_11,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0a, 0x04, 0x00),
+                       raw_pdu(0x01, 0x0a, 0x04, 0x00, 0x0c));
+
+       define_test_client("/TP/GAR/CL/BV-07-C", test_client, service_db_1,
+                       &test_long_read_9,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0c, 0x04, 0x00, 0x00, 0x00),
+                       raw_pdu(0x0b, 0x01, 0x02, 0x03));
+
+       define_test_client("/TP/GAR/CL/BV-07-C/512B", test_client, service_db_1,
+                       &test_long_read_10,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0c, 0x04, 0x00, 0x00, 0x00),
+                       raw_pdu(0x0d, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff, 0xff, 0xff,
+                               0xff, 0xff, 0xff),
+                       raw_pdu(0x0c, 0x04, 0x00, 0xff, 0x01),
+                       raw_pdu(0x0d, 0xff));
+
+       define_test_client("/TP/GAR/CL/BI-28-C", test_client, service_db_1,
+                       &test_long_read_11,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0c, 0x04, 0x00, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0c, 0x04, 0x00, 0x02));
+
+       define_test_client("/TP/GAR/CL/BI-29-C", test_client, service_db_1,
+                       &test_long_read_12,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0c, 0x04, 0x00, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0c, 0x04, 0x00, 0x07));
+
+       define_test_client("/TP/GAR/CL/BI-30-C", test_client, service_db_1,
+                       &test_long_read_5,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0c, 0x00, 0x00, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0c, 0x00, 0x00, 0x01));
+
+       define_test_client("/TP/GAR/CL/BI-31-C", test_client, service_db_1,
+                       &test_long_read_13,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0c, 0x04, 0x00, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0c, 0x04, 0x00, 0x08));
+
+       define_test_client("/TP/GAR/CL/BI-32-C", test_client, service_db_1,
+                       &test_long_read_14,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0c, 0x04, 0x00, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0c, 0x04, 0x00, 0x05));
+
+       define_test_client("/TP/GAR/CL/BI-33-C", test_client, service_db_1,
+                       &test_long_read_15,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0c, 0x04, 0x00, 0x00, 0x00),
+                       raw_pdu(0x01, 0x0c, 0x04, 0x00, 0x0c));
+
+       define_test_client("/TP/GAR/CL/BI-34-C", test_client, service_db_1,
+                       &test_read_12,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0a, 0x03, 0x00),
+                       raw_pdu(0x01, 0x0a, 0x03, 0x00, 0x80));
+
+       define_test_client("/TP/GAR/CL/BI-35-C", test_client, service_db_1,
+                       &test_read_12,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x0a, 0x03, 0x00),
+                       raw_pdu(0x01, 0x0a, 0x03, 0x00, 0x80));
+
+       define_test_client("/TP/GAW/CL/BV-01-C", test_client, service_db_1,
+                       &test_write_without_response_1,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x52, 0x07, 0x00, 0x01, 0x02, 0x03));
+
+       define_test_client("/TP/GAW/CL/BV-02-C", test_client, service_db_1,
+                       &test_signed_write_1,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0xd2, 0x07, 0x00, 0x01, 0x02, 0x03, 0x00, 0x00,
+                               0x00, 0x00, 0x31, 0x1f, 0x0a, 0xcd, 0x1c, 0x3a,
+                               0x5b, 0x0a));
+
+       define_test_client("/TP/GAW/CL/BV-02-C/seclevel", test_client,
+                       service_db_1, &test_signed_write_seclevel_1,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x52, 0x07, 0x00, 0x01, 0x02, 0x03));
+
+       define_test_client("/TP/GAW/CL/BV-03-C", test_client, service_db_1,
+                       &test_write_1,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x12, 0x07, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x13));
+
+       define_test_client("/TP/GAW/CL/BI-02-C", test_client, service_db_1,
+                       &test_write_2,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x12, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x00, 0x00, 0x01));
+
+       define_test_client("/TP/GAW/CL/BI-03-C", test_client, service_db_1,
+                       &test_write_3,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x12, 0x07, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x07, 0x00, 0x03));
+
+       define_test_client("/TP/GAW/CL/BI-04-C", test_client, service_db_1,
+                       &test_write_4,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x12, 0x07, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x07, 0x00, 0x08));
+
+       define_test_client("/TP/GAW/CL/BI-05-C", test_client, service_db_1,
+                       &test_write_5,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x12, 0x07, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x07, 0x00, 0x05));
+
+       define_test_client("/TP/GAW/CL/BI-06-C", test_client, service_db_1,
+                       &test_write_6,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x12, 0x07, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x07, 0x00, 0x0c));
+
+       define_test_server("/TP/GAW/SR/BV-03-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x12, 0x03, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x13));
+
+       define_test_server("/TP/GAW/SR/BV-03-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x12, 0x82, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x13));
+
+       define_test_server("/TP/GAW/SR/BI-02-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x12, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x00, 0x00, 0x01));
+
+       define_test_server("/TP/GAW/SR/BI-02-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x12, 0x0f, 0xf0, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x0f, 0xf0, 0x01));
+
+       define_test_server("/TP/GAW/SR/BI-03-C/small", test_server,
+                       ts_small_db, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x12, 0x13, 0xf0, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x13, 0xf0, 0x03));
+
+       define_test_server("/TP/GAW/SR/BI-03-C/large-1", test_server,
+                       ts_large_db_1, NULL,
+                       raw_pdu(0x03, 0x00, 0x02),
+                       raw_pdu(0x12, 0x04, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x04, 0x00, 0x03));
+
+       define_test_client("/TP/GAW/CL/BV-08-C", test_client, service_db_1,
+                       &test_write_7,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x12, 0x08, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x13));
+
+       define_test_client("/TP/GAW/CL/BI-20-C", test_client, service_db_1,
+                       &test_write_8,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x12, 0x00, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x00, 0x00, 0x01));
+
+       define_test_client("/TP/GAW/CL/BI-21-C", test_client, service_db_1,
+                       &test_write_9,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x12, 0x08, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x08, 0x00, 0x03));
+
+       define_test_client("/TP/GAW/CL/BI-22-C", test_client, service_db_1,
+                       &test_write_10,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x12, 0x08, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x08, 0x00, 0x08));
+
+       define_test_client("/TP/GAW/CL/BI-23-C", test_client, service_db_1,
+                       &test_write_11,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x12, 0x08, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x08, 0x00, 0x05));
+
+       define_test_client("/TP/GAW/CL/BI-24-C", test_client, service_db_1,
+                       &test_write_12,
+                       SERVICE_DATA_1_PDUS,
+                       raw_pdu(0x12, 0x08, 0x00, 0x01, 0x02, 0x03),
+                       raw_pdu(0x01, 0x12, 0x08, 0x00, 0x0c));
+
+       return tester_run();
 }
index 109e516..28542f3 100644 (file)
@@ -36,6 +36,7 @@
 #include <glib.h>
 
 #include "src/shared/util.h"
+#include "lib/bluetooth.h"
 #include "lib/uuid.h"
 #include "attrib/att.h"
 #include "attrib/gattrib.h"
index d0b6ce7..11ad1f7 100644 (file)
@@ -26,7 +26,8 @@
 #endif
 
 #include <glib.h>
-#include <gdbus.h>
+
+#include "gdbus/gdbus.h"
 
 #define SERVICE_NAME "org.bluez.unit.test-gdbus-client"
 #define SERVICE_NAME1 "org.bluez.unit.test-gdbus-client1"
index 976c541..7541c49 100644 (file)
@@ -27,7 +27,8 @@
 #include <stdint.h>
 #include <string.h>
 
-#include <gobex/gobex-apparam.h>
+#include "gobex/gobex.h"
+#include "gobex/gobex-apparam.h"
 
 #include "util.h"
 
index 31c49a6..6f49312 100644 (file)
@@ -27,7 +27,8 @@
 #include <stdint.h>
 #include <string.h>
 
-#include <gobex/gobex-header.h>
+#include "gobex/gobex.h"
+#include "gobex/gobex-header.h"
 
 #include "util.h"
 
index bf2035b..0d62460 100644 (file)
@@ -28,7 +28,8 @@
 #include <string.h>
 #include <errno.h>
 
-#include <gobex/gobex-packet.h>
+#include "gobex/gobex.h"
+#include "gobex/gobex-packet.h"
 
 #include "util.h"
 
index ffb5bdc..6807c9f 100644 (file)
@@ -34,7 +34,7 @@
 #include <stdint.h>
 #include <fcntl.h>
 
-#include <gobex/gobex.h>
+#include "gobex/gobex.h"
 
 #include "util.h"
 
index 180f817..66531a2 100644 (file)
@@ -32,7 +32,7 @@
 #include <string.h>
 #include <stdint.h>
 
-#include <gobex/gobex.h>
+#include "gobex/gobex.h"
 
 #include "util.h"
 
index cb85605..12319b0 100644 (file)
@@ -214,6 +214,42 @@ static void test_push_after(void)
        queue_destroy(queue, NULL);
 }
 
+static bool match_int(const void *a, const void *b)
+{
+       int i = PTR_TO_INT(a);
+       int j = PTR_TO_INT(b);
+
+       return i == j;
+}
+
+static bool match_ptr(const void *a, const void *b)
+{
+       return a == b;
+}
+
+static void test_remove_all(void)
+{
+       struct queue *queue;
+
+       queue = queue_new();
+       g_assert(queue != NULL);
+
+       g_assert(queue_push_tail(queue, INT_TO_PTR(10)));
+
+       g_assert(queue_remove_all(queue, match_int, INT_TO_PTR(10), NULL) == 1);
+       g_assert(queue_isempty(queue));
+
+       g_assert(queue_push_tail(queue, NULL));
+       g_assert(queue_remove_all(queue, match_ptr, NULL, NULL) == 1);
+       g_assert(queue_isempty(queue));
+
+       g_assert(queue_push_tail(queue, UINT_TO_PTR(0)));
+       g_assert(queue_remove_all(queue, match_int, UINT_TO_PTR(0), NULL) == 1);
+       g_assert(queue_isempty(queue));
+
+       queue_destroy(queue, NULL);
+}
+
 int main(int argc, char *argv[])
 {
        g_test_init(&argc, &argv, NULL);
@@ -226,6 +262,7 @@ int main(int argc, char *argv[])
                                                test_foreach_remove_backward);
        g_test_add_func("/queue/destroy_remove", test_destroy_remove);
        g_test_add_func("/queue/push_after", test_push_after);
+       g_test_add_func("/queue/remove_all", test_remove_all);
 
        return g_test_run();
 }
index 01f44f4..60c4791 100644 (file)
@@ -27,8 +27,7 @@
 
 #include <glib.h>
 
-#include <bluetooth/bluetooth.h>
-
+#include "lib/bluetooth.h"
 #include "lib/uuid.h"
 
 struct uuid_test_data {
index 71fe7ca..8e3115f 100644 (file)
@@ -33,6 +33,8 @@
 
 #include <glib.h>
 
+#include "gobex/gobex.h"
+
 #include "util.h"
 
 GQuark test_error_quark(void)
index 96528a6..6783c52 100644 (file)
@@ -19,8 +19,6 @@
  *
  */
 
-#include <gobex/gobex.h>
-
 enum {
        TEST_ERROR_TIMEOUT,
        TEST_ERROR_UNEXPECTED,