Merge with lastest private git
authorDoHyun Pyun <dh79.pyun@samsung.com>
Thu, 9 Feb 2012 05:55:06 +0000 (14:55 +0900)
committerDoHyun Pyun <dh79.pyun@samsung.com>
Thu, 9 Feb 2012 05:55:06 +0000 (14:55 +0900)
241 files changed:
AUTHORS
ChangeLog
Makefile.am
Makefile.tools
TODO
acinclude.m4
alert/main.c [new file with mode: 0644]
alert/server.c [new file with mode: 0644]
alert/server.h [moved from attrib/example.h with 82% similarity]
attrib/att.c
attrib/att.h
attrib/client.c
attrib/client.h
attrib/example.c [deleted file]
attrib/gatt-service.c [new file with mode: 0644]
attrib/gatt-service.h [new file with mode: 0644]
attrib/gatt.c
attrib/gatt.h
attrib/gattrib.c
attrib/gattrib.h
attrib/gatttool.c
attrib/interactive.c
attrib/manager.c [deleted file]
attrib/utils.c
audio/a2dp.c
audio/a2dp.h
audio/audio.conf
audio/avctp.c
audio/avdtp.c
audio/avrcp.c
audio/avrcp.h
audio/ctl_bluetooth.c
audio/device.c
audio/gateway.c
audio/gstavdtpsink.c
audio/headset.c
audio/ipc.c
audio/manager.c
audio/media.c
audio/module-bluetooth-sink.c [deleted file]
audio/pcm_bluetooth.c
audio/telephony-maemo6.c
audio/telephony-ofono.c
audio/telephony-tizen.c
audio/transport.c
audio/unix.c
btio/btio.c
btio/btio.h
compat/dun.c
compat/fakehid.c
compat/fakehid.txt [new file with mode: 0644]
compat/hidd.c
configure.ac
cups/hcrp.c
debian/changelog
debian/rules
doc/adapter-api.txt
doc/agent-api.txt
doc/attribute-api.txt
doc/bluez-docs.xml [new file with mode: 0644]
doc/device-api.txt
doc/gtk-doc.make [new file with mode: 0644]
doc/media-api.txt
doc/mgmt-api.txt [new file with mode: 0644]
doc/node-api.txt [new file with mode: 0644]
doc/oob-api.txt [new file with mode: 0644]
doc/proximity-api.txt [new file with mode: 0644]
doc/serial-api.txt
doc/thermometer-api.txt [new file with mode: 0644]
gdbus/object.c
gdbus/watch.c
health/hdp.c
health/hdp.h
health/hdp_main.c
health/hdp_manager.c
health/hdp_manager.h
health/hdp_types.h
health/hdp_util.c
health/hdp_util.h
health/mcap.c
health/mcap.h
health/mcap_internal.h
health/mcap_lib.h
health/mcap_sync.c
input/device.c
input/manager.c
input/server.c
input/sixpair.c [new file with mode: 0644]
lib/bluetooth.c
lib/bluetooth.h
lib/hci.c
lib/hci.h
lib/l2cap.h
lib/mgmt.h
lib/sdp.c
lib/sdp.h
lib/sdp_lib.h
lib/uuid.c
mgmt/main.c [new file with mode: 0644]
network/common.c
network/common.h
network/connection.c
network/manager.c
network/server.c
packaging/bluez.spec
plugins/adaptername.c [new file with mode: 0644]
plugins/dbusoob.c [new file with mode: 0644]
plugins/echo.c [deleted file]
plugins/external-dummy.c [new file with mode: 0644]
plugins/formfactor.c
plugins/gatt-example.c [new file with mode: 0644]
plugins/hciops.c
plugins/maemo6.c
plugins/mgmtops.c
plugins/service.c
plugins/wiimote.c [new file with mode: 0644]
proximity/main.c [new file with mode: 0644]
proximity/manager.c [new file with mode: 0644]
proximity/manager.h [new file with mode: 0644]
proximity/monitor.c [new file with mode: 0644]
proximity/monitor.h [new file with mode: 0644]
proximity/proximity.conf [new file with mode: 0644]
proximity/reporter.c [new file with mode: 0644]
proximity/reporter.h [moved from attrib/manager.h with 81% similarity]
sap/sap-dummy.c
sap/sap-u8500.c [new file with mode: 0644]
sap/sap.h
sap/server.c
sbc/sbc.c
sbc/sbc_math.h
sbc/sbc_primitives_armv6.c
sbc/sbc_primitives_armv6.h
sbc/sbc_primitives_iwmmxt.c
sbc/sbc_primitives_mmx.c
sbc/sbc_primitives_neon.c
sbc/sbc_tables.h
sbc/sbcinfo.c
sbc/sbctester.c
scripts/bluetooth-hid2hci.rules
serial/manager.c
serial/port.c
serial/proxy.c
src/adapter.c
src/adapter.h
src/agent.c
src/agent.h
src/attio.h [new file with mode: 0644]
src/attrib-server.c
src/attrib-server.h
src/bluetooth.conf
src/bluetooth.service.in [new file with mode: 0644]
src/dbus-common.c
src/device.c
src/device.h
src/eir.c [new file with mode: 0644]
src/eir.h [new file with mode: 0644]
src/event.c
src/event.h
src/glib-compat.h [new file with mode: 0644]
src/glib-helper.c
src/glib-helper.h
src/hcid.h
src/log.c
src/log.h
src/main.c
src/main.conf
src/manager.c
src/manager.h
src/oob.c [new file with mode: 0644]
src/oob.h [new file with mode: 0644]
src/plugin.c
src/plugin.h
src/sdp-client.c [new file with mode: 0644]
src/sdp-client.h [new file with mode: 0644]
src/sdp-xml.c
src/sdp-xml.h
src/sdpd-database.c
src/sdpd-request.c
src/sdpd-service.c
src/sdpd.h
src/storage.c
src/storage.h
src/textfile.c
test/agent.c
test/apitest
test/avtest.c
test/bdaddr.c
test/btiotest.c
test/hciemu.c
test/hstest.c
test/ipctest-a2dp-easy.test [new file with mode: 0644]
test/ipctest-a2dp-resume-fast.test [new file with mode: 0644]
test/ipctest-hsp-a2dp-switch.test [new file with mode: 0644]
test/ipctest-hsp-easy.test [new file with mode: 0644]
test/ipctest-init-shutdown.test [new file with mode: 0644]
test/ipctest.c
test/l2test.c
test/list-devices
test/mpris-player.c [new file with mode: 0644]
test/rctest.c
test/sap-client [new file with mode: 0644]
test/scotest.c
test/simple-agent
test/simple-endpoint [changed mode: 0644->0755]
test/simple-player [new file with mode: 0755]
test/test-adapter
test/test-attrib [changed mode: 0644->0755]
test/test-health [new file with mode: 0755]
test/test-health-sink [new file with mode: 0755]
test/test-nap [new file with mode: 0755]
test/test-oob [new file with mode: 0755]
test/test-proximity [new file with mode: 0755]
test/test-sap-server [new file with mode: 0755]
test/test-serial-proxy [new file with mode: 0755]
test/test-textfile.c
test/test-thermometer [new file with mode: 0755]
thermometer/main.c [moved from attrib/main.c with 73% similarity]
thermometer/manager.c [new file with mode: 0644]
thermometer/manager.h [new file with mode: 0644]
thermometer/thermometer.c [new file with mode: 0644]
thermometer/thermometer.h [new file with mode: 0644]
time/main.c [new file with mode: 0644]
time/server.c [new file with mode: 0644]
time/server.h [new file with mode: 0644]
tools/avinfo.c
tools/bccmd.c
tools/csr_bcsp.c
tools/example.psr [new file with mode: 0644]
tools/hciattach.c
tools/hciattach.h
tools/hciattach_ath3k.c
tools/hciattach_ti.c
tools/hciconfig.c
tools/hcitool.c
tools/hid2hci.8
tools/hid2hci.c
tools/rfcomm.1
tools/sdptool.c
tools/ubcsp.c
tracer/main.c
unit/test-eir.c [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
index 3e4b3b9..eeecec4 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -12,7 +12,7 @@ Fabrizio Gennari <fabrizio.gennari@philips.com>
 Brad Midgley <bmidgley@xmission.com>
 Henryk Ploetz <henryk@ploetzli.ch>
 Philip Blundell <pb@nexus.co.uk>
-Johan Hedberg <johan.hedberg@nokia.com>
+Johan Hedberg <johan.hedberg@intel.com>
 Claudio Takahasi <claudio.takahasi@indt.org.br>
 Eduardo Rocha <eduardo.rocha@indt.org.br>
 Denis Kenzior <denis.kenzior@trolltech.com>
@@ -35,7 +35,7 @@ Pekka Pessi <pekka.pessi@nokia.com>
 Siarhei Siamashka <siarhei.siamashka@nokia.com>
 Nick Pelly <npelly@google.com>
 Lennart Poettering <lennart@poettering.net>
-Gustavo F. Padovan <gustavo@las.ic.unicamp.br>
+Gustavo F. Padovan <padovan@profusion.mobi>
 Marc-Andre Lureau <marc-andre.lureau@nokia.com>
 Bea Lam <bea.lam@nokia.com>
 Zygo Blaxell <zygo.blaxell@xandros.com>
@@ -47,6 +47,14 @@ Filippo Giunchedi <filippo@esaurito.net>
 Jaikumar Ganesh <jaikumar@google.com>
 Elvis Pfutzenreuter <epx@signove.com>
 Santiago Carot-Nemesio <scarot@libresoft.es>
-José Antonio Santos Cadenas <jcaden@libresoft.es>
+José Antonio Santos Cadenas <jcaden@libresoft.es>
 Francisco Alecrim <francisco.alecrim@openbossa.org>
 Daniel Orstadius <daniel.orstadius@gmail.com>
+Anderson Briglia <anderson.briglia@openbossa.org>
+Anderson Lizardo <anderson.lizardo@openbossa.org>
+Bruna Moreira <bruna.moreira@openbossa.org>
+Brian Gix <bgix@codeaurora.org>
+Andre Guedes <andre.guedes@openbossa.org>
+Sheldon Demario <sheldon.demario@openbossa.org>
+Lucas De Marchi <lucas.demarchi@profusion.mobi>
+Szymon Janc <szymon.janc@tieto.com>
index 1f936e7..2c9aaf8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,81 @@
+ver 4.98:
+       Fix issue with adapter list upon initialization failure.
+       Fix issue with missing legacy property for Low Energy.
+       Fix issue with missing EIR information handling.
+       Fix issue with device address type tracking.
+       Fix issue with alert level characteristic.
+       Fix issue with headset shutdown handling.
+       Fix issue with Wiimote address handling.
+       Add support for advanced l2test options.
+       Add support for attribute protocol and multiple adapters.
+
+ver 4.97:
+       Update support for proximity profile.
+       Fix issue with SBC audio decoding quality.
+       Fix multiple issues with HFP support.
+       Fix multiple issues with A2DP support.
+       Fix multiple issues with AVDTP support.
+       Fix multiple issues with AVRCP support.
+       Add support for AVRCP meta-data transfer.
+       Add support for Bluetooth based thermometers.
+
+ver 4.96:
+       Fix issue with race condition in AVDTP stream start.
+       Fix issue with global adapter offline switching.
+       Fix issue with pairing and No Bonding devices.
+       Add support for Nintendo Wii Remote pairing.
+
+ver 4.95:
+       Fix issue with AVCTP replies with invalid PID.
+       Fix issue with AVRCP and unknown packet types.
+       Fix issue with AVRCP not using NOT_IMPLEMENTED correctly.
+       Fix issue with AVDTP discovery if all endpoints are in use.
+       Fix issue with invalid memory writes and media support.
+       Fix issue with not removing device alias and unbonding.
+       Fix issue with device disconnects and offline mode handling.
+       Add support for setting adapter name based on machine-info.
+       Add support for systemd service configuration.
+
+ver 4.94:
+       Fix issue with invalid read of memory in various modules.
+       Fix issue with buffer overflow when sending AVDTP commands.
+       Fix issue with response to vendor dependent AVRCP commands.
+       Fix issue with headset when not able to reply with ERROR.
+       Fix issue with crash when creating a device from storage.
+       Fix issue with handling non UTF-8 devices names.
+       Add support for improved discovery procedure.
+
+ver 4.93:
+       Fix issue with property type and Health Main channel.
+       Fix issue with crash when removing devices.
+       Add support for hid2hci and udev integration.
+
+ver 4.92:
+       Fix issue with handling of A2DP suspend response.
+       Fix issue with crashing when acquiring A2DP stream.
+       Fix issue with missing check for valid SCO before shutdown.
+       Fix issue with waiting for POLLERR when disconnecting SCO.
+       Fix issue with disconnect after primary service discovery.
+       Fix issue with attribute interface registration.
+       Add support for primary services over BR/EDR.
+       Add support for flushable packets of A2DP media.
+
+ver 4.91:
+       Fix issue with LMP version string and hciconfig.
+       Fix issue with missing discovery signal when scanning.
+       Fix issue with wrong state and canceling name resolving.
+       Fix issue with missing check during adapter initialization.
+       Fix issue with missing protocol not supported error and A2DP.
+       Fix issue with crash during driver unregistering and A2DP.
+       Fix issue with crash when receiving AVDTP close command.
+       Fix issue with remote SEP handling when A2DP codec changes.
+       Fix issue with SCO hangup handling and state changes.
+       Fix issue with security level and MCAP instances.
+       Fix issue with memory leak and HDP data channels.
+       Add support for discover characteristics by UUID to gatttool.
+       Add initial support for Out-of-Band association model.
+       Add initial support for SIM Access Profile.
+
 ver 4.90:
        Fix issue with setting of global mode property.
        Fix issue with handling of RequestSession responses.
index 07dcd08..5ed6c27 100644 (file)
@@ -3,6 +3,8 @@ AM_MAKEFLAGS = --no-print-directory
 
 lib_LTLIBRARIES =
 
+noinst_LIBRARIES =
+
 noinst_LTLIBRARIES =
 
 bin_PROGRAMS =
@@ -23,7 +25,7 @@ includedir = @includedir@/bluetooth
 
 include_HEADERS =
 
-if CONFIGFILES
+if DATAFILES
 dbusdir = $(sysconfdir)/dbus-1/system.d
 
 dbus_DATA = src/bluetooth.conf
@@ -35,10 +37,23 @@ conf_DATA =
 statedir = $(localstatedir)/lib/bluetooth
 
 state_DATA =
+
+if SYSTEMD
+systemdunitdir = @SYSTEMD_UNITDIR@
+
+systemdunit_DATA = src/bluetooth.service
+endif
 endif
 
 plugindir = $(libdir)/bluetooth/plugins
 
+if MAINTAINER_MODE
+build_plugindir = $(abs_top_srcdir)/plugins/.libs
+else
+build_plugindir = $(plugindir)
+endif
+
+
 plugin_LTLIBRARIES =
 
 
@@ -47,17 +62,20 @@ lib_headers = lib/bluetooth.h lib/hci.h lib/hci_lib.h lib/mgmt.h \
                lib/rfcomm.h lib/bnep.h lib/cmtp.h lib/hidp.h
 local_headers = $(foreach file,$(lib_headers), lib/bluetooth/$(notdir $(file)))
 
+BUILT_SOURCES = $(local_headers) src/builtin.h
+
 include_HEADERS += $(lib_headers)
 
 lib_LTLIBRARIES += lib/libbluetooth.la
 
 lib_libbluetooth_la_SOURCES = $(lib_headers) \
                                lib/bluetooth.c lib/hci.c lib/sdp.c lib/uuid.c
-lib_libbluetooth_la_LDFLAGS = -version-info 14:0:11
+lib_libbluetooth_la_LDFLAGS = -version-info 14:5:11
 lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
 
-CLEANFILES += $(local_headers)
+noinst_LTLIBRARIES += lib/libbluetooth-private.la
 
+lib_libbluetooth_private_la_SOURCES = $(lib_libbluetooth_la_SOURCES)
 
 if SBC
 noinst_LTLIBRARIES += sbc/libsbc.la
@@ -69,7 +87,7 @@ sbc_libsbc_la_SOURCES = sbc/sbc.h sbc/sbc.c sbc/sbc_math.h sbc/sbc_tables.h \
                        sbc/sbc_primitives_neon.h sbc/sbc_primitives_neon.c \
                        sbc/sbc_primitives_armv6.h sbc/sbc_primitives_armv6.c
 
-sbc_libsbc_la_CFLAGS = -finline-functions -fgcse-after-reload \
+sbc_libsbc_la_CFLAGS = $(AM_CFLAGS) -finline-functions -fgcse-after-reload \
                                        -funswitch-loops -funroll-loops
 
 noinst_PROGRAMS += sbc/sbcinfo sbc/sbcdec sbc/sbcenc
@@ -84,12 +102,13 @@ if SNDFILE
 noinst_PROGRAMS += sbc/sbctester
 
 sbc_sbctester_LDADD = @SNDFILE_LIBS@ -lm
-sbc_sbctest_CFLAGS = @SNDFILE_CFLAGS@
+sbc_sbctest_CFLAGS = $(AM_CFLAGS) @SNDFILE_CFLAGS@
 endif
 endif
 
 attrib_sources = attrib/att.h attrib/att.c attrib/gatt.h attrib/gatt.c \
-               attrib/gattrib.h attrib/gattrib.c
+               attrib/gattrib.h attrib/gattrib.c attrib/client.h \
+               attrib/client.c attrib/gatt-service.h attrib/gatt-service.c
 
 gdbus_sources = gdbus/gdbus.h gdbus/mainloop.c gdbus/watch.c \
                                        gdbus/object.c gdbus/polkit.c
@@ -112,11 +131,6 @@ builtin_modules += pnat
 builtin_sources += plugins/pnat.c
 endif
 
-if ECHOPLUGIN
-builtin_modules += echo
-builtin_sources += plugins/echo.c
-endif
-
 if AUDIOPLUGIN
 builtin_modules += audio
 builtin_sources += audio/main.c \
@@ -138,14 +152,11 @@ builtin_sources += audio/main.c \
                        audio/telephony.h audio/a2dp-codecs.h
 builtin_nodist += audio/telephony.c
 
-noinst_LIBRARIES = audio/libtelephony.a
+noinst_LIBRARIES += audio/libtelephony.a
 
 audio_libtelephony_a_SOURCES = audio/telephony.h audio/telephony-dummy.c \
                                audio/telephony-maemo5.c audio/telephony-ofono.c \
                                audio/telephony-maemo6.c audio/telephony-tizen.c
-
-$(audio_libtelephony_a_OBJECTS): $(local_headers)
-
 endif
 
 if SAPPLUGIN
@@ -153,7 +164,13 @@ builtin_modules += sap
 builtin_sources += sap/main.c \
                        sap/manager.h sap/manager.c \
                        sap/server.h sap/server.c \
-                       sap/sap.h sap/sap-dummy.c
+                       sap/sap.h
+
+builtin_nodist += sap/sap.c
+
+noinst_LIBRARIES += sap/libsap.a
+
+sap_libsap_a_SOURCES = sap/sap.h sap/sap-dummy.c sap/sap-u8500.c
 endif
 
 if INPUTPLUGIN
@@ -182,29 +199,34 @@ builtin_sources += network/main.c \
                        network/connection.h network/connection.c
 endif
 
+if PROXIMITYPLUGIN
+builtin_modules += proximity
+builtin_sources += proximity/main.c \
+                       proximity/manager.h proximity/manager.c \
+                       proximity/monitor.h proximity/monitor.c \
+                       proximity/reporter.h proximity/reporter.c
+endif
+
 if SERVICEPLUGIN
 builtin_modules += service
 builtin_sources += plugins/service.c
 endif
 
-if ATTRIBPLUGIN
-
-if READLINE
-bin_PROGRAMS += attrib/gatttool
+if GATT_EXAMPLE_PLUGIN
+builtin_modules += gatt_example
+builtin_sources += plugins/gatt-example.c
+endif
 
-attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \
-                               attrib/gattrib.c btio/btio.c \
-                               src/glib-helper.h src/glib-helper.c \
-                               attrib/gatttool.h attrib/interactive.c \
-                               attrib/utils.c
-attrib_gatttool_LDADD = lib/libbluetooth.la @GLIB_LIBS@ @READLINE_LIBS@
+if TIMEPLUGIN
+builtin_modules += time
+builtin_sources += time/main.c \
+                  time/server.h time/server.c
 endif
 
-builtin_modules += attrib
-builtin_sources += attrib/main.c \
-               attrib/manager.h attrib/manager.c \
-               attrib/client.h attrib/client.c \
-               attrib/example.h attrib/example.c
+if ALERTPLUGIN
+builtin_modules += alert
+builtin_sources += alert/main.c \
+                  alert/server.h alert/server.c
 endif
 
 if HEALTHPLUGIN
@@ -215,6 +237,13 @@ builtin_sources += health/hdp_main.c health/hdp_types.h \
                        health/hdp_util.h health/hdp_util.c
 endif
 
+if THERMOMETERPLUGIN
+builtin_modules += thermometer
+builtin_sources += thermometer/main.c \
+                       thermometer/manager.h thermometer/manager.c \
+                       thermometer/thermometer.h thermometer/thermometer.c
+endif
+
 builtin_modules += hciops mgmtops
 builtin_sources += plugins/hciops.c plugins/mgmtops.c
 
@@ -231,11 +260,31 @@ EXTRA_DIST += plugins/hal.c plugins/formfactor.c
 builtin_modules += storage
 builtin_sources += plugins/storage.c
 
+builtin_modules += adaptername
+builtin_sources += plugins/adaptername.c
+
+if WIIMOTEPLUGIN
+builtin_modules += wiimote
+builtin_sources += plugins/wiimote.c
+endif
+
 if MAEMO6PLUGIN
 builtin_modules += maemo6
 builtin_sources += plugins/maemo6.c
 endif
 
+if DBUSOOBPLUGIN
+builtin_modules += dbusoob
+builtin_sources += plugins/dbusoob.c
+endif
+
+if MAINTAINER_MODE
+plugin_LTLIBRARIES += plugins/external-dummy.la
+plugins_external_dummy_la_SOURCES = plugins/external-dummy.c
+plugins_external_dummy_la_LDFLAGS = -module -avoid-version -no-undefined
+plugins_external_dummy_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden
+endif
+
 sbin_PROGRAMS += src/bluetoothd
 
 src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
@@ -247,7 +296,8 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
                        src/sdpd-service.c src/sdpd-database.c \
                        src/attrib-server.h src/attrib-server.c \
                        src/sdp-xml.h src/sdp-xml.c \
-                       src/textfile.h src/textfile.c \
+                       src/sdp-client.h src/sdp-client.c \
+                       src/textfile.h src/textfile.c src/glib-compat.h \
                        src/glib-helper.h src/glib-helper.c \
                        src/oui.h src/oui.c src/uinput.h src/ppoll.h \
                        src/plugin.h src/plugin.c \
@@ -256,15 +306,20 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
                        src/error.h src/error.c \
                        src/manager.h src/manager.c \
                        src/adapter.h src/adapter.c \
-                       src/device.h src/device.c \
+                       src/device.h src/device.c src/attio.h \
                        src/dbus-common.c src/dbus-common.h \
-                       src/event.h src/event.c
-src_bluetoothd_LDADD = lib/libbluetooth.la @GLIB_LIBS@ @DBUS_LIBS@ \
+                       src/event.h src/event.c \
+                       src/oob.h src/oob.c src/eir.h src/eir.c
+src_bluetoothd_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @DBUS_LIBS@ \
                                                        @CAPNG_LIBS@ -ldl -lrt
 src_bluetoothd_LDFLAGS = -Wl,--export-dynamic \
                                -Wl,--version-script=$(srcdir)/src/bluetooth.ver
 
-src_bluetoothd_DEPENDENCIES = lib/libbluetooth.la
+src_bluetoothd_DEPENDENCIES = lib/libbluetooth-private.la
+
+src_bluetoothd_CFLAGS = $(AM_CFLAGS) -DBLUETOOTH_PLUGIN_BUILTIN \
+                                       -DPLUGINDIR=\""$(build_plugindir)"\"
+src_bluetoothd_SHORTNAME = bluetoothd
 
 builtin_files = src/builtin.h $(builtin_nodist)
 
@@ -274,7 +329,7 @@ CLEANFILES += $(builtin_files)
 
 man_MANS = src/bluetoothd.8
 
-if CONFIGFILES
+if DATAFILES
 conf_DATA += src/main.conf
 endif
 
@@ -283,8 +338,8 @@ EXTRA_DIST += src/genbuiltin src/bluetooth.conf \
                        input/input.conf serial/serial.conf \
                        audio/audio.conf audio/telephony-dummy.c \
                        audio/telephony-maemo5.c audio/telephony-ofono.c \
-                       audio/telephony-maemo6.c audio/telephony-tizen.c
-
+                       audio/telephony-maemo6.c sap/sap-dummy.c sap/sap-u8500.c \
+                       proximity/proximity.conf
 
 if ALSA
 alsadir = $(libdir)/alsa-lib
@@ -296,16 +351,17 @@ audio_libasound_module_pcm_bluetooth_la_SOURCES = audio/pcm_bluetooth.c \
                                        audio/rtp.h audio/ipc.h audio/ipc.c
 audio_libasound_module_pcm_bluetooth_la_LDFLAGS = -module -avoid-version #-export-symbols-regex [_]*snd_pcm_.*
 audio_libasound_module_pcm_bluetooth_la_LIBADD = sbc/libsbc.la \
-                                               lib/libbluetooth.la @ALSA_LIBS@
-audio_libasound_module_pcm_bluetooth_la_CFLAGS = @ALSA_CFLAGS@
+                                       lib/libbluetooth-private.la @ALSA_LIBS@
+audio_libasound_module_pcm_bluetooth_la_CFLAGS = $(AM_CFLAGS) @ALSA_CFLAGS@
 
 audio_libasound_module_ctl_bluetooth_la_SOURCES = audio/ctl_bluetooth.c \
                                        audio/rtp.h audio/ipc.h audio/ipc.c
 audio_libasound_module_ctl_bluetooth_la_LDFLAGS = -module -avoid-version #-export-symbols-regex [_]*snd_ctl_.*
-audio_libasound_module_ctl_bluetooth_la_LIBADD = lib/libbluetooth.la @ALSA_LIBS@
-audio_libasound_module_ctl_bluetooth_la_CFLAGS = @ALSA_CFLAGS@
+audio_libasound_module_ctl_bluetooth_la_LIBADD = \
+                                       lib/libbluetooth-private.la @ALSA_LIBS@
+audio_libasound_module_ctl_bluetooth_la_CFLAGS = $(AM_CLAGS) @ALSA_CFLAGS@
 
-if CONFIGFILES
+if DATAFILES
 alsaconfdir = $(datadir)/alsa
 
 alsaconf_DATA = audio/bluetooth.conf
@@ -328,11 +384,11 @@ audio_libgstbluetooth_la_SOURCES = audio/gstbluetooth.c audio/gstpragma.h \
                                audio/gstrtpsbcpay.h audio/gstrtpsbcpay.c \
                                audio/rtp.h audio/ipc.h audio/ipc.c
 audio_libgstbluetooth_la_LDFLAGS = -module -avoid-version
-audio_libgstbluetooth_la_LIBADD = sbc/libsbc.la lib/libbluetooth.la \
-                               @GSTREAMER_LIBS@ -lgstaudio-0.10 -lgstrtp-0.10
-$(audio_libgstbluetooth_la_OBJECTS): $(local_headers)
+audio_libgstbluetooth_la_LIBADD = sbc/libsbc.la lib/libbluetooth-private.la \
+                                               @DBUS_LIBS@ @GSTREAMER_LIBS@ \
+                                               -lgstaudio-0.10 -lgstrtp-0.10
 audio_libgstbluetooth_la_CFLAGS = -fvisibility=hidden -fno-strict-aliasing \
-                                               $(AM_CFLAGS) @GSTREAMER_CFLAGS@
+                               $(AM_CFLAGS) @DBUS_CFLAGS@ @GSTREAMER_CFLAGS@
 endif
 endif
 
@@ -341,8 +397,8 @@ EXTRA_DIST += audio/bluetooth.conf
 
 include Makefile.tools
 
-if UDEVRULES
-rulesdir = @UDEV_DATADIR@
+if DATAFILES
+rulesdir = @UDEV_DIR@/rules.d
 
 udev_files = scripts/bluetooth.rules
 
@@ -351,7 +407,11 @@ udev_files += scripts/bluetooth-hid2hci.rules
 endif
 
 if PCMCIA
+udevdir = @UDEV_DIR@
+
 udev_files += scripts/bluetooth-serial.rules
+
+dist_udev_SCRIPTS = scripts/bluetooth_serial
 endif
 
 rules_DATA = $(foreach file,$(udev_files), scripts/97-$(notdir $(file)))
@@ -362,12 +422,6 @@ CLEANFILES += $(rules_DATA)
 EXTRA_DIST += scripts/bluetooth.rules \
                scripts/bluetooth-hid2hci.rules scripts/bluetooth-serial.rules
 
-if PCMCIA
-udevdir = $(libexecdir)/udev
-
-dist_udev_SCRIPTS = scripts/bluetooth_serial
-endif
-
 EXTRA_DIST += doc/manager-api.txt \
                doc/adapter-api.txt doc/device-api.txt \
                doc/service-api.txt doc/agent-api.txt doc/attribute-api.txt \
@@ -378,22 +432,39 @@ EXTRA_DIST += doc/manager-api.txt \
 
 AM_YFLAGS = -d
 
-AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @CAPNG_CFLAGS@ \
-               -DBLUETOOTH_PLUGIN_BUILTIN -DPLUGINDIR=\""$(plugindir)"\"
+AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @CAPNG_CFLAGS@
 
 INCLUDES = -I$(builddir)/lib -I$(builddir)/src -I$(srcdir)/src \
                        -I$(srcdir)/audio -I$(srcdir)/sbc -I$(srcdir)/gdbus \
-                       -I$(srcdir)/attrib -I$(srcdir)/btio
+                       -I$(srcdir)/attrib -I$(srcdir)/btio -I$(srcdir)/tools \
+                       -I$(builddir)/tools
 
 if MCAP
 INCLUDES += -I$(builddir)/health
 endif
 
+unit_objects =
+
+if TEST
+unit_tests = unit/test-eir
+
+noinst_PROGRAMS += $(unit_tests)
+
+unit_test_eir_SOURCES = unit/test-eir.c src/eir.c src/glib-helper.c
+unit_test_eir_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @CHECK_LIBS@
+unit_test_eir_CFLAGS = $(AM_CFLAGS) @CHECK_CFLAGS@
+unit_objects += $(unit_test_eir_OBJECTS)
+else
+unit_tests =
+endif
+
+TESTS = $(unit_tests)
+
 pkgconfigdir = $(libdir)/pkgconfig
 
 pkgconfig_DATA = bluez.pc
 
-DISTCHECK_CONFIGURE_FLAGS = --disable-udevrules --enable-attrib
+DISTCHECK_CONFIGURE_FLAGS = --disable-datafiles
 
 DISTCLEANFILES = $(pkgconfig_DATA)
 
@@ -401,12 +472,13 @@ MAINTAINERCLEANFILES = Makefile.in \
        aclocal.m4 configure config.h.in config.sub config.guess \
        ltmain.sh depcomp compile missing install-sh mkinstalldirs ylwrap
 
-src/plugin.$(OBJEXT): src/builtin.h
-
 src/builtin.h: src/genbuiltin $(builtin_sources)
        $(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
 
 audio/telephony.c: audio/@TELEPHONY_DRIVER@
+       $(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
+
+sap/sap.c: sap/@SAP_DRIVER@
        $(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
 
 scripts/%.rules:
@@ -416,7 +488,7 @@ $(lib_libbluetooth_la_OBJECTS): $(local_headers)
 
 lib/bluetooth/%.h: lib/%.h
        $(AM_V_at)$(MKDIR_P) lib/bluetooth
-       $(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
+       $(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
 
 clean-local:
        $(RM) -r lib/bluetooth
index 1a1f5a1..eea1a9b 100644 (file)
@@ -1,6 +1,6 @@
 
 if TOOLS
-if CONFIGFILES
+if DATAFILES
 conf_DATA += tools/rfcomm.conf
 endif
 
@@ -18,9 +18,9 @@ tools_rfcomm_SOURCES = tools/rfcomm.c tools/parser.y tools/lexer.l \
                                        tools/kword.h tools/kword.c
 EXTRA_tools_rfcomm_SOURCES = tools/parser.h tools/parser.c \
                                                        tools/lexer.c
-tools_rfcomm_LDADD = lib/libbluetooth.la
+tools_rfcomm_LDADD = lib/libbluetooth-private.la
 
-tools_l2ping_LDADD = lib/libbluetooth.la
+tools_l2ping_LDADD = lib/libbluetooth-private.la
 
 tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
                                                tools/hciattach_st.c \
@@ -28,26 +28,40 @@ tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
                                                tools/hciattach_tialt.c \
                                                tools/hciattach_ath3k.c \
                                                tools/hciattach_qualcomm.c
-tools_hciattach_LDADD = lib/libbluetooth.la
+tools_hciattach_LDADD = lib/libbluetooth-private.la
 
 tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c \
                                                src/textfile.h src/textfile.c
-tools_hciconfig_LDADD = lib/libbluetooth.la
+tools_hciconfig_LDADD = lib/libbluetooth-private.la
 
 tools_hcitool_SOURCES = tools/hcitool.c src/oui.h src/oui.c \
                                                src/textfile.h src/textfile.c
-tools_hcitool_LDADD = lib/libbluetooth.la
+tools_hcitool_LDADD = lib/libbluetooth-private.la
 
 tools_sdptool_SOURCES = tools/sdptool.c src/sdp-xml.h src/sdp-xml.c
-tools_sdptool_LDADD = lib/libbluetooth.la
+tools_sdptool_LDADD = lib/libbluetooth-private.la
 
-tools_ciptool_LDADD = lib/libbluetooth.la
+tools_ciptool_LDADD = lib/libbluetooth-private.la
 
-tools_avinfo_LDADD = lib/libbluetooth.la
+tools_avinfo_LDADD = lib/libbluetooth-private.la
 
-tools_ppporc_LDADD = lib/libbluetooth.la
+tools_ppporc_LDADD = lib/libbluetooth-private.la
 
-tools_hcieventmask_LDADD = lib/libbluetooth.la
+tools_hcieventmask_LDADD = lib/libbluetooth-private.la
+
+noinst_PROGRAMS += mgmt/btmgmt
+mgmt_btmgmt_SOURCES = mgmt/main.c
+mgmt_btmgmt_LDADD = lib/libbluetooth-private.la
+
+if READLINE
+bin_PROGRAMS += attrib/gatttool
+
+attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \
+                               attrib/gattrib.c btio/btio.c \
+                               attrib/gatttool.h attrib/interactive.c \
+                               attrib/utils.c
+attrib_gatttool_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @READLINE_LIBS@
+endif
 
 dist_man_MANS += tools/rfcomm.1 tools/l2ping.8 \
                        tools/hciattach.8 tools/hciconfig.8 \
@@ -66,9 +80,9 @@ if TRACER
 sbin_PROGRAMS += tracer/hcitrace
 
 tracer_hcitrace_SOURCES = tracer/main.c
-tracer_hcitrace_LDADD = lib/libbluetooth.la \
+tracer_hcitrace_LDADD = lib/libbluetooth-private.la \
                                @GLIB_LIBS@ @DBUS_LIBS@ @CAPNG_LIBS@
-tracer_hcitrace_DEPENDENCIES = lib/libbluetooth.la
+tracer_hcitrace_DEPENDENCIES = lib/libbluetooth-private.la
 endif
 
 if BCCMD
@@ -77,7 +91,7 @@ sbin_PROGRAMS += tools/bccmd
 tools_bccmd_SOURCES = tools/bccmd.c tools/csr.h tools/csr.c \
                        tools/csr_hci.c tools/csr_h4.c tools/csr_3wire.c \
                        tools/csr_bcsp.c tools/ubcsp.h tools/ubcsp.c
-tools_bccmd_LDADD = lib/libbluetooth.la
+tools_bccmd_LDADD = lib/libbluetooth-private.la
 
 if USB
 tools_bccmd_SOURCES += tools/csr_usb.c
@@ -90,9 +104,11 @@ EXTRA_DIST += tools/bccmd.8
 endif
 
 if HID2HCI
-sbin_PROGRAMS += tools/hid2hci
+udevdir = @UDEV_DIR@
+
+udev_PROGRAMS = tools/hid2hci
 
-tools_hid2hci_LDADD = @USB_LIBS@
+tools_hid2hci_LDADD = @USB_LIBS@ @UDEV_LIBS@
 
 dist_man_MANS += tools/hid2hci.8
 else
@@ -130,7 +146,7 @@ cups_PROGRAMS = cups/bluetooth
 cups_bluetooth_SOURCES = $(gdbus_sources) cups/main.c cups/cups.h \
                                        cups/sdp.c cups/spp.c cups/hcrp.c
 
-cups_bluetooth_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ lib/libbluetooth.la
+cups_bluetooth_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ lib/libbluetooth-private.la
 endif
 
 
@@ -143,41 +159,43 @@ noinst_PROGRAMS += test/gaptest test/sdptest test/scotest \
                        test/attest test/hstest test/avtest test/ipctest \
                                        test/lmptest test/bdaddr test/agent \
                                        test/btiotest test/test-textfile \
-                                       test/uuidtest
+                                       test/uuidtest test/mpris-player
 
-test_hciemu_LDADD = @GLIB_LIBS@ lib/libbluetooth.la
+test_hciemu_LDADD = lib/libbluetooth-private.la
 
-test_l2test_LDADD = lib/libbluetooth.la
+test_l2test_LDADD = lib/libbluetooth-private.la
 
-test_rctest_LDADD = lib/libbluetooth.la
+test_rctest_LDADD = lib/libbluetooth-private.la
 
 test_gaptest_LDADD = @DBUS_LIBS@
 
-test_sdptest_LDADD = lib/libbluetooth.la
+test_sdptest_LDADD = lib/libbluetooth-private.la
 
-test_scotest_LDADD = lib/libbluetooth.la
+test_scotest_LDADD = lib/libbluetooth-private.la
 
-test_attest_LDADD = lib/libbluetooth.la
+test_attest_LDADD = lib/libbluetooth-private.la
 
-test_hstest_LDADD = lib/libbluetooth.la
+test_hstest_LDADD = lib/libbluetooth-private.la
 
-test_avtest_LDADD = lib/libbluetooth.la
+test_avtest_LDADD = lib/libbluetooth-private.la
 
-test_lmptest_LDADD = lib/libbluetooth.la
+test_lmptest_LDADD = lib/libbluetooth-private.la
 
 test_ipctest_SOURCES = test/ipctest.c audio/ipc.h audio/ipc.c
 test_ipctest_LDADD= @GLIB_LIBS@ sbc/libsbc.la
 
 test_bdaddr_SOURCES = test/bdaddr.c src/oui.h src/oui.c
-test_bdaddr_LDADD = lib/libbluetooth.la
+test_bdaddr_LDADD = lib/libbluetooth-private.la
 
 test_agent_LDADD = @DBUS_LIBS@
 
 test_btiotest_SOURCES = test/btiotest.c btio/btio.h btio/btio.c
-test_btiotest_LDADD = @GLIB_LIBS@ lib/libbluetooth.la
+test_btiotest_LDADD = @GLIB_LIBS@ lib/libbluetooth-private.la
 
 test_uuidtest_SOURCES = test/uuidtest.c
-test_uuidtest_LDADD = lib/libbluetooth.la
+test_uuidtest_LDADD = lib/libbluetooth-private.la
+
+test_mpris_player_LDADD = @DBUS_LIBS@ @GLIB_LIBS@
 
 test_test_textfile_SOURCES = test/test-textfile.c src/textfile.h src/textfile.c
 
@@ -188,13 +206,16 @@ else
 EXTRA_DIST += test/rctest.1 test/hciemu.1 test/bdaddr.8
 endif
 
-EXTRA_DIST += test/apitest test/hsplay test/hsmicro test/dbusdef.py \
-               test/monitor-bluetooth test/list-devices test/test-discovery \
-               test/test-manager test/test-adapter test/test-device \
-               test/test-service test/test-serial test/test-telephony \
-               test/test-network test/simple-agent test/simple-service \
-               test/simple-endpoint test/test-audio test/test-input \
-               test/test-attrib test/service-record.dtd test/service-did.xml \
+EXTRA_DIST += test/apitest test/sap-client test/hsplay test/hsmicro \
+               test/dbusdef.py test/monitor-bluetooth test/list-devices \
+               test/test-discovery test/test-manager test/test-adapter \
+               test/test-device test/test-service test/test-serial \
+               test/test-telephony test/test-network test/simple-agent \
+               test/simple-service test/simple-endpoint test/test-audio \
+               test/test-input test/test-attrib test/test-proximity \
+               test/test-sap-server test/test-oob test/test-serial-proxy \
+               test/test-thermometer test/test-health test/test-health-sink \
+               test/service-record.dtd test/service-did.xml \
                test/service-spp.xml test/service-opp.xml test/service-ftp.xml
 
 
@@ -204,7 +225,7 @@ bin_PROGRAMS += compat/hidd
 compat_hidd_SOURCES = compat/hidd.c compat/hidd.h src/uinput.h \
                                compat/sdp.h compat/sdp.c compat/fakehid.c \
                                                src/textfile.h src/textfile.c
-compat_hidd_LDADD = -lm lib/libbluetooth.la
+compat_hidd_LDADD = -lm lib/libbluetooth-private.la
 
 dist_man_MANS += compat/hidd.1
 else
@@ -217,7 +238,7 @@ bin_PROGRAMS += compat/pand
 compat_pand_SOURCES = compat/pand.c compat/pand.h \
                                compat/bnep.c compat/sdp.h compat/sdp.c \
                                                src/textfile.h src/textfile.c
-compat_pand_LDADD = lib/libbluetooth.la
+compat_pand_LDADD = lib/libbluetooth-private.la
 
 dist_man_MANS += compat/pand.1
 else
@@ -230,7 +251,7 @@ bin_PROGRAMS += compat/dund
 compat_dund_SOURCES = compat/dund.c compat/dund.h compat/lib.h \
                        compat/sdp.h compat/sdp.c compat/dun.c compat/msdun.c \
                                                src/textfile.h src/textfile.c
-compat_dund_LDADD = lib/libbluetooth.la
+compat_dund_LDADD = lib/libbluetooth-private.la
 
 dist_man_MANS += compat/dund.1
 else
diff --git a/TODO b/TODO
index 1120ad9..fab3ec0 100644 (file)
--- a/TODO
+++ b/TODO
@@ -17,18 +17,12 @@ Background
 General
 ==========
 
-- UUID128 handling: Create new functions to handle UUIDs on host order.
-  Functions should start with prefix "bt_uuid". In the first phase, attribute
-  server/client and gatttool code should be changed to use these new functions.
-  The idea is to keep the consistency for UUID-16, UUID-32 and UUID-128. SDP
-  functions store UUID-16 and UUID-32 on host order, however UUID-128 is stored
-  on network order/big endian. Attribute Protocol uses little endian, while
-  SDP uses big endian. The idea is always store the UUID values on host order
-  and use utility functions to convert to the proper byte order depending on
-  the protocol: ATT or SDP.
+- UUID handling: Use the new functions created for UUID handling in all parts
+  of BlueZ code.  Currently, the new bt_uuid_* functions are being used by
+  GATT-related code only.
 
   Priority: high
-  Complexity: C1
+  Complexity: C4
 
 - Rename glib-helper file to a more convenient name. The ideia is try to keep
   only sdp helpers functions. bt_* prefix shall be also changed.
@@ -120,12 +114,11 @@ Low Energy
 ATT/GATT
 ========
 
-- For BR/EDR, primary services can be registered based on the information
-  extracted from the service records. UUIDs, start and end handles information
-  are available in the record, Discover All Primary Services procedure is not
-  necessary. If a GATT service doesn't export a service record means that
-  it should not be used over BR/EDR. Don't start this task before to move the
-  attribute client code to the bluetoothd core.
+- At the moment authentication and authorization is not supported at the
+  same time, read/write requirements in the attribute server needs to
+  be extended. According to Bluetooth Specification a server shall check
+  authentication and authorization requirements before any other check is
+  performed.
 
   Priority: Medium
   Complexity: C1
@@ -136,11 +129,6 @@ ATT/GATT
   Priority: Medium
   Complexity: C2
 
-- GATT server: fix MTU exchange
-
-  Priority: Medium
-  Complexity: C2
-
 - Implement ATT PDU validation. Malformed PDUs can cause division by zero
   when decoding PDUs. A proper error PDU should be returned for this case.
   See decoding function in att.c file.
@@ -148,6 +136,11 @@ ATT/GATT
   Priority: Medium
   Complexity: C1
 
+- Fix hard-coded PSM for GATT services over basic rate.
+
+  Priority: Low
+  Complexity: C1
+
 - Refactor read_by_group() and read_by_type() in src/attrib-server.c
   (they've grown simply too big). First step could be to move out the
   long for-loops to new functions called e.g. get_groups() and get_types().
@@ -224,6 +217,7 @@ ATT/GATT
 
   Priority: Low
   Complexity: C2
+  Owner: Anderson Lizardo <anderson.lizardo@openbossa.org>
 
 Management Interface
 ====================
@@ -233,11 +227,6 @@ Management Interface
   Priority: High
   Complexity: C3
 
-- EIR generation support
-
-  Priority: High
-  Complexity: C2
-
 - Blacklist support
 
   Priority: Medium
@@ -252,3 +241,4 @@ Management Interface
 
   Priority: Medium
   Complexity: C2
+  Owner: Andre Guedes <andre.guedes@openbossa.org>
index 5c884d9..57fc5e0 100644 (file)
@@ -84,13 +84,11 @@ AC_DEFUN([AC_INIT_BLUEZ], [
        AC_SUBST(CONFIGDIR, "${configdir}")
        AC_SUBST(STORAGEDIR, "${storagedir}")
 
-       UDEV_DATADIR="`$PKG_CONFIG --variable=udevdir udev`"
-       if (test -z "${UDEV_DATADIR}"); then
-               UDEV_DATADIR="${sysconfdir}/udev/rules.d"
-       else
-               UDEV_DATADIR="${UDEV_DATADIR}/rules.d"
+       UDEV_DIR="`$PKG_CONFIG --variable=udevdir udev`"
+       if (test -z "${UDEV_DIR}"); then
+               UDEV_DIR="/lib/udev"
        fi
-       AC_SUBST(UDEV_DATADIR)
+       AC_SUBST(UDEV_DIR)
 ])
 
 AC_DEFUN([AC_PATH_DBUS], [
@@ -118,19 +116,14 @@ AC_DEFUN([AC_PATH_GLIB], [
 ])
 
 AC_DEFUN([AC_PATH_GSTREAMER], [
-       PKG_CHECK_MODULES(GSTREAMER, gstreamer-0.10 gstreamer-plugins-base-0.10, gstreamer_found=yes, gstreamer_found=no)
+       PKG_CHECK_MODULES(GSTREAMER, gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10, gstreamer_found=yes,
+                               AC_MSG_WARN(GStreamer library version 0.10.30 or later is required);gstreamer_found=no)
        AC_SUBST(GSTREAMER_CFLAGS)
        AC_SUBST(GSTREAMER_LIBS)
        GSTREAMER_PLUGINSDIR=`$PKG_CONFIG --variable=pluginsdir gstreamer-0.10`
        AC_SUBST(GSTREAMER_PLUGINSDIR)
 ])
 
-AC_DEFUN([AC_PATH_PULSE], [
-       PKG_CHECK_MODULES(PULSE, libpulse, pulse_found=yes, pulse_found=no)
-       AC_SUBST(PULSE_CFLAGS)
-       AC_SUBST(PULSE_LIBS)
-])
-
 AC_DEFUN([AC_PATH_ALSA], [
        PKG_CHECK_MODULES(ALSA, alsa, alsa_found=yes, alsa_found=no)
        AC_CHECK_LIB(rt, clock_gettime, ALSA_LIBS="$ALSA_LIBS -lrt", alsa_found=no)
@@ -150,6 +143,12 @@ AC_DEFUN([AC_PATH_USB], [
                        [Define to 1 if you need the usb_interrupt_read() function.]))
 ])
 
+AC_DEFUN([AC_PATH_UDEV], [
+       PKG_CHECK_MODULES(UDEV, libudev, udev_found=yes, udev_found=no)
+       AC_SUBST(UDEV_CFLAGS)
+       AC_SUBST(UDEV_LIBS)
+])
+
 AC_DEFUN([AC_PATH_SNDFILE], [
        PKG_CHECK_MODULES(SNDFILE, sndfile, sndfile_found=yes, sndfile_found=no)
        AC_SUBST(SNDFILE_CFLAGS)
@@ -165,6 +164,12 @@ AC_DEFUN([AC_PATH_READLINE], [
                [])
 ])
 
+AC_DEFUN([AC_PATH_CHECK], [
+       PKG_CHECK_MODULES(CHECK, check >= 0.9.6, check_found=yes, check_found=no)
+       AC_SUBST(CHECK_CFLAGS)
+       AC_SUBST(CHECK_LIBS)
+])
+
 AC_DEFUN([AC_PATH_OUI], [
        AC_ARG_WITH(ouifile,
                    AS_HELP_STRING([--with-ouifile=PATH],[Path to the oui.txt file @<:@auto@:>@]),
@@ -179,7 +184,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
        fortify_enable=yes
        pie_enable=yes
        sndfile_enable=${sndfile_found}
-       hal_enable=${hal_found}
+       hal_enable=no
        usb_enable=${usb_found}
        alsa_enable=${alsa_found}
        gstreamer_enable=${gstreamer_found}
@@ -188,10 +193,13 @@ AC_DEFUN([AC_ARG_BLUEZ], [
        serial_enable=yes
        network_enable=yes
        sap_enable=no
+       proximity_enable=no
+       time_enable=no
+       alert_enable=no
        service_enable=yes
-       health_enable=yes
+       health_enable=no
        pnat_enable=no
-       attrib_enable=no
+       gatt_example_enable=no
        tracer_enable=no
        tools_enable=yes
        hidd_enable=no
@@ -203,10 +211,13 @@ AC_DEFUN([AC_ARG_BLUEZ], [
        pcmcia_enable=no
        hid2hci_enable=no
        dfutool_enable=no
-       udevrules_enable=yes
-       configfiles_enable=yes
+       datafiles_enable=yes
        telephony_driver=dummy
        maemo6_enable=no
+       sap_driver=dummy
+       dbusoob_enable=no
+       wiimote_enable=no
+       thermometer_enable=no
 
        AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization], [disable code optimization]), [
                optimization_enable=${enableval}
@@ -228,6 +239,23 @@ AC_DEFUN([AC_ARG_BLUEZ], [
                sap_enable=${enableval}
        ])
 
+       AC_ARG_WITH(sap, AC_HELP_STRING([--with-sap=DRIVER], [select SAP driver]), [
+               sap_driver=${withval}
+       ])
+       AC_SUBST([SAP_DRIVER], [sap-${sap_driver}.c])
+
+       AC_ARG_ENABLE(proximity, AC_HELP_STRING([--enable-proximity], [enable proximity plugin]), [
+               proximity_enable=${enableval}
+       ])
+
+       AC_ARG_ENABLE(time, AC_HELP_STRING([--enable-time], [enable Time Profile plugin]), [
+               time_enable=${enableval}
+       ])
+
+       AC_ARG_ENABLE(alert, AC_HELP_STRING([--enable-alert], [enable Phone Alert Profile plugin]), [
+               alert_enable=${enableval}
+       ])
+
        AC_ARG_ENABLE(serial, AC_HELP_STRING([--disable-serial], [disable serial plugin]), [
                serial_enable=${enableval}
        ])
@@ -252,8 +280,8 @@ AC_DEFUN([AC_ARG_BLUEZ], [
                pnat_enable=${enableval}
        ])
 
-       AC_ARG_ENABLE(attrib, AC_HELP_STRING([--enable-attrib], [enable attrib plugin]), [
-               attrib_enable=${enableval}
+       AC_ARG_ENABLE(gatt-example, AC_HELP_STRING([--enable-gatt-example], [enable GATT example plugin]), [
+               gatt_example_enable=${enableval}
        ])
 
        AC_ARG_ENABLE(gstreamer, AC_HELP_STRING([--enable-gstreamer], [enable GStreamer support]), [
@@ -312,12 +340,8 @@ AC_DEFUN([AC_ARG_BLUEZ], [
                test_enable=${enableval}
        ])
 
-       AC_ARG_ENABLE(udevrules, AC_HELP_STRING([--enable-udevrules], [install Bluetooth udev rules]), [
-               udevrules_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(configfiles, AC_HELP_STRING([--enable-configfiles], [install Bluetooth configuration files]), [
-               configfiles_enable=${enableval}
+       AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--enable-datafiles], [install Bluetooth configuration and data files]), [
+               datafiles_enable=${enableval}
        ])
 
        AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [enable compiling with debugging information]), [
@@ -334,10 +358,22 @@ AC_DEFUN([AC_ARG_BLUEZ], [
                maemo6_enable=${enableval}
        ])
 
+       AC_ARG_ENABLE(dbusoob, AC_HELP_STRING([--enable-dbusoob], [compile with D-Bus OOB plugin]), [
+               dbusoob_enable=${enableval}
+       ])
+
+       AC_ARG_ENABLE(wiimote, AC_HELP_STRING([--enable-wiimote], [compile with Wii Remote plugin]), [
+               wiimote_enable=${enableval}
+       ])
+
        AC_ARG_ENABLE(hal, AC_HELP_STRING([--enable-hal], [Use HAL to determine adapter class]), [
                hal_enable=${enableval}
        ])
 
+       AC_ARG_ENABLE(thermometer, AC_HELP_STRING([--enable-thermometer], [enable thermometer plugin]), [
+               thermometer_enable=${enableval}
+       ])
+
        if (test "${fortify_enable}" = "yes"); then
                CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2"
        fi
@@ -370,26 +406,30 @@ AC_DEFUN([AC_ARG_BLUEZ], [
        AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes")
        AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes")
        AM_CONDITIONAL(SAPPLUGIN, test "${sap_enable}" = "yes")
+       AM_CONDITIONAL(PROXIMITYPLUGIN, test "${proximity_enable}" = "yes")
+       AM_CONDITIONAL(TIMEPLUGIN, test "${time_enable}" = "yes")
+       AM_CONDITIONAL(ALERTPLUGIN, test "${alert_enable}" = "yes")
        AM_CONDITIONAL(SERVICEPLUGIN, test "${service_enable}" = "yes")
        AM_CONDITIONAL(HEALTHPLUGIN, test "${health_enable}" = "yes")
        AM_CONDITIONAL(MCAP, test "${health_enable}" = "yes")
        AM_CONDITIONAL(HAL, test "${hal_enable}" = "yes")
        AM_CONDITIONAL(READLINE, test "${readline_found}" = "yes")
-       AM_CONDITIONAL(ATTRIBPLUGIN, test "${attrib_enable}" = "yes")
-       AM_CONDITIONAL(ECHOPLUGIN, test "no" = "yes")
+       AM_CONDITIONAL(GATT_EXAMPLE_PLUGIN, test "${gatt_example_enable}" = "yes")
        AM_CONDITIONAL(PNATPLUGIN, test "${pnat_enable}" = "yes")
        AM_CONDITIONAL(TRACER, test "${tracer_enable}" = "yes")
        AM_CONDITIONAL(HIDD, test "${hidd_enable}" = "yes")
        AM_CONDITIONAL(PAND, test "${pand_enable}" = "yes")
        AM_CONDITIONAL(DUND, test "${dund_enable}" = "yes")
        AM_CONDITIONAL(CUPS, test "${cups_enable}" = "yes")
-       AM_CONDITIONAL(TEST, test "${test_enable}" = "yes")
+       AM_CONDITIONAL(TEST, test "${test_enable}" = "yes" && test "${check_found}" = "yes")
        AM_CONDITIONAL(TOOLS, test "${tools_enable}" = "yes")
        AM_CONDITIONAL(BCCMD, test "${bccmd_enable}" = "yes")
        AM_CONDITIONAL(PCMCIA, test "${pcmcia_enable}" = "yes")
-       AM_CONDITIONAL(HID2HCI, test "${hid2hci_enable}" = "yes" && test "${usb_found}" = "yes")
+       AM_CONDITIONAL(HID2HCI, test "${hid2hci_enable}" = "yes" && test "${usb_found}" = "yes" && test "${udev_found}" = "yes")
        AM_CONDITIONAL(DFUTOOL, test "${dfutool_enable}" = "yes" && test "${usb_found}" = "yes")
-       AM_CONDITIONAL(UDEVRULES, test "${udevrules_enable}" = "yes")
-       AM_CONDITIONAL(CONFIGFILES, test "${configfiles_enable}" = "yes")
+       AM_CONDITIONAL(DATAFILES, test "${datafiles_enable}" = "yes")
        AM_CONDITIONAL(MAEMO6PLUGIN, test "${maemo6_enable}" = "yes")
+       AM_CONDITIONAL(DBUSOOBPLUGIN, test "${dbusoob_enable}" = "yes")
+       AM_CONDITIONAL(WIIMOTEPLUGIN, test "${wiimote_enable}" = "yes")
+       AM_CONDITIONAL(THERMOMETERPLUGIN, test "${thermometer_enable}" = "yes")
 ])
diff --git a/alert/main.c b/alert/main.c
new file mode 100644 (file)
index 0000000..25100e9
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <glib.h>
+
+#include "plugin.h"
+#include "hcid.h"
+#include "log.h"
+#include "server.h"
+
+static int alert_init(void)
+{
+       if (!main_opts.attrib_server) {
+               DBG("Attribute server is disabled");
+               return -1;
+       }
+
+       return alert_server_init();
+}
+
+static void alert_exit(void)
+{
+       if (!main_opts.attrib_server)
+               return;
+
+       alert_server_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(alert, VERSION,
+                       BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                       alert_init, alert_exit)
diff --git a/alert/server.c b/alert/server.c
new file mode 100644 (file)
index 0000000..d91b156
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "server.h"
+
+int alert_server_init(void)
+{
+       return 0;
+}
+
+void alert_server_exit(void)
+{
+}
similarity index 82%
rename from attrib/example.h
rename to alert/server.h
index a2b07fe..e59bdb1 100644 (file)
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2010  Nokia Corporation
- *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -22,5 +22,5 @@
  *
  */
 
-int server_example_init(void);
-void server_example_exit(void);
+int alert_server_init(void);
+void alert_server_exit(void);
index 08000e0..a3a8947 100644 (file)
@@ -39,18 +39,18 @@ const char *att_ecode2str(uint8_t status)
        case ATT_ECODE_INVALID_HANDLE:
                return "Invalid handle";
        case ATT_ECODE_READ_NOT_PERM:
-               return "Atribute can't be read";
+               return "Attribute can't be read";
        case ATT_ECODE_WRITE_NOT_PERM:
                return "Attribute can't be written";
        case ATT_ECODE_INVALID_PDU:
                return "Attribute PDU was invalid";
-       case ATT_ECODE_INSUFF_AUTHEN:
+       case ATT_ECODE_AUTHENTICATION:
                return "Attribute requires authentication before read/write";
        case ATT_ECODE_REQ_NOT_SUPP:
                return "Server doesn't support the request received";
        case ATT_ECODE_INVALID_OFFSET:
                return "Offset past the end of the attribute";
-       case ATT_ECODE_INSUFF_AUTHO:
+       case ATT_ECODE_AUTHORIZATION:
                return "Attribute requires authorization before read/write";
        case ATT_ECODE_PREP_QUEUE_FULL:
                return "Too many prepare writes have been queued";
@@ -820,62 +820,65 @@ struct att_data_list *dec_find_info_resp(const uint8_t *pdu, int len,
        return list;
 }
 
-uint16_t enc_notification(struct attribute *a, uint8_t *pdu, int len)
+uint16_t enc_notification(uint16_t handle, uint8_t *value, int vlen,
+                                               uint8_t *pdu, int len)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
 
        if (pdu == NULL)
                return 0;
 
-       if (len < (a->len + min_len))
+       if (len < (vlen + min_len))
                return 0;
 
        pdu[0] = ATT_OP_HANDLE_NOTIFY;
-       att_put_u16(a->handle, &pdu[1]);
-       memcpy(&pdu[3], a->data, a->len);
+       att_put_u16(handle, &pdu[1]);
+       memcpy(&pdu[3], value, vlen);
 
-       return a->len + min_len;
+       return vlen + min_len;
 }
 
-uint16_t enc_indication(struct attribute *a, uint8_t *pdu, int len)
+uint16_t enc_indication(uint16_t handle, uint8_t *value, int vlen,
+                                               uint8_t *pdu, int len)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
 
        if (pdu == NULL)
                return 0;
 
-       if (len < (a->len + min_len))
+       if (len < (vlen + min_len))
                return 0;
 
        pdu[0] = ATT_OP_HANDLE_IND;
-       att_put_u16(a->handle, &pdu[1]);
-       memcpy(&pdu[3], a->data, a->len);
+       att_put_u16(handle, &pdu[1]);
+       memcpy(&pdu[3], value, vlen);
 
-       return a->len + min_len;
+       return vlen + min_len;
 }
 
-struct attribute *dec_indication(const uint8_t *pdu, int len)
+uint16_t dec_indication(const uint8_t *pdu, int len, uint16_t *handle,
+                                               uint8_t *value, int vlen)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
-
-       struct attribute *a;
+       uint16_t dlen;
 
        if (pdu == NULL)
-               return NULL;
+               return 0;
 
        if (pdu[0] != ATT_OP_HANDLE_IND)
-               return NULL;
+               return 0;
 
        if (len < min_len)
-               return NULL;
+               return 0;
+
+       dlen = MIN(len - min_len, vlen);
 
-       a = g_malloc0(sizeof(struct attribute) + len - min_len);
-       a->len = len - min_len;
+       if (handle)
+               *handle = att_get_u16(&pdu[1]);
 
-       a->handle = att_get_u16(&pdu[1]);
-       memcpy(a->data, &pdu[3], a->len);
+       memcpy(value, &pdu[3], dlen);
 
-       return a;
+       return dlen;
 }
 
 uint16_t enc_confirmation(uint8_t *pdu, int len)
index 7a83bfa..dc266f1 100644 (file)
@@ -43,6 +43,7 @@
 #define GATT_SERVER_CHARAC_CFG_UUID    0x2903
 #define GATT_CHARAC_FMT_UUID           0x2904
 #define GATT_CHARAC_AGREG_FMT_UUID     0x2905
+#define GATT_CHARAC_VALID_RANGE_UUID   0x2906
 
 /* Attribute Protocol Opcodes */
 #define ATT_OP_ERROR                   0x01
 #define ATT_ECODE_READ_NOT_PERM                        0x02
 #define ATT_ECODE_WRITE_NOT_PERM               0x03
 #define ATT_ECODE_INVALID_PDU                  0x04
-#define ATT_ECODE_INSUFF_AUTHEN                        0x05
+#define ATT_ECODE_AUTHENTICATION               0x05
 #define ATT_ECODE_REQ_NOT_SUPP                 0x06
 #define ATT_ECODE_INVALID_OFFSET               0x07
-#define ATT_ECODE_INSUFF_AUTHO                 0x08
+#define ATT_ECODE_AUTHORIZATION                        0x08
 #define ATT_ECODE_PREP_QUEUE_FULL              0x09
 #define ATT_ECODE_ATTR_NOT_FOUND               0x0A
 #define ATT_ECODE_ATTR_NOT_LONG                        0x0B
 #define ATT_CHAR_PROPER_AUTH                   0x40
 #define ATT_CHAR_PROPER_EXT_PROPER             0x80
 
+/* Client Characteristic Configuration bit field */
+#define ATT_CLIENT_CHAR_CONF_NOTIFICATION      0x0001
+#define ATT_CLIENT_CHAR_CONF_INDICATION                0x0002
 
 #define ATT_MAX_MTU                            256
 #define ATT_DEFAULT_L2CAP_MTU                  48
 #define ATT_DEFAULT_LE_MTU                     23
 
+#define ATT_CID                                        4
+#define ATT_PSM                                        31
+
 /* Requirements for read/write operations */
 enum {
        ATT_NONE,               /* No restrictions */
@@ -127,7 +134,7 @@ struct attribute {
        uint8_t (*write_cb)(struct attribute *a, gpointer user_data);
        gpointer cb_user_data;
        int len;
-       uint8_t data[0];
+       uint8_t *data;
 };
 
 struct att_data_list {
@@ -295,9 +302,12 @@ uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list,
                                                        uint8_t *pdu, int len);
 struct att_data_list *dec_find_info_resp(const uint8_t *pdu, int len,
                                                        uint8_t *format);
-uint16_t enc_notification(struct attribute *a, uint8_t *pdu, int len);
-uint16_t enc_indication(struct attribute *a, uint8_t *pdu, int len);
-struct attribute *dec_indication(const uint8_t *pdu, int len);
+uint16_t enc_notification(uint16_t handle, uint8_t *value, int vlen,
+                                               uint8_t *pdu, int len);
+uint16_t enc_indication(uint16_t handle, uint8_t *value, int vlen,
+                                               uint8_t *pdu, int len);
+uint16_t dec_indication(const uint8_t *pdu, int len, uint16_t *handle,
+                                               uint8_t *value, int vlen);
 uint16_t enc_confirmation(uint8_t *pdu, int len);
 
 uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, int len);
index 3237a6b..60cff01 100644 (file)
@@ -34,6 +34,7 @@
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/uuid.h>
 
+#include "glib-compat.h"
 #include "adapter.h"
 #include "device.h"
 #include "log.h"
 
 #include "att.h"
 #include "gattrib.h"
+#include "attio.h"
 #include "gatt.h"
 #include "client.h"
 
 #define CHAR_INTERFACE "org.bluez.Characteristic"
 
-struct gatt_service {
-       struct btd_device *dev;
-       bdaddr_t sba;
-       bdaddr_t dba;
-       char *path;
-       GSList *primary;
-       GAttrib *attrib;
-       DBusMessage *msg;
-       int psm;
-       gboolean listen;
-};
-
 struct format {
        guint8 format;
        guint8 exponent;
@@ -70,16 +60,28 @@ struct format {
        guint16 desc;
 } __attribute__ ((packed));
 
-struct primary {
-       struct gatt_service *gatt;
-       struct att_primary *att;
+struct query {
+       DBusMessage *msg;
+       guint attioid;
+       GSList *list;
+};
+
+struct gatt_service {
+       struct btd_device *dev;
+       struct att_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 primary *prim;
+       struct gatt_service *gatt;
        char *path;
        uint16_t handle;
        uint16_t end;
@@ -93,9 +95,8 @@ struct characteristic {
 };
 
 struct query_data {
-       struct primary *prim;
+       struct gatt_service *gatt;
        struct characteristic *chr;
-       DBusMessage *msg;
        uint16_t handle;
 };
 
@@ -103,13 +104,11 @@ struct watcher {
        guint id;
        char *name;
        char *path;
-       struct primary *prim;
+       struct gatt_service *gatt;
 };
 
 static GSList *gatt_services = NULL;
 
-static DBusConnection *connection;
-
 static void characteristic_free(void *user_data)
 {
        struct characteristic *chr = user_data;
@@ -131,40 +130,26 @@ static void watcher_free(void *user_data)
        g_free(watcher);
 }
 
-static void primary_free(void *user_data)
-{
-       struct primary *prim = user_data;
-       GSList *l;
-
-       for (l = prim->watchers; l; l = l->next) {
-               struct watcher *watcher = l->data;
-               g_dbus_remove_watch(connection, watcher->id);
-       }
-
-       g_slist_foreach(prim->chars, (GFunc) characteristic_free, NULL);
-       g_slist_free(prim->chars);
-       g_free(prim->path);
-       g_free(prim);
-}
-
-static void gatt_service_free(void *user_data)
+static void gatt_service_free(struct gatt_service *gatt)
 {
-       struct gatt_service *gatt = user_data;
-
-       g_slist_foreach(gatt->primary, (GFunc) primary_free, NULL);
-       g_slist_free(gatt->primary);
-       g_attrib_unref(gatt->attrib);
+       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 int gatt_dev_cmp(gconstpointer a, gconstpointer b)
+static void gatt_get_address(struct gatt_service *gatt,
+                               bdaddr_t *sba, bdaddr_t *dba)
 {
-       const struct gatt_service *gatt = a;
-       const struct btd_device *dev = b;
+       struct btd_device *device = gatt->dev;
+       struct btd_adapter *adapter;
 
-       return gatt->dev != dev;
+       adapter = device_get_adapter(device);
+       adapter_get_address(adapter, sba);
+       device_get_address(device, dba, NULL);
 }
 
 static int characteristic_handle_cmp(gconstpointer a, gconstpointer b)
@@ -222,14 +207,11 @@ static void append_char_dict(DBusMessageIter *iter, struct characteristic *chr)
 static void watcher_exit(DBusConnection *conn, void *user_data)
 {
        struct watcher *watcher = user_data;
-       struct primary *prim = watcher->prim;
-       struct gatt_service *gatt = prim->gatt;
-
-       DBG("%s watcher %s exited", prim->path, watcher->name);
+       struct gatt_service *gatt = watcher->gatt;
 
-       prim->watchers = g_slist_remove(prim->watchers, watcher);
+       DBG("%s watcher %s exited", gatt->path, watcher->name);
 
-       g_attrib_unref(gatt->attrib);
+       gatt->watchers = g_slist_remove(gatt->watchers, watcher);
 }
 
 static int characteristic_set_value(struct characteristic *chr,
@@ -249,6 +231,7 @@ 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,
@@ -261,7 +244,7 @@ static void update_watchers(gpointer data, gpointer user_data)
                        &chr->value, chr->vlen, DBUS_TYPE_INVALID);
 
        dbus_message_set_no_reply(msg, TRUE);
-       g_dbus_send_message(connection, msg);
+       g_dbus_send_message(conn, msg);
 }
 
 static void events_handler(const uint8_t *pdu, uint16_t len,
@@ -269,8 +252,7 @@ static void events_handler(const uint8_t *pdu, uint16_t len,
 {
        struct gatt_service *gatt = user_data;
        struct characteristic *chr;
-       struct primary *prim;
-       GSList *lprim, *lchr;
+       GSList *l;
        uint8_t opdu[ATT_MAX_MTU];
        guint handle;
        uint16_t olen;
@@ -283,17 +265,12 @@ static void events_handler(const uint8_t *pdu, uint16_t len,
 
        handle = att_get_u16(&pdu[1]);
 
-       for (lprim = gatt->primary, prim = NULL, chr = NULL; lprim;
-                                               lprim = lprim->next) {
-               prim = lprim->data;
+       l = g_slist_find_custom(gatt->chars, GUINT_TO_POINTER(handle),
+                                               characteristic_handle_cmp);
+       if (!l)
+               return;
 
-               lchr = g_slist_find_custom(prim->chars,
-                       GUINT_TO_POINTER(handle), characteristic_handle_cmp);
-               if (lchr) {
-                       chr = lchr->data;
-                       break;
-               }
-       }
+       chr = l->data;
 
        if (chr == NULL) {
                DBG("Attribute handle 0x%02x not found", handle);
@@ -309,131 +286,84 @@ static void events_handler(const uint8_t *pdu, uint16_t len,
                if (characteristic_set_value(chr, &pdu[3], len - 3) < 0)
                        DBG("Can't change Characteristic 0x%02x", handle);
 
-               g_slist_foreach(prim->watchers, update_watchers, chr);
+               g_slist_foreach(gatt->watchers, update_watchers, chr);
                break;
        }
 }
 
-static void attrib_destroy(gpointer user_data)
+static void offline_char_written(gpointer user_data)
 {
-       struct gatt_service *gatt = user_data;
+       struct characteristic *chr = user_data;
+       struct gatt_service *gatt = chr->gatt;
 
-       gatt->attrib = NULL;
+       gatt->offline_chars = g_slist_remove(gatt->offline_chars, chr);
+
+       if (gatt->offline_chars || gatt->watchers)
+               return;
+
+       btd_device_remove_attio_callback(gatt->dev, gatt->attioid);
+       gatt->attioid = 0;
 }
 
-static void attrib_disconnect(gpointer user_data)
+static void offline_char_write(gpointer data, gpointer user_data)
 {
-       struct gatt_service *gatt = user_data;
+       struct characteristic *chr = data;
+       GAttrib *attrib = user_data;
 
-       /* Remote initiated disconnection only */
-       g_attrib_unref(gatt->attrib);
+       gatt_write_cmd(attrib, chr->handle, chr->value, chr->vlen,
+                                               offline_char_written, chr);
 }
 
-static void connect_cb(GIOChannel *chan, GError *gerr, gpointer user_data)
+static void attio_connected(GAttrib *attrib, gpointer user_data)
 {
        struct gatt_service *gatt = user_data;
 
-       if (gerr) {
-               if (gatt->msg) {
-                       DBusMessage *reply = btd_error_failed(gatt->msg,
-                                                       gerr->message);
-                       g_dbus_send_message(connection, reply);
-               }
-
-               error("%s", gerr->message);
-               goto fail;
-       }
+       gatt->attrib = g_attrib_ref(attrib);
 
-       if (gatt->attrib == NULL)
-               return;
-
-       /* Listen mode: used for notification and indication */
-       if (gatt->listen == TRUE) {
-               g_attrib_register(gatt->attrib,
-                                       ATT_OP_HANDLE_NOTIFY,
+       g_attrib_register(gatt->attrib, ATT_OP_HANDLE_NOTIFY,
                                        events_handler, gatt, NULL);
-               g_attrib_register(gatt->attrib,
-                                       ATT_OP_HANDLE_IND,
+       g_attrib_register(gatt->attrib, ATT_OP_HANDLE_IND,
                                        events_handler, gatt, NULL);
-               return;
-       }
 
-       return;
-fail:
-       g_attrib_unref(gatt->attrib);
+       g_slist_foreach(gatt->offline_chars, offline_char_write, attrib);
 }
 
-static int l2cap_connect(struct gatt_service *gatt, GError **gerr,
-                                                               gboolean listen)
+static void attio_disconnected(gpointer user_data)
 {
-       GIOChannel *io;
+       struct gatt_service *gatt = user_data;
 
-       if (gatt->attrib != NULL) {
-               gatt->attrib = g_attrib_ref(gatt->attrib);
-               gatt->listen = listen;
-               return 0;
+       if (gatt->attrib) {
+               g_attrib_unref(gatt->attrib);
+               gatt->attrib = NULL;
        }
-
-       /*
-        * FIXME: If the service doesn't support Client Characteristic
-        * Configuration it is necessary to poll the server from time
-        * to time checking for modifications.
-        */
-       if (gatt->psm < 0)
-               io = bt_io_connect(BT_IO_L2CAP, connect_cb, gatt, NULL, gerr,
-                       BT_IO_OPT_SOURCE_BDADDR, &gatt->sba,
-                       BT_IO_OPT_DEST_BDADDR, &gatt->dba,
-                       BT_IO_OPT_CID, GATT_CID,
-                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
-                       BT_IO_OPT_INVALID);
-       else
-               io = bt_io_connect(BT_IO_L2CAP, connect_cb, gatt, NULL, gerr,
-                       BT_IO_OPT_SOURCE_BDADDR, &gatt->sba,
-                       BT_IO_OPT_DEST_BDADDR, &gatt->dba,
-                       BT_IO_OPT_PSM, gatt->psm,
-                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
-                       BT_IO_OPT_INVALID);
-       if (!io)
-               return -1;
-
-       gatt->attrib = g_attrib_new(io);
-       g_io_channel_unref(io);
-       gatt->listen = listen;
-
-       g_attrib_set_destroy_function(gatt->attrib, attrib_destroy, gatt);
-       g_attrib_set_disconnect_function(gatt->attrib, attrib_disconnect,
-                                                                       gatt);
-
-       return 0;
 }
 
 static DBusMessage *register_watcher(DBusConnection *conn,
                                                DBusMessage *msg, void *data)
 {
        const char *sender = dbus_message_get_sender(msg);
-       struct primary *prim = data;
+       struct gatt_service *gatt = data;
        struct watcher *watcher;
-       GError *gerr = NULL;
        char *path;
 
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
                                                        DBUS_TYPE_INVALID))
                return btd_error_invalid_args(msg);
 
-       if (l2cap_connect(prim->gatt, &gerr, TRUE) < 0) {
-               DBusMessage *reply = btd_error_failed(msg, gerr->message);
-               g_error_free(gerr);
-               return reply;
-       }
-
        watcher = g_new0(struct watcher, 1);
        watcher->name = g_strdup(sender);
-       watcher->prim = prim;
+       watcher->gatt = gatt;
        watcher->path = g_strdup(path);
        watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
                                                        watcher, watcher_free);
 
-       prim->watchers = g_slist_append(prim->watchers, watcher);
+       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);
 }
@@ -442,7 +372,7 @@ static DBusMessage *unregister_watcher(DBusConnection *conn,
                                                DBusMessage *msg, void *data)
 {
        const char *sender = dbus_message_get_sender(msg);
-       struct primary *prim = data;
+       struct gatt_service *gatt = data;
        struct watcher *watcher, *match;
        GSList *l;
        char *path;
@@ -454,25 +384,29 @@ static DBusMessage *unregister_watcher(DBusConnection *conn,
        match = g_new0(struct watcher, 1);
        match->name = g_strdup(sender);
        match->path = g_strdup(path);
-       l = g_slist_find_custom(prim->watchers, match, watcher_cmp);
+       l = g_slist_find_custom(gatt->watchers, match, watcher_cmp);
        watcher_free(match);
        if (!l)
                return btd_error_not_authorized(msg);
 
        watcher = l->data;
        g_dbus_remove_watch(conn, watcher->id);
-       prim->watchers = g_slist_remove(prim->watchers, watcher);
+       gatt->watchers = g_slist_remove(gatt->watchers, watcher);
        watcher_free(watcher);
 
+       if (gatt->watchers == NULL && gatt->attioid) {
+               btd_device_remove_attio_callback(gatt->dev, gatt->attioid);
+               gatt->attioid = 0;
+       }
+
        return dbus_message_new_method_return(msg);
 }
 
 static DBusMessage *set_value(DBusConnection *conn, DBusMessage *msg,
                        DBusMessageIter *iter, struct characteristic *chr)
 {
-       struct gatt_service *gatt = chr->prim->gatt;
+       struct gatt_service *gatt = chr->gatt;
        DBusMessageIter sub;
-       GError *gerr = NULL;
        uint8_t *value;
        int len;
 
@@ -484,15 +418,19 @@ static DBusMessage *set_value(DBusConnection *conn, DBusMessage *msg,
 
        dbus_message_iter_get_fixed_array(&sub, &value, &len);
 
-       if (l2cap_connect(gatt, &gerr, FALSE) < 0) {
-               DBusMessage *reply = btd_error_failed(msg, gerr->message);
-               g_error_free(gerr);
-               return reply;
-       }
+       characteristic_set_value(chr, value, len);
 
-       gatt_write_cmd(gatt->attrib, chr->handle, value, len, NULL, NULL);
+       if (gatt->attioid == 0)
+               gatt->attioid = btd_device_add_attio_callback(gatt->dev,
+                                                       attio_connected,
+                                                       attio_disconnected,
+                                                       gatt);
 
-       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);
 }
@@ -572,34 +510,34 @@ static char *characteristic_list_to_string(GSList *chars)
        return g_string_free(characteristics, FALSE);
 }
 
-static void store_characteristics(struct gatt_service *gatt,
-                                                       struct primary *prim)
+static void store_characteristics(const bdaddr_t *sba, const bdaddr_t *dba,
+                                               uint16_t start, GSList *chars)
 {
        char *characteristics;
-       struct att_primary *att = prim->att;
 
-       characteristics = characteristic_list_to_string(prim->chars);
+       characteristics = characteristic_list_to_string(chars);
 
-       write_device_characteristics(&gatt->sba, &gatt->dba, att->start,
-                                                       characteristics);
+       write_device_characteristics(sba, dba, start, characteristics);
 
        g_free(characteristics);
 }
 
-static void register_characteristics(struct primary *prim)
+static void register_characteristic(gpointer data, gpointer user_data)
 {
-       GSList *lc;
-
-       for (lc = prim->chars; lc; lc = lc->next) {
-               struct characteristic *chr = lc->data;
-               g_dbus_register_interface(connection, chr->path,
-                               CHAR_INTERFACE, char_methods,
-                               NULL, NULL, chr, NULL);
-               DBG("Registered: %s", chr->path);
-       }
+       struct characteristic *chr = data;
+       DBusConnection *conn = chr->gatt->conn;
+       const char *gatt_path = user_data;
+
+       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 primary *prim,
+static GSList *string_to_characteristic_list(struct gatt_service *gatt,
                                                        const char *str)
 {
        GSList *l = NULL;
@@ -626,10 +564,7 @@ static GSList *string_to_characteristic_list(struct primary *prim,
                        continue;
                }
 
-               chr->prim = prim;
-               chr->path = g_strdup_printf("%s/characteristic%04x",
-                                               prim->path, chr->handle);
-
+               chr->gatt = gatt;
                l = g_slist_append(l, chr);
        }
 
@@ -638,39 +573,29 @@ static GSList *string_to_characteristic_list(struct primary *prim,
        return l;
 }
 
-static void load_characteristics(gpointer data, gpointer user_data)
+static GSList *load_characteristics(struct gatt_service *gatt, uint16_t start)
 {
-       struct primary *prim = data;
-       struct att_primary *att = prim->att;
-       struct gatt_service *gatt = user_data;
        GSList *chrs_list;
+       bdaddr_t sba, dba;
        char *str;
 
-       if (prim->chars) {
-               DBG("Characteristics already loaded");
-               return;
-       }
+       gatt_get_address(gatt, &sba, &dba);
 
-       str = read_device_characteristics(&gatt->sba, &gatt->dba, att->start);
+       str = read_device_characteristics(&sba, &dba, start);
        if (str == NULL)
-               return;
+               return NULL;
 
-       chrs_list = string_to_characteristic_list(prim, str);
+       chrs_list = string_to_characteristic_list(gatt, str);
 
        free(str);
 
-       if (chrs_list == NULL)
-               return;
-
-       prim->chars = chrs_list;
-       register_characteristics(prim);
-
-       return;
+       return chrs_list;
 }
 
 static void store_attribute(struct gatt_service *gatt, uint16_t handle,
                                uint16_t type, uint8_t *value, gsize len)
 {
+       bdaddr_t sba, dba;
        bt_uuid_t uuid;
        char *str, *tmp;
        guint i;
@@ -685,15 +610,39 @@ static void store_attribute(struct gatt_service *gatt, uint16_t handle,
        for (i = 0, tmp = str + MAX_LEN_UUID_STR; i < len; i++, tmp += 2)
                sprintf(tmp, "%02X", value[i]);
 
-       write_device_attribute(&gatt->sba, &gatt->dba, handle, str);
+       gatt_get_address(gatt, &sba, &dba);
+
+       write_device_attribute(&sba, &dba, 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;
+
+       btd_device_remove_attio_callback(gatt->dev, query->attioid);
+       g_free(query);
+
+       gatt->query = NULL;
+}
+
 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->prim->gatt;
+       struct gatt_service *gatt = current->gatt;
        struct characteristic *chr = current->chr;
 
        if (status == 0) {
@@ -719,7 +668,7 @@ static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len,
                }
        }
 
-       g_attrib_unref(gatt->attrib);
+       query_list_remove(gatt, current);
        g_free(current);
 }
 
@@ -727,7 +676,7 @@ 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->prim->gatt;
+       struct gatt_service *gatt = current->gatt;
        struct characteristic *chr = current->chr;
 
        if (status != 0)
@@ -745,7 +694,7 @@ static void update_char_format(guint8 status, const guint8 *pdu, guint16 len,
                                (void *) chr->format, sizeof(*chr->format));
 
 done:
-       g_attrib_unref(gatt->attrib);
+       query_list_remove(gatt, current);
        g_free(current);
 }
 
@@ -753,7 +702,7 @@ 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->prim->gatt;
+       struct gatt_service *gatt = current->gatt;
        struct characteristic *chr = current->chr;
 
        if (status == 0)
@@ -770,7 +719,7 @@ static void update_char_value(guint8 status, const guint8 *pdu,
                }
        }
 
-       g_attrib_unref(gatt->attrib);
+       query_list_remove(gatt, current);
        g_free(current);
 }
 
@@ -787,7 +736,7 @@ 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->prim->gatt;
+       struct gatt_service *gatt = current->gatt;
        struct att_data_list *list;
        guint8 format;
        int i;
@@ -819,16 +768,16 @@ static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
                        continue;
                }
                qfmt = g_new0(struct query_data, 1);
-               qfmt->prim = current->prim;
+               qfmt->gatt = current->gatt;
                qfmt->chr = current->chr;
                qfmt->handle = handle;
 
                if (uuid_desc16_cmp(&uuid, GATT_CHARAC_USER_DESC_UUID) == 0) {
-                       gatt->attrib = g_attrib_ref(gatt->attrib);
+                       query_list_append(gatt, qfmt);
                        gatt_read_char(gatt->attrib, handle, 0, update_char_desc,
                                                                        qfmt);
                } else if (uuid_desc16_cmp(&uuid, GATT_CHARAC_FMT_UUID) == 0) {
-                       gatt->attrib = g_attrib_ref(gatt->attrib);
+                       query_list_append(gatt, qfmt);
                        gatt_read_char(gatt->attrib, handle, 0,
                                                update_char_format, qfmt);
                } else
@@ -837,7 +786,7 @@ static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
 
        att_data_list_free(list);
 done:
-       g_attrib_unref(gatt->attrib);
+       query_list_remove(gatt, current);
        g_free(current);
 }
 
@@ -845,22 +794,23 @@ static void update_all_chars(gpointer data, gpointer user_data)
 {
        struct query_data *qdesc, *qvalue;
        struct characteristic *chr = data;
-       struct primary *prim = user_data;
-       struct gatt_service *gatt = prim->gatt;
+       struct gatt_service *gatt = user_data;
 
        qdesc = g_new0(struct query_data, 1);
-       qdesc->prim = prim;
+       qdesc->gatt = gatt;
        qdesc->chr = chr;
 
-       gatt->attrib = g_attrib_ref(gatt->attrib);
+       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->prim = prim;
+       qvalue->gatt = gatt;
        qvalue->chr = chr;
 
-       gatt->attrib = g_attrib_ref(gatt->attrib);
+       query_list_append(gatt, qvalue);
+
        gatt_read_char(gatt->attrib, chr->handle, 0, update_char_value, qvalue);
 }
 
@@ -870,17 +820,17 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
        DBusMessage *reply;
        DBusMessageIter iter, array_iter;
        struct query_data *current = user_data;
-       struct primary *prim = current->prim;
-       struct att_primary *att = prim->att;
-       struct gatt_service *gatt = prim->gatt;
+       struct gatt_service *gatt = current->gatt;
+       struct att_primary *prim = gatt->prim;
        uint16_t *previous_end = NULL;
        GSList *l;
+       bdaddr_t sba, dba;
 
        if (status != 0) {
                const char *str = att_ecode2str(status);
 
                DBG("Discover all characteristics failed: %s", str);
-               reply = btd_error_failed(current->msg, str);
+               reply = btd_error_failed(gatt->query->msg, str);
                goto fail;
        }
 
@@ -890,17 +840,15 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
                guint handle = current_chr->value_handle;
                GSList *lchr;
 
-               lchr = g_slist_find_custom(prim->chars,
+               lchr = g_slist_find_custom(gatt->chars,
                        GUINT_TO_POINTER(handle), characteristic_handle_cmp);
                if (lchr)
                        continue;
 
                chr = g_new0(struct characteristic, 1);
-               chr->prim = prim;
+               chr->gatt = gatt;
                chr->perm = current_chr->properties;
                chr->handle = current_chr->value_handle;
-               chr->path = g_strdup_printf("%s/characteristic%04x",
-                                               prim->path, chr->handle);
                strncpy(chr->type, current_chr->uuid, sizeof(chr->type));
 
                if (previous_end)
@@ -908,23 +856,25 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
 
                previous_end = &chr->end;
 
-               prim->chars = g_slist_append(prim->chars, chr);
+               gatt->chars = g_slist_append(gatt->chars, chr);
        }
 
        if (previous_end)
-               *previous_end = att->end;
+               *previous_end = prim->end;
+
+       gatt_get_address(gatt, &sba, &dba);
+       store_characteristics(&sba, &dba, prim->start, gatt->chars);
 
-       store_characteristics(gatt, prim);
-       register_characteristics(prim);
+       g_slist_foreach(gatt->chars, register_characteristic, gatt->path);
 
-       reply = dbus_message_new_method_return(current->msg);
+       reply = dbus_message_new_method_return(gatt->query->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 = prim->chars; l; l = l->next) {
+       for (l = gatt->chars; l; l = l->next) {
                struct characteristic *chr = l->data;
 
                dbus_message_iter_append_basic(&array_iter,
@@ -933,35 +883,59 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
 
        dbus_message_iter_close_container(&iter, &array_iter);
 
-       g_slist_foreach(prim->chars, update_all_chars, prim);
+       g_slist_foreach(gatt->chars, update_all_chars, gatt);
 
 fail:
-       g_dbus_send_message(connection, reply);
-       g_attrib_unref(gatt->attrib);
+       g_dbus_send_message(gatt->conn, reply);
+       query_list_remove(gatt, current);
        g_free(current);
 }
 
+static void send_discover(GAttrib *attrib, gpointer user_data)
+{
+       struct query_data *qchr = user_data;
+       struct gatt_service *gatt = qchr->gatt;
+       struct att_primary *prim = gatt->prim;
+
+       gatt->attrib = g_attrib_ref(attrib);
+
+       gatt_discover_char(gatt->attrib, prim->start, prim->end, NULL,
+                                               char_discovered_cb, qchr);
+}
+
+static void cancel_discover(gpointer user_data)
+{
+       struct query_data *qchr = user_data;
+       struct gatt_service *gatt = qchr->gatt;
+
+       g_attrib_unref(gatt->attrib);
+       gatt->attrib = NULL;
+}
+
 static DBusMessage *discover_char(DBusConnection *conn, DBusMessage *msg,
                                                                void *data)
 {
-       struct primary *prim = data;
-       struct att_primary *att = prim->att;
-       struct gatt_service *gatt = prim->gatt;
+       struct gatt_service *gatt = data;
+       struct query *query;
        struct query_data *qchr;
-       GError *gerr = NULL;
 
-       if (l2cap_connect(prim->gatt, &gerr, FALSE) < 0) {
-               DBusMessage *reply = btd_error_failed(msg, gerr->message);
-               g_error_free(gerr);
-               return reply;
-       }
+       if (gatt->query)
+               return btd_error_busy(msg);
+
+       query = g_new0(struct query, 1);
 
        qchr = g_new0(struct query_data, 1);
-       qchr->prim = prim;
-       qchr->msg = dbus_message_ref(msg);
+       qchr->gatt = gatt;
 
-       gatt_discover_char(gatt->attrib, att->start, att->end,
-                                               char_discovered_cb, qchr);
+       query->msg = dbus_message_ref(msg);
+       query->attioid = btd_device_add_attio_callback(gatt->dev,
+                                                       send_discover,
+                                                       cancel_discover,
+                                                       qchr);
+
+       gatt->query = query;
+
+       query_list_append(gatt, qchr);
 
        return NULL;
 }
@@ -969,7 +943,7 @@ static DBusMessage *discover_char(DBusConnection *conn, DBusMessage *msg,
 static DBusMessage *prim_get_properties(DBusConnection *conn, DBusMessage *msg,
                                                                void *data)
 {
-       struct primary *prim = data;
+       struct gatt_service *gatt = data;
        DBusMessage *reply;
        DBusMessageIter iter;
        DBusMessageIter dict;
@@ -989,16 +963,16 @@ static DBusMessage *prim_get_properties(DBusConnection *conn, DBusMessage *msg,
                        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(prim->chars) + 1);
+       chars = g_new0(char *, g_slist_length(gatt->chars) + 1);
 
-       for (i = 0, l = prim->chars; l; l = l->next, i++) {
+       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 = prim->att->uuid;
+       uuid = gatt->prim->uuid;
        dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &uuid);
 
        g_free(chars);
@@ -1019,98 +993,95 @@ static GDBusMethodTable prim_methods[] = {
        { }
 };
 
-static void register_primaries(struct gatt_service *gatt, GSList *primaries)
+static struct gatt_service *primary_register(DBusConnection *conn,
+                                               struct btd_device *device,
+                                               struct att_primary *prim,
+                                               int psm)
 {
-       GSList *l;
+       struct gatt_service *gatt;
+       const char *device_path;
 
-       for (l = primaries; l; l = l->next) {
-               struct att_primary *att = l->data;
-               struct primary *prim;
+       device_path = device_get_path(device);
 
-               prim = g_new0(struct primary, 1);
-               prim->att = att;
-               prim->gatt = gatt;
-               prim->path = g_strdup_printf("%s/service%04x", gatt->path,
-                                                               att->start);
+       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->start);
 
-               g_dbus_register_interface(connection, prim->path,
-                               CHAR_INTERFACE, prim_methods,
-                               NULL, NULL, prim, NULL);
-               DBG("Registered: %s", prim->path);
+       g_dbus_register_interface(gatt->conn, gatt->path,
+                                       CHAR_INTERFACE, prim_methods,
+                                       NULL, NULL, gatt, NULL);
+       gatt->chars = load_characteristics(gatt, prim->start);
+       g_slist_foreach(gatt->chars, register_characteristic, gatt->path);
 
-               gatt->primary = g_slist_append(gatt->primary, prim);
-               btd_device_add_service(gatt->dev, prim->path);
-               load_characteristics(prim, gatt);
-       }
+       return gatt;
 }
 
-int attrib_client_register(struct btd_device *device, int psm)
+GSList *attrib_client_register(DBusConnection *connection,
+                                       struct btd_device *device, int psm,
+                                       GAttrib *attrib, GSList *primaries)
 {
-       struct btd_adapter *adapter = device_get_adapter(device);
-       const char *path = device_get_path(device);
-       struct gatt_service *gatt;
-       GSList *primaries = btd_device_get_primaries(device);
-       bdaddr_t sba, dba;
+       GSList *l, *services;
 
-       adapter_get_address(adapter, &sba);
-       device_get_address(device, &dba);
+       for (l = primaries, services = NULL; l; l = l->next) {
+               struct att_primary *prim = l->data;
+               struct gatt_service *gatt;
 
-       gatt = g_new0(struct gatt_service, 1);
-       gatt->dev = btd_device_ref(device);
-       gatt->listen = FALSE;
-       gatt->path = g_strdup(path);
-       bacpy(&gatt->sba, &sba);
-       bacpy(&gatt->dba, &dba);
-       gatt->psm = psm;
+               gatt = primary_register(connection, device, prim, psm);
 
-       register_primaries(gatt, primaries);
+               DBG("Registered: %s", gatt->path);
 
-       gatt_services = g_slist_append(gatt_services, gatt);
+               services = g_slist_append(services, g_strdup(gatt->path));
+               gatt_services = g_slist_append(gatt_services, gatt);
 
-       return 0;
+       }
+
+       return services;
 }
 
-void attrib_client_unregister(struct btd_device *device)
+static void primary_unregister(struct gatt_service *gatt)
 {
-       struct gatt_service *gatt;
-       GSList *l, *lp, *lc;
-
-       l = g_slist_find_custom(gatt_services, device, gatt_dev_cmp);
-       if (!l)
-               return;
+       GSList *l;
 
-       gatt = l->data;
-       gatt_services = g_slist_remove(gatt_services, gatt);
+       if (gatt->attioid)
+               btd_device_remove_attio_callback(gatt->dev, gatt->attioid);
 
-       for (lp = gatt->primary; lp; lp = lp->next) {
-               struct primary *prim = lp->data;
-               for (lc = prim->chars; lc; lc = lc->next) {
-                       struct characteristic *chr = lc->data;
-                       g_dbus_unregister_interface(connection, chr->path,
-                                                               CHAR_INTERFACE);
-               }
-               g_dbus_unregister_interface(connection, prim->path,
-                                                               CHAR_INTERFACE);
+       for (l = gatt->chars; l; l = l->next) {
+               struct characteristic *chr = l->data;
+               g_dbus_unregister_interface(gatt->conn, chr->path,
+                                                       CHAR_INTERFACE);
        }
 
-       gatt_service_free(gatt);
+       g_dbus_unregister_interface(gatt->conn, gatt->path, CHAR_INTERFACE);
 }
 
-int attrib_client_init(DBusConnection *conn)
+static int path_cmp(gconstpointer data, gconstpointer user_data)
 {
+       const char *path = data;
+       const char *gatt_path = user_data;
 
-       connection = dbus_connection_ref(conn);
-
-       /*
-        * FIXME: if the adapter supports BLE start scanning. Temporary
-        * solution, this approach doesn't allow to control scanning based
-        * on the discoverable property.
-        */
-
-       return 0;
+       return g_strcmp0(path, gatt_path);
 }
 
-void attrib_client_exit(void)
+void attrib_client_unregister(GSList *services)
 {
-       dbus_connection_unref(connection);
+       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;
 }
index 50e2b5f..948f030 100644 (file)
@@ -22,7 +22,7 @@
  *
  */
 
-int attrib_client_init(DBusConnection *conn);
-void attrib_client_exit(void);
-int attrib_client_register(struct btd_device *device, int psm);
-void attrib_client_unregister(struct btd_device *device);
+GSList *attrib_client_register(DBusConnection *connection,
+                                       struct btd_device *device, int psm,
+                                       GAttrib *attrib, GSList *primaries);
+void attrib_client_unregister(GSList *services);
diff --git a/attrib/example.c b/attrib/example.c
deleted file mode 100644 (file)
index fae288c..0000000
+++ /dev/null
@@ -1,341 +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 HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <arpa/inet.h>
-
-#include <bluetooth/uuid.h>
-
-#include <glib.h>
-
-#include "log.h"
-#include "attrib-server.h"
-
-#include "att.h"
-#include "example.h"
-
-/* FIXME: Not defined by SIG? UUID128? */
-#define OPCODES_SUPPORTED_UUID          0xA001
-#define BATTERY_STATE_SVC_UUID         0xA002
-#define BATTERY_STATE_UUID             0xA003
-#define THERM_HUMIDITY_SVC_UUID                0xA004
-#define MANUFACTURER_SVC_UUID          0xA005
-#define TEMPERATURE_UUID               0xA006
-#define FMT_CELSIUS_UUID               0xA007
-#define FMT_OUTSIDE_UUID               0xA008
-#define RELATIVE_HUMIDITY_UUID         0xA009
-#define FMT_PERCENT_UUID               0xA00A
-#define BLUETOOTH_SIG_UUID             0xA00B
-#define MANUFACTURER_NAME_UUID         0xA00C
-#define MANUFACTURER_SERIAL_UUID       0xA00D
-#define VENDOR_SPECIFIC_SVC_UUID       0xA00E
-#define VENDOR_SPECIFIC_TYPE_UUID      0xA00F
-#define FMT_KILOGRAM_UUID              0xA010
-#define FMT_HANGING_UUID               0xA011
-
-static GSList *sdp_handles = NULL;
-
-static int register_attributes(void)
-{
-       const char *desc_out_temp = "Outside Temperature";
-       const char *desc_out_hum = "Outside Relative Humidity";
-       const char *desc_weight = "Rucksack Weight";
-       const char *manufacturer_name1 = "ACME Temperature Sensor";
-       const char *manufacturer_name2 = "ACME Weighing Scales";
-       const char *serial1 = "237495-3282-A";
-       const char *serial2 = "11267-2327A00239";
-
-       const uint128_t char_weight_uuid_btorder = {
-               .data = { 0x80, 0x88, 0xF2, 0x18, 0x90, 0x2C, 0x45, 0x0B,
-                         0xB6, 0xC4, 0x62, 0x89, 0x1E, 0x8C, 0x25, 0xE9 } };
-       const uint128_t prim_weight_uuid_btorder = {
-               .data = { 0x4F, 0x0A, 0xC0, 0x96, 0x35, 0xD4, 0x49, 0x11,
-                         0x96, 0x31, 0xDE, 0xA8, 0xDC, 0x74, 0xEE, 0xFE } };
-
-       uint128_t char_weight_uuid;
-       uint8_t atval[256];
-       uint32_t handle;
-       bt_uuid_t uuid;
-       int len;
-
-       btoh128(&char_weight_uuid_btorder, &char_weight_uuid);
-
-       /* Battery state service: primary service definition */
-       bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
-       att_put_u16(BATTERY_STATE_SVC_UUID, &atval[0]);
-       attrib_db_add(0x0100, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
-
-       /* Battery: battery state characteristic */
-       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
-       atval[0] = ATT_CHAR_PROPER_READ;
-       att_put_u16(0x0110, &atval[1]);
-       att_put_u16(BATTERY_STATE_UUID, &atval[3]);
-       attrib_db_add(0x0106, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
-
-       /* Battery: battery state attribute */
-       bt_uuid16_create(&uuid, BATTERY_STATE_UUID);
-       atval[0] = 0x04;
-       attrib_db_add(0x0110, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 1);
-
-       /* Battery: Client Characteristic Configuration */
-       bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
-       atval[0] = 0x00;
-       atval[1] = 0x00;
-       attrib_db_add(0x0111, &uuid, ATT_NONE, ATT_AUTHENTICATION, atval, 2);
-
-       /* Add an SDP record for the above service */
-       handle = attrib_create_sdp(0x0100, "Battery State Service");
-       if (handle)
-               sdp_handles = g_slist_prepend(sdp_handles, GUINT_TO_POINTER(handle));
-
-       /* Thermometer: primary service definition */
-       bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
-       att_put_u16(THERM_HUMIDITY_SVC_UUID, &atval[0]);
-       attrib_db_add(0x0200, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
-
-       /* Thermometer: Include */
-       bt_uuid16_create(&uuid, GATT_INCLUDE_UUID);
-       att_put_u16(0x0500, &atval[0]);
-       att_put_u16(0x0504, &atval[2]);
-       att_put_u16(MANUFACTURER_SVC_UUID, &atval[4]);
-       attrib_db_add(0x0201, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 6);
-
-       /* Thermometer: Include */
-       att_put_u16(0x0550, &atval[0]);
-       att_put_u16(0x0568, &atval[2]);
-       att_put_u16(VENDOR_SPECIFIC_SVC_UUID, &atval[4]);
-       attrib_db_add(0x0202, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 6);
-
-       /* Thermometer: temperature characteristic */
-       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
-       atval[0] = ATT_CHAR_PROPER_READ;
-       att_put_u16(0x0204, &atval[1]);
-       att_put_u16(TEMPERATURE_UUID, &atval[3]);
-       attrib_db_add(0x0203, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
-
-       /* Thermometer: temperature characteristic value */
-       bt_uuid16_create(&uuid, TEMPERATURE_UUID);
-       atval[0] = 0x8A;
-       atval[1] = 0x02;
-       attrib_db_add(0x0204, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
-
-       /* Thermometer: temperature characteristic format */
-       bt_uuid16_create(&uuid, GATT_CHARAC_FMT_UUID);
-       atval[0] = 0x0E;
-       atval[1] = 0xFE;
-       att_put_u16(FMT_CELSIUS_UUID, &atval[2]);
-       atval[4] = 0x01;
-       att_put_u16(FMT_OUTSIDE_UUID, &atval[5]);
-       attrib_db_add(0x0205, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 7);
-
-       /* Thermometer: characteristic user description */
-       bt_uuid16_create(&uuid, GATT_CHARAC_USER_DESC_UUID);
-       len = strlen(desc_out_temp);
-       strncpy((char *) atval, desc_out_temp, len);
-       attrib_db_add(0x0206, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, len);
-
-       /* Thermometer: relative humidity characteristic */
-       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
-       atval[0] = ATT_CHAR_PROPER_READ;
-       att_put_u16(0x0212, &atval[1]);
-       att_put_u16(RELATIVE_HUMIDITY_UUID, &atval[3]);
-       attrib_db_add(0x0210, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
-
-       /* Thermometer: relative humidity value */
-       bt_uuid16_create(&uuid, RELATIVE_HUMIDITY_UUID);
-       atval[0] = 0x27;
-       attrib_db_add(0x0212, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 1);
-
-       /* Thermometer: relative humidity characteristic format */
-       bt_uuid16_create(&uuid, GATT_CHARAC_FMT_UUID);
-       atval[0] = 0x04;
-       atval[1] = 0x00;
-       att_put_u16(FMT_PERCENT_UUID, &atval[2]);
-       att_put_u16(BLUETOOTH_SIG_UUID, &atval[4]);
-       att_put_u16(FMT_OUTSIDE_UUID, &atval[6]);
-       attrib_db_add(0x0213, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 8);
-
-       /* Thermometer: characteristic user description */
-       bt_uuid16_create(&uuid, GATT_CHARAC_USER_DESC_UUID);
-       len = strlen(desc_out_hum);
-       strncpy((char *) atval, desc_out_hum, len);
-       attrib_db_add(0x0214, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, len);
-
-       /* Add an SDP record for the above service */
-       handle = attrib_create_sdp(0x0200, "Thermometer");
-       if (handle)
-               sdp_handles = g_slist_prepend(sdp_handles, GUINT_TO_POINTER(handle));
-
-       /* Secondary Service: Manufacturer Service */
-       bt_uuid16_create(&uuid, GATT_SND_SVC_UUID);
-       att_put_u16(MANUFACTURER_SVC_UUID, &atval[0]);
-       attrib_db_add(0x0500, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
-
-       /* Manufacturer name characteristic definition */
-       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
-       atval[0] = ATT_CHAR_PROPER_READ;
-       att_put_u16(0x0502, &atval[1]);
-       att_put_u16(MANUFACTURER_NAME_UUID, &atval[3]);
-       attrib_db_add(0x0501, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
-
-       /* Manufacturer name characteristic value */
-       bt_uuid16_create(&uuid, MANUFACTURER_NAME_UUID);
-       len = strlen(manufacturer_name1);
-       strncpy((char *) atval, manufacturer_name1, len);
-       attrib_db_add(0x0502, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, len);
-
-       /* Manufacturer serial number characteristic */
-       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
-       atval[0] = ATT_CHAR_PROPER_READ;
-       att_put_u16(0x0504, &atval[1]);
-       att_put_u16(MANUFACTURER_SERIAL_UUID, &atval[3]);
-       attrib_db_add(0x0503, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
-
-       /* Manufacturer serial number characteristic value */
-       bt_uuid16_create(&uuid, MANUFACTURER_SERIAL_UUID);
-       len = strlen(serial1);
-       strncpy((char *) atval, serial1, len);
-       attrib_db_add(0x0504, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, len);
-
-       /* Secondary Service: Manufacturer Service */
-       bt_uuid16_create(&uuid, GATT_SND_SVC_UUID);
-       att_put_u16(MANUFACTURER_SVC_UUID, &atval[0]);
-       attrib_db_add(0x0505, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
-
-       /* Manufacturer name characteristic definition */
-       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
-       atval[0] = ATT_CHAR_PROPER_READ;
-       att_put_u16(0x0507, &atval[1]);
-       att_put_u16(MANUFACTURER_NAME_UUID, &atval[3]);
-       attrib_db_add(0x0506, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
-
-       /* Secondary Service: Vendor Specific Service */
-       bt_uuid16_create(&uuid, GATT_SND_SVC_UUID);
-       att_put_u16(VENDOR_SPECIFIC_SVC_UUID, &atval[0]);
-       attrib_db_add(0x0550, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
-
-       /* Vendor Specific Type characteristic definition */
-       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
-       atval[0] = ATT_CHAR_PROPER_READ;
-       att_put_u16(0x0568, &atval[1]);
-       att_put_u16(VENDOR_SPECIFIC_TYPE_UUID, &atval[3]);
-       attrib_db_add(0x0560, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
-
-       /* Vendor Specific Type characteristic value */
-       bt_uuid16_create(&uuid, VENDOR_SPECIFIC_TYPE_UUID);
-       atval[0] = 0x56;
-       atval[1] = 0x65;
-       atval[2] = 0x6E;
-       atval[3] = 0x64;
-       atval[4] = 0x6F;
-       atval[5] = 0x72;
-       attrib_db_add(0x0568, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 6);
-
-       /* Manufacturer name attribute */
-       bt_uuid16_create(&uuid, MANUFACTURER_NAME_UUID);
-       len = strlen(manufacturer_name2);
-       strncpy((char *) atval, manufacturer_name2, len);
-       attrib_db_add(0x0507, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, len);
-
-       /* Characteristic: serial number */
-       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
-       atval[0] = ATT_CHAR_PROPER_READ;
-       att_put_u16(0x0509, &atval[1]);
-       att_put_u16(MANUFACTURER_SERIAL_UUID, &atval[3]);
-       attrib_db_add(0x0508, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
-
-       /* Serial number characteristic value */
-       bt_uuid16_create(&uuid, MANUFACTURER_SERIAL_UUID);
-       len = strlen(serial2);
-       strncpy((char *) atval, serial2, len);
-       attrib_db_add(0x0509, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, len);
-
-       /* Weight service: primary service definition */
-       bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
-       memcpy(atval, &prim_weight_uuid_btorder, 16);
-       attrib_db_add(0x0680, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 16);
-
-       /* Weight: include */
-       bt_uuid16_create(&uuid, GATT_INCLUDE_UUID);
-       att_put_u16(0x0505, &atval[0]);
-       att_put_u16(0x0509, &atval[2]);
-       att_put_u16(MANUFACTURER_SVC_UUID, &atval[4]);
-       attrib_db_add(0x0681, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 6);
-
-       /* Weight: characteristic */
-       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
-       atval[0] = ATT_CHAR_PROPER_READ;
-       att_put_u16(0x0683, &atval[1]);
-       memcpy(&atval[3], &char_weight_uuid_btorder, 16);
-       attrib_db_add(0x0682, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 19);
-
-       /* Weight: characteristic value */
-       bt_uuid128_create(&uuid, char_weight_uuid);
-       atval[0] = 0x82;
-       atval[1] = 0x55;
-       atval[2] = 0x00;
-       atval[3] = 0x00;
-       attrib_db_add(0x0683, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 4);
-
-       /* Weight: characteristic format */
-       bt_uuid16_create(&uuid, GATT_CHARAC_FMT_UUID);
-       atval[0] = 0x08;
-       atval[1] = 0xFD;
-       att_put_u16(FMT_KILOGRAM_UUID, &atval[2]);
-       att_put_u16(BLUETOOTH_SIG_UUID, &atval[4]);
-       att_put_u16(FMT_HANGING_UUID, &atval[6]);
-       attrib_db_add(0x0684, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 8);
-
-       /* Weight: characteristic user description */
-       bt_uuid16_create(&uuid, GATT_CHARAC_USER_DESC_UUID);
-       len = strlen(desc_weight);
-       strncpy((char *) atval, desc_weight, len);
-       attrib_db_add(0x0685, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, len);
-
-       /* Add an SDP record for the above service */
-       handle = attrib_create_sdp(0x0680, "Weight Service");
-       if (handle)
-               sdp_handles = g_slist_prepend(sdp_handles, GUINT_TO_POINTER(handle));
-
-       return 0;
-}
-
-int server_example_init(void)
-{
-       return register_attributes();
-}
-
-void server_example_exit(void)
-{
-       while (sdp_handles) {
-               uint32_t handle = GPOINTER_TO_UINT(sdp_handles->data);
-
-               attrib_free_sdp(handle);
-               sdp_handles = g_slist_remove(sdp_handles, sdp_handles->data);
-       }
-}
diff --git a/attrib/gatt-service.c b/attrib/gatt-service.c
new file mode 100644 (file)
index 0000000..bfefdee
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <bluetooth/uuid.h>
+#include <bluetooth/sdp.h>
+#include <adapter.h>
+
+#include "att.h"
+#include "gattrib.h"
+#include "attrib-server.h"
+#include "gatt-service.h"
+#include "log.h"
+#include "glib-compat.h"
+
+struct gatt_info {
+       bt_uuid_t uuid;
+       uint8_t props;
+       int authentication;
+       int authorization;
+       GSList *callbacks;
+       unsigned int num_attrs;
+       uint16_t *value_handle;
+       uint16_t *ccc_handle;
+};
+
+struct attrib_cb {
+       attrib_event_t event;
+       void *fn;
+       void *user_data;
+};
+
+static GSList *parse_opts(gatt_option opt1, va_list args)
+{
+       gatt_option opt = opt1;
+       struct gatt_info *info;
+       struct attrib_cb *cb;
+       GSList *l = NULL;
+
+       info = g_new0(struct gatt_info, 1);
+       l = g_slist_append(l, info);
+
+       while (opt != GATT_OPT_INVALID) {
+               switch (opt) {
+               case GATT_OPT_CHR_UUID:
+                       bt_uuid16_create(&info->uuid, va_arg(args, int));
+                       /* characteristic declaration and value */
+                       info->num_attrs += 2;
+                       break;
+               case GATT_OPT_CHR_PROPS:
+                       info->props = va_arg(args, int);
+
+                       if (info->props & (ATT_CHAR_PROPER_NOTIFY |
+                                               ATT_CHAR_PROPER_INDICATE))
+                               /* client characteristic configuration */
+                               info->num_attrs += 1;
+
+                       /* TODO: "Extended Properties" property requires a
+                        * descriptor, but it is not supported yet. */
+                       break;
+               case GATT_OPT_CHR_VALUE_CB:
+                       cb = g_new0(struct attrib_cb, 1);
+                       cb->event = va_arg(args, attrib_event_t);
+                       cb->fn = va_arg(args, void *);
+                       cb->user_data = va_arg(args, void *);
+                       info->callbacks = g_slist_append(info->callbacks, cb);
+                       break;
+               case GATT_OPT_CHR_VALUE_GET_HANDLE:
+                       info->value_handle = va_arg(args, void *);
+                       break;
+               case GATT_OPT_CCC_GET_HANDLE:
+                       info->ccc_handle = va_arg(args, void *);
+                       break;
+               case GATT_OPT_CHR_AUTHENTICATION:
+                       info->authentication = va_arg(args, gatt_option);
+                       break;
+               case GATT_OPT_CHR_AUTHORIZATION:
+                       info->authorization = va_arg(args, gatt_option);
+                       break;
+               default:
+                       error("Invalid option: %d", opt);
+               }
+
+               opt = va_arg(args, gatt_option);
+               if (opt == GATT_OPT_CHR_UUID) {
+                       info = g_new0(struct gatt_info, 1);
+                       l = g_slist_append(l, info);
+               }
+       }
+
+       return l;
+}
+
+static int att_read_reqs(int authorization, int authentication, uint8_t props)
+{
+       if (authorization == GATT_CHR_VALUE_READ ||
+                               authorization == GATT_CHR_VALUE_BOTH)
+               return ATT_AUTHORIZATION;
+       else if (authentication == GATT_CHR_VALUE_READ ||
+                               authentication == GATT_CHR_VALUE_BOTH)
+               return ATT_AUTHENTICATION;
+       else if (!(props & ATT_CHAR_PROPER_READ))
+               return ATT_NOT_PERMITTED;
+
+       return ATT_NONE;
+}
+
+static int att_write_reqs(int authorization, int authentication, uint8_t props)
+{
+       if (authorization == GATT_CHR_VALUE_WRITE ||
+                               authorization == GATT_CHR_VALUE_BOTH)
+               return ATT_AUTHORIZATION;
+       else if (authentication == GATT_CHR_VALUE_WRITE ||
+                               authentication == GATT_CHR_VALUE_BOTH)
+               return ATT_AUTHENTICATION;
+       else if (!(props & (ATT_CHAR_PROPER_WRITE |
+                                       ATT_CHAR_PROPER_WRITE_WITHOUT_RESP)))
+               return ATT_NOT_PERMITTED;
+
+       return ATT_NONE;
+}
+
+static gint find_callback(gconstpointer a, gconstpointer b)
+{
+       const struct attrib_cb *cb = a;
+       unsigned int event = GPOINTER_TO_UINT(b);
+
+       return cb->event - event;
+}
+
+static gboolean add_characteristic(struct btd_adapter *adapter,
+                               uint16_t *handle, struct gatt_info *info)
+{
+       int read_reqs, write_reqs;
+       uint16_t h = *handle;
+       struct attribute *a;
+       bt_uuid_t bt_uuid;
+       uint8_t atval[5];
+       GSList *l;
+
+       if (!info->uuid.value.u16 || !info->props) {
+               error("Characteristic UUID or properties are missing");
+               return FALSE;
+       }
+
+       read_reqs = att_read_reqs(info->authorization, info->authentication,
+                                                               info->props);
+       write_reqs = att_write_reqs(info->authorization, info->authentication,
+                                                               info->props);
+
+       /* TODO: static characteristic values are not supported, therefore a
+        * callback must be always provided if a read/write property is set */
+       if (read_reqs != ATT_NOT_PERMITTED) {
+               gpointer reqs = GUINT_TO_POINTER(ATTRIB_READ);
+
+               if (!g_slist_find_custom(info->callbacks, reqs,
+                                                       find_callback)) {
+                       error("Callback for read required");
+                       return FALSE;
+               }
+       }
+
+       if (write_reqs != ATT_NOT_PERMITTED) {
+               gpointer reqs = GUINT_TO_POINTER(ATTRIB_WRITE);
+
+               if (!g_slist_find_custom(info->callbacks, reqs,
+                                                       find_callback)) {
+                       error("Callback for write required");
+                       return FALSE;
+               }
+       }
+
+       /* characteristic declaration */
+       bt_uuid16_create(&bt_uuid, GATT_CHARAC_UUID);
+       atval[0] = info->props;
+       att_put_u16(h + 1, &atval[1]);
+       att_put_u16(info->uuid.value.u16, &atval[3]);
+       if (attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                               atval, sizeof(atval)) == NULL)
+               return FALSE;
+
+       /* characteristic value */
+       a = attrib_db_add(adapter, h++, &info->uuid, read_reqs, write_reqs,
+                                                               NULL, 0);
+       if (a == NULL)
+               return FALSE;
+
+       for (l = info->callbacks; l != NULL; l = l->next) {
+               struct attrib_cb *cb = l->data;
+
+               switch (cb->event) {
+               case ATTRIB_READ:
+                       a->read_cb = cb->fn;
+                       break;
+               case ATTRIB_WRITE:
+                       a->write_cb = cb->fn;
+                       break;
+               }
+
+               a->cb_user_data = cb->user_data;
+       }
+
+       if (info->value_handle != NULL)
+               *info->value_handle = a->handle;
+
+       /* client characteristic configuration descriptor */
+       if (info->props & (ATT_CHAR_PROPER_NOTIFY | ATT_CHAR_PROPER_INDICATE)) {
+               uint8_t cfg_val[2];
+
+               bt_uuid16_create(&bt_uuid, GATT_CLIENT_CHARAC_CFG_UUID);
+               cfg_val[0] = 0x00;
+               cfg_val[1] = 0x00;
+               a = attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE,
+                               ATT_AUTHENTICATION, cfg_val, sizeof(cfg_val));
+               if (a == NULL)
+                       return FALSE;
+
+               if (info->ccc_handle != NULL)
+                       *info->ccc_handle = a->handle;
+       }
+
+       *handle = h;
+
+       return TRUE;
+}
+
+static void free_gatt_info(void *data)
+{
+       struct gatt_info *info = data;
+
+       g_slist_free_full(info->callbacks, g_free);
+       g_free(info);
+}
+
+static void service_attr_del(struct btd_adapter *adapter, uint16_t start_handle,
+                                                       uint16_t end_handle)
+{
+       uint16_t handle;
+
+       for (handle = start_handle; handle <= end_handle; handle++)
+               if (attrib_db_del(adapter, handle) < 0)
+                       error("Can't delete handle 0x%04x", handle);
+}
+
+gboolean gatt_service_add(struct btd_adapter *adapter, uint16_t uuid,
+                               uint16_t svc_uuid, gatt_option opt1, ...)
+{
+       uint16_t start_handle, h;
+       unsigned int size;
+       bt_uuid_t bt_uuid;
+       uint8_t atval[2];
+       va_list args;
+       GSList *chrs, *l;
+
+       va_start(args, opt1);
+       chrs = parse_opts(opt1, args);
+       /* calculate how many attributes are necessary for this service */
+       for (l = chrs, size = 1; l != NULL; l = l->next) {
+               struct gatt_info *info = l->data;
+               size += info->num_attrs;
+       }
+       va_end(args);
+       start_handle = attrib_db_find_avail(adapter, size);
+       if (start_handle == 0) {
+               error("Not enough free handles to register service");
+               g_slist_free_full(chrs, free_gatt_info);
+               return FALSE;
+       }
+
+       DBG("New service: handle 0x%04x, UUID 0x%04x, %d attributes",
+                                               start_handle, svc_uuid, size);
+
+       /* service declaration */
+       h = start_handle;
+       bt_uuid16_create(&bt_uuid, uuid);
+       att_put_u16(svc_uuid, &atval[0]);
+       if (attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                               atval, sizeof(atval)) == NULL) {
+               g_slist_free_full(chrs, free_gatt_info);
+               return FALSE;
+       }
+
+       for (l = chrs; l != NULL; l = l->next) {
+               struct gatt_info *info = l->data;
+
+               DBG("New characteristic: handle 0x%04x", h);
+               if (!add_characteristic(adapter, &h, info)) {
+                       g_slist_free_full(chrs, free_gatt_info);
+                       service_attr_del(adapter, start_handle, h - 1);
+                       return FALSE;
+               }
+       }
+
+       g_assert(size < USHRT_MAX);
+       g_assert(h - start_handle == (uint16_t) size);
+       g_slist_free_full(chrs, free_gatt_info);
+
+       return TRUE;
+}
diff --git a/attrib/gatt-service.h b/attrib/gatt-service.h
new file mode 100644 (file)
index 0000000..7af2d3e
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+typedef enum {
+       GATT_OPT_INVALID = 0,
+       GATT_OPT_CHR_UUID,
+       GATT_OPT_CHR_PROPS,
+       GATT_OPT_CHR_VALUE_CB,
+       GATT_OPT_CHR_AUTHENTICATION,
+       GATT_OPT_CHR_AUTHORIZATION,
+
+       /* Get attribute handle for characteristic value */
+       GATT_OPT_CHR_VALUE_GET_HANDLE,
+
+       /* Get handle for ccc attribute */
+       GATT_OPT_CCC_GET_HANDLE,
+
+       /* arguments for authentication/authorization */
+       GATT_CHR_VALUE_READ,
+       GATT_CHR_VALUE_WRITE,
+       GATT_CHR_VALUE_BOTH,
+} gatt_option;
+
+typedef enum {
+       ATTRIB_READ,
+       ATTRIB_WRITE,
+} attrib_event_t;
+
+gboolean gatt_service_add(struct btd_adapter *adapter, uint16_t uuid,
+                               uint16_t svc_uuid, gatt_option opt1, ...);
index 32bd4a0..452a4cf 100644 (file)
  *
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include <stdint.h>
+#include <stdlib.h>
 #include <glib.h>
 #include <bluetooth/uuid.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "glib-compat.h"
 
 #include "att.h"
 #include "gattrib.h"
@@ -40,7 +49,7 @@ struct discover_primary {
 
 struct discover_char {
        GAttrib *attrib;
-       bt_uuid_t uuid;
+       bt_uuid_t *uuid;
        uint16_t end;
        GSList *characteristics;
        gatt_cb_t cb;
@@ -56,9 +65,9 @@ static void discover_primary_free(struct discover_primary *dp)
 
 static void discover_char_free(struct discover_char *dc)
 {
-       g_slist_foreach(dc->characteristics, (GFunc) g_free, NULL);
-       g_slist_free(dc->characteristics);
+       g_slist_free_full(dc->characteristics, g_free);
        g_attrib_unref(dc->attrib);
+       g_free(dc->uuid);
        g_free(dc);
 }
 
@@ -67,13 +76,11 @@ static guint16 encode_discover_primary(uint16_t start, uint16_t end,
 {
        bt_uuid_t prim;
        guint16 plen;
-       uint8_t op;
 
        bt_uuid16_create(&prim, GATT_PRIM_SVC_UUID);
 
        if (uuid == NULL) {
                /* Discover all primary services */
-               op = ATT_OP_READ_BY_GROUP_REQ;
                plen = enc_read_by_grp_req(start, end, &prim, pdu, len);
        } else {
                uint16_t u16;
@@ -82,7 +89,6 @@ static guint16 encode_discover_primary(uint16_t start, uint16_t end,
                int vlen;
 
                /* Discover primary service by service UUID */
-               op = ATT_OP_FIND_BY_TYPE_REQ;
 
                if (uuid->type == BT_UUID16) {
                        u16 = htobs(uuid->value.u16);
@@ -108,9 +114,9 @@ static void primary_by_uuid_cb(guint8 status, const guint8 *ipdu,
        struct discover_primary *dp = user_data;
        GSList *ranges, *last;
        struct att_range *range;
-       uint8_t opdu[ATT_DEFAULT_LE_MTU];
+       uint8_t *buf;
        guint16 oplen;
-       int err = 0;
+       int err = 0, buflen;
 
        if (status) {
                err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status;
@@ -129,13 +135,14 @@ static void primary_by_uuid_cb(guint8 status, const guint8 *ipdu,
        if (range->end == 0xffff)
                goto done;
 
+       buf = g_attrib_get_buffer(dp->attrib, &buflen);
        oplen = encode_discover_primary(range->end + 1, 0xffff, &dp->uuid,
-                                                       opdu, sizeof(opdu));
+                                                               buf, buflen);
 
        if (oplen == 0)
                goto done;
 
-       g_attrib_send(dp->attrib, 0, opdu[0], opdu, oplen, primary_by_uuid_cb,
+       g_attrib_send(dp->attrib, 0, buf[0], buf, oplen, primary_by_uuid_cb,
                                                                dp, NULL);
        return;
 
@@ -196,12 +203,13 @@ static void primary_all_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
        err = 0;
 
        if (end != 0xffff) {
-               uint8_t opdu[ATT_DEFAULT_LE_MTU];
+               int buflen;
+               uint8_t *buf = g_attrib_get_buffer(dp->attrib, &buflen);
                guint16 oplen = encode_discover_primary(end + 1, 0xffff, NULL,
-                                                       opdu, sizeof(opdu));
+                                                               buf, buflen);
 
-               g_attrib_send(dp->attrib, 0, opdu[0], opdu, oplen,
-                                               primary_all_cb, dp, NULL);
+               g_attrib_send(dp->attrib, 0, buf[0], buf, oplen, primary_all_cb,
+                                                               dp, NULL);
 
                return;
        }
@@ -215,11 +223,12 @@ guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
                                                        gpointer user_data)
 {
        struct discover_primary *dp;
-       uint8_t pdu[ATT_DEFAULT_LE_MTU];
+       int buflen;
+       uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
        GAttribResultFunc cb;
        guint16 plen;
 
-       plen = encode_discover_primary(0x0001, 0xffff, uuid, pdu, sizeof(pdu));
+       plen = encode_discover_primary(0x0001, 0xffff, uuid, buf, buflen);
        if (plen == 0)
                return 0;
 
@@ -232,12 +241,12 @@ guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
        dp->user_data = user_data;
 
        if (uuid) {
-               memcpy(&dp->uuid, uuid, sizeof(bt_uuid_t));
+               dp->uuid = *uuid;
                cb = primary_by_uuid_cb;
        } else
                cb = primary_all_cb;
 
-       return g_attrib_send(attrib, 0, pdu[0], pdu, plen, cb, dp, NULL);
+       return g_attrib_send(attrib, 0, buf[0], buf, plen, cb, dp, NULL);
 }
 
 static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
@@ -246,7 +255,8 @@ 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;
-       uint8_t opdu[ATT_DEFAULT_LE_MTU];
+       int buflen;
+       uint8_t *buf;
        guint16 oplen;
        bt_uuid_t uuid;
        uint16_t last = 0;
@@ -281,6 +291,9 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
                        goto done;
                }
 
+               if (dc->uuid && bt_uuid_cmp(dc->uuid, &uuid))
+                       break;
+
                chars->handle = last;
                chars->properties = value[2];
                chars->value_handle = att_get_u16(&value[3]);
@@ -293,15 +306,17 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
        err = 0;
 
        if (last != 0) {
+               buf = g_attrib_get_buffer(dc->attrib, &buflen);
+
                bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
 
-               oplen = enc_read_by_type_req(last + 1, dc->end, &uuid, opdu,
-                                                               sizeof(opdu));
+               oplen = enc_read_by_type_req(last + 1, dc->end, &uuid, buf,
+                                                                       buflen);
 
                if (oplen == 0)
                        return;
 
-               g_attrib_send(dc->attrib, 0, opdu[0], opdu, oplen,
+               g_attrib_send(dc->attrib, 0, buf[0], buf, oplen,
                                                char_discovered_cb, dc, NULL);
 
                return;
@@ -313,16 +328,18 @@ done:
 }
 
 guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
-                                       gatt_cb_t func, gpointer user_data)
+                                               bt_uuid_t *uuid, gatt_cb_t func,
+                                               gpointer user_data)
 {
-       uint8_t pdu[ATT_DEFAULT_LE_MTU];
+       int buflen;
+       uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
        struct discover_char *dc;
+       bt_uuid_t type_uuid;
        guint16 plen;
-       bt_uuid_t uuid;
 
-       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
+       bt_uuid16_create(&type_uuid, GATT_CHARAC_UUID);
 
-       plen = enc_read_by_type_req(start, end, &uuid, pdu, sizeof(pdu));
+       plen = enc_read_by_type_req(start, end, &type_uuid, buf, buflen);
        if (plen == 0)
                return 0;
 
@@ -334,8 +351,9 @@ guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
        dc->cb = func;
        dc->user_data = user_data;
        dc->end = end;
+       dc->uuid = g_memdup(uuid, sizeof(bt_uuid_t));
 
-       return g_attrib_send(attrib, 0, pdu[0], pdu, plen, char_discovered_cb,
+       return g_attrib_send(attrib, 0, buf[0], buf, plen, char_discovered_cb,
                                                                dc, NULL);
 }
 
@@ -343,15 +361,16 @@ guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end,
                                        bt_uuid_t *uuid, GAttribResultFunc func,
                                        gpointer user_data)
 {
-       uint8_t pdu[ATT_DEFAULT_LE_MTU];
+       int buflen;
+       uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
        guint16 plen;
 
-       plen = enc_read_by_type_req(start, end, uuid, pdu, sizeof(pdu));
+       plen = enc_read_by_type_req(start, end, uuid, buf, buflen);
        if (plen == 0)
                return 0;
 
        return g_attrib_send(attrib, 0, ATT_OP_READ_BY_TYPE_REQ,
-                                       pdu, plen, func, user_data, NULL);
+                                       buf, plen, func, user_data, NULL);
 }
 
 struct read_long_data {
@@ -382,7 +401,8 @@ static void read_blob_helper(guint8 status, const guint8 *rpdu, guint16 rlen,
                                                        gpointer user_data)
 {
        struct read_long_data *long_read = user_data;
-       uint8_t pdu[ATT_DEFAULT_LE_MTU];
+       uint8_t *buf;
+       int buflen;
        guint8 *tmp;
        guint16 plen;
        guint id;
@@ -403,13 +423,14 @@ static void read_blob_helper(guint8 status, const guint8 *rpdu, guint16 rlen,
        long_read->buffer = tmp;
        long_read->size += rlen - 1;
 
-       if (rlen < ATT_DEFAULT_LE_MTU)
+       buf = g_attrib_get_buffer(long_read->attrib, &buflen);
+       if (rlen < buflen)
                goto done;
 
        plen = enc_read_blob_req(long_read->handle, long_read->size - 1,
-                                                       pdu, sizeof(pdu));
+                                                               buf, buflen);
        id = g_attrib_send(long_read->attrib, long_read->id,
-                               ATT_OP_READ_BLOB_REQ, pdu, plen,
+                               ATT_OP_READ_BLOB_REQ, buf, plen,
                                read_blob_helper, long_read, read_long_destroy);
 
        if (id != 0) {
@@ -428,11 +449,12 @@ static void read_char_helper(guint8 status, const guint8 *rpdu,
                                        guint16 rlen, gpointer user_data)
 {
        struct read_long_data *long_read = user_data;
-       uint8_t pdu[ATT_DEFAULT_LE_MTU];
+       int buflen;
+       uint8_t *buf = g_attrib_get_buffer(long_read->attrib, &buflen);
        guint16 plen;
        guint id;
 
-       if (status != 0 || rlen < ATT_DEFAULT_LE_MTU)
+       if (status != 0 || rlen < buflen)
                goto done;
 
        long_read->buffer = g_malloc(rlen);
@@ -443,9 +465,9 @@ static void read_char_helper(guint8 status, const guint8 *rpdu,
        memcpy(long_read->buffer, rpdu, rlen);
        long_read->size = rlen;
 
-       plen = enc_read_blob_req(long_read->handle, rlen - 1, pdu, sizeof(pdu));
+       plen = enc_read_blob_req(long_read->handle, rlen - 1, buf, buflen);
        id = g_attrib_send(long_read->attrib, long_read->id,
-                       ATT_OP_READ_BLOB_REQ, pdu, plen, read_blob_helper,
+                       ATT_OP_READ_BLOB_REQ, buf, plen, read_blob_helper,
                        long_read, read_long_destroy);
 
        if (id != 0) {
@@ -462,7 +484,8 @@ done:
 guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset,
                                GAttribResultFunc func, gpointer user_data)
 {
-       uint8_t pdu[ATT_DEFAULT_LE_MTU];
+       uint8_t *buf;
+       int buflen;
        guint16 plen;
        guint id;
        struct read_long_data *long_read;
@@ -477,14 +500,15 @@ guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset,
        long_read->user_data = user_data;
        long_read->handle = handle;
 
+       buf = g_attrib_get_buffer(attrib, &buflen);
        if (offset > 0) {
-               plen = enc_read_blob_req(long_read->handle, offset, pdu,
-                                                               sizeof(pdu));
-               id = g_attrib_send(attrib, 0, ATT_OP_READ_BLOB_REQ, pdu, plen,
+               plen = enc_read_blob_req(long_read->handle, offset, buf,
+                                                                       buflen);
+               id = g_attrib_send(attrib, 0, ATT_OP_READ_BLOB_REQ, buf, plen,
                                read_blob_helper, long_read, read_long_destroy);
        } else {
-               plen = enc_read_req(handle, pdu, sizeof(pdu));
-               id = g_attrib_send(attrib, 0, ATT_OP_READ_REQ, pdu, plen,
+               plen = enc_read_req(handle, buf, buflen);
+               id = g_attrib_send(attrib, 0, ATT_OP_READ_REQ, buf, plen,
                                read_char_helper, long_read, read_long_destroy);
        }
 
@@ -501,39 +525,133 @@ guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset,
 guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
                        int vlen, GAttribResultFunc func, gpointer user_data)
 {
-       uint8_t pdu[ATT_DEFAULT_LE_MTU];
+       uint8_t *buf;
+       int buflen;
        guint16 plen;
 
+       buf = g_attrib_get_buffer(attrib, &buflen);
        if (func)
-               plen = enc_write_req(handle, value, vlen, pdu, sizeof(pdu));
+               plen = enc_write_req(handle, value, vlen, buf, buflen);
        else
-               plen = enc_write_cmd(handle, value, vlen, pdu, sizeof(pdu));
+               plen = enc_write_cmd(handle, value, vlen, buf, buflen);
+
+       return g_attrib_send(attrib, 0, buf[0], buf, plen, func,
+                                                       user_data, NULL);
+}
 
-       return g_attrib_send(attrib, 0, pdu[0], pdu, plen, func,
+guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func,
+                                                       gpointer user_data)
+{
+       uint8_t *buf;
+       int buflen;
+       guint16 plen;
+
+       buf = g_attrib_get_buffer(attrib, &buflen);
+       plen = enc_mtu_req(mtu, buf, buflen);
+       return g_attrib_send(attrib, 0, ATT_OP_MTU_REQ, buf, plen, func,
                                                        user_data, NULL);
 }
 
 guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
                                GAttribResultFunc func, gpointer user_data)
 {
-       uint8_t pdu[ATT_DEFAULT_LE_MTU];
+       uint8_t *buf;
+       int buflen;
        guint16 plen;
 
-       plen = enc_find_info_req(start, end, pdu, sizeof(pdu));
+       buf = g_attrib_get_buffer(attrib, &buflen);
+       plen = enc_find_info_req(start, end, buf, buflen);
        if (plen == 0)
                return 0;
 
-       return g_attrib_send(attrib, 0, ATT_OP_FIND_INFO_REQ, pdu, plen, func,
+       return g_attrib_send(attrib, 0, ATT_OP_FIND_INFO_REQ, buf, plen, func,
                                                        user_data, NULL);
 }
 
 guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen,
                                GDestroyNotify notify, gpointer user_data)
 {
-       uint8_t pdu[ATT_DEFAULT_LE_MTU];
+       uint8_t *buf;
+       int buflen;
        guint16 plen;
 
-       plen = enc_write_cmd(handle, value, vlen, pdu, sizeof(pdu));
-       return g_attrib_send(attrib, 0, ATT_OP_WRITE_CMD, pdu, plen, NULL,
+       buf = g_attrib_get_buffer(attrib, &buflen);
+       plen = enc_write_cmd(handle, value, vlen, buf, buflen);
+       return g_attrib_send(attrib, 0, ATT_OP_WRITE_CMD, buf, plen, NULL,
                                                        user_data, notify);
 }
+
+static sdp_data_t *proto_seq_find(sdp_list_t *proto_list)
+{
+       sdp_list_t *list;
+       uuid_t proto;
+
+       sdp_uuid16_create(&proto, ATT_UUID);
+
+       for (list = proto_list; list; list = list->next) {
+               sdp_list_t *p;
+               for (p = list->data; p; p = p->next) {
+                       sdp_data_t *seq = p->data;
+                       if (seq && seq->dtd == SDP_UUID16 &&
+                               sdp_uuid16_cmp(&proto, &seq->val.uuid) == 0)
+                               return seq->next;
+               }
+       }
+
+       return NULL;
+}
+
+static gboolean parse_proto_params(sdp_list_t *proto_list, uint16_t *psm,
+                                               uint16_t *start, uint16_t *end)
+{
+       sdp_data_t *seq1, *seq2;
+
+       if (psm)
+               *psm = sdp_get_proto_port(proto_list, L2CAP_UUID);
+
+       /* Getting start and end handle */
+       seq1 = proto_seq_find(proto_list);
+       if (!seq1 || seq1->dtd != SDP_UINT16)
+               return FALSE;
+
+       seq2 = seq1->next;
+       if (!seq2 || seq2->dtd != SDP_UINT16)
+               return FALSE;
+
+       if (start)
+               *start = seq1->val.uint16;
+
+       if (end)
+               *end = seq2->val.uint16;
+
+       return TRUE;
+}
+
+gboolean gatt_parse_record(const sdp_record_t *rec,
+                                       uuid_t *prim_uuid, uint16_t *psm,
+                                       uint16_t *start, uint16_t *end)
+{
+       sdp_list_t *list;
+       uuid_t uuid;
+       gboolean ret;
+
+       if (sdp_get_service_classes(rec, &list) < 0)
+               return FALSE;
+
+       memcpy(&uuid, list->data, sizeof(uuid));
+       sdp_list_free(list, free);
+
+       if (sdp_get_access_protos(rec, &list) < 0)
+               return FALSE;
+
+       ret = parse_proto_params(list, psm, start, end);
+
+       sdp_list_foreach(list, (sdp_list_func_t) sdp_list_free, NULL);
+       sdp_list_free(list, NULL);
+
+       /* FIXME: replace by bt_uuid_t after uuid_t/sdp code cleanup */
+       if (ret && prim_uuid)
+               memcpy(prim_uuid, &uuid, sizeof(uuid_t));
+
+       return ret;
+}
index 730de7e..c5f95ac 100644 (file)
@@ -21,8 +21,7 @@
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
-
-#define GATT_CID 4
+#include <bluetooth/sdp.h>
 
 typedef void (*gatt_cb_t) (GSList *l, guint8 status, gpointer user_data);
 
@@ -30,7 +29,8 @@ guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
                                                        gpointer user_data);
 
 guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
-                                       gatt_cb_t func, gpointer user_data);
+                                       bt_uuid_t *uuid, gatt_cb_t func,
+                                       gpointer user_data);
 
 guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset,
                                GAttribResultFunc func, gpointer user_data);
@@ -47,3 +47,10 @@ guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen,
 guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end,
                                bt_uuid_t *uuid, GAttribResultFunc func,
                                gpointer user_data);
+
+guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func,
+                                                       gpointer user_data);
+
+gboolean gatt_parse_record(const sdp_record_t *rec,
+                                       uuid_t *prim_uuid, uint16_t *psm,
+                                       uint16_t *start, uint16_t *end);
index 07e56de..4d901f1 100644 (file)
@@ -40,6 +40,8 @@
 struct _GAttrib {
        GIOChannel *io;
        gint refs;
+       uint8_t *buf;
+       int buflen;
        guint read_watch;
        guint write_watch;
        guint timeout_watch;
@@ -193,6 +195,8 @@ static void attrib_destroy(GAttrib *attrib)
                g_io_channel_unref(attrib->io);
        }
 
+       g_free(attrib->buf);
+
        if (attrib->destroy)
                attrib->destroy(attrib->destroy_user_data);
 
@@ -342,7 +346,9 @@ static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
                struct event *evt = l->data;
 
                if (evt->expected == buf[0] ||
-                                       evt->expected == GATTRIB_ALL_EVENTS)
+                               evt->expected == GATTRIB_ALL_EVENTS ||
+                               (is_response(buf[0]) == FALSE &&
+                                               evt->expected == GATTRIB_ALL_REQS))
                        evt->func(buf, len, evt->user_data);
        }
 
@@ -386,6 +392,7 @@ done:
 GAttrib *g_attrib_new(GIOChannel *io)
 {
        struct _GAttrib *attrib;
+       uint16_t omtu;
 
        g_io_channel_set_encoding(io, NULL, NULL);
        g_io_channel_set_buffered(io, FALSE);
@@ -401,6 +408,17 @@ GAttrib *g_attrib_new(GIOChannel *io)
                        G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
                        received_data, attrib);
 
+       if (bt_io_get(attrib->io, BT_IO_L2CAP, NULL,
+                       BT_IO_OPT_OMTU, &omtu,
+                       BT_IO_OPT_INVALID)) {
+               if (omtu == 0 || omtu > ATT_MAX_MTU)
+                       omtu = ATT_MAX_MTU;
+       } else
+               omtu = ATT_DEFAULT_LE_MTU;
+
+       attrib->buf = g_malloc0(omtu);
+       attrib->buflen = omtu;
+
        return g_attrib_ref(attrib);
 }
 
@@ -504,6 +522,36 @@ gboolean g_attrib_set_debug(GAttrib *attrib,
        return TRUE;
 }
 
+uint8_t *g_attrib_get_buffer(GAttrib *attrib, int *len)
+{
+       if (len == NULL)
+               return NULL;
+
+       *len = attrib->buflen;
+
+       return attrib->buf;
+}
+
+gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu)
+{
+       if (mtu < ATT_DEFAULT_LE_MTU)
+               mtu = ATT_DEFAULT_LE_MTU;
+
+       if (mtu > ATT_MAX_MTU)
+               mtu = ATT_MAX_MTU;
+
+       if (!bt_io_set(attrib->io, BT_IO_L2CAP, NULL,
+                       BT_IO_OPT_OMTU, mtu,
+                       BT_IO_OPT_INVALID))
+               return FALSE;
+
+       attrib->buf = g_realloc(attrib->buf, mtu);
+
+       attrib->buflen = mtu;
+
+       return TRUE;
+}
+
 guint g_attrib_register(GAttrib *attrib, guint8 opcode,
                                GAttribNotifyFunc func, gpointer user_data,
                                GDestroyNotify notify)
index f25208d..47c0d60 100644 (file)
@@ -29,6 +29,7 @@ extern "C" {
 #endif
 
 #define GATTRIB_ALL_EVENTS 0xFF
+#define GATTRIB_ALL_REQS 0xFE
 
 struct _GAttrib;
 typedef struct _GAttrib GAttrib;
@@ -68,6 +69,9 @@ guint g_attrib_register(GAttrib *attrib, guint8 opcode,
 
 gboolean g_attrib_is_encrypted(GAttrib *attrib);
 
+uint8_t *g_attrib_get_buffer(GAttrib *attrib, int *len);
+gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu);
+
 gboolean g_attrib_unregister(GAttrib *attrib, guint id);
 gboolean g_attrib_unregister_all(GAttrib *attrib);
 
index 729e18d..17ee913 100644 (file)
@@ -63,6 +63,7 @@ static gboolean opt_char_write_req = FALSE;
 static gboolean opt_interactive = FALSE;
 static GMainLoop *event_loop;
 static gboolean got_error = FALSE;
+static GSourceFunc operation;
 
 struct characteristic_data {
        GAttrib *attrib;
@@ -70,13 +71,68 @@ struct characteristic_data {
        uint16_t end;
 };
 
+static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+       GAttrib *attrib = user_data;
+       uint8_t opdu[ATT_MAX_MTU];
+       uint16_t handle, i, olen = 0;
+
+       handle = att_get_u16(&pdu[1]);
+
+       switch (pdu[0]) {
+       case ATT_OP_HANDLE_NOTIFY:
+               g_print("Notification handle = 0x%04x value: ", handle);
+               break;
+       case ATT_OP_HANDLE_IND:
+               g_print("Indication   handle = 0x%04x value: ", handle);
+               break;
+       default:
+               g_print("Invalid opcode\n");
+               return;
+       }
+
+       for (i = 3; i < len; i++)
+               g_print("%02x ", pdu[i]);
+
+       g_print("\n");
+
+       if (pdu[0] == ATT_OP_HANDLE_NOTIFY)
+               return;
+
+       olen = enc_confirmation(opdu, sizeof(opdu));
+
+       if (olen > 0)
+               g_attrib_send(attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL);
+}
+
+static gboolean listen_start(gpointer user_data)
+{
+       GAttrib *attrib = user_data;
+
+       g_attrib_register(attrib, ATT_OP_HANDLE_NOTIFY, events_handler,
+                                                       attrib, NULL);
+       g_attrib_register(attrib, ATT_OP_HANDLE_IND, events_handler,
+                                                       attrib, NULL);
+
+       return FALSE;
+}
+
 static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
 {
+       GAttrib *attrib;
+
        if (err) {
                g_printerr("%s\n", err->message);
                got_error = TRUE;
                g_main_loop_quit(event_loop);
        }
+
+       attrib = g_attrib_new(io);
+
+       if (opt_listen)
+               g_idle_add(listen_start, attrib);
+
+       operation(attrib);
 }
 
 static void primary_all_cb(GSList *services, guint8 status, gpointer user_data)
@@ -120,52 +176,6 @@ done:
        g_main_loop_quit(event_loop);
 }
 
-static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
-{
-       GAttrib *attrib = user_data;
-       uint8_t opdu[ATT_MAX_MTU];
-       uint16_t handle, i, olen = 0;
-
-       handle = att_get_u16(&pdu[1]);
-
-       switch (pdu[0]) {
-       case ATT_OP_HANDLE_NOTIFY:
-               g_print("Notification handle = 0x%04x value: ", handle);
-               break;
-       case ATT_OP_HANDLE_IND:
-               g_print("Indication   handle = 0x%04x value: ", handle);
-               break;
-       default:
-               g_print("Invalid opcode\n");
-               return;
-       }
-
-       for (i = 3; i < len; i++)
-               g_print("%02x ", pdu[i]);
-
-       g_print("\n");
-
-       if (pdu[0] == ATT_OP_HANDLE_NOTIFY)
-               return;
-
-       olen = enc_confirmation(opdu, sizeof(opdu));
-
-       if (olen > 0)
-               g_attrib_send(attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL);
-}
-
-static gboolean listen_start(gpointer user_data)
-{
-       GAttrib *attrib = user_data;
-
-       g_attrib_register(attrib, ATT_OP_HANDLE_NOTIFY, events_handler,
-                                                       attrib, NULL);
-       g_attrib_register(attrib, ATT_OP_HANDLE_IND, events_handler,
-                                                       attrib, NULL);
-
-       return FALSE;
-}
-
 static gboolean primary(gpointer user_data)
 {
        GAttrib *attrib = user_data;
@@ -206,7 +216,8 @@ static gboolean characteristics(gpointer user_data)
 {
        GAttrib *attrib = user_data;
 
-       gatt_discover_char(attrib, opt_start, opt_end, char_discovered_cb, NULL);
+       gatt_discover_char(attrib, opt_start, opt_end, opt_uuid,
+                                               char_discovered_cb, NULL);
 
        return FALSE;
 }
@@ -272,12 +283,6 @@ static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
 
        att_data_list_free(list);
 
-       gatt_read_char_by_uuid(char_data->attrib, char_data->start,
-                                       char_data->end, opt_uuid,
-                                       char_read_by_uuid_cb,
-                                       char_data);
-
-       return;
 done:
        g_free(char_data);
        g_main_loop_quit(event_loop);
@@ -365,7 +370,7 @@ static void char_write_req_cb(guint8 status, const guint8 *pdu, guint16 plen,
                goto done;
        }
 
-       g_print("Characteristic value was written sucessfully\n");
+       g_print("Characteristic value was written successfully\n");
 
 done:
        if (opt_listen == FALSE)
@@ -532,9 +537,7 @@ int main(int argc, char *argv[])
        GOptionContext *context;
        GOptionGroup *gatt_group, *params_group, *char_rw_group;
        GError *gerr = NULL;
-       GAttrib *attrib;
        GIOChannel *chan;
-       GSourceFunc callback;
 
        opt_sec_level = g_strdup("low");
 
@@ -575,17 +578,17 @@ int main(int argc, char *argv[])
        }
 
        if (opt_primary)
-               callback = primary;
+               operation = primary;
        else if (opt_characteristics)
-               callback = characteristics;
+               operation = characteristics;
        else if (opt_char_read)
-               callback = characteristics_read;
+               operation = characteristics_read;
        else if (opt_char_write)
-               callback = characteristics_write;
+               operation = characteristics_write;
        else if (opt_char_write_req)
-               callback = characteristics_write_req;
+               operation = characteristics_write_req;
        else if (opt_char_desc)
-               callback = characteristics_desc;
+               operation = characteristics_desc;
        else {
                gchar *help = g_option_context_get_help(context, TRUE, NULL);
                g_print("%s\n", help);
@@ -601,24 +604,12 @@ int main(int argc, char *argv[])
                goto done;
        }
 
-       attrib = g_attrib_new(chan);
-       g_io_channel_unref(chan);
-
        event_loop = g_main_loop_new(NULL, FALSE);
 
-       if (opt_listen)
-               g_idle_add(listen_start, attrib);
-
-       g_idle_add(callback, attrib);
-
        g_main_loop_run(event_loop);
 
-       g_attrib_unregister_all(attrib);
-
        g_main_loop_unref(event_loop);
 
-       g_attrib_unref(attrib);
-
 done:
        g_option_context_free(context);
        g_free(opt_src);
index b32e9e7..a772362 100644 (file)
@@ -315,14 +315,8 @@ static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
 
        att_data_list_free(list);
 
-       gatt_read_char_by_uuid(attrib, char_data->start, char_data->end,
-                                       &char_data->uuid, char_read_by_uuid_cb,
-                                       char_data);
-
        rl_forced_update_display();
 
-       return;
-
 done:
        g_free(char_data);
 }
@@ -362,6 +356,7 @@ static void cmd_disconnect(int argcp, char **argvp)
 
        g_attrib_unref(attrib);
        attrib = NULL;
+       opt_mtu = 0;
 
        g_io_channel_shutdown(iochannel, FALSE, NULL);
        g_io_channel_unref(iochannel);
@@ -431,7 +426,19 @@ static void cmd_char(int argcp, char **argvp)
                }
        }
 
-       gatt_discover_char(attrib, start, end, char_cb, NULL);
+       if (argcp > 3) {
+               bt_uuid_t uuid;
+
+               if (bt_string_to_uuid(&uuid, argvp[3]) < 0) {
+                       printf("Invalid UUID\n");
+                       return;
+               }
+
+               gatt_discover_char(attrib, start, end, &uuid, char_cb, NULL);
+               return;
+       }
+
+       gatt_discover_char(attrib, start, end, NULL, char_cb, NULL);
 }
 
 static void cmd_char_desc(int argcp, char **argvp)
@@ -642,6 +649,65 @@ static void cmd_sec_level(int argcp, char **argvp)
        }
 }
 
+static void exchange_mtu_cb(guint8 status, const guint8 *pdu, guint16 plen,
+                                                       gpointer user_data)
+{
+       uint16_t mtu;
+
+       if (status != 0) {
+               printf("Exchange MTU Request failed: %s\n",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       if (!dec_mtu_resp(pdu, plen, &mtu)) {
+               printf("Protocol error\n");
+               return;
+       }
+
+       mtu = MIN(mtu, opt_mtu);
+       /* Set new value for MTU in client */
+       if (g_attrib_set_mtu(attrib, mtu))
+               printf("MTU was exchanged successfully: %d\n", mtu);
+       else
+               printf("Error exchanging MTU\n");
+}
+
+static void cmd_mtu(int argcp, char **argvp)
+{
+       if (conn_state != STATE_CONNECTED) {
+               printf("Command failed: not connected.\n");
+               return;
+       }
+
+       if (opt_psm) {
+               printf("Command failed: operation is only available for LE"
+                                                       " transport.\n");
+               return;
+       }
+
+       if (argcp < 2) {
+               printf("Usage: mtu <value>\n");
+               return;
+       }
+
+       if (opt_mtu) {
+               printf("Command failed: MTU exchange can only occur once per"
+                                                       " connection.\n");
+               return;
+       }
+
+       errno = 0;
+       opt_mtu = strtoll(argvp[1], NULL, 0);
+       if (errno != 0 || opt_mtu < ATT_DEFAULT_LE_MTU) {
+               printf("Invalid value. Minimum MTU size is %d\n",
+                                                       ATT_DEFAULT_LE_MTU);
+               return;
+       }
+
+       gatt_exchange_mtu(attrib, opt_mtu, exchange_mtu_cb, NULL);
+}
+
 static struct {
        const char *cmd;
        void (*func)(int argcp, char **argvp);
@@ -652,13 +718,15 @@ static struct {
                "Show this help"},
        { "exit",               cmd_exit,       "",
                "Exit interactive mode" },
+       { "quit",               cmd_exit,       "",
+               "Exit interactive mode" },
        { "connect",            cmd_connect,    "[address]",
                "Connect to a remote device" },
        { "disconnect",         cmd_disconnect, "",
                "Disconnect from a remote device" },
        { "primary",            cmd_primary,    "[UUID]",
                "Primary Service Discovery" },
-       { "characteristics",    cmd_char,       "[start hnd] [end hnd]",
+       { "characteristics",    cmd_char,       "[start hnd [end hnd [UUID]]]",
                "Characteristics Discovery" },
        { "char-desc",          cmd_char_desc,  "[start hnd] [end hnd]",
                "Characteristics Descriptor Discovery" },
@@ -672,6 +740,8 @@ static struct {
                "Characteristic Value Write (No response)" },
        { "sec-level",          cmd_sec_level,  "[low | medium | high]",
                "Set security level. Default: low" },
+       { "mtu",                cmd_mtu,        "<value>",
+               "Exchange MTU for GATT/ATT" },
        { NULL, NULL, NULL}
 };
 
diff --git a/attrib/manager.c b/attrib/manager.c
deleted file mode 100644 (file)
index a5a7de4..0000000
+++ /dev/null
@@ -1,105 +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 HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include "../src/adapter.h"
-#include "../src/device.h"
-#include "hcid.h"
-
-#include "manager.h"
-#include "client.h"
-#include "example.h"
-
-#define GATT_UUID      "00001801-0000-1000-8000-00805f9b34fb"
-
-static DBusConnection *connection;
-
-static int client_probe(struct btd_device *device, GSList *uuids)
-{
-       const sdp_record_t *rec;
-       int psm = -1;
-
-       rec = btd_device_get_record(device, GATT_UUID);
-       if (rec) {
-               sdp_list_t *list;
-               if (sdp_get_access_protos(rec, &list) < 0)
-                       return -1;
-
-               psm = sdp_get_proto_port(list, L2CAP_UUID);
-
-               sdp_list_foreach(list, (sdp_list_func_t) sdp_list_free, NULL);
-               sdp_list_free(list, NULL);
-
-               if (psm < 0)
-                       return -1;
-       }
-
-       return attrib_client_register(device, psm);
-}
-
-static void client_remove(struct btd_device *device)
-{
-       attrib_client_unregister(device);
-}
-
-static struct btd_device_driver client_driver = {
-       .name = "gatt-client",
-       .uuids = BTD_UUIDS(GATT_UUID),
-       .probe = client_probe,
-       .remove = client_remove,
-};
-
-int attrib_manager_init(DBusConnection *conn)
-{
-       connection = dbus_connection_ref(conn);
-
-       attrib_client_init(connection);
-
-       btd_register_device_driver(&client_driver);
-
-
-       if (main_opts.attrib_server)
-               return server_example_init();
-
-       return 0;
-}
-
-void attrib_manager_exit(void)
-{
-       btd_unregister_device_driver(&client_driver);
-
-       if (main_opts.attrib_server)
-               server_example_exit();
-
-       attrib_client_exit();
-
-       dbus_connection_unref(connection);
-}
index 5f4444a..22d23a4 100644 (file)
@@ -30,6 +30,7 @@
 #include <bluetooth/uuid.h>
 #include <bluetooth/sdp.h>
 
+#include "att.h"
 #include "gattrib.h"
 #include "gatt.h"
 #include "btio.h"
@@ -84,7 +85,7 @@ GIOChannel *gatt_connect(const gchar *src, const gchar *dst,
                chan = bt_io_connect(BT_IO_L2CAP, connect_cb, NULL, NULL, &err,
                                BT_IO_OPT_SOURCE_BDADDR, &sba,
                                BT_IO_OPT_DEST_BDADDR, &dba,
-                               BT_IO_OPT_CID, GATT_CID,
+                               BT_IO_OPT_CID, ATT_CID,
                                BT_IO_OPT_OMTU, mtu,
                                BT_IO_OPT_SEC_LEVEL, sec,
                                BT_IO_OPT_INVALID);
index 4c8a02f..cd6d327 100644 (file)
@@ -4,6 +4,7 @@
  *
  *  Copyright (C) 2006-2010  Nokia Corporation
  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011  BMW Car IT GmbH. All rights reserved.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -36,7 +37,7 @@
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
-#include "glib-helper.h"
+#include "glib-compat.h"
 #include "log.h"
 #include "device.h"
 #include "manager.h"
@@ -638,11 +639,9 @@ static gboolean mpeg_getcap_ind(struct avdtp *session,
        return TRUE;
 }
 
-static void endpoint_setconf_cb(struct a2dp_sep *sep, guint setup_id,
-                                                               gboolean ret)
-{
-       struct a2dp_setup *setup = GUINT_TO_POINTER(setup_id);
 
+static void endpoint_setconf_cb(struct a2dp_setup *setup, gboolean ret)
+{
        if (ret == FALSE) {
                setup->err = g_new(struct avdtp_error, 1);
                avdtp_error_init(setup->err, AVDTP_MEDIA_CODEC,
@@ -704,7 +703,7 @@ static gboolean endpoint_setconf_ind(struct avdtp *session,
                ret = a2dp_sep->endpoint->set_configuration(a2dp_sep,
                                                setup->dev, codec->data,
                                                cap->length - sizeof(*codec),
-                                               GPOINTER_TO_UINT(setup),
+                                               setup,
                                                endpoint_setconf_cb,
                                                a2dp_sep->user_data);
                if (ret == 0)
@@ -768,10 +767,8 @@ static gboolean endpoint_getcap_ind(struct avdtp *session,
        return TRUE;
 }
 
-static void endpoint_open_cb(struct a2dp_sep *sep, guint setup_id,
-                                                               gboolean ret)
+static void endpoint_open_cb(struct a2dp_setup *setup, gboolean ret)
 {
-       struct a2dp_setup *setup = GUINT_TO_POINTER(setup_id);
        int err;
 
        if (ret == FALSE) {
@@ -839,7 +836,7 @@ static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
                err = a2dp_sep->endpoint->set_configuration(a2dp_sep, dev,
                                                codec->data, service->length -
                                                sizeof(*codec),
-                                               GPOINTER_TO_UINT(setup),
+                                               setup,
                                                endpoint_open_cb,
                                                a2dp_sep->user_data);
                if (err == 0)
@@ -1889,10 +1886,8 @@ static gboolean select_capabilities(struct avdtp *session,
        return TRUE;
 }
 
-static void select_cb(struct a2dp_sep *sep, guint setup_id, void *ret,
-                                                               int size)
+static void select_cb(struct a2dp_setup *setup, void *ret, int size)
 {
-       struct a2dp_setup *setup = GUINT_TO_POINTER(setup_id);
        struct avdtp_service_capability *media_transport, *media_codec;
        struct avdtp_media_codec_capability *cap;
 
@@ -2033,7 +2028,7 @@ unsigned int a2dp_select_capabilities(struct avdtp *session,
 
        err = sep->endpoint->select_configuration(sep, codec->data,
                                        service->length - sizeof(*codec),
-                                       GPOINTER_TO_UINT(setup),
+                                       setup,
                                        select_cb, sep->user_data);
        if (err == 0)
                return cb_data->id;
index 1637580..887c5ac 100644 (file)
@@ -4,6 +4,7 @@
  *
  *  Copyright (C) 2006-2010  Nokia Corporation
  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011  BMW Car IT GmbH. All rights reserved.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -120,11 +121,11 @@ struct mpeg_codec_cap {
 #endif
 
 struct a2dp_sep;
+struct a2dp_setup;
 
-typedef void (*a2dp_endpoint_select_t) (struct a2dp_sep *sep, guint setup_id,
-                                                       void *ret, int size);
-typedef void (*a2dp_endpoint_config_t) (struct a2dp_sep *sep, guint setup_id,
-                                                               gboolean ret);
+typedef void (*a2dp_endpoint_select_t) (struct a2dp_setup *setup, void *ret,
+                                       int size);
+typedef void (*a2dp_endpoint_config_t) (struct a2dp_setup *setup, gboolean ret);
 
 struct a2dp_endpoint {
        const char *(*get_name) (struct a2dp_sep *sep, void *user_data);
@@ -134,14 +135,14 @@ struct a2dp_endpoint {
        int (*select_configuration) (struct a2dp_sep *sep,
                                                uint8_t *capabilities,
                                                size_t length,
-                                               guint setup_id,
+                                               struct a2dp_setup *setup,
                                                a2dp_endpoint_select_t cb,
                                                void *user_data);
        int (*set_configuration) (struct a2dp_sep *sep,
                                                struct audio_device *dev,
                                                uint8_t *configuration,
                                                size_t length,
-                                               guint setup_id,
+                                               struct a2dp_setup *setup,
                                                a2dp_endpoint_config_t cb,
                                                void *user_data);
        void (*clear_configuration) (struct a2dp_sep *sep, void *user_data);
index b75a39f..ec90131 100644 (file)
@@ -9,12 +9,19 @@
 
 # If we want to disable support for specific services
 # Defaults to supporting all implemented services
-Disable=Gateway
-Enable=Media
+#Disable=Control,Source
+
+#ifdef __SAMSUNG_PATCH__
+Enable=Socket
+#endif
 
 # SCO routing. Either PCM or HCI (in which case audio is routed to/from ALSA)
-# Defaults to HCI
+#ifdef __SAMSUNG_PATCH__
 SCORouting=PCM
+#else
+# Defaults to HCI
+#SCORouting=PCM
+#endif
 
 # Automatically connect both A2DP and HFP/HSP profiles for incoming
 # connections. Some headsets that support both profiles will only connect the
@@ -41,7 +48,11 @@ MaxConnected=1
 FastConnectable=false
 
 # Just an example of potential config options for the other interfaces
+#ifdef __SAMSUNG_PATCH__
 [A2DP]
 SBCSources=1
-APTXSources=1
+#else
+#[A2DP]
+#SBCSources=1
 #MPEG12Sources=0
+#endif
index df3b2b8..5bd5db1 100644 (file)
@@ -502,10 +502,10 @@ static int uinput_create(char *name)
                if (fd < 0) {
                        fd = open("/dev/misc/uinput", O_RDWR);
                        if (fd < 0) {
-                               err = errno;
+                               err = -errno;
                                error("Can't open input device: %s (%d)",
-                                                       strerror(err), err);
-                               return -err;
+                                                       strerror(-err), -err);
+                               return err;
                        }
                }
        }
@@ -520,12 +520,11 @@ static int uinput_create(char *name)
        dev.id.version = 0x0000;
 
        if (write(fd, &dev, sizeof(dev)) < 0) {
-               err = errno;
+               err = -errno;
                error("Can't write device information: %s (%d)",
-                                               strerror(err), err);
+                                               strerror(-err), -err);
                close(fd);
-               errno = err;
-               return -err;
+               return err;
        }
 
        ioctl(fd, UI_SET_EVBIT, EV_KEY);
@@ -537,12 +536,11 @@ static int uinput_create(char *name)
                ioctl(fd, UI_SET_KEYBIT, key_map[i].uinput);
 
        if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {
-               err = errno;
+               err = -errno;
                error("Can't create uinput device: %s (%d)",
-                                               strerror(err), err);
+                                               strerror(-err), -err);
                close(fd);
-               errno = err;
-               return -err;
+               return err;
        }
 
        return fd;
@@ -895,7 +893,7 @@ int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
        struct avctp_header *avctp;
        struct avc_header *avc;
        uint8_t *pdu;
-       int sk, err;
+       int sk, err = 0;
        uint16_t size;
 
        if (session->state != AVCTP_STATE_CONNECTED)
@@ -920,14 +918,11 @@ int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
 
        memcpy(pdu, operands, operand_count);
 
-       err = write(sk, buf, size);
-       if (err < 0) {
-               g_free(buf);
-               return -errno;
-       }
+       if (write(sk, buf, size) < 0)
+               err = -errno;
 
        g_free(buf);
-       return 0;
+       return err;
 }
 
 unsigned int avctp_add_state_cb(avctp_state_cb cb, void *user_data)
index 9aba77a..45cd41f 100644 (file)
@@ -52,7 +52,7 @@
 #include "manager.h"
 #include "control.h"
 #include "avdtp.h"
-#include "glib-helper.h"
+#include "glib-compat.h"
 #include "btio.h"
 #include "sink.h"
 #include "source.h"
@@ -89,7 +89,7 @@
 #define AVDTP_MSG_TYPE_ACCEPT                  0x02
 #define AVDTP_MSG_TYPE_REJECT                  0x03
 
-#ifdef __TIZEN_PATCH__
+#ifdef __SAMSUNG_PATCH__
 #define REQ_TIMEOUT 10
 #else
 #define REQ_TIMEOUT 6
index 29891fd..c9ec314 100644 (file)
@@ -52,7 +52,7 @@
 #include "avctp.h"
 #include "avrcp.h"
 #include "sdpd.h"
-#include "glib-helper.h"
+#include "glib-compat.h"
 #include "dbus-common.h"
 
 /* Company IDs for vendor dependent commands */
@@ -383,6 +383,7 @@ int avrcp_player_event(struct avrcp_player *player, uint8_t id, void *data)
                memcpy(&pdu->params[1], data, sizeof(uint64_t));
 
                break;
+       case AVRCP_EVENT_TRACK_REACHED_END:
        case AVRCP_EVENT_TRACK_REACHED_START:
                size = 1;
                break;
@@ -904,6 +905,7 @@ static uint8_t avrcp_handle_register_notification(struct avrcp_player *player,
                memcpy(&pdu->params[1], &uid, sizeof(uint64_t));
 
                break;
+       case AVRCP_EVENT_TRACK_REACHED_END:
        case AVRCP_EVENT_TRACK_REACHED_START:
                len = 1;
                break;
index c798658..fb64f3b 100644 (file)
@@ -71,6 +71,7 @@
 /* Notification events */
 #define AVRCP_EVENT_STATUS_CHANGED     0x01
 #define AVRCP_EVENT_TRACK_CHANGED      0x02
+#define AVRCP_EVENT_TRACK_REACHED_END  0x03
 #define AVRCP_EVENT_TRACK_REACHED_START        0x04
 #define AVRCP_EVENT_LAST               AVRCP_EVENT_TRACK_REACHED_START
 
index d941421..a16f476 100644 (file)
@@ -257,18 +257,19 @@ static int bluetooth_read_event(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id,
        struct bluetooth_data *data = ext->private_data;
        char buf[BT_SUGGESTED_BUFFER_SIZE];
        struct bt_control_ind *ind = (void *) buf;
-       int ret;
+       int err;
        const char *type, *name;
 
        DBG("ext %p id %p", ext, id);
 
        memset(buf, 0, sizeof(buf));
 
-       ret = recv(data->sock, ind, BT_SUGGESTED_BUFFER_SIZE, MSG_DONTWAIT);
-       if (ret < 0) {
-               SNDERR("Failed while receiving data: %s (%d)",
-                               strerror(errno), errno);
-               return -errno;
+       err = recv(data->sock, ind, BT_SUGGESTED_BUFFER_SIZE, MSG_DONTWAIT);
+       if (err < 0) {
+               err = -errno;
+               SNDERR("Failed while receiving data: %s (%d)", strerror(-err),
+                                                                       -err);
+               return err;
        }
 
        type = bt_audio_strtype(ind->h.type);
index a444f7b..a9d35f9 100644 (file)
@@ -42,7 +42,6 @@
 #include <gdbus.h>
 
 #include "log.h"
-#include "textfile.h"
 #include "../src/adapter.h"
 #include "../src/device.h"
 
index 1a1c035..9b1aab3 100644 (file)
@@ -42,7 +42,8 @@
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
-#include "glib-helper.h"
+#include "glib-compat.h"
+#include "sdp-client.h"
 #include "device.h"
 #include "gateway.h"
 #include "log.h"
index 0f3abf3..c5392c5 100644 (file)
@@ -279,10 +279,10 @@ static gint gst_avdtp_sink_bluetooth_recvmsg_fd(GstAvdtpSink *sink)
                        g_io_channel_unix_get_fd(sink->server));
 
        if (ret < 0) {
-               err = errno;
+               err = -errno;
                GST_ERROR_OBJECT(sink, "Unable to receive fd: %s (%d)",
-                               strerror(err), err);
-               return -err;
+                               strerror(-err), -err);
+               return err;
        }
 
        sink->stream = g_io_channel_unix_new(ret);
@@ -1448,11 +1448,11 @@ static gboolean gst_avdtp_sink_start(GstBaseSink *basesink)
        self->watch_id = 0;
 
        sk = bt_audio_service_open();
-       if (sk <= 0) {
-               err = errno;
+       if (sk < 0) {
+               err = -errno;
                GST_ERROR_OBJECT(self, "Cannot open connection to bt "
-                       "audio service: %s %d", strerror(err), err);
-               goto failed;
+                       "audio service: %s %d", strerror(-err), -err);
+               return FALSE;
        }
 
        self->server = g_io_channel_unix_new(sk);
@@ -1841,7 +1841,7 @@ static int gst_avdtp_sink_audioservice_send(GstAvdtpSink *self,
        ssize_t written;
        const char *type, *name;
        uint16_t length;
-       int fd;
+       int fd, err;
 
        length = msg->length ? msg->length : BT_SUGGESTED_BUFFER_SIZE;
 
@@ -1849,9 +1849,10 @@ static int gst_avdtp_sink_audioservice_send(GstAvdtpSink *self,
 
        written = write(fd, msg, length);
        if (written < 0) {
+               err = -errno;
                GST_ERROR_OBJECT(self, "Error sending data to audio service:"
-                       " %s", strerror(errno));
-               return -errno;
+                       " %s", strerror(-err));
+               return err;
        }
 
        type = bt_audio_strtype(msg->type);
@@ -1876,9 +1877,10 @@ static int gst_avdtp_sink_audioservice_recv(GstAvdtpSink *self,
 
        bytes_read = read(fd, inmsg, length);
        if (bytes_read < 0) {
+               err = -errno;
                GST_ERROR_OBJECT(self, "Error receiving data from "
-                               "audio service: %s", strerror(errno));
-               return -errno;
+                               "audio service: %s", strerror(-err));
+               return err;
        }
 
        type = bt_audio_strtype(inmsg->type);
index 4e41a49..ee4fa90 100644 (file)
@@ -53,7 +53,8 @@
 #include "error.h"
 #include "telephony.h"
 #include "headset.h"
-#include "glib-helper.h"
+#include "glib-compat.h"
+#include "sdp-client.h"
 #include "btio.h"
 #include "dbus-common.h"
 #include "../src/adapter.h"
@@ -165,7 +166,7 @@ struct headset {
 
        guint dc_timer;
 
-#ifdef __TIZEN_PATCH__
+#ifdef __SAMSUNG_PATCH__
        guint rfcomm_io_id;
 #endif
        gboolean hfp_active;
@@ -1203,13 +1204,14 @@ static int voice_dial(struct audio_device *device, const char *buf)
        return 0;
 }
 
+#ifdef __SAMSUNG_PATCH__
 int telephony_list_phonebook_store_rsp(void *telephony_device, const char *buf, cme_error_t err)
 {
        struct audio_device *device = telephony_device;
        struct headset *hs = device->headset;
        struct headset_slc *slc = hs->slc;
 
-       if ( (err != CME_ERROR_NONE) || (NULL == buf) ) {
+       if ((err != CME_ERROR_NONE) || (NULL == buf)) {
                if (slc->cme_enabled)
                        return headset_send(hs, "\r\n+CME ERROR: %d\r\n", err);
                else
@@ -1221,7 +1223,7 @@ int telephony_list_phonebook_store_rsp(void *telephony_device, const char *buf,
                        return -ENODEV;
 
                send_foreach_headset(active_devices, hfp_cmp,
-                                       "\r\n+CPBS: %s\r\n",buf);
+                                       "\r\n+CPBS: %s\r\n", buf);
 
        }
        return headset_send(hs, "\r\nOK\r\n");
@@ -1233,19 +1235,20 @@ int telephony_read_phonebook_store_rsp(void *telephony_device, char* pb_store, u
        struct headset *hs = device->headset;
        struct headset_slc *slc = hs->slc;
 
-       if (err != CME_ERROR_NONE){
+       if (err != CME_ERROR_NONE) {
                if (slc->cme_enabled)
                        return headset_send(hs, "\r\n+CME ERROR: %d\r\n", err);
                else
                        return headset_send(hs, "\r\nERROR\r\n");
        }
 
-       if0 != total && 0 != used) {
+       if (0 != total && 0 != used) {
                if (!active_devices)
                        return -ENODEV;
 
                send_foreach_headset(active_devices, hfp_cmp,
-                                       "\r\n+CPBS: \"%s\",%d,%d\r\n",pb_store,used,total);
+                                       "\r\n+CPBS: \"%s\",%d,%d\r\n",
+                                       pb_store, used, total);
        }
        return headset_send(hs, "\r\nOK\r\n");
 }
@@ -1255,7 +1258,7 @@ static int select_phonebook_memory(struct audio_device *device, const char *buf)
        struct headset *hs = device->headset;
        int err;
 
-       ifNULL != buf) {
+       if (NULL != buf) {
                if (strlen(buf) < 9)
                        return -EINVAL;
 
@@ -1265,11 +1268,10 @@ static int select_phonebook_memory(struct audio_device *device, const char *buf)
                }
 
                if (buf[8] == '=') {
-                       if(buf[9] == '?') {
+                       if (buf[9] == '?') {
                                telephony_list_phonebook_store(device);
-                       }
-                       else {
-                               telephony_set_phonebook_store(device,&buf[9]);
+                       } else {
+                               telephony_set_phonebook_store(device, &buf[9]);
                                return headset_send(hs, "\r\nOK\r\n");
                        }
                }
@@ -1278,8 +1280,10 @@ static int select_phonebook_memory(struct audio_device *device, const char *buf)
 }
 
 int telephony_read_phonebook_attributes_rsp(void *telephony_device,
-                                                                               uint32_t total, uint32_t number_length,
-                                                                               uint32_t name_length,cme_error_t err)
+                                               uint32_t total,
+                                               uint32_t number_length,
+                                               uint32_t name_length,
+                                               cme_error_t err)
 {
        struct audio_device *device = telephony_device;
        struct headset *hs = device->headset;
@@ -1292,17 +1296,19 @@ int telephony_read_phonebook_attributes_rsp(void *telephony_device,
                        return headset_send(hs, "\r\nERROR\r\n");
        }
 
-       if( total != 0 && name_length !=0 && number_length != 0 ) {
+       if (total != 0 && name_length != 0 && number_length != 0) {
                if (!active_devices)
                        return -ENODEV;
 
                send_foreach_headset(active_devices, hfp_cmp,
-                                       "\r\n+CPBR: (1-%d),%d,%d\r\n",total,number_length,name_length);
+                                       "\r\n+CPBR: (1-%d),%d,%d\r\n",
+                                       total, number_length, name_length);
        }
        return headset_send(hs, "\r\nOK\r\n");
 }
 
-int telephony_read_phonebook_rsp(void *telephony_device, const char *data, cme_error_t err)
+int telephony_read_phonebook_rsp(void *telephony_device, const char *data,
+                                       cme_error_t err)
 {
        struct audio_device *device = telephony_device;
        struct headset *hs = device->headset;
@@ -1315,12 +1321,12 @@ int telephony_read_phonebook_rsp(void *telephony_device, const char *data, cme_e
                        return headset_send(hs, "\r\nERROR\r\n");
        }
 
-       ifNULL != data) {
+       if (NULL != data) {
                if (!active_devices)
                        return -ENODEV;
 
                send_foreach_headset(active_devices, hfp_cmp,
-                                       "\r\n+CPBR:  %s\r\n",data);
+                                       "\r\n+CPBR:  %s\r\n", data);
        }
 }
 
@@ -1329,23 +1335,23 @@ static int read_phonebook_entries(struct audio_device *device, const char *buf)
        struct headset *hs = device->headset;
        int err;
 
-       ifNULL != buf) {
+       if (NULL != buf) {
                if (strlen(buf) < 8)
                        return -EINVAL;
 
                if (buf[9] == '?') {
                        telephony_read_phonebook_attributes(device);
-               }
-               else {
-                       telephony_read_phonebook(device,&buf[9]);
+               } else {
+                       telephony_read_phonebook(device, &buf[9]);
                }
        }
        return 0;
 }
 
 int telephony_find_phonebook_entry_properties_rsp(void *telephony_device,
-                                                                               uint32_t max_number_length,
-                                                                               uint32_t max_name_length, cme_error_t err )
+                                               uint32_t max_number_length,
+                                               uint32_t max_name_length,
+                                               cme_error_t err)
 {
        struct audio_device *device = telephony_device;
        struct headset *hs = device->headset;
@@ -1358,12 +1364,14 @@ int telephony_find_phonebook_entry_properties_rsp(void *telephony_device,
                        return headset_send(hs, "\r\nERROR\r\n");
        }
 
-       if( max_name_length !=0 && max_number_length != 0 ) {
+       if (max_name_length != 0 && max_number_length != 0) {
                if (!active_devices)
                        return -ENODEV;
 
                send_foreach_headset(active_devices, hfp_cmp,
-                                       "\r\n+CPBF: %d,%d\r\n",max_number_length,max_name_length);
+                                       "\r\n+CPBF: %d,%d\r\n",
+                                       max_number_length,
+                                       max_name_length);
        }
        return headset_send(hs, "\r\nOK\r\n");
 }
@@ -1373,21 +1381,21 @@ static int find_phonebook_entires(struct audio_device *device, const char *buf)
        struct headset *hs = device->headset;
        int err;
 
-       if( NULL != buf )  {
+       if (NULL != buf)  {
                if (strlen(buf) < 8)
                        return -EINVAL;
 
-               if (buf[9] == '?') {
+               if (buf[9] == '?')
                        telephony_find_phonebook_entry_properties(device);
-               }
-               else {
-                       telephony_find_phonebook_entry(device,&buf[9]);
-               }
+               else
+                       telephony_find_phonebook_entry(device, &buf[9]);
        }
        return 0;
 }
 
-int telephony_list_preffered_store_rsp(void *telephony_device, char* prefrd_list, cme_error_t err )
+int telephony_list_preffered_store_rsp(void *telephony_device,
+                                       char *prefrd_list,
+                                       cme_error_t err)
 {
        struct audio_device *device = telephony_device;
        struct headset *hs = device->headset;
@@ -1400,17 +1408,19 @@ int telephony_list_preffered_store_rsp(void *telephony_device, char* prefrd_list
                        return headset_send(hs, "\r\nERROR\r\n");
        }
 
-       if( NULL != prefrd_list ) {
+       if (NULL != prefrd_list) {
                if (!active_devices)
                        return -ENODEV;
 
                send_foreach_headset(active_devices, hfp_cmp,
-                                       "\r\n+CPMS: %s\r\n",prefrd_list);
+                                       "\r\n+CPMS: %s\r\n", prefrd_list);
        }
        return headset_send(hs, "\r\nOK\r\n");
 }
 
-int telephony_get_preffered_store_capacity_rsp(void *telephony_device, uint32_t store_capacity, cme_error_t err )
+int telephony_get_preffered_store_capacity_rsp(void *telephony_device,
+                                               uint32_t store_capacity,
+                                               cme_error_t err)
 {
        struct audio_device *device = telephony_device;
        struct headset *hs = device->headset;
@@ -1423,12 +1433,12 @@ int telephony_get_preffered_store_capacity_rsp(void *telephony_device, uint32_t
                        return headset_send(hs, "\r\nERROR\r\n");
        }
 
-       if( 0 != store_capacity ) {
+       if (0 != store_capacity) {
                if (!active_devices)
                        return -ENODEV;
 
                send_foreach_headset(active_devices, hfp_cmp,
-                                       "\r\n+CPMS: %d\r\n",store_capacity);
+                                       "\r\n+CPMS: %d\r\n", store_capacity);
        }
        return headset_send(hs, "\r\nOK\r\n");
 }
@@ -1438,7 +1448,7 @@ static int preffered_message_storage(struct audio_device *device, const char *bu
        struct headset *hs = device->headset;
        int err;
 
-       if( NULL != buf ) {
+       if (NULL != buf) {
                if (strlen(buf) < 9)
                        return -EINVAL;
 
@@ -1448,11 +1458,10 @@ static int preffered_message_storage(struct audio_device *device, const char *bu
                }
 
                if (buf[8] == '=') {
-                       if(buf[9] == '?') {
+                       if (buf[9] == '?') {
                                telephony_list_preffered_store(device);
-                       }
-                       else {
-                               //telephony_set_preffered_store_capcity(device,&buf[9]);
+                       } else {
+                               /* telephony_set_preffered_store_capcity(device, &buf[9]); */
                                return headset_send(hs, "\r\nOK\r\n");
                        }
                }
@@ -1460,7 +1469,9 @@ static int preffered_message_storage(struct audio_device *device, const char *bu
        return 0;
 }
 
-int telephony_supported_character_generic_rsp(void *telephony_device, char* character_set_list, cme_error_t err )
+int telephony_supported_character_generic_rsp(void *telephony_device,
+                                               char *character_set_list,
+                                               cme_error_t err)
 {
        struct audio_device *device = telephony_device;
        struct headset *hs = device->headset;
@@ -1473,12 +1484,12 @@ int telephony_supported_character_generic_rsp(void *telephony_device, char* char
                        return headset_send(hs, "\r\nERROR\r\n");
        }
 
-       if( NULL != character_set_list ) {
+       if (NULL != character_set_list) {
                if (!active_devices)
                        return -ENODEV;
 
                send_foreach_headset(active_devices, hfp_cmp,
-                                       "\r\n+CPMS: %s\r\n",character_set_list);
+                                       "\r\n+CPMS: %s\r\n", character_set_list);
        }
        return headset_send(hs, "\r\nOK\r\n");
 }
@@ -1487,7 +1498,7 @@ static int select_character_set(struct audio_device *device, const char *buf)
 {
        struct headset *hs = device->headset;
        int err;
-       if( NULL != buf ) {
+       if (NULL != buf) {
                if (strlen(buf) < 9)
                        return -EINVAL;
 
@@ -1497,11 +1508,10 @@ static int select_character_set(struct audio_device *device, const char *buf)
                }
 
                if (buf[8] == '=') {
-                       if(buf[9] == '?') {
+                       if (buf[9] == '?') {
                                telephony_list_supported_character(device);
-                       }
-                       else {
-                               //telephony_set_characterset(device,&buf[9]);
+                       } else {
+                               /* telephony_set_characterset(device, &buf[9]); */
                                return headset_send(hs, "\r\nOK\r\n");
                        }
                }
@@ -1509,6 +1519,8 @@ static int select_character_set(struct audio_device *device, const char *buf)
        return 0;
 
 }
+#endif
+
 static int apple_command(struct audio_device *device, const char *buf)
 {
        DBG("Got Apple command: %s", buf);
@@ -1539,14 +1551,14 @@ static struct event event_callbacks[] = {
        { "AT+BVRA", voice_dial },
        { "AT+XAPL", apple_command },
        { "AT+IPHONEACCEV", apple_command },
-
-       /*TIZEN PATCH Starts here*/
+#ifdef __SAMSUNG_PATCH__
+       /*SAMSUNG PATCH Starts here*/
        { "AT+CPBS", select_phonebook_memory },
        { "AT+CPBR", read_phonebook_entries},
        { "AT+CPBF", find_phonebook_entires },
        { "AT+CPMS", preffered_message_storage },
        { "AT+CSCS", select_character_set },
-
+#endif
        { 0 }
 };
 
@@ -1596,8 +1608,8 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
                return FALSE;
 
        hs = device->headset;
-#ifdef __TIZEN_PATCH__
-       if(!hs)
+#ifdef __SAMSUNG_PATCH__
+       if (!hs)
                return FALSE;
 #endif
        slc = hs->slc;
@@ -1651,15 +1663,8 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
                if (err == -EINVAL) {
                        error("Badly formated or unrecognized command: %s",
                                        &slc->buf[slc->data_start]);
-#ifdef __TIZEN_PATCH__
-                       if (slc->cme_enabled)
-                               err = headset_send(hs, "\r\n+CME ERROR: %d\r\n",
-                                                       CME_ERROR_AG_FAILURE);
-                       else
-                               err = headset_send(hs, "\r\nERROR\r\n");
-#else
-                       err = headset_send(hs, "\r\nERROR\r\n");
-#endif
+                       err = telephony_generic_rsp(device,
+                                               CME_ERROR_NOT_SUPPORTED);
                        if (err < 0)
                                goto failed;
                } else if (err < 0)
@@ -1725,9 +1730,9 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
        else
                hs->auto_dc = FALSE;
 
-#ifdef __TIZEN_PATCH__
+#ifdef __SAMSUNG_PATCH__
        hs->rfcomm_io_id = g_io_add_watch(chan,
-                               G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
+                               G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
                                (GIOFunc) rfcomm_io_cb, dev);
 #else
        g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
@@ -1953,8 +1958,8 @@ static int rfcomm_connect(struct audio_device *dev, headset_stream_cb_t cb,
        DBG("%s: Connecting to %s channel %d", dev->path, address,
                hs->rfcomm_ch);
 
-#ifdef __TIZEN_PATCH__
-       if(hs->rfcomm_io_id) {
+#ifdef __SAMSUNG_PATCH__
+       if (hs->rfcomm_io_id) {
                g_source_remove(hs->rfcomm_io_id);
                hs->rfcomm_io_id = 0;
        }
@@ -2487,8 +2492,8 @@ static int headset_close_rfcomm(struct audio_device *dev)
                hs->rfcomm = NULL;
        }
 
-#ifdef __TIZEN_PATCH__
-       if(hs->rfcomm_io_id) {
+#ifdef __SAMSUNG_PATCH__
+       if (hs->rfcomm_io_id) {
                g_source_remove(hs->rfcomm_io_id);
                hs->rfcomm_io_id = 0;
        }
index 669eeef..02d956b 100644 (file)
@@ -56,19 +56,19 @@ int bt_audio_service_open(void)
 
        sk = socket(PF_LOCAL, SOCK_STREAM, 0);
        if (sk < 0) {
-               err = errno;
+               err = -errno;
                fprintf(stderr, "%s: Cannot open socket: %s (%d)\n",
-                       __FUNCTION__, strerror(err), err);
-               errno = err;
+                       __FUNCTION__, strerror(-err), -err);
+               errno = -err;
                return -1;
        }
 
        if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               err = errno;
+               err = -errno;
                fprintf(stderr, "%s: connect() failed: %s (%d)\n",
-                       __FUNCTION__, strerror(err), err);
+                       __FUNCTION__, strerror(-err), -err);
                close(sk);
-               errno = err;
+               errno = -err;
                return -1;
        }
 
@@ -96,10 +96,10 @@ int bt_audio_service_get_data_fd(int sk)
 
        ret = recvmsg(sk, &msgh, 0);
        if (ret < 0) {
-               err = errno;
+               err = -errno;
                fprintf(stderr, "%s: Unable to receive fd: %s (%d)\n",
-                       __FUNCTION__, strerror(err), err);
-               errno = err;
+                       __FUNCTION__, strerror(-err), -err);
+               errno = -err;
                return -1;
        }
 
index b8ade89..e9187ce 100644 (file)
@@ -53,7 +53,6 @@
 #include "../src/device.h"
 
 #include "log.h"
-#include "textfile.h"
 #include "ipc.h"
 #include "device.h"
 #include "error.h"
@@ -118,8 +117,8 @@ static struct enabled_interfaces enabled = {
        .sink           = TRUE,
        .source         = FALSE,
        .control        = TRUE,
-       .socket         = TRUE,
-       .media          = FALSE,
+       .socket         = FALSE,
+       .media          = TRUE,
 };
 
 static struct audio_adapter *find_adapter(GSList *list,
@@ -779,7 +778,7 @@ static int audio_probe(struct btd_device *device, GSList *uuids)
        struct audio_device *audio_dev;
 
        adapter_get_address(adapter, &src);
-       device_get_address(device, &dst);
+       device_get_address(device, &dst, NULL);
 
        audio_dev = manager_get_device(&src, &dst, TRUE);
        if (!audio_dev) {
@@ -1388,7 +1387,7 @@ gboolean manager_allow_headset_connection(struct audio_device *device)
                if (dev == device)
                        continue;
 
-               if (bacmp(&dev->src, &device->src))
+               if (device && bacmp(&dev->src, &device->src) != 0)
                        continue;
 
                if (!hs)
@@ -1408,6 +1407,11 @@ void manager_set_fast_connectable(gboolean enable)
 {
        GSList *l;
 
+       if (enable && !manager_allow_headset_connection(NULL)) {
+               DBG("Refusing enabling fast connectable");
+               return;
+       }
+
        for (l = adapters; l != NULL; l = l->next) {
                struct audio_adapter *adapter = l->data;
 
index cf157d7..a363b8e 100644 (file)
@@ -4,6 +4,7 @@
  *
  *  Copyright (C) 2006-2007  Nokia Corporation
  *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011  BMW Car IT GmbH. All rights reserved.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -196,7 +197,7 @@ static void headset_setconf_cb(struct media_endpoint *endpoint, void *ret,
        if (ret != NULL)
                return;
 
-       headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
+       headset_shutdown(dev);
 }
 
 static void clear_configuration(struct media_endpoint *endpoint)
@@ -481,12 +482,12 @@ static size_t get_capabilities(struct a2dp_sep *sep, uint8_t **capabilities,
 }
 
 struct a2dp_config_data {
-       guint setup_id;
+       struct a2dp_setup *setup;
        a2dp_endpoint_config_t cb;
 };
 
 struct a2dp_select_data {
-       guint setup_id;
+       struct a2dp_setup *setup;
        a2dp_endpoint_select_t cb;
 };
 
@@ -495,18 +496,18 @@ static void select_cb(struct media_endpoint *endpoint, void *ret, int size,
 {
        struct a2dp_select_data *data = user_data;
 
-       data->cb(endpoint->sep, data->setup_id, ret, size);
+       data->cb(data->setup, ret, size);
 }
 
 static int select_config(struct a2dp_sep *sep, uint8_t *capabilities,
-                               size_t length, guint setup_id,
+                               size_t length, struct a2dp_setup *setup,
                                a2dp_endpoint_select_t cb, void *user_data)
 {
        struct media_endpoint *endpoint = user_data;
        struct a2dp_select_data *data;
 
        data = g_new0(struct a2dp_select_data, 1);
-       data->setup_id = setup_id;
+       data->setup = setup;
        data->cb = cb;
 
        if (select_configuration(endpoint, capabilities, length,
@@ -522,19 +523,20 @@ static void config_cb(struct media_endpoint *endpoint, void *ret, int size,
 {
        struct a2dp_config_data *data = user_data;
 
-       data->cb(endpoint->sep, data->setup_id, ret ? TRUE : FALSE);
+       data->cb(data->setup, ret ? TRUE : FALSE);
 }
 
 static int set_config(struct a2dp_sep *sep, struct audio_device *dev,
                                uint8_t *configuration, size_t length,
-                               guint setup_id, a2dp_endpoint_config_t cb,
+                               struct a2dp_setup *setup,
+                               a2dp_endpoint_config_t cb,
                                void *user_data)
 {
        struct media_endpoint *endpoint = user_data;
        struct a2dp_config_data *data;
 
        data = g_new0(struct a2dp_config_data, 1);
-       data->setup_id = setup_id;
+       data->setup = setup;
        data->cb = cb;
 
        if (set_configuration(endpoint, dev, configuration, length,
@@ -659,7 +661,7 @@ static struct media_endpoint *media_endpoint_create(struct media_adapter *adapte
                        goto failed;
        } else if (strcasecmp(uuid, A2DP_SINK_UUID) == 0) {
                endpoint->sep = a2dp_add_sep(&adapter->src,
-                                       AVDTP_SEP_TYPE_SOURCE, codec,
+                                       AVDTP_SEP_TYPE_SINK, codec,
                                        delay_reporting, &a2dp_endpoint,
                                        endpoint, a2dp_destroy_endpoint, err);
                if (endpoint->sep == NULL)
@@ -1304,6 +1306,7 @@ static gboolean set_status(struct media_player *mp, DBusMessageIter *iter)
 static gboolean set_position(struct media_player *mp, DBusMessageIter *iter)
 {
        uint32_t value;
+       struct metadata_value *duration;
 
        if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
                        return FALSE;
@@ -1317,8 +1320,21 @@ static gboolean set_position(struct media_player *mp, DBusMessageIter *iter)
        if (!mp->position) {
                avrcp_player_event(mp->player,
                                        AVRCP_EVENT_TRACK_REACHED_START, NULL);
+               return TRUE;
        }
 
+       duration = g_hash_table_lookup(mp->track, GUINT_TO_POINTER(
+                                       AVRCP_MEDIA_ATTRIBUTE_DURATION));
+
+       /*
+        * If position is the maximum value allowed or greater than track's
+        * duration, we send a track-reached-end event.
+        */
+       if (mp->position == UINT32_MAX ||
+                       (duration && mp->position >= duration->value.num))
+               avrcp_player_event(mp->player, AVRCP_EVENT_TRACK_REACHED_END,
+                                                                       NULL);
+
        return TRUE;
 }
 
diff --git a/audio/module-bluetooth-sink.c b/audio/module-bluetooth-sink.c
deleted file mode 100644 (file)
index a0117c0..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#if 0
-#include <pulsecore/module.h>
-
-PA_MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>")
-PA_MODULE_DESCRIPTION("Bluetooth sink")
-PA_MODULE_VERSION(VERSION)
-
-int pa__init(pa_core *core, pa_module *module)
-{
-       return 0;
-}
-#endif
index e633d1a..85566a3 100644 (file)
@@ -420,9 +420,10 @@ static int bluetooth_prepare(snd_pcm_ioplug_t *io)
        }
 
        /* wake up any client polling at us */
-       err = write(data->pipefd[1], &c, 1);
-       if (err < 0)
+       if (write(data->pipefd[1], &c, 1) < 0) {
+               err = -errno;
                return err;
+       }
 
        return 0;
 }
@@ -968,7 +969,7 @@ static snd_pcm_sframes_t bluetooth_a2dp_read(snd_pcm_ioplug_t *io,
 
 static int avdtp_write(struct bluetooth_data *data)
 {
-       int ret = 0;
+       int err;
        struct rtp_header *header;
        struct rtp_payload *payload;
        struct bluetooth_a2dp *a2dp = &data->a2dp;
@@ -985,10 +986,10 @@ static int avdtp_write(struct bluetooth_data *data)
        header->timestamp = htonl(a2dp->nsamples);
        header->ssrc = htonl(1);
 
-       ret = send(data->stream.fd, a2dp->buffer, a2dp->count, MSG_DONTWAIT);
-       if (ret < 0) {
-               DBG("send returned %d errno %s.", ret, strerror(errno));
-               ret = -errno;
+       err = send(data->stream.fd, a2dp->buffer, a2dp->count, MSG_DONTWAIT);
+       if (err < 0) {
+               err = -errno;
+               DBG("send failed: %s (%d)", strerror(-err), -err);
        }
 
        /* Reset buffer of data to send */
@@ -997,7 +998,7 @@ static int avdtp_write(struct bluetooth_data *data)
        a2dp->samples = 0;
        a2dp->seq_num++;
 
-       return ret;
+       return err;
 }
 
 static snd_pcm_sframes_t bluetooth_a2dp_write(snd_pcm_ioplug_t *io,
@@ -1546,7 +1547,7 @@ static int audioservice_send(int sk, const bt_audio_msg_header_t *msg)
        else {
                err = -errno;
                SNDERR("Error sending data to audio service: %s(%d)",
-                       strerror(errno), errno);
+                       strerror(-err), -err);
        }
 
        return err;
@@ -1567,7 +1568,7 @@ static int audioservice_recv(int sk, bt_audio_msg_header_t *inmsg)
        if (ret < 0) {
                err = -errno;
                SNDERR("Error receiving IPC data from bluetoothd: %s (%d)",
-                                               strerror(errno), errno);
+                                               strerror(-err), -err);
        } else if ((size_t) ret < sizeof(bt_audio_msg_header_t)) {
                SNDERR("Too short (%d bytes) IPC packet from bluetoothd", ret);
                err = -EINVAL;
@@ -1665,7 +1666,7 @@ static int bluetooth_init(struct bluetooth_data *data,
        data->stream.fd = -1;
 
        sk = bt_audio_service_open();
-       if (sk <= 0) {
+       if (sk < 0) {
                err = -errno;
                goto failed;
        }
index 7b716aa..dd75422 100644 (file)
@@ -38,7 +38,7 @@
 
 #include <bluetooth/sdp.h>
 
-#include "glib-helper.h"
+#include "glib-compat.h"
 #include "log.h"
 #include "telephony.h"
 #include "error.h"
index 26815cf..3607d7f 100644 (file)
@@ -37,7 +37,7 @@
 
 #include <bluetooth/sdp.h>
 
-#include "glib-helper.h"
+#include "glib-compat.h"
 #include "log.h"
 #include "telephony.h"
 
index c5bbc3f..d038d26 100644 (file)
 #define CSD_CALL_INTERFACE     "org.tizen.csd.Call"
 #define CSD_CALL_INSTANCE      "org.tizen.csd.Call.Instance"
 #define CSD_CALL_CONFERENCE    "org.tizen.csd.Call.Conference"
-#define CSD_CALL_PATH          "/org/tizen/csd/call"
+#define CSD_CALL_PATH  "/org/tizen/csd/call"
 #define CSD_CALL_CONFERENCE_PATH "/org/tizen/csd/call/conference"
 #define CSD_CALL_SENDER_PATH   "/org/tizen/csd/call/sender"
 
 /* libcsnet D-Bus definitions */
 #define CSD_CSNET_BUS_NAME     "org.tizen.csd.CSNet"
-#define CSD_CSNET_PATH         "/org/tizen/csd/csnet"
-#define CSD_CSNET_IFACE                "org.tizen.csd.CSNet"
+#define CSD_CSNET_PATH "/org/tizen/csd/csnet"
+#define CSD_CSNET_IFACE        "org.tizen.csd.CSNet"
 #define CSD_CSNET_REGISTRATION "org.tizen.csd.CSNet.NetworkRegistration"
 #define CSD_CSNET_OPERATOR     "org.tizen.csd.CSNet.NetworkOperator"
 #define CSD_CSNET_SIGNAL       "org.tizen.csd.CSNet.SignalStrength"
@@ -58,7 +58,7 @@
 #define CSD_CSNET_SUBSCRIBER   "org.tizen.csd.CSNet.SubscriberNumber"
 
 
-#define CALL_FLAG_NONE                         0
+#define CALL_FLAG_NONE 0
 #define CALL_FLAG_PRESENTATION_ALLOWED         0x01
 #define CALL_FLAG_PRESENTATION_RESTRICTED      0x02
 
@@ -86,7 +86,8 @@
 #define CALL_FLAG_PRESENTATION_RESTRICTED      0x02
 
 
-#define DBUS_STRUCT_STRING_STRING_UINT (dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INVALID))
+#define DBUS_STRUCT_STRING_STRING_UINT (dbus_g_type_get_struct ("GValueArray",\
+                       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INVALID))
 
 #define PHONEBOOK_STORE_LIST "(\"SM\",\"ME\",\"DC\",\"MC\",\"RC\")"
 #define PHONEBOOK_STORE_LIST_BLUENME "(\"ME\",\"DC\",\"MC\",\"RC\")"
 #define PHONEBOOK_PATH_LENGTH 5
 #define PHONEBOOK_NAME_MAX_LENGTH 20
 #define PHONEBOOK_NUMBER_MAX_LENGTH 20
+#define PHONEBOOK_MAX_CHARACTER_LENGTH 20
 
 #define PHONEBOOK_READ_RESP_LENGTH 20
 
-typedef struct
-{
+typedef struct {
        uint8_t utf_8;
        uint8_t gsm;
-}GsmUnicodeTable;
+} GsmUnicodeTable;
 
 
- //0xC3 charcterset
+ /*0xC3 charcterset*/
 const GsmUnicodeTable gsm_unicode_C3[] = {
        {0xA8,0x04},{0xA9,0x05},{0xB9,0x06},{0xAC,0x07},{0xB2,0x08},
        {0xB7,0x09},{0x98,0x0B},{0xB8,0x0C},{0x85,0x0E},{0xA5,0x0F},
@@ -120,15 +121,15 @@ const GsmUnicodeTable gsm_unicode_C3[] = {
        {0xB6,0x7C},{0xB1,0x7D},{0xBC,0x7E},{0xA0,0x7F},
 };
 
-//0xCE charcterset
+/*0xCE charcterset*/
 const GsmUnicodeTable gsm_unicode_CE[] = {
        {0x85,0x14},{0xA1,0x50},{0x98,0x19},{0xA0,0x16},{0x94,0x10},
        {0xA6,0x12},{0x93,0x13},{0x9E,0x1A},{0x9B,0x14},{0xA8,0x17},
        {0xA9,0x15},
 };
 
-#define GSM_UNI_MAX_C3         (sizeof(gsm_unicode_C3)/sizeof(GsmUnicodeTable))
-#define GSM_UNI_MAX_CE         (sizeof(gsm_unicode_CE)/sizeof(GsmUnicodeTable))
+#define GSM_UNI_MAX_C3 (sizeof(gsm_unicode_C3)/sizeof(GsmUnicodeTable))
+#define GSM_UNI_MAX_CE (sizeof(gsm_unicode_CE)/sizeof(GsmUnicodeTable))
 
 
 static DBusConnection *ag_connection = NULL;
@@ -215,7 +216,7 @@ static struct {
 };
 
 /* Supported set of call hold operations */
-//static const char *telephony_chld_str = "0,1,1x,2,2x,3,4";
+/*static const char *telephony_chld_str = "0,1,1x,2,2x,3,4";*/
 static const char *telephony_chld_str = "0,1,2,3";
 
 
@@ -243,7 +244,7 @@ static struct csd_call *find_call(uint32_t call_id)
        for (l = calls; l != NULL; l = l->next) {
                struct csd_call *call = l->data;
 
-               if(call->call_id == call_id)
+               if (call->call_id == call_id)
                        return call;
        }
 
@@ -285,7 +286,7 @@ static struct csd_call *find_call_with_status(int status)
 {
        GSList *l;
 
-       if( NULL != calls ) {
+       if (NULL != calls) {
                for (l = calls; l != NULL; l = l->next) {
                        struct csd_call *call = l->data;
 
@@ -357,17 +358,16 @@ static int reject_call(struct csd_call *call)
                return -ENOMEM;
        }
        DBG(" Object Path =[ %s] and Call id = [%d]\n", call->object_path, call->call_id);
-       if (!dbus_message_append_args(msg,DBUS_TYPE_UINT32,&call->call_id, DBUS_TYPE_INVALID))
-       {
+       if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
+                       DBUS_TYPE_INVALID)) {
 
-               DBG("dbus_message_append_args - ERROR\n");
+               DBG("dbus_message_append_args -ERROR\n");
                dbus_message_unref(msg);
                return -ENOMEM;
        }
 
-       gboolean ret = g_dbus_send_message(ag_connection, msg);
+       g_dbus_send_message(ag_connection, msg);
 
-       DBG(" ret  = [%d]\n", ret);
        DBG("-\n");
 
        return 0;
@@ -388,17 +388,16 @@ static int release_call(struct csd_call *call)
                return -ENOMEM;
        }
        DBG(" Object Path =[ %s] and Call id = [%d]\n", call->object_path, call->call_id);
-       if (!dbus_message_append_args(msg,DBUS_TYPE_UINT32,&call->call_id, DBUS_TYPE_INVALID))
-       {
+       if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
+                       DBUS_TYPE_INVALID)) {
 
-               DBG("dbus_message_append_args - ERROR\n");
+               DBG("dbus_message_append_args -ERROR\n");
                dbus_message_unref(msg);
                return -ENOMEM;
        }
 
-       gboolean ret = g_dbus_send_message(ag_connection, msg);
+       g_dbus_send_message(ag_connection, msg);
 
-       DBG(" ret  = [%d]\n", ret);
        DBG("-\n");
 
        return 0;
@@ -463,10 +462,10 @@ static int answer_call(struct csd_call *call)
                return -ENOMEM;
        }
 
-       if (!dbus_message_append_args(msg,DBUS_TYPE_UINT32,&call->call_id, DBUS_TYPE_INVALID))
-       {
+       if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
+                       DBUS_TYPE_INVALID)) {
 
-               DBG("dbus_message_append_args - ERROR\n");
+               DBG("dbus_message_append_args -ERROR\n");
                dbus_message_unref(msg);
                return -ENOMEM;
        }
@@ -489,9 +488,11 @@ static int number_type(const char *number)
 static void call_set_status(struct csd_call *call, dbus_uint32_t status)
 {
        dbus_uint32_t prev_status;
+       int callheld = 0;
+
        DBG("+\n");
 
-       int callheld = telephony_get_indicator(telephony_ag_indicators, "callheld");
+       callheld = telephony_get_indicator(telephony_ag_indicators, "callheld");
 
        prev_status = call->status;
        DBG("Call %s Call id %d changed from %s to %s", call->object_path, call->call_id,
@@ -591,14 +592,13 @@ static void call_set_status(struct csd_call *call, dbus_uint32_t status)
                if ((prev_status == CSD_CALL_STATUS_MO_ALERTING) ||
                        (prev_status == CSD_CALL_STATUS_COMING) ||
                        (prev_status == CSD_CALL_STATUS_CREATE) ||
-                       (prev_status == CSD_CALL_STATUS_WAITING))
-               {
+                       (prev_status == CSD_CALL_STATUS_WAITING)) {
                                telephony_update_indicator(telephony_ag_indicators,
                                                        "callsetup",
                                                        EV_CALLSETUP_INACTIVE);
                }
 
-               ifprev_status == CSD_CALL_STATUS_COMING) {
+               if (prev_status == CSD_CALL_STATUS_COMING) {
                        if (!call->originating)
                                telephony_calling_stopped_ind();
                }
@@ -660,7 +660,7 @@ static int split_call(struct csd_call *call)
 
        DBG("+n");
 
-       if(NULL != call ) {
+       if (NULL != call) {
                msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
                                                        call->object_path,
                                                        CSD_CALL_INSTANCE,
@@ -721,13 +721,13 @@ static int hold_call(struct csd_call *call)
                error("Unable to allocate new D-Bus message");
                return -ENOMEM;
        }
-       if( NULL != call ) {
+       if (NULL != call) {
                DBG(" Object Path =[ %s] and Call id = [%d]\n", call->object_path, call->call_id);
 
-               if (!dbus_message_append_args(msg,DBUS_TYPE_UINT32,&call->call_id, DBUS_TYPE_INVALID))
-               {
+               if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
+                               DBUS_TYPE_INVALID)) {
 
-                       DBG("dbus_message_append_args - ERROR\n");
+                       DBG("dbus_message_append_args -ERROR\n");
                        dbus_message_unref(msg);
                        return -ENOMEM;
                }
@@ -760,13 +760,13 @@ static int unhold_call(struct csd_call *call)
                return -ENOMEM;
        }
 
-       if( NULL != call ) {
+       if (NULL != call) {
                DBG(" Object Path =[ %s] and Call id = [%d]\n", call->object_path, call->call_id);
 
-               if (!dbus_message_append_args(msg,DBUS_TYPE_UINT32,&call->call_id, DBUS_TYPE_INVALID))
-               {
+               if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
+                               DBUS_TYPE_INVALID)) {
 
-                       DBG("dbus_message_append_args - ERROR\n");
+                       DBG("dbus_message_append_args -ERROR\n");
                        dbus_message_unref(msg);
                        return -ENOMEM;
                }
@@ -857,6 +857,8 @@ void telephony_call_hold_req(void *telephony_device, const char *cmd)
        const char *idx;
        struct csd_call *call;
        int err = 0;
+       int chld_value = 0;
+
        DBG("+\n");
 
        if (strlen(cmd) > 1)
@@ -939,7 +941,7 @@ void telephony_call_hold_req(void *telephony_device, const char *cmd)
                telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
 #else
        idx = &cmd[0];
-       int chld_value = strtol(idx, NULL, 0);
+       chld_value = strtol(idx, NULL, 0);
 
        err = dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
                                        CSD_CALL_INSTANCE, "Threeway",
@@ -982,16 +984,16 @@ static void handle_incoming_call(DBusMessage *msg)
        DBG("Incoming call to %s from number %s call id %d", call_path, number, call_id);
 
        if (find_call_with_status(CSD_CALL_STATUS_ACTIVE) ||
-                       find_call_with_status(CSD_CALL_STATUS_HOLD)){
+                       find_call_with_status(CSD_CALL_STATUS_HOLD)) {
                telephony_call_waiting_ind(call->number,
                                                number_type(call->number));
-               call_set_status(call,CSD_CALL_STATUS_WAITING);
-               }else {
+               call_set_status(call, CSD_CALL_STATUS_WAITING);
+       else {
                telephony_incoming_call_ind(call->number,
                                                number_type(call->number));
 
-               call_set_status(call,CSD_CALL_STATUS_COMING);
-               }
+               call_set_status(call, CSD_CALL_STATUS_COMING);
+       }
        telephony_update_indicator(telephony_ag_indicators, "callsetup",
                                        EV_CALLSETUP_INCOMING);
        DBG("-\n");
@@ -1002,7 +1004,6 @@ static void update_registration_status(uint8_t status)
        uint8_t new_status;
        DBG("+\n");
 
-       //new_status = str2status(status);
        new_status = status;
 
        if (net.status == new_status)
@@ -1051,11 +1052,11 @@ static void update_signal_strength(int32_t signal_bars)
 
        if (signal_bars < 0) {
                DBG("signal strength smaller than expected: %d < 0",
-                                                               signal_bars);
+                               signal_bars);
                signal_bars = 0;
        } else if (signal_bars > 5) {
                DBG("signal strength greater than expected: %d > 5",
-                                                               signal_bars);
+                               signal_bars);
                signal_bars = 5;
        }
 
@@ -1071,8 +1072,11 @@ static void update_signal_strength(int32_t signal_bars)
 
 static void update_battery_strength(int32_t battery_level)
 {
+       int current_battchg = 0;
+
        DBG("+\n");
-       int current_battchg = telephony_get_indicator(telephony_ag_indicators, "battchg");
+
+       current_battchg = telephony_get_indicator(telephony_ag_indicators, "battchg");
 
        if (battery_level < 0) {
                DBG("Battery strength smaller than expected: %d < 0",
@@ -1083,10 +1087,11 @@ static void update_battery_strength(int32_t battery_level)
                                                                battery_level);
                battery_level = 5;
        }
-       ifcurrent_battchg == battery_level)
+       if (current_battchg == battery_level)
                return;
 
-       telephony_update_indicator(telephony_ag_indicators, "battchg", battery_level);
+       telephony_update_indicator(telephony_ag_indicators,
+                       "battchg", battery_level);
 
 
        DBG("-\n");
@@ -1119,7 +1124,7 @@ static void handle_outgoing_call(DBusMessage *msg)
 
        DBG("Outgoing call to %s from number %s call id %d", call_path, number, call_id);
 
-       call_set_status(call,CSD_CALL_STATUS_CREATE);
+       call_set_status(call, CSD_CALL_STATUS_CREATE);
 
        telephony_update_indicator(telephony_ag_indicators, "callsetup",
                                        EV_CALLSETUP_OUTGOING);
@@ -1147,7 +1152,7 @@ static void handle_call_status(DBusMessage *msg, const char *call_path)
                return;
        }
 
-       DBG("status = [%d] and call_id = [%d]\n",status, call_id);
+       DBG("status = [%d] and call_id = [%d]\n", status, call_id);
        call = find_call(call_id);
        if (!call) {
 /*
@@ -1222,10 +1227,9 @@ static void handle_registration_changed(DBusMessage *msg)
 
 static void handle_operator_name_changed(DBusMessage *msg)
 {
-       DBG("+\n");
-
        const char *name;
-       DBG("handle_operator_name_changed()\n");
+
+       DBG("+\n");
 
        if (!dbus_message_get_args(msg, NULL,
                                        DBUS_TYPE_STRING, &name,
@@ -1240,10 +1244,9 @@ static void handle_operator_name_changed(DBusMessage *msg)
 
 static void handle_signal_bars_changed(DBusMessage *msg)
 {
-       DBG("+\n");
-
        int32_t signal_bars;
-       DBG("handle_signal_bars_changed()\n");
+
+       DBG("+\n");
 
        if (!dbus_message_get_args(msg, NULL,
                                        DBUS_TYPE_INT32, &signal_bars,
@@ -1258,10 +1261,9 @@ static void handle_signal_bars_changed(DBusMessage *msg)
 
 static void handle_battery_bars_changed(DBusMessage *msg)
 {
-       DBG("+\n");
-
        int32_t battery_level;
-       DBG("handle_signal_bars_changed()\n");
+
+       DBG("+\n");
 
        if (!dbus_message_get_args(msg, NULL,
                                        DBUS_TYPE_INT32, &battery_level,
@@ -1276,10 +1278,9 @@ static void handle_battery_bars_changed(DBusMessage *msg)
 
 static void handle_subscriber_number_changed(DBusMessage *msg)
 {
-       DBG("+\n");
-
        const char *number;
-       DBG("handle_subscriber_number_changed()\n");
+
+       DBG("+\n");
 
        if (!dbus_message_get_args(msg, NULL,
                                        DBUS_TYPE_STRING, &number,
@@ -1294,9 +1295,11 @@ static void handle_subscriber_number_changed(DBusMessage *msg)
 static gboolean signal_filter(DBusConnection *conn, DBusMessage *msg,
                                                                void *data)
 {
+       const char *path = NULL;
+
        DBG("+\n");
 
-       const char *path = dbus_message_get_path(msg);
+       path = dbus_message_get_path(msg);
 
        if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
                handle_incoming_call(msg);
@@ -1355,7 +1358,6 @@ static const char *telephony_memory_dial_lookup(int location)
 
 int telephony_init(void)
 {
-       //const char *battery_cap = "battery";
        uint32_t features = AG_FEATURE_EC_ANDOR_NR |
                                AG_FEATURE_REJECT_A_CALL |
                                AG_FEATURE_ENHANCED_CALL_STATUS |
@@ -1369,11 +1371,16 @@ int telephony_init(void)
        dbus_add_watch(NULL, CSD_CALL_PATH, CSD_CALL_INTERFACE, NULL);
        dbus_add_watch(NULL, CSD_CALL_PATH, CSD_CALL_INSTANCE, NULL);
        dbus_add_watch(NULL, CSD_CALL_PATH, CSD_CALL_CONFERENCE, NULL);
-       dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_CSNET_REGISTRATION, "RegistrationChanged");
-       dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_CSNET_OPERATOR, "OperatorNameChanged");
-       dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_CSNET_SIGNAL, "SignalBarsChanged");
-       dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_TELEPHONE_BATTERY, "BatteryBarsChanged");
-       dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_CSNET_SUBSCRIBER, "SubscriberNumberChanged");
+       dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_CSNET_REGISTRATION,
+                       "RegistrationChanged");
+       dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_CSNET_OPERATOR,
+                       "OperatorNameChanged");
+       dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_CSNET_SIGNAL,
+                       "SignalBarsChanged");
+       dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_TELEPHONE_BATTERY,
+                       "BatteryBarsChanged");
+       dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_CSNET_SUBSCRIBER,
+                       "SubscriberNumberChanged");
 
        /* Reset indicators */
        for (i = 0; telephony_ag_indicators[i].desc != NULL; i++) {
@@ -1470,23 +1477,9 @@ done:
        dbus_message_unref(reply);
 }
 
-void telephony_last_dial_number_req(void *telephony_device )
-{
-       int ret;
-
-       ret = dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                               CSD_CALL_INTERFACE, "DialLastNo",
-                               telephony_dial_number_reply, telephony_device,
-                               DBUS_TYPE_INVALID);
-       if (ret < 0) {
-               telephony_dial_number_rsp(telephony_device,
-                                               CME_ERROR_AG_FAILURE);
-       }
-}
 void telephony_dial_number_req(void *telephony_device, const char *number)
 {
        uint32_t flags = callerid;
-       int ret;
 
        if (strncmp(number, "*31#", 4) == 0) {
                number += 4;
@@ -1497,25 +1490,23 @@ void telephony_dial_number_req(void *telephony_device, const char *number)
        } else if (number[0] == '>') {
                int location = strtol(&number[1], NULL, 0);
 
-               ret = dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
+               if (0 != dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
                                        CSD_CALL_INTERFACE, "DialMemory",
                                        telephony_dial_number_reply, telephony_device,
                                        DBUS_TYPE_INT32, &location,
-                                       DBUS_TYPE_INVALID);
-               if (ret < 0) {
+                                       DBUS_TYPE_INVALID)) {
                        telephony_dial_number_rsp(telephony_device,
                                                        CME_ERROR_AG_FAILURE);
                }
                return;
        }
 
-       ret = dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
+       if (0 != dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
                                CSD_CALL_INTERFACE, "DialNo",
                                NULL, NULL,
                                DBUS_TYPE_STRING, &number,
                                DBUS_TYPE_UINT32, &flags,
-                               DBUS_TYPE_INVALID);
-       if (ret < 0) {
+                               DBUS_TYPE_INVALID)) {
                telephony_dial_number_rsp(telephony_device,
                                                CME_ERROR_AG_FAILURE);
                return;
@@ -1618,21 +1609,27 @@ void telephony_key_press_req(void *telephony_device, const char *keys)
        else
                telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
 }
+
 void telephony_last_dialed_number_req(void *telephony_device)
 {
-       telephony_last_dial_number_req(telephony_device);
+       if (0 != dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
+                               CSD_CALL_INTERFACE, "DialLastNo",
+                               telephony_dial_number_reply, telephony_device,
+                               DBUS_TYPE_INVALID)) {
+               telephony_dial_number_rsp(telephony_device,
+                                               CME_ERROR_AG_FAILURE);
+       }
 }
+
 void telephony_transmit_dtmf_req(void *telephony_device, char tone)
 {
-       int ret;
        char buf[2] = { tone, '\0' }, *buf_ptr = buf;
 
-       ret = dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
+       if (0 != dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
                                CSD_CALL_INTERFACE, "SendDtmf",
                                NULL, NULL,
                                DBUS_TYPE_STRING, &buf_ptr,
-                               DBUS_TYPE_INVALID);
-       if (ret < 0) {
+                               DBUS_TYPE_INVALID)) {
                telephony_transmit_dtmf_rsp(telephony_device,
                                                CME_ERROR_AG_FAILURE);
                return;
@@ -1746,13 +1743,16 @@ void telephony_subscriber_number_req(void *telephony_device)
 
 void telephony_list_phonebook_store(void *telephony_device)
 {
-       /*
-               For Blue & Me car kit we may have to add  the patch here( similar to the patch done in H1 and H2 )
-       */
-       telephony_list_phonebook_store_rsp(telephony_device, PHONEBOOK_STORE_LIST,CME_ERROR_NONE);
+/*
+       For Blue & Me car kit we may have to add  the
+       patch here(similar to the patch done in H1 and H2 )
+*/
+       telephony_list_phonebook_store_rsp(telephony_device,
+                       PHONEBOOK_STORE_LIST, CME_ERROR_NONE);
 }
 
-static int get_phonebook_count(const char *path, uint32_t *max_size, uint32_t *used)
+static int get_phonebook_count(const char *path, uint32_t *max_size,
+                                                                               uint32_t *used)
 {
        DBusConnection *conn;
        DBusMessageIter iter;
@@ -1772,6 +1772,7 @@ static int get_phonebook_count(const char *path, uint32_t *max_size, uint32_t *u
                                                                                "GetCallLogSize");
        if (!message) {
                DBG("Can't allocate new message");
+               dbus_connection_unref(conn);
                return -1;
        }
        dbus_message_iter_init_append(message, &iter);
@@ -1790,36 +1791,41 @@ static int get_phonebook_count(const char *path, uint32_t *max_size, uint32_t *u
                } else {
                        DBG("Failed to get contacts");
                }
+               dbus_message_unref(message);
+               dbus_connection_unref(conn);
                return -1;
        }
 
        if (!dbus_message_get_args(reply, &error,
                                DBUS_TYPE_UINT32, used,
-                               DBUS_TYPE_INVALID)) 
-       {
-                       DBG("Can't get reply arguments\n");
-                       if (dbus_error_is_set(&error)) {
-                               DBG("%s\n", error.message);
-                               dbus_error_free(&error);
-                       }
-                       return -1;
+                               DBUS_TYPE_INVALID)) {
+               DBG("Can't get reply arguments\n");
+               if (dbus_error_is_set(&error)) {
+                       DBG("%s\n", error.message);
+                       dbus_error_free(&error);
+               }
+               dbus_message_unref(reply);
+               dbus_message_unref(message);
+               dbus_connection_unref(conn);
+               return -1;
        }
 
-       if( (g_strcmp0(path, "SM") == 0 ) ||  (g_strcmp0(path, "ME") == 0)) {
+       if ((g_strcmp0(path, "SM") == 0) || (g_strcmp0(path, "ME") == 0)) {
                *max_size = PHONEBOOK_COUNT_MAX;
-               
-               if*used > PHONEBOOK_COUNT_MAX)
+
+               if (*used > PHONEBOOK_COUNT_MAX)
                        *used = PHONEBOOK_COUNT_MAX;
        }
-       if( (g_strcmp0(path, "DC") == 0) || (g_strcmp0(path, "MC") == 0) ||  (g_strcmp0(path, "RC") == 0) ) {
+       if ((g_strcmp0(path, "DC") == 0) || (g_strcmp0(path, "MC") == 0) ||
+                       (g_strcmp0(path, "RC") == 0)) {
                *max_size = CALL_LOG_COUNT_MAX;
 
-               if*used > CALL_LOG_COUNT_MAX)
+               if (*used > CALL_LOG_COUNT_MAX)
                        *used = CALL_LOG_COUNT_MAX;
        }
-       
-       dbus_message_unref(message);
+
        dbus_message_unref(reply);
+       dbus_message_unref(message);
        dbus_connection_unref(conn);
 
        return 0;
@@ -1827,26 +1833,33 @@ static int get_phonebook_count(const char *path, uint32_t *max_size, uint32_t *u
 
 void telephony_read_phonebook_store(void *telephony_device)
 {
-       if( '\0' != ag_pb_info.path[0] ) {
-               /* Check the phone path ag_pb_info.path[] to which path it was set. If the path is NULL then set to "SM"
-                    and get the max_size and used counts from the phonebook type through dbus call to pbap agent
-               */
-               if(!get_phonebook_count(ag_pb_info.path, &ag_pb_info.max_size, &ag_pb_info.used) ) {
-                                       telephony_read_phonebook_store_rsp(telephony_device, ag_pb_info.path, 
-                                                                                                       ag_pb_info.max_size, ag_pb_info.used,CME_ERROR_NONE);
-               } else {
-                       telephony_read_phonebook_store_rsp(telephony_device, ag_pb_info.path, 
-                                                                                       ag_pb_info.max_size, ag_pb_info.used,CME_ERROR_AG_FAILURE);
-               }
-               
+       if ('\0' != ag_pb_info.path[0]) {
+/*
+       Check the phone path ag_pb_info.path[] to which path it was set.
+       If the path is NULL then set to "SM" and get the max_size and used
+       counts from the phonebook type through dbus call to pbap agent
+*/
+               if (!get_phonebook_count(ag_pb_info.path, &ag_pb_info.max_size,
+                                               &ag_pb_info.used))
+                       telephony_read_phonebook_store_rsp(telephony_device,
+                                       ag_pb_info.path,
+                                       ag_pb_info.max_size,
+                                       ag_pb_info.used,
+                                       CME_ERROR_NONE);
+               else
+                       telephony_read_phonebook_store_rsp(telephony_device,
+                                       ag_pb_info.path,
+                                       ag_pb_info.max_size,
+                                       ag_pb_info.used,
+                                       CME_ERROR_AG_FAILURE);
        }
 }
 
 void telephony_set_phonebook_store(void *telephony_device, const char *path)
 {
-       if ( NULL != path ) {
-               DBG("set phonebook type to [%s]\n",path);
-               strncpy(ag_pb_info.path, path, 4 );
+       if (NULL != path) {
+               DBG("set phonebook type to [%s]\n", path);
+               g_strlcpy(ag_pb_info.path, path, sizeof(ag_pb_info.path));
        }
 }
 
@@ -1854,14 +1867,16 @@ void telephony_read_phonebook_attributes(void *telephony_device)
 {
        uint32_t total_count = 0;
        uint32_t used_count = 0;
-       
-       if( '\0' != ag_pb_info.path[0] ) {
-               /* Check the phone path ag_pb_info.path[] to which path it was set. If the path is NULL then set to "SM"
-                    and get the max_size and used counts from the phonebook type through dbus call to pbap agent
-               */
-               telephony_read_phonebook_attributes_rsp(telephony_device, 
-                                                                                               ag_pb_info.max_size,    PHONEBOOK_NUMBER_MAX_LENGTH,
-                                                                                               PHONEBOOK_NAME_MAX_LENGTH, CME_ERROR_NONE);
+
+       if ('\0' != ag_pb_info.path[0]) {
+/*
+       Check the phone path ag_pb_info.path[] to which path it was set.
+       If the path is NULL then set to "SM" and get the max_size and used
+       counts from the phonebook type through dbus call to pbap agent
+*/
+               telephony_read_phonebook_attributes_rsp(telephony_device,
+                       ag_pb_info.max_size,    PHONEBOOK_NUMBER_MAX_LENGTH,
+                       PHONEBOOK_NAME_MAX_LENGTH, CME_ERROR_NONE);
        }
 }
 
@@ -1869,23 +1884,16 @@ static int convert_utf8_gsm(uint8_t ascii, uint8_t utf_8, uint8_t *gsm)
 {
        uint32_t i = 0;
 
-       if( ascii == 0xC3 )
-       {
-               for(i =0; i< GSM_UNI_MAX_C3 ; i++ )
-               {
-                       if( gsm_unicode_C3[i].utf_8 == utf_8 )
-                       {
+       if (ascii == 0xC3) {
+               for (i = 0; i < GSM_UNI_MAX_C3 ; i++) {
+                       if (gsm_unicode_C3[i].utf_8 == utf_8) {
                                *gsm = gsm_unicode_C3[i].gsm;
                                return 0;
                        }
                }
-       }
-       else if (ascii == 0xCE)
-       {
-               for(i =0; i< GSM_UNI_MAX_CE ; i++ )
-               {
-                       if( gsm_unicode_CE[i].utf_8 == utf_8 )
-                       {
+       } else if (ascii == 0xCE) {
+               for (i = 0; i < GSM_UNI_MAX_CE ; i++) {
+                       if (gsm_unicode_CE[i].utf_8 == utf_8) {
                                *gsm = gsm_unicode_CE[i].gsm;
                                return 0;
                        }
@@ -1893,78 +1901,80 @@ static int convert_utf8_gsm(uint8_t ascii, uint8_t utf_8, uint8_t *gsm)
        }
 }
 
-static void get_unicode_string( const char *name, char *unicodename)
+static void get_unicode_string(const char *name, char *unicodename)
 {
-       if( NULL != name || NULL!= unicodename)
-       {
-               uint32_t len = strlen(name);
-               if(len > 0 ) {
+       if (NULL != name || NULL != unicodename) {
+               int len = strlen(name);
+               if (len > 0) {
                        int x = 0;
-                       int y =0;
-                       if( len > 20 )
-                               len = 20;
-                       for( x =0, y = 0 ; x < len ; x++, y++ ) {
-                               if(x < (len-1)){
-                                       if( convert_utf8_gsm(name[x],name[x+1] , (uint8_t *)&unicodename[y]) )
-                                       {
+                       int y = 0;
+                       if (len > PHONEBOOK_MAX_CHARACTER_LENGTH)
+                               len = PHONEBOOK_MAX_CHARACTER_LENGTH;
+                       for (x = 0, y = 0 ; x < len ; x++, y++) {
+                               if (x < (len - 1)) {
+                                       if (convert_utf8_gsm(name[x], name[x+1] ,
+                                               (uint8_t *)&unicodename[y])) {
                                                x++;
                                                continue;
                                        }
                                }
-                                       
-                               if( name[x] == '_' )
-                               {
+
+                               if (name[x] == '_') {
                                         unicodename[y] = ' ';
                                         continue;
                                }
 
-                               unicodename[y] = name[x];                       
+                               unicodename[y] = name[x];
                        }
                }
        }
-       return; 
+       return;
 }
 
-static int send_read_phonebook_resp(void *telephony_device, int32_t index, const char *name, const char *number )
+static int send_read_phonebook_resp(void *telephony_device, int32_t index,
+                                       const char *name, const char *number)
 {
        gchar *msg = NULL;
        int ret = -1;
 
-       msg =  g_new0(gchar, PHONEBOOK_NAME_MAX_LENGTH + PHONEBOOK_NUMBER_MAX_LENGTH + PHONEBOOK_READ_RESP_LENGTH + 3);
+       msg =  g_new0(gchar, PHONEBOOK_NAME_MAX_LENGTH +
+                               PHONEBOOK_NUMBER_MAX_LENGTH + PHONEBOOK_READ_RESP_LENGTH + 3);
 
-       if( NULL != msg )
-       {
-               char nm[PHONEBOOK_NAME_MAX_LENGTH +1] = {0,};
-               char nb[PHONEBOOK_NAME_MAX_LENGTH +1] = {0,};
+       if (NULL != msg) {
+               char nm[PHONEBOOK_NAME_MAX_LENGTH + 1] = {0,};
+               char nb[PHONEBOOK_NAME_MAX_LENGTH + 1] = {0,};
 
-               get_unicode_string(name,nm);
-               get_unicode_string(number,nb);
+               get_unicode_string(name, nm);
+               get_unicode_string(number, nb);
 
-               snprintf(msg, PHONEBOOK_NAME_MAX_LENGTH + PHONEBOOK_NUMBER_MAX_LENGTH + PHONEBOOK_READ_RESP_LENGTH + 3,
-                               "%d,\"%s\",0,\"%s\"",index, nb,nm);
+               snprintf(msg, PHONEBOOK_NAME_MAX_LENGTH +
+                       PHONEBOOK_NUMBER_MAX_LENGTH + PHONEBOOK_READ_RESP_LENGTH + 3,
+                       "%d,\"%s\",0,\"%s\"", index, nb, nm);
 
-               ret = telephony_read_phonebook_rsp(telephony_device,msg,CME_ERROR_NONE);
+               ret = telephony_read_phonebook_rsp(telephony_device, msg,
+                               CME_ERROR_NONE);
 
                g_free(msg);
        }
        return ret;
 }
 
-static int get_phonebook_list(void *telephony_device, const char* path, int32_t start_index, int32_t end_index )
+static int get_phonebook_list(void *telephony_device, const char* path,
+                                       int32_t start_index, int32_t end_index)
 {
        DBusConnection *conn;
        DBusMessage *message, *reply;
        DBusError error;
        DBusMessageIter iter, iter_struct, entry;
-       int32_t idx =0;
-       if( (start_index > ag_pb_info.max_size) || (start_index <=0) || (start_index > PHONEBOOK_COUNT_MAX) ) {
+       int32_t idx = 0;
+       if ((start_index > (int) ag_pb_info.max_size) || (start_index <= 0) ||
+                       (start_index > PHONEBOOK_COUNT_MAX)) {
                return -1;
        }
 
-       if(end_index > ag_pb_info.max_size )
+       if (end_index > (int) ag_pb_info.max_size)
                end_index = PHONEBOOK_COUNT_MAX ;
 
-
        conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
        if (!conn) {
                DBG("Can't get on system bus");
@@ -1972,9 +1982,9 @@ static int get_phonebook_list(void *telephony_device, const char* path, int32_t
        }
 
        message = dbus_message_new_method_call("org.bluez.pb_agent",
-                                                                               "/org/bluez/pb_agent",
-                                                                               "org.bluez.PbAgent",
-                                                                               "GetPhonebookList");
+                                               "/org/bluez/pb_agent",
+                                               "org.bluez.PbAgent",
+                                               "GetPhonebookList");
        if (!message) {
                DBG("Can't allocate new message");
                return -1;
@@ -1999,11 +2009,12 @@ static int get_phonebook_list(void *telephony_device, const char* path, int32_t
 
        idx = start_index;
        while (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_STRUCT) {
-                               dbus_message_iter_recurse(&iter_struct, &entry);
                const char *name = NULL;
                const char *tel = NULL;
                uint32_t handle = 0;
-               
+
+               dbus_message_iter_recurse(&iter_struct, &entry);
+
                dbus_message_iter_get_basic(&entry, &name);
                dbus_message_iter_next(&entry);
                dbus_message_iter_get_basic(&entry, &tel);
@@ -2013,18 +2024,17 @@ static int get_phonebook_list(void *telephony_device, const char* path, int32_t
                DBG("[%d] handle:%d name:%s tel:%s]\n", handle, name, tel);
 
                /*form the packet and sent to the remote headset*/
-               if( -1 == end_index ) {
-                       if(send_read_phonebook_resp(telephony_device, start_index, name, tel ) )
+               if (-1 == end_index) {
+                       if (send_read_phonebook_resp(telephony_device,
+                                       start_index, name, tel))
                                DBG("send_read_phonebook_resp - ERROR\n");
                        break;
-               }
-               else
-               {
-                       if( idx >= start_index || idx <= end_index )
-                       {
-                               if(send_read_phonebook_resp(telephony_device, idx, name, tel ) ) {
+               } else {
+                       if (idx >= start_index || idx <= end_index) {
+                               if (send_read_phonebook_resp(telephony_device, idx, name, tel)) {
                                        DBG("send_read_phonebook_resp - ERROR\n");
-                                       telephony_read_phonebook_rsp(telephony_device,NULL, CME_ERROR_AG_FAILURE);
+                                       telephony_read_phonebook_rsp(telephony_device, NULL,
+                                                       CME_ERROR_AG_FAILURE);
 
                                        dbus_message_unref(message);
                                        dbus_message_unref(reply);
@@ -2038,7 +2048,7 @@ static int get_phonebook_list(void *telephony_device, const char* path, int32_t
                dbus_message_iter_next(&iter_struct);
        }
 
-       telephony_read_phonebook_rsp(telephony_device,NULL, CME_ERROR_NONE);
+       telephony_read_phonebook_rsp(telephony_device, NULL, CME_ERROR_NONE);
 
        dbus_message_unref(message);
        dbus_message_unref(reply);
@@ -2048,19 +2058,21 @@ static int get_phonebook_list(void *telephony_device, const char* path, int32_t
        return 0;
 }
 
-static int get_call_log_list(void *telephony_device, char* path , int32_t start_index, int32_t end_index )
+static int get_call_log_list(void *telephony_device, char* path ,
+                       int32_t start_index, int32_t end_index)
 {
        DBusConnection *conn;
        DBusMessage *message = NULL, *reply;
        DBusError error;
        DBusMessageIter iter, iter_struct, entry;
-       int32_t idx =0;
+       int32_t idx = 0;
 
-       if( (start_index > ag_pb_info.max_size) || (start_index <=0) || (start_index > CALL_LOG_COUNT_MAX) ) {
+       if ((start_index > (int) ag_pb_info.max_size) || (start_index <= 0) ||
+                       (start_index > CALL_LOG_COUNT_MAX)) {
                return -1;
        }
 
-       if(end_index > ag_pb_info.max_size )
+       if (end_index > (int) ag_pb_info.max_size)
                end_index = CALL_LOG_COUNT_MAX ;
 
 
@@ -2070,21 +2082,21 @@ static int get_call_log_list(void *telephony_device, char* path , int32_t start_
                return -1;
        }
 
-       ifg_strcmp0(ag_pb_info.path, "DC") == 0) {
+       if (g_strcmp0(ag_pb_info.path, "DC") == 0) {
                message = dbus_message_new_method_call("org.bluez.pb_agent",
-                                                                                       "/org/bluez/pb_agent",
-                                                                                       "org.bluez.PbAgent",
-                                                                                       "GetOutgoingCallsList");
-       }else if(g_strcmp0(ag_pb_info.path, "MC") == 0) {
+                                                       "/org/bluez/pb_agent",
+                                                       "org.bluez.PbAgent",
+                                                       "GetOutgoingCallsList");
+       } else if (g_strcmp0(ag_pb_info.path, "MC") == 0) {
                message = dbus_message_new_method_call("org.bluez.pb_agent",
-                                                                                       "/org/bluez/pb_agent",
-                                                                                       "org.bluez.PbAgent",
-                                                                                       "GetMissedCallsList");
-       }else if(g_strcmp0(ag_pb_info.path, "RC") == 0) {
+                                                       "/org/bluez/pb_agent",
+                                                       "org.bluez.PbAgent",
+                                                       "GetMissedCallsList");
+       } else if (g_strcmp0(ag_pb_info.path, "RC") == 0) {
                message = dbus_message_new_method_call("org.bluez.pb_agent",
-                                                                                       "/org/bluez/pb_agent",
-                                                                                       "org.bluez.PbAgent",
-                                                                                       "GetIncomingCallsList");
+                                                       "/org/bluez/pb_agent",
+                                                       "org.bluez.PbAgent",
+                                                       "GetIncomingCallsList");
        }
        if (!message) {
                DBG("Can't allocate new message");
@@ -2113,11 +2125,12 @@ static int get_call_log_list(void *telephony_device, char* path , int32_t start_
 
        idx = start_index;
        while (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_STRUCT) {
-                               dbus_message_iter_recurse(&iter_struct, &entry);
                const char *name = NULL;
                const char *tel = NULL;
                uint32_t handle = 0;
 
+               dbus_message_iter_recurse(&iter_struct, &entry);
+
                dbus_message_iter_get_basic(&entry, &name);
                dbus_message_iter_next(&entry);
                dbus_message_iter_get_basic(&entry, &tel);
@@ -2127,19 +2140,18 @@ static int get_call_log_list(void *telephony_device, char* path , int32_t start_
                DBG("[%d] handle:%d name:%s tel:%s]\n", handle, name, tel);
 
                /*form the packet and sent to the remote headset*/
-               if( -1 == end_index ) {
-                       if(send_read_phonebook_resp(telephony_device, start_index, name, tel ) )
+               if (-1 == end_index) {
+                       if (send_read_phonebook_resp(telephony_device,
+                                       start_index, name, tel))
                                DBG("send_read_phonebook_resp - ERROR\n");
                        break;
-               }
-               else
-               {
-                       if( idx >= start_index || idx <= end_index )
-                       {
+               } else {
+                       if (idx >= start_index || idx <= end_index) {
                                /* Need to form the time stamp pkt  also */
-                               if(send_read_phonebook_resp(telephony_device, idx, name, tel ) ) {
+                               if (send_read_phonebook_resp(telephony_device, idx, name, tel)) {
                                        DBG("send_read_phonebook_resp - ERROR\n");
-                                       telephony_read_phonebook_rsp(telephony_device,NULL, CME_ERROR_AG_FAILURE);
+                                       telephony_read_phonebook_rsp(telephony_device, NULL,
+                                                       CME_ERROR_AG_FAILURE);
 
                                        dbus_message_unref(message);
                                        dbus_message_unref(reply);
@@ -2153,7 +2165,7 @@ static int get_call_log_list(void *telephony_device, char* path , int32_t start_
                dbus_message_iter_next(&iter_struct);
        }
 
-       telephony_read_phonebook_rsp(telephony_device,NULL, CME_ERROR_NONE);
+       telephony_read_phonebook_rsp(telephony_device, NULL, CME_ERROR_NONE);
 
        dbus_message_unref(message);
        dbus_message_unref(reply);
@@ -2167,70 +2179,78 @@ void telephony_read_phonebook(void *telephony_device, const char *cmd)
 {
        char *ptr = 0;
 
-       if( NULL != cmd ) {
+       if (NULL != cmd) {
                int32_t start_index;
                int32_t end_index;
-               ptr = (char*) strchr(cmd,(int32_t)',');
-               if( NULL == ptr ) {
+               ptr = (char *) strchr(cmd, (int32_t)',');
+               if (NULL == ptr) {
                        start_index = strtol(cmd, NULL, 0);
                        end_index = -1;
-                       DBG("telephony_read_phonebook:start_index = [%d] \n", start_index);
+                       DBG("start_index = [%d] \n", start_index);
                } else {
                        ptr++;
                        start_index = strtol(cmd, NULL, 0);
                        end_index = strtol(ptr, NULL, 0);
-                       DBG("telephony_read_phonebook:start_index = [%d], end_index = [%d] \n", start_index,end_index);
+                       DBG("start_index = [%d], end_index = [%d] \n",
+                                       start_index, end_index);
                }
 
-               if( (g_strcmp0(ag_pb_info.path, "SM") == 0 ) ||  (g_strcmp0(ag_pb_info.path, "ME") == 0 )) {
-                       if( get_phonebook_list(telephony_device, ag_pb_info.path, start_index, end_index) ) {
-                               telephony_read_phonebook_rsp(telephony_device,NULL,CME_ERROR_AG_FAILURE);
+               if ((g_strcmp0(ag_pb_info.path, "SM") == 0) ||
+                               (g_strcmp0(ag_pb_info.path, "ME") == 0)) {
+                       if (get_phonebook_list(telephony_device, ag_pb_info.path,
+                                       start_index, end_index)) {
+                               telephony_read_phonebook_rsp(telephony_device, NULL,
+                                       CME_ERROR_AG_FAILURE);
                                return;
                        }
                }
-               if( (g_strcmp0(ag_pb_info.path, "DC") == 0 ) || (g_strcmp0(ag_pb_info.path, "MC") == 0 ) ||
-                                                                                                       (g_strcmp0(ag_pb_info.path, "RC") == 0) ) {
-                       if(get_call_log_list(telephony_device,ag_pb_info.path, start_index, end_index) ) {
-                               telephony_read_phonebook_rsp(telephony_device,NULL,CME_ERROR_AG_FAILURE);
+               if ((g_strcmp0(ag_pb_info.path, "DC") == 0) ||
+                               (g_strcmp0(ag_pb_info.path, "MC") == 0) ||
+                               (g_strcmp0(ag_pb_info.path, "RC") == 0)) {
+                       if (get_call_log_list(telephony_device, ag_pb_info.path,
+                                       start_index, end_index)) {
+                               telephony_read_phonebook_rsp(telephony_device, NULL,
+                                               CME_ERROR_AG_FAILURE);
                                return;
                        }
                }
-               
-               /*
-               Using the start and end index get the contact list from the pbap agent and send the data 
-               to remote headset.
-               */
+
+/*
+       Using the start and end index get the contact list from the pbap agent and
+       send the data to remote headset.
+*/
        }
  }
 
 void telephony_find_phonebook_entry_properties(void *telephony_device)
 {
-       telephony_find_phonebook_entry_properties_rsp( telephony_device, 
-                                                                                       20,
-                                                                                       128,
-                                                                                       CME_ERROR_NONE );
+       telephony_find_phonebook_entry_properties_rsp(telephony_device,
+                       PHONEBOOK_NUMBER_MAX_LENGTH,
+                       PHONEBOOK_NAME_MAX_LENGTH,
+                       CME_ERROR_NONE);
 
 }
 
 void telephony_find_phonebook_entry(void *telephony_device, const char *cmd)
 {
-       /* Get the contact that matches with the string "cmd" and send it back to the remote headset
-       Need a dbus API to pbap agent that does the above operation
-       */
+/*
+       Get the contact that matches with the string "cmd" and send it back to the
+       remote headset Need a dbus API to pbap agent that does the above operation
+*/
 
 }
 void telephony_get_preffered_store_capacity(void *telephony_device)
 {
-       telephony_get_preffered_store_capacity_rsp( telephony_device, 
-                                                                                               PREFFERED_MESSAGE_STORAGE_MAX,
-                                                                                               CME_ERROR_NONE );
+       telephony_get_preffered_store_capacity_rsp(telephony_device,
+                       PREFFERED_MESSAGE_STORAGE_MAX,
+                       CME_ERROR_NONE);
 }
 
 void telephony_list_preffered_store(void *telephony_device)
 {
-       telephony_list_preffered_store_rsp( telephony_device, 
-                                                                               PREFFERED_MESSAGE_STORAGE_LIST,
-                                                                               CME_ERROR_NONE );
+       telephony_list_preffered_store_rsp(telephony_device,
+                       PREFFERED_MESSAGE_STORAGE_LIST,
+                       CME_ERROR_NONE);
 }
 
 /*
@@ -2240,17 +2260,17 @@ void telephony_set_preffered_store_capcity(void *telephony_device, const char *c
 */
 void telephony_get_character_set(void *telephony_device)
 {
-       telephony_supported_character_generic_rsp( telephony_device, 
-                                                                               PHONEBOOK_CHARACTER_SET_SUPPORTED,
-                                                                               CME_ERROR_NONE );
+       telephony_supported_character_generic_rsp(telephony_device,
+                       PHONEBOOK_CHARACTER_SET_SUPPORTED,
+                       CME_ERROR_NONE);
 
 }
 
 void telephony_list_supported_character(void *telephony_device)
 {
-       telephony_supported_character_generic_rsp( telephony_device, 
-                                                                               PHONEBOOK_CHARACTER_SET_LIST,
-                                                                               CME_ERROR_NONE );
+       telephony_supported_character_generic_rsp(telephony_device,
+                       PHONEBOOK_CHARACTER_SET_LIST,
+                       CME_ERROR_NONE);
 }
 
 /*
@@ -2258,4 +2278,3 @@ void telephony_set_characterset(void *telephony_device, const char *cmd)
 {
 }
 */
-
index 2739199..7bde32d 100644 (file)
@@ -670,6 +670,7 @@ static DBusMessage *acquire(DBusConnection *conn, DBusMessage *msg,
        owner = media_owner_create(conn, msg, accesstype);
        id = transport->resume(transport, owner);
        if (id == 0) {
+               media_transport_release(transport, accesstype);
                media_owner_free(owner);
                return btd_error_not_authorized(msg);
        }
index c2d6d4a..5199831 100644 (file)
@@ -52,7 +52,7 @@
 #include "source.h"
 #include "gateway.h"
 #include "unix.h"
-#include "glib-helper.h"
+#include "glib-compat.h"
 
 #define check_nul(str) (str[sizeof(str) - 1] == '\0')
 
@@ -1864,25 +1864,28 @@ int unix_init(void)
 
        sk = socket(PF_LOCAL, SOCK_STREAM, 0);
        if (sk < 0) {
-               err = errno;
-               error("Can't create unix socket: %s (%d)", strerror(err), err);
-               return -err;
+               err = -errno;
+               error("Can't create unix socket: %s (%d)", strerror(-err),
+                                                                       -err);
+               return err;
        }
 
        if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               error("Can't bind unix socket: %s (%d)", strerror(errno),
-                               errno);
+               err = -errno;
+               error("Can't bind unix socket: %s (%d)", strerror(-err),
+                                                                       -err);
                close(sk);
-               return -1;
+               return err;
        }
 
        set_nonblocking(sk);
 
        if (listen(sk, 1) < 0) {
-               error("Can't listen on unix socket: %s (%d)",
-                                               strerror(errno), errno);
+               err = -errno;
+               error("Can't listen on unix socket: %s (%d)", strerror(-err),
+                                                                       -err);
                close(sk);
-               return -1;
+               return err;
        }
 
        unix_sock = sk;
index 2cc9082..0d177a3 100644 (file)
@@ -64,6 +64,7 @@ struct set_opts {
        int master;
        uint8_t mode;
        int flushable;
+       uint32_t priority;
 };
 
 struct connect {
@@ -152,16 +153,18 @@ static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
                return FALSE;
 
        if (cond & G_IO_OUT) {
-               int err = 0, sock = g_io_channel_unix_get_fd(io);
-               socklen_t len = sizeof(err);
+               int err, sk_err = 0, sock = g_io_channel_unix_get_fd(io);
+               socklen_t len = sizeof(sk_err);
 
-               if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) < 0)
-                       err = errno;
+               if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+                       err = -errno;
+               else
+                       err = -sk_err;
 
-               if (err)
+               if (err < 0)
                        g_set_error(&gerr, BT_IO_ERROR,
                                        BT_IO_ERROR_CONNECT_FAILED, "%s (%d)",
-                                       strerror(err), err);
+                                       strerror(-err), -err);
        } else if (cond & (G_IO_HUP | G_IO_ERR))
                g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
                                "HUP or ERR on socket");
@@ -502,9 +505,17 @@ static int l2cap_set_flushable(int sock, gboolean flushable)
        return 0;
 }
 
+static int set_priority(int sock, uint32_t prio)
+{
+       if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)) < 0)
+               return -errno;
+
+       return 0;
+}
+
 static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu,
                                uint16_t omtu, uint8_t mode, int master,
-                               int flushable, GError **err)
+                               int flushable, uint32_t priority, GError **err)
 {
        if (imtu || omtu || mode) {
                struct l2cap_options l2o;
@@ -542,6 +553,11 @@ static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu,
                return FALSE;
        }
 
+       if (priority > 0 && set_priority(sock, priority) < 0) {
+               ERROR_FAILED(err, "set_priority", errno);
+               return FALSE;
+       }
+
        if (sec_level && !set_sec_level(sock, BT_IO_L2CAP, sec_level, err))
                return FALSE;
 
@@ -669,6 +685,7 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
        opts->sec_level = BT_IO_SEC_MEDIUM;
        opts->mode = L2CAP_MODE_BASIC;
        opts->flushable = -1;
+       opts->priority = 0;
 
        while (opt != BT_IO_OPT_INVALID) {
                switch (opt) {
@@ -727,6 +744,9 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
                case BT_IO_OPT_FLUSHABLE:
                        opts->flushable = va_arg(args, gboolean);
                        break;
+               case BT_IO_OPT_PRIORITY:
+                       opts->priority = va_arg(args, int);
+                       break;
                default:
                        g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
                                        "Unknown option %d", opt);
@@ -797,6 +817,17 @@ static int l2cap_get_flushable(int sock, gboolean *flushable)
        return 0;
 }
 
+static int get_priority(int sock, uint32_t *prio)
+{
+       socklen_t len;
+
+       len = sizeof(*prio);
+       if (getsockopt(sock, SOL_SOCKET, SO_PRIORITY, prio, &len) < 0)
+               return -errno;
+
+       return 0;
+}
+
 static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
                                                                va_list args)
 {
@@ -808,6 +839,7 @@ static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
        uint16_t handle;
        socklen_t len;
        gboolean flushable = FALSE;
+       uint32_t priority;
 
        len = sizeof(l2o);
        memset(&l2o, 0, len);
@@ -850,11 +882,11 @@ static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
                        break;
                case BT_IO_OPT_PSM:
                        *(va_arg(args, uint16_t *)) = src.l2_psm ?
-                                               src.l2_psm : dst.l2_psm;
+                                       btohs(src.l2_psm) : btohs(dst.l2_psm);
                        break;
                case BT_IO_OPT_CID:
                        *(va_arg(args, uint16_t *)) = src.l2_cid ?
-                                               src.l2_cid : dst.l2_cid;
+                                       btohs(src.l2_cid) : btohs(dst.l2_cid);
                        break;
                case BT_IO_OPT_OMTU:
                        *(va_arg(args, uint16_t *)) = l2o.omtu;
@@ -897,6 +929,13 @@ static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
                        }
                        *(va_arg(args, gboolean *)) = flushable;
                        break;
+               case BT_IO_OPT_PRIORITY:
+                       if (get_priority(sock, &priority) < 0) {
+                               ERROR_FAILED(err, "get_priority", errno);
+                               return FALSE;
+                       }
+                       *(va_arg(args, uint32_t *)) = priority;
+                       break;
                default:
                        g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
                                        "Unknown option %d", opt);
@@ -1172,7 +1211,8 @@ gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
        case BT_IO_L2RAW:
        case BT_IO_L2CAP:
                return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu,
-                               opts.mode, opts.master, opts.flushable, err);
+                               opts.mode, opts.master, opts.flushable,
+                               opts.priority, err);
        case BT_IO_RFCOMM:
                return rfcomm_set(sock, opts.sec_level, opts.master, err);
        case BT_IO_SCO:
@@ -1213,7 +1253,7 @@ static GIOChannel *create_io(BtIOType type, gboolean server,
                if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0,
                                                        opts->cid, err) < 0)
                        goto failed;
-               if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, -1, err))
+               if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, -1, 0, err))
                        goto failed;
                break;
        case BT_IO_L2CAP:
@@ -1226,7 +1266,8 @@ static GIOChannel *create_io(BtIOType type, gboolean server,
                                                        opts->cid, err) < 0)
                        goto failed;
                if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu,
-                               opts->mode, opts->master, opts->flushable, err))
+                               opts->mode, opts->master, opts->flushable,
+                               opts->priority, err))
                        goto failed;
                break;
        case BT_IO_RFCOMM:
index c6b736f..ae55b61 100644 (file)
@@ -65,6 +65,7 @@ typedef enum {
        BT_IO_OPT_CLASS,
        BT_IO_OPT_MODE,
        BT_IO_OPT_FLUSHABLE,
+       BT_IO_OPT_PRIORITY,
 } BtIOOption;
 
 typedef enum {
index 59f036f..de98830 100644 (file)
@@ -104,7 +104,7 @@ static int uses_rfcomm(char *path, char *dev)
 
        while ((de = readdir(dir)) != NULL) {
                char link[PATH_MAX + 1];
-               int  len = readlink(de->d_name, link, sizeof(link));
+               int  len = readlink(de->d_name, link, PATH_MAX);
                if (len > 0) {
                        link[len] = 0;
                        if (strstr(link, dev)) {
index b996d10..66161b3 100644 (file)
@@ -60,20 +60,19 @@ static void sig_term(int sig)
        __io_canceled = 1;
 }
 
-static void send_event(int fd, uint16_t type, uint16_t code, int32_t value)
+static int send_event(int fd, uint16_t type, uint16_t code, int32_t value)
 {
        struct uinput_event event;
-       int len;
 
        if (fd <= fileno(stderr))
-               return;
+               return -EINVAL;
 
        memset(&event, 0, sizeof(event));
        event.type = type;
        event.code = code;
        event.value = value;
 
-       len = write(fd, &event, sizeof(event));
+       return write(fd, &event, sizeof(event));
 }
 
 static int uinput_create(char *name, int keyboard, int mouse)
@@ -125,9 +124,10 @@ static int uinput_create(char *name, int keyboard, int mouse)
 
                for (aux = KEY_RESERVED; aux <= KEY_UNKNOWN; aux++)
                        ioctl(fd, UI_SET_KEYBIT, aux);
-
-               //for (aux = LED_NUML; aux <= LED_MISC; aux++)
-               //      ioctl(fd, UI_SET_LEDBIT, aux);
+               /*
+                *for (aux = LED_NUML; aux <= LED_MISC; aux++)
+                *      ioctl(fd, UI_SET_LEDBIT, aux);
+                */
        }
 
        if (mouse) {
diff --git a/compat/fakehid.txt b/compat/fakehid.txt
new file mode 100644 (file)
index 0000000..000d0ee
--- /dev/null
@@ -0,0 +1,134 @@
+EPox Presenter
+==============
+
+# hcitool inq
+Inquiring ...
+        00:04:61:aa:bb:cc       clock offset: 0x1ded    class: 0x004000
+
+# hcitool info 00:04:61:aa:bb:cc
+Requesting information ...
+        BD Address:  00:04:61:aa:bb:cc
+        OUI Company: EPOX Computer Co., Ltd. (00-04-61)
+        Device Name: EPox BT-PM01B aabbcc
+        LMP Version: 1.1 (0x1) LMP Subversion: 0xf78
+        Manufacturer: Cambridge Silicon Radio (10)
+        Features: 0xff 0xff 0x0f 0x00 0x00 0x00 0x00 0x00
+                <3-slot packets> <5-slot packets> <encryption> <slot offset> 
+                <timing accuracy> <role switch> <hold mode> <sniff mode> 
+                <park state> <RSSI> <channel quality> <SCO link> <HV2 packets> 
+                <HV3 packets> <u-law log> <A-law log> <CVSD> <paging scheme> 
+                <power control> <transparent SCO> 
+
+# sdptool records --raw 00:04:61:aa:bb:cc
+Sequence
+        Attribute 0x0000 - ServiceRecordHandle
+                UINT32 0x00010000
+        Attribute 0x0001 - ServiceClassIDList
+                Sequence
+                        UUID16 0x1101 - SerialPort
+        Attribute 0x0004 - ProtocolDescriptorList
+                Sequence
+                        Sequence
+                                UUID16 0x0100 - L2CAP
+                        Sequence
+                                UUID16 0x0003 - RFCOMM
+                                UINT8 0x01
+        Attribute 0x0100
+                String Cable Replacement
+
+
+J-Three Keyboard
+================
+
+# hcitool inq
+Inquiring ...
+        00:0A:3A:aa:bb:cc       clock offset: 0x3039    class: 0x001f00
+
+# hcitool info 00:0A:3A:aa:bb:cc
+Password:
+Requesting information ...
+        BD Address:  00:0A:3A:aa:bb:cc
+        OUI Company: J-THREE INTERNATIONAL Holding Co., Ltd. (00-0A-3A)
+        Device Name: KEYBOARD
+        LMP Version: 1.1 (0x1) LMP Subversion: 0x2c2
+        Manufacturer: Cambridge Silicon Radio (10)
+        Features: 0xbc 0x06 0x07 0x00 0x00 0x00 0x00 0x00
+                <encryption> <slot offset> <timing accuracy> <role switch> 
+                <sniff mode> <RSSI> <channel quality> <CVSD> <paging scheme> 
+                <power control> 
+
+# sdptool records --raw 00:0A:3A:aa:bb:cc
+Sequence
+        Attribute 0x0000 - ServiceRecordHandle
+                UINT32 0x00010000
+        Attribute 0x0001 - ServiceClassIDList
+                Sequence
+                        UUID16 0x1101 - SerialPort
+        Attribute 0x0004 - ProtocolDescriptorList
+                Sequence
+                        Sequence
+                                UUID16 0x0100 - L2CAP
+                        Sequence
+                                UUID16 0x0003 - RFCOMM
+                                UINT8 0x01
+        Attribute 0x0006 - LanguageBaseAttributeIDList
+                Sequence
+                        UINT16 0x656e
+                        UINT16 0x006a
+                        UINT16 0x0100
+        Attribute 0x0100
+                String SPP slave
+
+
+Celluon Laserkey Keyboard
+=========================
+
+# hcitool inq
+Inquiring ...
+       00:0B:24:aa:bb:cc       clock offset: 0x3ab6    class: 0x400210
+
+# hcitool info 00:0B:24:aa:bb:cc
+Requesting information ...
+       BD Address:  00:0B:24:aa:bb:cc
+       OUI Company: AirLogic (00-0B-24)
+       Device Name: CL800BT
+       LMP Version: 1.1 (0x1) LMP Subversion: 0x291
+       Manufacturer: Cambridge Silicon Radio (10)
+       Features: 0xff 0xff 0x0f 0x00 0x00 0x00 0x00 0x00
+               <3-slot packets> <5-slot packets> <encryption> <slot offset>
+               <timing accuracy> <role switch> <hold mode> <sniff mode>
+               <park state> <RSSI> <channel quality> <SCO link> <HV2 packets>
+               <HV3 packets> <u-law log> <A-law log> <CVSD> <paging scheme>
+               <power control> <transparent SCO>
+
+# sdptool records --raw 00:0B:24:aa:bb:cc
+Sequence
+         Attribute 0x0000 - ServiceRecordHandle
+                 UINT32 0x00010000
+         Attribute 0x0001 - ServiceClassIDList
+                 Sequence
+                         UUID16 0x1101 - SerialPort
+         Attribute 0x0004 - ProtocolDescriptorList
+                 Sequence
+                         Sequence
+                                 UUID16 0x0100 - L2CAP
+                         Sequence
+                                 UUID16 0x0003 - RFCOMM
+                                 UINT8 0x01
+         Attribute 0x0100
+                 String Serial Port
+
+Packet format is as follows (all fields little-endian):
+     0 uint16  magic            # 0x5a5a
+     2 uint32  unknown          # ???
+     6 uint8   action           # 0 = keyup, 1 = keydown, 2 = repeat
+                                # 3, 4, 5, 6 = ??? (Mouse mode)
+     7 uint8   unknown[9]       # ???
+    16 uint8   action2          # ??? same as action
+    17 uint16  x                # Horizontal coordinate
+    19 uint16  y                # Vertical coordinate
+    21 uint16  time             # Some sort of timestamp
+    23 uint8   unknown[5]       # ???
+    28 uint8   key[]            # single byte keycode or 0xff byte
+                                # follwed by special keycode byte.
+    Each packet followed by a checksum byte.
index 88944cf..fd1b28c 100644 (file)
@@ -237,16 +237,6 @@ static int request_encryption(bdaddr_t *src, bdaddr_t *dst)
        return err;
 }
 
-static void enable_sixaxis(int csk)
-{
-       const unsigned char buf[] = {
-               0x53 /*HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE*/,
-               0xf4,  0x42, 0x03, 0x00, 0x00 };
-       int err;
-
-       err = write(csk, buf, sizeof(buf));
-}
-
 static int create_device(int ctl, int csk, int isk, uint8_t subclass, int nosdp, int nocheck, int bootonly, int encrypt, int timeout)
 {
        struct hidp_connadd_req req;
@@ -335,14 +325,10 @@ create:
                req.flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
        }
 
-       if (req.vendor == 0x054c && req.product == 0x0268)
-               enable_sixaxis(csk);
-
        err = ioctl(ctl, HIDPCONNADD, &req);
 
 error:
-       if (req.rd_data)
-               free(req.rd_data);
+       free(req.rd_data);
 
        return err;
 }
index fe2f88c..5b81f28 100644 (file)
@@ -1,7 +1,7 @@
 AC_PREREQ(2.60)
-AC_INIT(bluez, 4.90)
+AC_INIT(bluez, 4.98)
 
-AM_INIT_AUTOMAKE([foreign subdir-objects])
+AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
 AM_CONFIG_HEADER(config.h)
 
 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
@@ -35,14 +35,20 @@ AC_FUNC_PPOLL
 AC_CHECK_LIB(dl, dlopen, dummy=yes,
                        AC_MSG_ERROR(dynamic linking loader is required))
 
+AC_CHECK_HEADER([sys/inotify.h],
+               [AC_DEFINE([HAVE_SYS_INOTIFY_H], 1,
+                       [Define to 1 if you have <sys/inotify.h>.])],
+                       [AC_MSG_ERROR(inotify headers are required and missing)])
 AC_PATH_DBUS
 AC_PATH_GLIB
 AC_PATH_ALSA
 AC_PATH_GSTREAMER
 AC_PATH_USB
+AC_PATH_UDEV
 AC_PATH_SNDFILE
 AC_PATH_OUI
 AC_PATH_READLINE
+AC_PATH_CHECK
 
 AC_ARG_BLUEZ
 
@@ -56,5 +62,14 @@ if (test "${enable_capng}" = "yes"); then
        AC_DEFINE(HAVE_CAPNG, 1, [Define to 1 if you have capabilities library.])
 fi
 
+AC_ARG_WITH([systemdunitdir], AC_HELP_STRING([--with-systemdunitdir=DIR],
+       [path to systemd system service directory]), [path_systemdunit=${withval}],
+               [path_systemdunit="`$PKG_CONFIG --variable=systemdsystemunitdir systemd`"])
+if (test -n "${path_systemdunit}"); then
+       SYSTEMD_UNITDIR="${path_systemdunit}"
+       AC_SUBST(SYSTEMD_UNITDIR)
+fi
+AM_CONDITIONAL(SYSTEMD, test -n "${path_systemdunit}")
+
 AC_OUTPUT(Makefile scripts/bluetooth.rules doc/version.xml
-                                       src/bluetoothd.8 bluez.pc)
+                       src/bluetoothd.8 src/bluetooth.service bluez.pc)
index 7aafcdc..a93dda0 100644 (file)
@@ -94,8 +94,13 @@ static int hcrp_credit_grant(int sk, uint16_t tid, uint32_t credit)
        memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
        memcpy(buf + HCRP_PDU_HDR_SIZE, &cp, HCRP_CREDIT_GRANT_CP_SIZE);
        len = write(sk, buf, HCRP_PDU_HDR_SIZE + HCRP_CREDIT_GRANT_CP_SIZE);
+       if (len < 0)
+               return len;
 
        len = read(sk, buf, sizeof(buf));
+       if (len < 0)
+               return len;
+
        memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
        memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_GRANT_RP_SIZE);
 
@@ -119,8 +124,13 @@ static int hcrp_credit_request(int sk, uint16_t tid, uint32_t *credit)
        hdr.plen = htons(0);
        memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
        len = write(sk, buf, HCRP_PDU_HDR_SIZE);
+       if (len < 0)
+               return len;
 
        len = read(sk, buf, sizeof(buf));
+       if (len < 0)
+               return len;
+
        memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
        memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_REQUEST_RP_SIZE);
 
@@ -147,8 +157,13 @@ static int hcrp_get_lpt_status(int sk, uint16_t tid, uint8_t *lpt_status)
        hdr.plen = htons(0);
        memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
        len = write(sk, buf, HCRP_PDU_HDR_SIZE);
+       if (len < 0)
+               return len;
 
        len = read(sk, buf, sizeof(buf));
+       if (len < 0)
+               return len;
+
        memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
        memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_GET_LPT_STATUS_RP_SIZE);
 
index fcec51c..f82e14e 100644 (file)
@@ -1,3 +1,11 @@
+bluez (4.98-slp2+1-1) unstable; urgency=low
+
+  * Merge with lastest private git
+  * Git: pkgs/b/bluez
+  * Tag: bluez_4.98-slp2+1-1
+
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Thu, 09 Feb 2012 14:31:53 +0900
+
 bluez (4.90-slp2+18-2) unstable; urgency=low
 
   * Change "SAMSUNG_PATCH" -> "TIZEN_PATCH"
index cd49ab0..99d9cc4 100755 (executable)
@@ -37,7 +37,7 @@ config.status: configure
        dh_testdir
 
        # Add here commands to configure the package.
-       CFLAGS="$(CFLAGS) -D__TIZEN_PATCH__ $(BT_CHIP_CFLAGS)" \
+       CFLAGS="$(CFLAGS) -D__SAMSUNG_PATCH__ $(BT_CHIP_CFLAGS)" \
        LDFLAGS="$(LDFLAGS) -Wl,--warn-unresolved-symbols" \
        ./configure     --prefix=$(PREFIX) \
                        --sysconfdir=$(PREFIX)/etc \
@@ -58,6 +58,7 @@ config.status: configure
                        --disable-test \
                        --enable-health \
                        --disable-udevrules \
+                       --enable-dbusoob \
                        --with-telephony=tizen
 
 build: build-stamp
index 67fe9d0..20cef03 100644 (file)
@@ -31,15 +31,25 @@ Methods             dict GetProperties()
 
                void RequestSession()
 
-                       This method will request a client session that
-                       provides operational Bluetooth. A possible mode
-                       change must be confirmed by the user via the agent.
+                       This method requests a client session that provides
+                       operational Bluetooth. A possible mode change must be
+                       confirmed by the user via the agent.
+
+                       Clients may request multiple sessions. All sessions
+                       are released when adapter's mode is changed to off
+                       state.
 
                        Possible Errors: org.bluez.Error.Rejected
 
                void ReleaseSession()
 
-                       Release a previous requested session.
+                       Release a previously requested session. It sets
+                       adapter to the mode in use on the moment of session
+                       request.
+
+                       SetProperty method call changes adapter's mode
+                       persistently, such that session release will not
+                       modify it.
 
                        Possible Errors: org.bluez.Error.DoesNotExist
 
@@ -218,7 +228,7 @@ Properties  string Address [readonly]
                boolean Powered [readwrite]
 
                        Switch an adapter on or off. This will also set the
-                       appropiate connectable state.
+                       appropriate connectable state.
 
                boolean Discoverable [readwrite]
 
@@ -238,14 +248,6 @@ Properties string Address [readonly]
                        this property will be updated via a PropertyChanged
                        signal.
 
-               # __TIZEN_PATCH__
-               boolean Limited [readwrite]
-
-                       Switch an adapter to limited discoverable or non-limited. This is
-                       a global setting and should only be used by the
-                       settings application.
-               # __TIZEN_PATCH__
-
                boolean Pairable [readwrite]
 
                        Switch an adapter to pairable or non-pairable. This is
@@ -255,7 +257,7 @@ Properties  string Address [readonly]
                        Note that this property only affects incoming pairing
                        requests.
 
-               uint32 PaireableTimeout [readwrite]
+               uint32 PairableTimeout [readwrite]
 
                        The pairable timeout in seconds. A value of zero
                        means that the timeout is disabled and it will stay in
index d8d35c0..9ab2063 100644 (file)
@@ -57,6 +57,10 @@ Methods              void Release()
                        During the pairing process this method might be
                        called multiple times to update the entered value.
 
+                       Note that the passkey will always be a 6-digit number,
+                       so the display should be zero-padded at the start if
+                       the value contains less than 6 digits.
+
                void RequestConfirmation(object device, uint32 passkey)
 
                        This method gets called when the service daemon
@@ -65,6 +69,10 @@ Methods              void Release()
                        To confirm the value it should return an empty reply
                        or an error in case the passkey is invalid.
 
+                       Note that the passkey will always be a 6-digit number,
+                       so the display should be zero-padded at the start if
+                       the value contains less than 6 digits.
+
                        Possible errors: org.bluez.Error.Rejected
                                         org.bluez.Error.Canceled
 
index f2778f3..98d7f30 100644 (file)
@@ -12,7 +12,7 @@ or service from attribute database.
 
 Local services are children of the adapter object path. Remote services
 are children of the remote device object path. This doesn't solve the
-problem where local atttributes can have different instances based on
+problem where local attributes can have different instances based on
 the remote device.
 
 In general the idea is to also represent SDP records as services so that
diff --git a/doc/bluez-docs.xml b/doc/bluez-docs.xml
new file mode 100644 (file)
index 0000000..74a8bd1
--- /dev/null
@@ -0,0 +1,97 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+               "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+<!ENTITY version SYSTEM "version.xml">
+]>
+<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
+  <bookinfo>
+    <title>BlueZ Reference Manual</title>
+    <releaseinfo>Version &version;</releaseinfo>
+    <authorgroup>
+      <author>
+       <firstname>Marcel</firstname>
+       <surname>Holtmann</surname>
+       <affiliation>
+         <address>
+           <email>marcel@holtmann.org</email>
+         </address>
+       </affiliation>
+      </author>
+    </authorgroup>
+
+    <copyright>
+      <year>2002-2008</year>
+      <holder>Marcel Holtmann</holder>
+    </copyright>
+
+    <legalnotice>
+      <para>
+       Permission is granted to copy, distribute and/or modify this
+       document under the terms of the <citetitle>GNU Free
+       Documentation License</citetitle>, Version 1.1 or any later
+       version published by the Free Software Foundation with no
+       Invariant Sections, no Front-Cover Texts, and no Back-Cover
+       Texts. You may obtain a copy of the <citetitle>GNU Free
+       Documentation License</citetitle> from the Free Software
+       Foundation by visiting <ulink type="http"
+       url="http://www.fsf.org">their Web site</ulink> or by writing
+       to:
+
+       <address>
+         The Free Software Foundation, Inc.,
+         <street>59 Temple Place</street> - Suite 330,
+         <city>Boston</city>, <state>MA</state> <postcode>02111-1307</postcode>,
+         <country>USA</country>
+       </address>
+      </para>
+    </legalnotice>
+  </bookinfo>
+
+  <reference id="manager">
+    <title>Manager interface</title>
+    <para>
+<programlisting><xi:include href="manager-api.txt" parse="text" /></programlisting>
+    </para>
+  </reference>
+
+  <reference id="adapter">
+    <title>Adapter interface</title>
+    <para>
+<programlisting><xi:include href="adapter-api.txt" parse="text" /></programlisting>
+    </para>
+  </reference>
+
+  <reference id="device">
+    <title>Device interface</title>
+    <para>
+<programlisting><xi:include href="device-api.txt" parse="text" /></programlisting>
+    </para>
+  </reference>
+
+  <reference id="agent">
+    <title>Agent interface</title>
+    <para>
+<programlisting><xi:include href="agent-api.txt" parse="text" /></programlisting>
+    </para>
+  </reference>
+
+  <reference id="reference">
+    <title>API Reference</title>
+    <partintro>
+      <para>
+       This part presents the function reference for BlueZ.
+      </para>
+    </partintro>
+  </reference>
+
+  <appendix id="license">
+    <title>License</title>
+    <para>
+<programlisting><xi:include href="../COPYING" parse="text" /></programlisting>
+    </para>
+  </appendix>
+
+  <index>
+    <title>Index</title>
+  </index>
+</book>
index 60bcc29..e8fc314 100644 (file)
@@ -22,17 +22,6 @@ Methods              dict GetProperties()
                        Possible Errors: org.bluez.Error.DoesNotExist
                                         org.bluez.Error.InvalidArguments
 
-               # __TIZEN_PATCH__
-               dict GetVersionProperties()
-
-                       Returns all version properties for the device.
-                       See the version properties section for available
-                       properties.
-
-                       Possible Errors: org.bluez.Error.DoesNotExist
-                                        org.bluez.Error.InvalidArguments
-               # __TIZEN_PATCH__
-
                void SetProperty(string name, variant value)
 
                        Changes the value of the specified property. Only
@@ -136,6 +125,18 @@ Properties string Address [readonly]
                        The Bluetooth remote name. This value can not be
                        changed. Use the Alias property instead.
 
+               uint16 Vendor [readonly]
+
+                       Vendor unique numeric identifier.
+
+               uint16 Product [readonly]
+
+                       Product unique numeric identifier.
+
+               uint16 Version [readonly]
+
+                       Version unique numeric identifier.
+
                string Icon [readonly]
 
                        Proposed icon name according to the freedesktop.org
@@ -158,13 +159,6 @@ Properties string Address [readonly]
 
                        Indicates if the remote device is paired.
 
-               # __TIZEN_PATCH__
-               uint32 PinLength [readonly]
-
-                       he PIN code length that was used in the pairing
-                       process.
-               # __TIZEN_PATCH__
-
                boolean Connected [readonly]
 
                        Indicates if the remote device is currently connected.
@@ -215,52 +209,3 @@ Properties string Address [readonly]
                        Note that this property can exhibit false-positives
                        in the case of Bluetooth 2.1 (or newer) devices that
                        have disabled Extended Inquiry Response support.
-
-               # __TIZEN_PATCH__
-VersionProperties      string Address [readonly]
-
-                       The Bluetooth device address of the remote device.
-
-               string Name [readonly]
-
-                       The Bluetooth remote name. This value can not be
-                       changed. Use the Alias property instead.
-
-               string Icon [readonly]
-
-                       Proposed icon name according to the freedesktop.org
-                       icon naming specification.
-
-               uint32 Class [readonly]
-
-                       The Bluetooth class of device of the remote device.
-
-               string Company [readonly]
-
-                       the company name from the OUI database of the
-                       Bluetooth device address. This function will need a
-                       valid and up-to-date oui.txt from the IEEE. This value
-                       will be different from the manufacturer string in the
-                       most cases.
-
-               string Manufacturer [readonly]
-
-                       the manufacturer of the chip for a remote device.
-
-               string Revision [readonly]
-
-                       the revision of the Bluetooth chip. This is a
-                       vendor specific value and in most cases it represents
-                       the firmware version. This derives only from the LMP
-                       subversion value.
-
-               string Version [readonly]
-
-                       the version info for a remote device. The base for this
-                       string is the LMP version value and the features for
-                       EDR support.
-                       Not available can be received if the remote device was
-                       not contacted(connected) previously. Remote data is
-                       automatically retrieved in the first connection.
-
-               # __TIZEN_PATCH__
diff --git a/doc/gtk-doc.make b/doc/gtk-doc.make
new file mode 100644 (file)
index 0000000..354ffb7
--- /dev/null
@@ -0,0 +1,173 @@
+# -*- mode: makefile -*-
+
+####################################
+# Everything below here is generic #
+####################################
+
+if GTK_DOC_USE_LIBTOOL
+GTKDOC_CC = $(LIBTOOL) --mode=compile $(CC) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+GTKDOC_LD = $(LIBTOOL) --mode=link $(CC) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS)
+else
+GTKDOC_CC = $(CC) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+GTKDOC_LD = $(CC) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS)
+endif
+
+# We set GPATH here; this gives us semantics for GNU make
+# which are more like other make's VPATH, when it comes to
+# whether a source that is a target of one rule is then
+# searched for in VPATH/GPATH.
+#
+GPATH = $(srcdir)
+
+TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE)
+
+EXTRA_DIST =                           \
+       $(content_files)                \
+       $(HTML_IMAGES)                  \
+       $(DOC_MAIN_SGML_FILE)           \
+       $(DOC_MODULE)-sections.txt      \
+       $(DOC_MODULE)-overrides.txt
+
+DOC_STAMPS=scan-build.stamp tmpl-build.stamp sgml-build.stamp html-build.stamp \
+          $(srcdir)/tmpl.stamp $(srcdir)/sgml.stamp $(srcdir)/html.stamp
+
+SCANOBJ_FILES =                 \
+       $(DOC_MODULE).args       \
+       $(DOC_MODULE).hierarchy  \
+       $(DOC_MODULE).interfaces \
+       $(DOC_MODULE).prerequisites \
+       $(DOC_MODULE).signals
+
+REPORT_FILES = \
+       $(DOC_MODULE)-undocumented.txt \
+       $(DOC_MODULE)-undeclared.txt \
+       $(DOC_MODULE)-unused.txt
+
+CLEANFILES = $(SCANOBJ_FILES) $(REPORT_FILES) $(DOC_STAMPS)
+
+if ENABLE_GTK_DOC
+all-local: html-build.stamp
+else
+all-local:
+endif
+
+docs: html-build.stamp
+
+#### scan ####
+
+scan-build.stamp: $(HFILE_GLOB) $(CFILE_GLOB)
+       @echo 'gtk-doc: Scanning header files'
+       @-chmod -R u+w $(srcdir)
+       cd $(srcdir) && \
+         gtkdoc-scan --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --ignore-headers="$(IGNORE_HFILES)" $(SCAN_OPTIONS) $(EXTRA_HFILES)
+       if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null 2>&1 ; then \
+           CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" CFLAGS="$(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" gtkdoc-scangobj $(SCANGOBJ_OPTIONS) --module=$(DOC_MODULE) --output-dir=$(srcdir) ; \
+       else \
+           cd $(srcdir) ; \
+           for i in $(SCANOBJ_FILES) ; do \
+               test -f $$i || touch $$i ; \
+           done \
+       fi
+       touch scan-build.stamp
+
+$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt: scan-build.stamp
+       @true
+
+#### templates ####
+
+tmpl-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt
+       @echo 'gtk-doc: Rebuilding template files'
+       @-chmod -R u+w $(srcdir)
+       cd $(srcdir) && gtkdoc-mktmpl --module=$(DOC_MODULE) $(MKTMPL_OPTIONS)
+       touch tmpl-build.stamp
+
+tmpl.stamp: tmpl-build.stamp
+       @true
+
+tmpl/*.sgml:
+       @true
+
+
+#### xml ####
+
+sgml-build.stamp: tmpl.stamp $(HFILE_GLOB) $(CFILE_GLOB) $(DOC_MODULE)-sections.txt $(srcdir)/tmpl/*.sgml $(expand_content_files)
+       @echo 'gtk-doc: Building XML'
+       @-chmod -R u+w $(srcdir)
+       cd $(srcdir) && \
+       gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --output-format=xml --expand-content-files="$(expand_content_files)" --main-sgml-file=$(DOC_MAIN_SGML_FILE) $(MKDB_OPTIONS)
+       touch sgml-build.stamp
+
+sgml.stamp: sgml-build.stamp
+       @true
+
+#### html ####
+
+html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files)
+       @echo 'gtk-doc: Building HTML'
+       @-chmod -R u+w $(srcdir)
+       rm -rf $(srcdir)/html
+       mkdir $(srcdir)/html
+       cd $(srcdir)/html && gtkdoc-mkhtml $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE)
+       test "x$(HTML_IMAGES)" = "x" || ( cd $(srcdir) && cp $(HTML_IMAGES) html )
+       @echo 'gtk-doc: Fixing cross-references'
+       cd $(srcdir) && gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS)
+       touch html-build.stamp
+
+##############
+
+clean-local:
+       rm -f *~ *.bak
+       rm -rf .libs
+
+distclean-local:
+       cd $(srcdir) && \
+         rm -rf xml $(REPORT_FILES) \
+                $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt
+
+maintainer-clean-local: clean
+       cd $(srcdir) && rm -rf xml html
+
+install-data-local:
+       -installfiles=`echo $(srcdir)/html/*`; \
+       if test "$$installfiles" = '$(srcdir)/html/*'; \
+       then echo '-- Nothing to install' ; \
+       else \
+         $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR); \
+         for i in $$installfiles; do \
+           echo '-- Installing '$$i ; \
+           $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \
+         done; \
+         echo '-- Installing $(srcdir)/html/index.sgml' ; \
+         $(INSTALL_DATA) $(srcdir)/html/index.sgml $(DESTDIR)$(TARGET_DIR) || :; \
+         which gtkdoc-rebase >/dev/null && \
+           gtkdoc-rebase --relative --dest-dir=$(DESTDIR) --html-dir=$(DESTDIR)$(TARGET_DIR) ; \
+       fi
+       
+
+uninstall-local:
+       rm -f $(DESTDIR)$(TARGET_DIR)/*
+
+#
+# Require gtk-doc when making dist
+#
+if ENABLE_GTK_DOC
+dist-check-gtkdoc:
+else
+dist-check-gtkdoc:
+       @echo "*** gtk-doc must be installed and enabled in order to make dist"
+       @false
+endif
+
+dist-hook: dist-check-gtkdoc dist-hook-local
+       mkdir $(distdir)/tmpl
+       mkdir $(distdir)/xml
+       mkdir $(distdir)/html
+       -cp $(srcdir)/tmpl/*.sgml $(distdir)/tmpl
+       -cp $(srcdir)/xml/*.xml $(distdir)/xml
+       cp $(srcdir)/html/* $(distdir)/html
+       -cp $(srcdir)/$(DOC_MODULE).types $(distdir)/
+       -cp $(srcdir)/$(DOC_MODULE)-sections.txt $(distdir)/
+       cd $(distdir) && rm -f $(DISTCLEANFILES)
+       -gtkdoc-rebase --online --relative --html-dir=$(distdir)/html
+
+.PHONY : dist-hook-local docs
index 690f373..c53ab7b 100644 (file)
@@ -213,7 +213,14 @@ Properties string Equalizer [readwrite]
 
                uint32 Position [readonly]
 
-                       Playback position in milliseconds
+                       Playback position in milliseconds. Changing the
+                       position may generate additional events that will be
+                       sent to the remote device. When position is 0 it means
+                       the track is starting and when it's greater than or
+                       equal to track's duration the track has ended. Note
+                       that even if duration is not available in metadata it's
+                       possible to signal its end by setting position to the
+                       maximum uint32 value.
 
 MediaEndpoint hierarchy
 =======================
diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
new file mode 100644 (file)
index 0000000..c8305d9
--- /dev/null
@@ -0,0 +1,769 @@
+Bluetooth Management API
+*************************
+
+Copyright (C) 2008-2009  Marcel Holtmann <marcel@holtmann.org>
+
+
+Packet Structures
+=================
+
+       Commands:
+
+       0    4    8   12   16   22   24   28   31   35   39   43   47
+       +-------------------+-------------------+-------------------+
+       |  Command Code     |  Controller Index |  Parameter Length |
+       +-------------------+-------------------+-------------------+
+       |                                                           |
+
+       Events:
+
+       0    4    8   12   16   22   24   28   31   35   39   43   47
+       +-------------------+-------------------+-------------------+
+       |  Event Code       |  Controller Index |  Parameter Length |
+       +-------------------+-------------------+-------------------+
+       |                                                           |
+
+Controller Index can have a special value <non-controller> to indicate that
+command or event is not related to any controller. Possible values:
+
+       <controller id>         0x0000 to 0xFFFE
+       <non-controller>        0xFFFF
+
+
+Read Management Version Information Command
+===========================================
+
+       Command Code:           0x0001
+       Controller Index:       <non-controller>
+       Command Parameters:
+       Return Parameters:      Version (1 Octets)
+                               Revision (2 Octets)
+
+
+Read Management Supported Features Command
+==========================================
+
+       Command Code:           0x0002
+       Controller Index:       <non-controller>
+       Command Parameters:
+       Return Parameters:      Features (8 Octets)
+
+               Feature Bit 0:  Controller Support
+               Feature Bit 1:  Tracing Support
+
+
+Read Controller Index List Command
+==================================
+
+       Command Code:           0x0003
+       Controller Index:       <non-controller>
+       Command Parameters:
+       Return Parameters:      Num_Controllers (2 Octets)
+                               Controller_Index[i] (2 Octets)
+
+
+Read Controller Information Command
+===================================
+
+       Command Code:           0x0004
+       Controller Index:       <controller id>
+       Command Parameters:
+       Return Parameters:      Address (6 Octets)
+                               Bluetooth_Version (1 Octet)
+                               Manufacturer (2 Octets)
+                               Supported_Settings (4 Octets)
+                               Current_Settings (4 Octets)
+                               Class_Of_Device (3 Octets)
+                               Name (249 Octets)
+                               Short_Name (11 Octets)
+
+       If not short name is set the Short_Name parameter will be empty
+       (begin with a nul byte).
+
+       Current_Settings & Supported_Settings is a bitmask with
+       currently the following available bits:
+
+               1       Powered
+               2       Connectable
+               3       Fast Connectable
+               4       Discoverable
+               5       Pairable
+               6       Link Level Security (Sec. mode 3)
+               7       Secure Simple Pairing
+               8       Basic Rate/Enhanced Data Rate
+               9       High Speed
+               10      Low Energy
+
+
+Set Powered Command
+===================
+
+       Command Code:           0x0005
+       Controller Index:       <controller id>
+       Command Parameters:     Powered (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+
+Set Discoverable Command
+========================
+
+       Command Code:           0x0006
+       Controller Index:       <controller id>
+       Command Parameters:     Discoverable (1 Octet)
+                               Timeout (2 Octets)
+       Return Parameters:      Current_Settings (4 Octets)
+
+       Timeout is the time in seconds and is only meningful when
+       Discoverable is set to 1.
+
+
+Set Connectable Command
+=======================
+
+       Command Code:           0x0007
+       Controller Index:       <controller id>
+       Command Parameters:     Connectable (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+
+Set Fast Connectable Command
+============================
+
+       Command Code:           0x0008
+       Controller Index:       <controller id>
+       Command Parameters:     Enable (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+
+Set Pairable Command
+====================
+
+       Command Code:           0x0009
+       Controller Index:       <controller id>
+       Command Parameters:     Pairable (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+
+Set Link Security Command
+=========================
+
+       Command Code:           0x000A
+       Controller Index:       <controller id>
+       Command Parameters:     Link_Security (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+
+Set Secure Simple Pairing Command
+=================================
+
+       Command Code:           0x000B
+       Controller Index:       <controller id>
+       Command Parameters:     Secure_Simple_Pairing (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+
+Set High Speed Command
+======================
+
+       Command Code:           0x000C
+       Controller Index:       <controller id>
+       Command Parameters:     High_Speed (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+
+Set Low Energy Command
+======================
+
+       Command Code:           0x000D
+       Controller Index:       <controller id>
+       Command Parameters:     Low_Energy (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+
+Set Device Class
+================
+
+       Command Code:           0x000E
+       Controller Index:       <controller id>
+       Command Parameters:     Major_Class (1 Octet)
+                               Minor_Class (1 Octet)
+       Return Parameters:      Class_Of_Device (3 Octets)
+
+       This command will also implicitly disable caching of pending CoD
+       and EIR updates.
+
+
+Set Local Name Command
+======================
+
+       Command Code:           0x000F
+       Controller Index:       <controller id>
+       Command Parameters:     Name (249 Octets)
+                               Short_Name (11 Octets)
+       Return Parameters:      Name (249 Octets)
+                               Short_Name (11 Octets)
+
+       The name parameters need to always end with a nul byte (failure
+       to do so will cause the command to fail).
+
+
+Add UUID Command
+================
+
+       Command Code:           0x0010
+       Controller Index:       <controller id>
+       Command Parameters:     UUID (16 Octets)
+                               SVC_Hint (1 Octet)
+       Return Parameters:      Class_Of_Device (3 Octets)
+
+
+Remove UUID Command
+===================
+
+       Command Code:           0x0011
+       Controller Index:       <controller id>
+       Command Parameters:     UUID (16 Octets)
+       Return Parameters:      Class_Of_Device (3 Octets)
+
+
+Load Link Keys Command
+======================
+
+       Command Code:           0x0012
+       Controller Index:       <controller id>
+       Command Parameters:     Debug_Keys (1 Octet)
+                               Key_Count (2 Octets)
+                               Key1 {
+                                       Address (6 Octets)
+                                       Type (1 Octet)
+                                       Value (16 Octets)
+                                       PIN_Length (1 Octet)
+                               }
+                               Key2 { }
+                               ...
+       Return Parameters:
+
+
+Remove Keys Command
+===================
+
+       Command Code:           0x0013
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Disconnect (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Status (1 Octet)
+
+       Removes all keys associated with the remote device.
+
+
+Disconnect Command
+==================
+
+       Command Code:           0x0014
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+       Return Parameters:      Address (6 Octets)
+                               Status (6 Octets)
+
+
+Get Connections Command
+=======================
+
+       Command Code:           0x0015
+       Controller Index:       <controller id>
+       Command Parameters:
+       Return Parameters:      Connection_Count (2 Octets)
+                               Address1 {
+                                       Address (6 Octets)
+                                       Type (1 Octet)
+                               }
+                               Address2 { }
+                               ...
+
+       Possible values for the Type parameter:
+               0       BR/EDR
+               1       LE Public
+               2       LE Random
+
+
+PIN Code Reply Command
+=======================
+
+       Command Code:           0x0016
+       Controller Index:       <controller id>
+       Command Parameters:
+       Return Parameters:      Address (6 Octets)
+                               PIN_Length (1 Octet)
+                               PIN_Code (16 Octets)
+
+
+PIN Code Negative Reply Command
+===============================
+
+       Command Code:           0x0017
+       Controller Index:       <controller id>
+       Command Parameters:
+       Return Parameters:      Address (6 Octets)
+
+
+Set IO Capability Command
+=========================
+
+       Command Code:           0x0018
+       Controller Index:       <controller id>
+       Command Parameters:     IO_Capability (1 Octet)
+       Return Parameters:
+
+
+Pair Device Command
+===================
+
+       Command Code:           0x0019
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
+                               IO_Capability (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+                               Status (1 Octet)
+
+       Possible values for the Address_Type parameter:
+               0       BR/EDR
+               1       LE Public
+               2       LE Random
+
+
+User Confirmation Reply Command
+===============================
+
+       Command Code:           0x001A
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+       Return Parameters:      Address (6 Octets)
+                               Status (1 Octet)
+
+
+User Confirmation Negative Reply Command
+========================================
+
+       Command Code:           0x001B
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+       Return Parameters:      Address (6 Octets)
+                               Status (1 Octet)
+
+
+User Passkey Reply Command
+==========================
+
+       Command Code:           0x001C
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Passkey (4 Octets)
+       Return Parameters:      Address (6 Octets)
+                               Status (1 Octet)
+
+
+User Passkey Negative Reply Command
+===================================
+
+       Command Code:           0x001D
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+       Return Parameters:      Address (6 Octets)
+                               Status (1 Octet)
+
+
+Read Local Out Of Band Data Command
+===================================
+
+       Command Code:           0x001E
+       Controller Index:       <controller id>
+       Command Parameters:
+       Return Parameters:      Hash (16 Octets)
+                               Randomizer (16 Octets)
+
+
+Add Remote Out Of Band Data Command
+===================================
+
+       Command Code:           0x001F
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Hash (16 Octets)
+                               Randomizer (16 Octets)
+       Return Parameters:
+
+
+Remove Remote Out Of Band Data Command
+========================================
+
+       Command Code:           0x0020
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+       Return Parameters:
+
+
+Start Discovery Command
+=======================
+
+       Command Code:           0x00021
+       Controller Index:       <controller id>
+       Command Parameters:     Type (1 Octet)
+       Return Parameters:
+
+       Possible values for the Type parameter are a bit-wise or of the
+       following bits:
+
+               1       BR/EDR
+               2       LE Public
+               3       LE Random
+
+       By combining these e.g. the following values are possible:
+
+               1       BR/EDR
+               6       LE (public & random)
+               7       BR/EDR/LE (interleaved discovery)
+
+
+Stop Discovery Command
+======================
+
+       Command Code:           0x00022
+       Controller Index:       <controller id>
+       Command Parameters:
+       Return Parameters:
+
+
+Confirm Name Command
+====================
+
+       Command Code:           0x00023
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Name_Known (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Status (1 Octet)
+
+       This command is only valid during device discovery and is
+       expected for each Device Found event with the Confirm Name
+       flag set.
+
+
+Block Device Command
+====================
+
+       Command Code:           0x00024
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+       Return Parameters:
+
+
+Unblock Device Command
+======================
+
+       Command Code:           0x00025
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+       Return Parameters:
+
+
+Load Long Term Keys Command
+===========================
+
+       Command Code:           0x0026
+       Controller Index:       <controller id>
+       Command Parameters:     Key Count (2 Octets)
+                               Key1 {
+                                       Address (6 Octets)
+                                       Authenticated (1 Octet)
+                                       Encryption Size (1 Octet)
+                                       Enc. Diversifier (2 Octets)
+                                       Random Number (8 Octets)
+                                       Value (16 Octets)
+                               }
+                               Key2 {  }
+                               ...
+
+
+Read Tracing Buffer Size Command
+================================
+
+       Command Code:           <not yet assigned>
+       Controller Index:       <non-controller>
+       Command Parameters:
+       Return Parameters:      Status (1 Octet)
+                               Buffer_Size (2 Octets)
+
+               Buffer Size in Kilobytes
+
+
+Write Tracing Buffer Size Command
+=================================
+
+       Command Code:           <not yet assigned>
+       Controller Index:       <non-controller>
+       Command Parameters:     Buffer_Size (2 Octets)
+       Return Parameters:      Status (1 Octet)
+
+               Buffer Size in Kilobytes
+
+
+Read Controller Tracing Filter Command
+=======================================
+
+       Command Code:           <not yet assigned>
+       Controller Index:       <controller id>
+       Command Parameters:
+       Return Parameters:      Status (1 Octet)
+                               Tracing_Enable (1 Octect)
+                               Num_Filters (2 Octect)
+                               Protocol_UUID[i] (16 Octets)
+                               Protocol_Identifier[i] (16 Octets)
+
+               Tracing_Enable: 0x00 Tracing disabled
+                               0x01 Command and Event tracing
+                               0x02 Command, Event and ACL tracing
+                               0x03 Command, Event, ACL and SCO tracing
+
+
+Write Controller Tracing Filter Command
+=======================================
+
+       Command Code:           <not yet assigned>
+       Controller Index:       <controller id>
+       Command Parameters:     Tracing_Enable (1 Octect)
+                               Num_Filters (2 Octect)
+                               Protocol_UUID[i] (16 Octets)
+                               Protocol_Identifier[i] (16 Octets)
+       Return Parameters:      Status (1 Octet)
+
+
+Command Complete Event
+======================
+
+Event Code             0x0001
+Controller Index:      <controller id> or <non-controller>
+Event Parameters       Command_Opcode (2 Octets)
+                       Return_Parameters
+
+
+Command Status Event
+====================
+
+Event Code             0x0002
+Controller Index:      <controller id> or <non-controller>
+Event Parameters       Status (1 Octet)
+                       Command_Opcode (2 Octets)
+
+
+Controller Error Event
+======================
+
+Event Code             0x0003
+Controller Index:      <controller id>
+Event Parameters       Error_Code (1 Octet)
+
+
+Index Added Event
+=================
+
+Event Code             0x0004
+Controller Index:      <controller id>
+Event Parameters
+
+
+Index Removed Event
+===================
+
+Event Code             0x0005
+Controller Index:      <controller id>
+Event Parameters
+
+
+New Settings Event
+==================
+
+Event Code             0x0006
+Controller Index:      <controller id>
+Event Parameters:      Current_Settings (4 Octets)
+
+
+Class Of Device Changed Event
+=============================
+
+Event Code             0x0007
+Controller Index:      <controller id>
+Event Parameters:      Class_Of_Device (3 Octets)
+
+
+Local Name Changed Event
+========================
+
+Event Code             0x0008
+Controller Index       <controller id>
+Event Parameters       Name (249 Octets)
+                       Short_Name (11 Octets)
+
+
+New Link Key Event
+==================
+
+Event Code             0x0009
+Controller Index:      <controller id>
+Event Parameters       Key {
+                               Address (6 Octets)
+                               Type (1 Octet)
+                               Value (16 Octets)
+                               PIN_Length (1 Octet)
+                       }
+                       Old_Key_Type (1 Octet)
+
+
+Device Connected Event
+======================
+
+Event Code             0x000A
+Controller Index:      <controller id>
+Event Parameters       Address (6 Octets)
+                       Type (1 Octet)
+
+       Possible values for the Type parameter:
+               0       BR/EDR
+               1       LE Public
+               2       LE Random
+
+
+Device Disconnected Event
+=========================
+
+Event Code             0x000B
+Controller Index:      <controller id>
+Event Parameters       Address (6 Octets)
+                       Type (1 Octet)
+
+       Possible values for the Type parameter:
+               0       BR/EDR
+               1       LE Public
+               2       LE Random
+
+
+Connect Failed Event
+====================
+
+Event Code             0x000C
+Controller Index:      <controller id>
+Event Parameters       Address (6 Octets)
+                       Type (1 Octet)
+                       Status (1 Octet)
+
+       Possible values for the Type parameter:
+               0       BR/EDR
+               1       LE Public
+               2       LE Random
+
+
+PIN Code Request Event
+======================
+
+Event Code             0x000D
+Controller Index:      <controller id>
+Event Parameters       Address (6 Octets)
+                       Secure (1 Octet)
+
+       Secure: 0x01  secure PIN code required
+               0x00  secure PIN code not required
+
+
+User Confirmation Request Event
+===============================
+
+Event Code             0x000E
+Controller Index:      <controller id>
+Event Parameters       Address (6 Octets)
+                       Value (4 Octets)
+
+
+User Passkey Request Event
+==========================
+
+Event Code             0x000F
+Controller Index:      <controller id>
+Event Parameters       Address (6 Octets)
+
+
+Authentication Failed Event
+===========================
+
+Event Code             0x0010
+Controller Index:      <controller id>
+Event Parameters       Address (6 Octets)
+                       Status (1 Octet)
+
+
+Device Found Event
+==================
+
+Event Code             0x0011
+Controller Index       <controller id>
+Event Parameters       Address (6 Octets)
+                       Type (1 Octet)
+                       Class_Of_Device (3 Octets)
+                       RSSI (1 Octet)
+                       Confirm Name (1 Octet)
+                       EIR_Data (240 Octets)
+
+       Possible values for the Type parameter:
+               0       BR/EDR
+               1       LE Public
+               2       LE Random
+
+
+Remote Name Event
+=================
+
+Event Code             0x0012
+Controller Index       <controller id>
+Event Parameters       Address (6 Octets)
+                       Name (249 Octets)
+
+
+Discovering Event
+=================
+
+Event Code             0x00013
+Controller Index       <controller id>
+Event Parameters       Discovering (1 Octet)
+
+
+Device Blocked Event
+====================
+
+Event Code             0x00014
+Controller Index       <controller id>
+Event Parameters       Address (6 Octets)
+
+
+Device Unblocked Event
+======================
+
+Event Code             0x00015
+Controller Index       <controller id>
+Event Parameters       Address (6 Octets)
+
+
+New Long Term Key Event
+=======================
+
+Event Code             0x0016
+Controller Index       <controller id>
+Event Parameters       Store Hint (1 Octet)
+                       Key {
+                               Address (6 Octets)
+                               Authenticated (1 Octet)
+                               Encryption Size (1 Octet)
+                               Enc. Diversifier (2 Octets)
+                               Random Number (8 Octets)
+                               Value (16 Octets)
+                       }
diff --git a/doc/node-api.txt b/doc/node-api.txt
new file mode 100644 (file)
index 0000000..3ae4dee
--- /dev/null
@@ -0,0 +1,28 @@
+BlueZ D-Bus Node API description
+********************************
+
+Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+
+
+Node hierarchy
+==============
+
+Service                org.bluez
+Interface      org.bluez.Node
+Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/{node0,...}
+
+Methods                dict GetProperties()
+
+                       Returns all properties for the device node. See the
+                       properties section for available properties.
+
+                       Possible Errors: org.bluez.Error.DoesNotExist
+                                        org.bluez.Error.InvalidArguments
+
+Properties     string Name [readonly]
+
+                       The name of the node. For example "rfcomm0".
+
+               object Device [readonly]
+
+                       The object path of the device this node belongs to.
diff --git a/doc/oob-api.txt b/doc/oob-api.txt
new file mode 100644 (file)
index 0000000..d838712
--- /dev/null
@@ -0,0 +1,38 @@
+BlueZ D-Bus Out Of Band Pairing API description
+===============================================
+
+Copyright (C) 2011  Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson
+
+Service                org.bluez
+Interface      org.bluez.OutOfBand
+Object path    [variable prefix]/{hci0,hci1,...}
+
+Methods                array{byte} hash, array{byte} randomizer ReadLocalData()
+
+                       This method reads local OOB data from adapter. Return
+                       value is pair of arrays 16 bytes each.
+
+                       Note: This method will generate and return new local
+                       OOB data.
+
+                       Possible errors: org.bluez.Error.Failed
+                                        org.bluez.Error.InProgress
+
+               void AddRemoteData(string address, array{byte} hash,
+                                                       array{byte} randomizer)
+
+                       This method adds new Out Of Band data for
+                       specified address. If data for specified address
+                       already exists it will be overwritten with new one.
+
+                       Possible errors: org.bluez.Error.Failed
+                                        org.bluez.Error.InvalidArguments
+
+               void RemoveRemoteData(string address)
+
+                       This method removes Out Of Band data for specified
+                       address. If data for specified address does not exist
+                       nothing is removed.
+
+                       Possible errors: org.bluez.Error.Failed
+                                        org.bluez.Error.InvalidArguments
diff --git a/doc/proximity-api.txt b/doc/proximity-api.txt
new file mode 100644 (file)
index 0000000..cf64bbf
--- /dev/null
@@ -0,0 +1,54 @@
+BlueZ D-Bus Proximity API description
+***********************************
+
+Copyright (C) 2011  Claudio Takahasi <claudio.takahasi@openbossa.org>
+
+
+Proximity hierarchy
+=================
+
+Service                org.bluez
+Interface      org.bluez.ProximityMonitor
+Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+Methods                dict GetProperties()
+
+                       Returns all properties for the interface. See the
+                       properties section for available properties.
+
+               void SetProperty(string name, variant value)
+
+                       Changes the value of the specified property. Only
+                       properties that are listed a read-write are changeable.
+                       On success this will emit a PropertyChanged signal.
+
+                       Possible Errors: org.bluez.Error.InvalidArguments
+
+Signals                PropertyChanged(string name, variant value)
+
+                       This signal indicates a changed value of a given
+                       property.
+
+Properties
+
+               string SignalLevel[readonly]
+
+                       Alert indicating that a threshold has been reached.
+                       Possible values: "unknown", "good", "regular", "weak"
+
+               string LinkLossAlertLevel [readwrite]
+
+                       Persistent property. Sets the alert level in the
+                       proximity reporter for link loss scenario. Values:
+                       "none", "mild", "high".
+
+               string ImmediateAlertLevel [readwrite]
+
+                       Alert level to be written in the Immediate Alert Level.
+                       Property shared between Path Loss and Find Me.
+                       Values: "none", "mild", "high". Default value is
+                       "none". Applications can disable the alert setting
+                       the value to "none". If the "Target" is not found,
+                       "none" will be emitted after the configured timeout.
+                       When changing the level, signal is the confirmation
+                       that the value was written in the remote.
index 5f9bd5f..ad496d2 100644 (file)
@@ -26,6 +26,22 @@ Methods              string Connect(string pattern)
                                         org.bluez.Error.ConnectionAttemptFailed
                                         org.bluez.Error.NotSupported
 
+Methods                fd ConnectFD(string pattern) [experimental]
+
+                       Connects to a specific RFCOMM based service on a
+                       remote device and returns a file descriptor to talk
+                        with this device.
+
+                       Possible patterns: UUID 128 bit as string
+                                          Profile short names, e.g: spp, dun
+                                          RFCOMM channel as string, 1-30
+
+                       Possible errors: org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.InProgress
+                                        org.bluez.Error.ConnectionAttemptFailed
+                                        org.bluez.Error.NotSupported
+
+
                void Disconnect(string device)
 
                        Disconnect a RFCOMM TTY device that has been
@@ -39,3 +55,109 @@ Methods             string Connect(string pattern)
 
                        Possible errors: org.bluez.Error.InvalidArguments
                                         org.bluez.Error.DoesNotExist
+
+Serial Proxy Manager hierarchy [experimental]
+=============================================
+
+Service                org.bluez
+Interface      org.bluez.SerialProxyManager
+Object path    [variable prefix]/{hci0,hci1,...}
+
+Methods                array{string} ListProxies()
+
+                       Returns an array of the object path strings of
+                       all the proxies created for the adapter.
+
+               string CreateProxy(string pattern, string address)
+
+                       Possible patterns: UUID 128 bit as string
+                                          Profile short names, e.g: spp, dun
+                                          RFCOMM channel as string, 1-30
+
+                       Address is the path to the TTY or Unix socket to be used.
+                       Only one proxy per address (TTY or Unix socket)
+                       is allowed.
+
+                       The object path of created proxy is returned.
+                       On success this will emit a ProxyCreated signal.
+
+                       Possible Errors: org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.AlreadyExists
+                                        org.bluez.Error.Failed
+
+               void RemoveProxy(string path)
+
+                       This removes the proxy object at the given path.
+                       On success this will emit a ProxyRemoved signal.
+
+                       Possible Errors: org.bluez.Error.DoesNotExist
+                                        org.bluez.Error.NotAuthorized
+
+Signals                ProxyCreated(string path)
+
+                       This signal indicates a proxy was created.
+                       Parameter is object path of created proxy.
+
+               ProxyRemoved(string path)
+
+                       This signal indicates a proxy was removed.
+                       Parameter is object path of removed proxy.
+
+Serial Proxy hierarchy [experimental]
+=====================================
+
+Service                org.bluez
+Interface      org.bluez.SerialProxy
+Object path    [variable prefix]/{hci0,hci1,...}/{proxy0,proxy1,...}
+
+Methods                void Enable()
+
+                       Starts to listen to the TTY or Unix socket, allocates
+                       a RFCOMM channel and add record to the server.
+
+                       Possible errors: org.bluez.Error.Failed
+
+               void Disable()
+
+                       Stops to listen to the TTY or Unix socket, shutdown
+                       the RFCOMM channel allocated for the proxy, and remove
+                       record from the server.
+
+                       Possible errors: org.bluez.Error.Failed
+
+               dict GetInfo()
+
+                       Returns all properties for the proxy. See the
+                       properties section for available properties.
+
+               void SetSerialParameters(string rate, uint8 data, uint8 stop,
+                       string parity)
+
+                       Configures serial communication setting baud rate,
+                       data bits, stop bits and parity.
+
+                       Doesn't allow change TTY settings if it is open.
+
+                       Possible errors: org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.NotAuthorized
+
+Properties     string uuid [readonly]
+
+                       128-bit UUID that represents the available remote service.
+
+               string address [readonly]
+
+                       Address is the path to the TTY or Unix socket name used,
+                       set when the proxy was created.
+
+               uint8 channel [readonly]
+
+                       RFCOMM channel.
+
+               boolean enabled [readonly]
+
+                       Indicates if the proxy is currently enabled.
+
+               boolean connected [readonly]
+
+                       Indicates if the proxy is currently connected.
diff --git a/doc/thermometer-api.txt b/doc/thermometer-api.txt
new file mode 100644 (file)
index 0000000..6392d39
--- /dev/null
@@ -0,0 +1,126 @@
+BlueZ D-Bus Thermometer API description
+****************************************
+
+       Santiago Carot-Nemesio <sancane@gmail.com>
+
+Health Thermometer Profile hierarchy
+=====================================
+
+Service                org.bluez
+Interface      org.bluez.Thermometer
+Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+
+Methods                void SetProperty(string name, variant value)
+
+                       Changes the value of the specified property. Only
+                       read-write properties can be changed. On success
+                       this will emit a PropertyChanged signal.
+
+                       Possible Errors: org.bluez.Error.InvalidArguments
+
+               dict GetProperties()
+
+                       Returns all properties for the interface. See the
+                       Properties section for the available properties.
+
+               RegisterWatcher(object agent)
+
+                       Registers a watcher to monitor scanned measurements.
+                       This agent will be notified about final temperature
+                       measurements.
+
+                       Possible Errors: org.bluez.Error.InvalidArguments
+
+               UnregisterWatcher(object agent)
+
+                       Unregisters a watcher.
+
+                       Final and intermediate temperatures won't be notified to
+                       this agent any more.
+
+                       Possible Errors: org.bluez.Error.InvalidArguments
+                                       org.bluez.Error.NotFound
+
+               EnableIntermediateMeasurement(object agent)
+
+                       Enables intermediate measurement notifications for this
+                       agent if the thermometer supports it.
+
+                       Possible Errors: org.bluez.Error.InvalidArguments
+                                       org.bluez.Error.NotSupported
+
+               DisableIntermediateMeasurement(object agent)
+
+                       Disables intermediate measurement notifications for this
+                       agent. It will disable notifications in the thermometer
+                       when the last agent removes the watcher for intermediate
+                       measurements.
+
+                       Possible Errors: org.bluez.Error.InvalidArguments
+                                       org.bluez.Error.NotFound
+
+Signals                PropertyChanged(string name, variant value)
+
+                       This signal indicates a changed value of the given
+                       property.
+
+Properties     boolean Intermediate [readonly]
+
+                       True if the thermometer supports intermediate measurement
+                       notifications.
+
+               uint16 Interval (optional) [readwrite]
+
+                       The Measurement Interval defines the time (in seconds)
+                       between measurements. This interval is not related to
+                       the intermediate measurements and must be defined into
+                       a valid range. Setting it to zero means that no periodic
+                       measurements will be taken.
+
+               uint16 Maximum (optional) [readonly]
+
+                       Defines the maximum value allowed for the interval
+                       between periodic measurements.
+
+               uint16 Minimum (optional) [readonly]
+
+                       Defines the minimum value allowed for the interval
+                       between periodic measurements.
+
+
+Health Thermometer Watcher hierarchy
+====================================
+Service                unique name
+Interface      org.bluez.ThermometerWatcher
+Object path    freely definable
+
+Methods                void MeasurementReceived(dict measure)
+
+                       This callback gets called when a measure has been
+                       scanned in the thermometer. The Time entry in the dict
+                       will be only present if the device supports storing of
+                       data. The time value is expressed in seconds since epoch.
+                       The value represented is (mantissa) x (10**exponent)
+                       See foot note for special values when treating with
+                       health devices.
+
+                       Dict is defined as below:
+                       {
+                               "Exponent" : int8,
+                               "Mantissa" : int32,
+                               "Unit" : ("Celsius" or "Fahrenheit"),
+                               "Time" : uint64,
+                               "Type" : ("Armpit", "Body", "Ear", "Finger",
+                                       "Intestines", "Mouth", "Rectum", "Toe",
+                                       "Tympanum"),
+                               "Measurement" : ("Final" or "Intermediate"),
+                       }
+
+                       For special cases, the exponent shall always be zero and
+                       the mantissa should be one of following values:
+
+                       NRes = -(2**23)
+                       NaN = +(2**23-1)
+                       INFINITY = (2**23-2)
+                       -INFINITY = -(2**23-2)
index d714947..f0f5613 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "gdbus.h"
 
-#ifdef __TIZEN_PATCH__
+#ifdef __SAMSUNG_PATCH__
 #include "log.h"
 #else
 #define info(fmt...)
@@ -80,7 +80,7 @@ static void print_arguments(GString *gstr, const char *sig,
 
                /* Gather enough data to have a single complete type */
                for (len = 0; len < (sizeof(type) - 1) && sig[i]; len++, i++) {
-                       switch (sig[i]){
+                       switch (sig[i]) {
                        case '(':
                                struct_level++;
                                break;
@@ -259,14 +259,13 @@ void g_dbus_pending_success(DBusConnection *connection,
 
         for (list = pending_security; list; list = list->next) {
                struct security_data *secdata = list->data;
-               DBusHandlerResult result;
 
                if (secdata->pending != pending)
                        continue;
 
                pending_security = g_slist_remove(pending_security, secdata);
 
-               result = process_message(connection, secdata->message,
+               process_message(connection, secdata->message,
                                secdata->method, secdata->iface_user_data);
 
                dbus_message_unref(secdata->message);
@@ -449,7 +448,7 @@ static DBusHandlerResult generic_message(DBusConnection *connection,
                                                iface->user_data) == TRUE)
                        return DBUS_HANDLER_RESULT_HANDLED;
 
-#ifdef __TIZEN_PATCH__
+#ifdef __SAMSUNG_PATCH__
                DBG("%s: %s.%s()",dbus_message_get_path(message),
                                                                        iface->name,method->name);
 #endif
index 558a47c..fba58c3 100644 (file)
@@ -572,6 +572,7 @@ static void service_reply(DBusPendingCall *call, void *user_data)
        reply = dbus_pending_call_steal_reply(call);
        if (reply == NULL)
                return;
+
        dbus_error_init(&err);
 
        if (dbus_set_error_from_message(&err, reply))
index 7491fa0..812352f 100644 (file)
@@ -3,9 +3,6 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *  Authors:
- *  Santiago Carot Nemesio <sancane at gmail.com>
- *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
  *
  *  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
  *
  */
 
-#include <gdbus.h>
-
-#include "log.h"
-#include "error.h"
 #include <stdlib.h>
 #include <stdint.h>
-#include <hdp_types.h>
-#include <hdp_util.h>
+#include <sdpd.h>
+#include <unistd.h>
+
+#include <glib.h>
+
+#include <bluetooth/l2cap.h>
+#include <gdbus.h>
+#include <dbus-common.h>
+#include <log.h>
+#include <error.h>
 #include <adapter.h>
 #include <device.h>
-#include <hdp.h>
-#include <mcap.h>
 #include <btio.h>
-#include <mcap_lib.h>
-#include <l2cap.h>
-#include <sdpd.h>
-#include "../src/dbus-common.h"
-#include <unistd.h>
+
+#include "mcap_lib.h"
+#include "hdp_types.h"
+#include "hdp_util.h"
+#include "hdp.h"
+#include "mcap.h"
 
 #ifndef DBUS_TYPE_UNIX_FD
        #define DBUS_TYPE_UNIX_FD -1
@@ -89,7 +89,7 @@ struct hdp_echo_data {
 
 static struct hdp_channel *hdp_channel_ref(struct hdp_channel *chan)
 {
-       if (!chan)
+       if (chan == NULL)
                return NULL;
 
        chan->ref++;
@@ -114,7 +114,7 @@ static void free_health_channel(struct hdp_channel *chan)
 
 static void hdp_channel_unref(struct hdp_channel *chan)
 {
-       if (!chan)
+       if (chan == NULL)
                return;
 
        chan->ref --;
@@ -222,7 +222,7 @@ static gint cmp_dev_addr(gconstpointer a, gconstpointer dst)
        const struct hdp_device *device = a;
        bdaddr_t addr;
 
-       device_get_address(device->dev, &addr);
+       device_get_address(device->dev, &addr, NULL);
        return bacmp(&addr, dst);
 }
 
@@ -260,14 +260,14 @@ static gint cmp_chan_mdl(gconstpointer a, gconstpointer mdl)
        return -1;
 }
 
-static uint8_t get_app_id()
+static uint8_t get_app_id(void)
 {
        uint8_t id = next_app_id;
 
        do {
                GSList *l = g_slist_find_custom(applications, &id, cmp_app_id);
 
-               if (!l) {
+               if (l == NULL) {
                        next_app_id = (id % HDP_MDEP_FINAL) + 1;
                        return id;
                } else
@@ -288,7 +288,7 @@ static int cmp_app(gconstpointer a, gconstpointer b)
 static gboolean set_app_path(struct hdp_application *app)
 {
        app->id = get_app_id();
-       if (!app->id)
+       if (app->id == 0)
                return FALSE;
        app->path = g_strdup_printf(MANAGER_PATH "/health_app_%d", app->id);
 
@@ -297,7 +297,7 @@ static gboolean set_app_path(struct hdp_application *app)
 
 static void device_unref_mcl(struct hdp_device *hdp_device)
 {
-       if (!hdp_device->mcl)
+       if (hdp_device->mcl == NULL)
                return;
 
        mcap_close_mcl(hdp_device->mcl, FALSE);
@@ -308,12 +308,12 @@ static void device_unref_mcl(struct hdp_device *hdp_device)
 
 static void free_health_device(struct hdp_device *device)
 {
-       if (device->conn) {
+       if (device->conn != NULL) {
                dbus_connection_unref(device->conn);
                device->conn = NULL;
        }
 
-       if (device->dev) {
+       if (device->dev != NULL) {
                btd_device_unref(device->dev);
                device->dev = NULL;
        }
@@ -352,13 +352,13 @@ static DBusMessage *manager_create_application(DBusConnection *conn,
 
        dbus_message_iter_init(msg, &iter);
        app = hdp_get_app_config(&iter, &err);
-       if (err) {
+       if (err != NULL) {
                g_error_free(err);
                return btd_error_invalid_args(msg);
        }
 
        name = dbus_message_get_sender(msg);
-       if (!name) {
+       if (name == NULL) {
                hdp_application_unref(app);
                return g_dbus_create_error(msg,
                                        ERROR_INTERFACE ".HealthError",
@@ -400,7 +400,7 @@ static DBusMessage *manager_destroy_application(DBusConnection *conn,
 
        l = g_slist_find_custom(applications, path, cmp_app);
 
-       if (!l)
+       if (l == NULL)
                return g_dbus_create_error(msg,
                                        ERROR_INTERFACE ".InvalidArguments",
                                        "Invalid arguments in method call, "
@@ -440,7 +440,7 @@ static DBusMessage *channel_get_properties(DBusConnection *conn,
        char *type;
 
        reply = dbus_message_new_method_return(msg);
-       if (!reply)
+       if (reply == NULL)
                return NULL;
 
        dbus_message_iter_init_append(reply, &iter);
@@ -479,7 +479,7 @@ static void hdp_tmp_dc_data_destroy(gpointer data)
 
 static void abort_mdl_cb(GError *err, gpointer data)
 {
-       if (err)
+       if (err != NULL)
                error("Aborting error: %s", err->message);
 }
 
@@ -489,7 +489,7 @@ static void hdp_mdl_reconn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
        DBusMessage *reply;
        int fd;
 
-       if (err) {
+       if (err != NULL) {
                struct hdp_channel *chan = dc_data->hdp_chann;
                GError *gerr = NULL;
 
@@ -536,7 +536,7 @@ static void hdp_get_dcpsm_cb(uint16_t dcpsm, gpointer user_data, GError *err)
        GError *gerr = NULL;
        uint8_t mode;
 
-       if (err) {
+       if (err != NULL) {
                hdp_conn->cb(hdp_chann->mdl, err, hdp_conn);
                return;
        }
@@ -563,7 +563,7 @@ static void device_reconnect_mdl_cb(struct mcap_mdl *mdl, GError *err,
        GError *gerr = NULL;
        DBusMessage *reply;
 
-       if (err) {
+       if (err != NULL) {
                reply = g_dbus_create_error(dc_data->msg,
                                        ERROR_INTERFACE ".HealthError",
                                        "Cannot reconnect: %s", err->message);
@@ -586,7 +586,6 @@ static void device_reconnect_mdl_cb(struct mcap_mdl *mdl, GError *err,
        g_dbus_send_message(dc_data->conn, reply);
        hdp_tmp_dc_data_unref(dc_data);
        g_error_free(gerr);
-       gerr = NULL;
 
        /* Send abort request because remote side is now in PENDING state */
        if (!mcap_mdl_abort(mdl, abort_mdl_cb, NULL, NULL, &gerr)) {
@@ -602,7 +601,7 @@ static DBusMessage *channel_acquire_continue(struct hdp_tmp_dc_data *data,
        GError *gerr = NULL;
        int fd;
 
-       if (err) {
+       if (err != NULL) {
                return g_dbus_create_error(data->msg,
                                                ERROR_INTERFACE ".HealthError",
                                                "%s", err->message);
@@ -633,7 +632,7 @@ static void channel_acquire_cb(gpointer data, GError *err)
 
        reply = channel_acquire_continue(data, err);
 
-       if (reply)
+       if (reply != NULL)
                g_dbus_send_message(dc_data->conn, reply);
 }
 
@@ -693,13 +692,13 @@ static DBusMessage *channel_release(DBusConnection *conn,
 
 static void free_echo_data(struct hdp_echo_data *edata)
 {
-       if (!edata)
+       if (edata == NULL)
                return;
 
-       if (edata->tid)
+       if (edata->tid > 0)
                g_source_remove(edata->tid);
 
-       if (edata->buf)
+       if (edata->buf != NULL)
                g_free(edata->buf);
 
 
@@ -712,7 +711,7 @@ static void health_channel_destroy(void *data)
        struct hdp_device *dev = hdp_chan->dev;
 
        DBG("Destroy Health Channel %s", hdp_chan->path);
-       if (!g_slist_find(dev->channels, hdp_chan))
+       if (g_slist_find(dev->channels, hdp_chan) == NULL)
                goto end;
 
        dev->channels = g_slist_remove(dev->channels, hdp_chan);
@@ -755,7 +754,7 @@ static struct hdp_channel *create_channel(struct hdp_device *dev,
 {
        struct hdp_channel *hdp_chann;
 
-       if (!dev)
+       if (dev == NULL)
                return NULL;
 
        hdp_chann = g_new0(struct hdp_channel, 1);
@@ -763,10 +762,10 @@ static struct hdp_channel *create_channel(struct hdp_device *dev,
        hdp_chann->dev = health_device_ref(dev);
        hdp_chann->mdlid = mdlid;
 
-       if (mdl)
+       if (mdl != NULL)
                hdp_chann->mdl = mcap_mdl_ref(mdl);
 
-       if (app) {
+       if (app != NULL) {
                hdp_chann->mdep = app->id;
                hdp_chann->app = hdp_application_ref(app);
        } else
@@ -800,7 +799,7 @@ static void remove_channels(struct hdp_device *dev)
        struct hdp_channel *chan;
        char *path;
 
-       while (dev->channels) {
+       while (dev->channels != NULL) {
                chan = dev->channels->data;
 
                path = g_strdup(chan->path);
@@ -813,7 +812,7 @@ static void remove_channels(struct hdp_device *dev)
 
 static void close_device_con(struct hdp_device *dev, gboolean cache)
 {
-       if (!dev->mcl)
+       if (dev->mcl == NULL)
                return;
 
        mcap_close_mcl(dev->mcl, cache);
@@ -920,9 +919,9 @@ static gboolean check_channel_conf(struct hdp_channel *chan)
        DBG("MDL imtu %d omtu %d Channel imtu %d omtu %d", imtu, omtu,
                                                chan->imtu, chan->omtu);
 
-       if (!chan->imtu)
+       if (chan->imtu == 0)
                chan->imtu = imtu;
-       if (!chan->omtu)
+       if (chan->omtu == 0)
                chan->omtu = omtu;
 
        if (chan->imtu != imtu || chan->omtu != omtu)
@@ -937,14 +936,14 @@ static void hdp_mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data)
        struct hdp_channel *chan;
 
        DBG("hdp_mcap_mdl_connected_cb");
-       if (!dev->ndc)
+       if (dev->ndc == NULL)
                return;
 
        chan = dev->ndc;
-       if (!chan->mdl)
+       if (chan->mdl == NULL)
                chan->mdl = mcap_mdl_ref(mdl);
 
-       if (!g_slist_find(dev->channels, chan))
+       if (g_slist_find(dev->channels, chan) == NULL)
                dev->channels = g_slist_prepend(dev->channels,
                                                        hdp_channel_ref(chan));
 
@@ -974,7 +973,7 @@ static void hdp_mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data)
                                        DBUS_TYPE_OBJECT_PATH, &chan->path,
                                        DBUS_TYPE_INVALID);
 
-       if (dev->fr)
+       if (dev->fr != NULL)
                goto end;
 
        dev->fr = hdp_channel_ref(chan);
@@ -1006,7 +1005,7 @@ static void hdp_mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
 
        DBG("hdp_mcap_mdl_deleted_cb");
        l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl);
-       if (!l)
+       if (l == NULL)
                return;
 
        chan = l->data;
@@ -1022,12 +1021,12 @@ static void hdp_mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
        struct hdp_device *dev = data;
 
        DBG("hdp_mcap_mdl_aborted_cb");
-       if (!dev->ndc)
+       if (dev->ndc == NULL)
                return;
 
        dev->ndc->mdl = mcap_mdl_ref(mdl);
 
-       if (!g_slist_find(dev->channels, dev->ndc))
+       if (g_slist_find(dev->channels, dev->ndc) == NULL)
                dev->channels = g_slist_prepend(dev->channels,
                                                hdp_channel_ref(dev->ndc));
 
@@ -1081,14 +1080,14 @@ static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
                }
 
                dev->ndc = create_channel(dev, *conf, NULL, mdlid, NULL, NULL);
-               if (!dev->ndc)
+               if (dev->ndc == NULL)
                        return MCAP_MDL_BUSY;
 
                return MCAP_SUCCESS;
        }
 
        l = g_slist_find_custom(applications, &mdepid, cmp_app_id);
-       if (!l)
+       if (l == NULL)
                return MCAP_INVALID_MDEP;
 
        app = l->data;
@@ -1120,7 +1119,7 @@ static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
        }
 
        l = g_slist_find_custom(dev->channels, &mdlid, cmp_chan_mdlid);
-       if (l) {
+       if (l != NULL) {
                struct hdp_channel *chan = l->data;
                char *path;
 
@@ -1137,7 +1136,7 @@ static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
        }
 
        dev->ndc = create_channel(dev, *conf, NULL, mdlid, app, NULL);
-       if (!dev->ndc)
+       if (dev->ndc == NULL)
                return MCAP_MDL_BUSY;
 
        return MCAP_SUCCESS;
@@ -1151,13 +1150,13 @@ static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data)
        GSList *l;
 
        l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl);
-       if (!l)
+       if (l == NULL)
                return MCAP_INVALID_MDL;
 
        chan = l->data;
 
-       if (!dev->fr && (chan->config != HDP_RELIABLE_DC) &&
-                                               (chan->mdep != HDP_MDEP_ECHO))
+       if (dev->fr == NULL && chan->config != HDP_RELIABLE_DC &&
+                                               chan->mdep != HDP_MDEP_ECHO)
                return MCAP_UNSPECIFIED_ERROR;
 
        if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi,
@@ -1176,7 +1175,7 @@ gboolean hdp_set_mcl_cb(struct hdp_device *device, GError **err)
 {
        gboolean ret;
 
-       if (!device->mcl)
+       if (device->mcl == NULL)
                return FALSE;
 
        ret = mcap_mcl_set_cb(device->mcl, device, err,
@@ -1205,7 +1204,7 @@ static void mcl_connected(struct mcap_mcl *mcl, gpointer data)
 
        mcap_mcl_get_addr(mcl, &addr);
        l = g_slist_find_custom(devices, &addr, cmp_dev_addr);
-       if (!l) {
+       if (l == NULL) {
                struct hdp_adapter *hdp_adapter = data;
                struct btd_device *device;
                char str[18];
@@ -1236,7 +1235,7 @@ static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data)
        GSList *l;
 
        l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
-       if (!l)
+       if (l == NULL)
                return;
 
        hdp_device = l->data;
@@ -1253,7 +1252,7 @@ static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data)
        GSList *l;
 
        l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
-       if (!l)
+       if (l == NULL)
                return;
 
        hdp_device = l->data;
@@ -1269,7 +1268,7 @@ static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
        GSList *l;
 
        l = g_slist_find_custom(devices, mcl, cmp_dev_mcl);
-       if (!l)
+       if (l == NULL)
                return;
 
        hdp_device = l->data;
@@ -1287,7 +1286,7 @@ static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
        DBG("Mcl uncached %s", path);
 }
 
-static void check_devices_mcl()
+static void check_devices_mcl(void)
 {
        struct hdp_device *dev;
        GSList *l, *to_delete = NULL;
@@ -1314,7 +1313,7 @@ static void check_devices_mcl()
 
 static void release_adapter_instance(struct hdp_adapter *hdp_adapter)
 {
-       if (!hdp_adapter->mi)
+       if (hdp_adapter->mi == NULL)
                return;
 
        check_devices_mcl();
@@ -1328,12 +1327,12 @@ static gboolean update_adapter(struct hdp_adapter *hdp_adapter)
        GError *err = NULL;
        bdaddr_t addr;
 
-       if (!applications) {
+       if (applications == NULL) {
                release_adapter_instance(hdp_adapter);
                goto update;
        }
 
-       if (hdp_adapter->mi)
+       if (hdp_adapter->mi != NULL)
                goto update;
 
        adapter_get_address(hdp_adapter->btd_adapter, &addr);
@@ -1343,20 +1342,20 @@ static gboolean update_adapter(struct hdp_adapter *hdp_adapter)
                                        NULL, /* CSP is not used by now */
                                        hdp_adapter, &err);
 
-       if (!hdp_adapter->mi) {
+       if (hdp_adapter->mi == NULL) {
                error("Error creating the MCAP instance: %s", err->message);
                g_error_free(err);
                return FALSE;
        }
 
        hdp_adapter->ccpsm = mcap_get_ctrl_psm(hdp_adapter->mi, &err);
-       if (err) {
+       if (err != NULL) {
                error("Error getting MCAP control PSM: %s", err->message);
                goto fail;
        }
 
        hdp_adapter->dcpsm = mcap_get_data_psm(hdp_adapter->mi, &err);
-       if (err) {
+       if (err != NULL) {
                error("Error getting MCAP data PSM: %s", err->message);
                goto fail;
        }
@@ -1368,8 +1367,9 @@ update:
 
 fail:
        release_adapter_instance(hdp_adapter);
-       if (err)
+       if (err != NULL)
                g_error_free(err);
+
        return FALSE;
 }
 
@@ -1400,12 +1400,12 @@ void hdp_adapter_unregister(struct btd_adapter *adapter)
 
        l = g_slist_find_custom(adapters, adapter, cmp_adapter);
 
-       if (!l)
+       if (l == NULL)
                return;
 
        hdp_adapter = l->data;
        adapters = g_slist_remove(adapters, hdp_adapter);
-       if (hdp_adapter->sdp_handler)
+       if (hdp_adapter->sdp_handler > 0)
                remove_record_from_server(hdp_adapter->sdp_handler);
        release_adapter_instance(hdp_adapter);
        btd_adapter_unref(hdp_adapter->btd_adapter);
@@ -1414,7 +1414,7 @@ void hdp_adapter_unregister(struct btd_adapter *adapter)
 
 static void delete_echo_channel_cb(GError *err, gpointer chan)
 {
-       if (err && err->code != MCAP_INVALID_MDL) {
+       if (err != NULL && err->code != MCAP_INVALID_MDL) {
                /* TODO: Decide if more action is required here */
                error("Error deleting echo channel: %s", err->message);
                return;
@@ -1448,7 +1448,7 @@ static void abort_echo_channel_cb(GError *err, gpointer data)
 {
        struct hdp_channel *chan = data;
 
-       if (err && err->code != MCAP_ERROR_INVALID_OPERATION) {
+       if (err != NULL && err->code != MCAP_ERROR_INVALID_OPERATION) {
                error("Aborting error: %s", err->message);
                if (err->code == MCAP_INVALID_MDL) {
                        /* MDL is removed from MCAP so we can */
@@ -1470,7 +1470,7 @@ static void destroy_create_dc_data(gpointer data)
        hdp_create_data_unref(dc_data);
 }
 
-static void *generate_echo_packet()
+static void *generate_echo_packet(void)
 {
        uint8_t *buf;
        int i;
@@ -1557,7 +1557,7 @@ static void hdp_echo_connect_cb(struct mcap_mdl *mdl, GError *err,
        GIOChannel *io;
        int fd;
 
-       if (err) {
+       if (err != NULL) {
                reply = g_dbus_create_error(hdp_conn->msg,
                                                ERROR_INTERFACE ".HealthError",
                                                "%s", err->message);
@@ -1595,7 +1595,7 @@ static void hdp_echo_connect_cb(struct mcap_mdl *mdl, GError *err,
        g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_IN,
                        check_echo, hdp_tmp_dc_data_ref(hdp_conn));
 
-       edata->tid  = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
+       edata->tid = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
                                        ECHO_TIMEOUT, echo_timeout,
                                        hdp_channel_ref(hdp_conn->hdp_chann),
                                        (GDestroyNotify) hdp_channel_unref);
@@ -1605,7 +1605,7 @@ static void hdp_echo_connect_cb(struct mcap_mdl *mdl, GError *err,
 
 static void delete_mdl_cb(GError *err, gpointer data)
 {
-       if (err)
+       if (err != NULL)
                error("Deleting error: %s", err->message);
 }
 
@@ -1614,7 +1614,7 @@ static void abort_and_del_mdl_cb(GError *err, gpointer data)
        struct mcap_mdl *mdl = data;
        GError *gerr = NULL;
 
-       if (err) {
+       if (err != NULL) {
                error("%s", err->message);
                if (err->code == MCAP_INVALID_MDL) {
                        /* MDL is removed from MCAP so we don't */
@@ -1629,6 +1629,25 @@ static void abort_and_del_mdl_cb(GError *err, gpointer data)
        }
 }
 
+static void abort_mdl_connection_cb(GError *err, gpointer data)
+{
+       struct hdp_tmp_dc_data *hdp_conn = data;
+       struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
+
+       if (err != NULL)
+               error("Aborting error: %s", err->message);
+
+       /* Connection operation has failed but we have to */
+       /* notify the channel created at MCAP level */
+       if (hdp_chann->mdep != HDP_MDEP_ECHO)
+               g_dbus_emit_signal(hdp_conn->conn,
+                                       device_get_path(hdp_chann->dev->dev),
+                                       HEALTH_DEVICE,
+                                       "ChannelConnected",
+                                       DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
+                                       DBUS_TYPE_INVALID);
+}
+
 static void hdp_mdl_conn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
 {
        struct hdp_tmp_dc_data *hdp_conn =  data;
@@ -1637,7 +1656,7 @@ static void hdp_mdl_conn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
        DBusMessage *reply;
        GError *gerr = NULL;
 
-       if (err) {
+       if (err != NULL) {
                error("%s", err->message);
                reply = g_dbus_create_reply(hdp_conn->msg,
                                        DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
@@ -1646,8 +1665,10 @@ static void hdp_mdl_conn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
 
                /* Send abort request because remote side */
                /* is now in PENDING state */
-               if (!mcap_mdl_abort(hdp_chann->mdl, abort_mdl_cb, NULL,
-                                                               NULL, &gerr)) {
+               if (!mcap_mdl_abort(hdp_chann->mdl, abort_mdl_connection_cb,
+                                       hdp_tmp_dc_data_ref(hdp_conn),
+                                       hdp_tmp_dc_data_destroy, &gerr)) {
+                       hdp_tmp_dc_data_unref(hdp_conn);
                        error("%s", gerr->message);
                        g_error_free(gerr);
                }
@@ -1659,12 +1680,19 @@ static void hdp_mdl_conn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
                                        DBUS_TYPE_INVALID);
        g_dbus_send_message(hdp_conn->conn, reply);
 
+       g_dbus_emit_signal(hdp_conn->conn,
+                                       device_get_path(hdp_chann->dev->dev),
+                                       HEALTH_DEVICE,
+                                       "ChannelConnected",
+                                       DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
+                                       DBUS_TYPE_INVALID);
+
        if (!check_channel_conf(hdp_chann)) {
                close_mdl(hdp_chann);
                return;
        }
 
-       if (dev->fr)
+       if (dev->fr != NULL)
                return;
 
        dev->fr = hdp_channel_ref(hdp_chann);
@@ -1683,7 +1711,7 @@ static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf,
        GError *gerr = NULL;
        DBusMessage *reply;
 
-       if (err) {
+       if (err != NULL) {
                reply = g_dbus_create_error(user_data->msg,
                                        ERROR_INTERFACE ".HealthError",
                                        "%s", err->message);
@@ -1693,7 +1721,7 @@ static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf,
 
        if (user_data->mdep != HDP_MDEP_ECHO &&
                                user_data->config == HDP_NO_PREFERENCE_DC) {
-               if (!user_data->dev->fr && (conf != HDP_RELIABLE_DC)) {
+               if (user_data->dev->fr == NULL && conf != HDP_RELIABLE_DC) {
                        g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
                                        "Data channel aborted, first data "
                                        "channel should be reliable");
@@ -1710,17 +1738,9 @@ static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf,
        hdp_chan = create_channel(user_data->dev, conf, mdl,
                                                        mcap_mdl_get_mdlid(mdl),
                                                        user_data->app, &gerr);
-       if (!hdp_chan)
+       if (hdp_chan == NULL)
                goto fail;
 
-       if (user_data->mdep != HDP_MDEP_ECHO)
-               g_dbus_emit_signal(user_data->conn,
-                                       device_get_path(hdp_chan->dev->dev),
-                                       HEALTH_DEVICE,
-                                       "ChannelConnected",
-                                       DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
-                                       DBUS_TYPE_INVALID);
-
        hdp_conn = g_new0(struct hdp_tmp_dc_data, 1);
        hdp_conn->msg = dbus_message_ref(user_data->msg);
        hdp_conn->conn = dbus_connection_ref(user_data->conn);
@@ -1735,7 +1755,6 @@ static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf,
 
        error("%s", gerr->message);
        g_error_free(gerr);
-       gerr = NULL;
 
        reply = g_dbus_create_reply(hdp_conn->msg,
                                        DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
@@ -1744,7 +1763,10 @@ static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf,
        hdp_tmp_dc_data_unref(hdp_conn);
 
        /* Send abort request because remote side is now in PENDING state */
-       if (!mcap_mdl_abort(mdl, abort_mdl_cb, NULL, NULL, &gerr)) {
+       if (!mcap_mdl_abort(hdp_chan->mdl, abort_mdl_connection_cb,
+                                       hdp_tmp_dc_data_ref(hdp_conn),
+                                       hdp_tmp_dc_data_destroy, &gerr)) {
+               hdp_tmp_dc_data_unref(hdp_conn);
                error("%s", gerr->message);
                g_error_free(gerr);
        }
@@ -1757,13 +1779,12 @@ fail:
                                                "%s", gerr->message);
        g_dbus_send_message(user_data->conn, reply);
        g_error_free(gerr);
-       gerr = NULL;
 
        /* Send abort request because remote side is now in PENDING */
        /* state. Then we have to delete it because we couldn't */
        /* register the HealthChannel interface */
-       if (!mcap_mdl_abort(mdl, abort_and_del_mdl_cb, mcap_mdl_ref(mdl), NULL,
-                                                               &gerr)) {
+       if (!mcap_mdl_abort(mdl, abort_and_del_mdl_cb, mcap_mdl_ref(mdl),
+                               (GDestroyNotify) mcap_mdl_unref, &gerr)) {
                error("%s", gerr->message);
                g_error_free(gerr);
                mcap_mdl_unref(mdl);
@@ -1776,7 +1797,7 @@ static void device_create_dc_cb(gpointer user_data, GError *err)
        DBusMessage *reply;
        GError *gerr = NULL;
 
-       if (err) {
+       if (err != NULL) {
                reply = g_dbus_create_error(data->msg,
                                        ERROR_INTERFACE ".HealthError",
                                        "%s", err->message);
@@ -1784,7 +1805,7 @@ static void device_create_dc_cb(gpointer user_data, GError *err)
                return;
        }
 
-       if (!data->dev->mcl) {
+       if (data->dev->mcl == NULL) {
                g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
                                "Mcl was closed");
                goto fail;
@@ -1822,7 +1843,7 @@ static DBusMessage *device_echo(DBusConnection *conn,
        data->cb = hdp_echo_connect_cb;
        hdp_create_data_ref(data);
 
-       if (device->mcl_conn && device->mcl) {
+       if (device->mcl_conn && device->mcl != NULL) {
                if (mcap_create_mdl(device->mcl, data->mdep, data->config,
                                                device_create_mdl_cb, data,
                                                destroy_create_dc_data, &err))
@@ -1848,7 +1869,7 @@ static void device_get_mdep_cb(uint8_t mdep, gpointer data, GError *err)
        DBusMessage *reply;
        GError *gerr = NULL;
 
-       if (err) {
+       if (err != NULL) {
                reply = g_dbus_create_error(user_data->msg,
                                                ERROR_INTERFACE ".HealthError",
                                                "%s", err->message);
@@ -1895,7 +1916,7 @@ static DBusMessage *device_create_channel(DBusConnection *conn,
                return btd_error_invalid_args(msg);
 
        l = g_slist_find_custom(applications, app_path, cmp_app);
-       if (!l)
+       if (l == NULL)
                return btd_error_invalid_args(msg);
 
        app = l->data;
@@ -1944,7 +1965,7 @@ static void hdp_mdl_delete_cb(GError *err, gpointer data)
        DBusMessage *reply;
        char *path;
 
-       if (err && err->code != MCAP_INVALID_MDL) {
+       if (err != NULL && err->code != MCAP_INVALID_MDL) {
                reply = g_dbus_create_error(del_data->msg,
                                                ERROR_INTERFACE ".HealthError",
                                                "%s", err->message);
@@ -1966,7 +1987,7 @@ static void hdp_continue_del_cb(gpointer user_data, GError *err)
        GError *gerr = NULL;
        DBusMessage *reply;
 
-       if (err) {
+       if (err != NULL) {
                reply = g_dbus_create_error(del_data->msg,
                                        ERROR_INTERFACE ".HealthError",
                                        "%s", err->message);
@@ -2004,7 +2025,7 @@ static DBusMessage *device_destroy_channel(DBusConnection *conn,
        }
 
        l = g_slist_find_custom(device->channels, path, cmp_chan_path);
-       if (!l)
+       if (l == NULL)
                return btd_error_invalid_args(msg);
 
        hdp_chan = l->data;
@@ -2043,7 +2064,7 @@ static DBusMessage *device_get_properties(DBusConnection *conn,
        char *path;
 
        reply = dbus_message_new_method_return(msg);
-       if (!reply)
+       if (reply == NULL)
                return NULL;
 
        dbus_message_iter_init_append(reply, &iter);
@@ -2053,11 +2074,11 @@ static DBusMessage *device_get_properties(DBusConnection *conn,
                        DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
                        DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
 
-       if (device->fr)
+       if (device->fr != NULL)
                path = g_strdup(device->fr->path);
        else
                path = g_strdup("");
-       dict_append_entry(&dict, "MainChannel", DBUS_TYPE_STRING, &path);
+       dict_append_entry(&dict, "MainChannel", DBUS_TYPE_OBJECT_PATH, &path);
        g_free(path);
        dbus_message_iter_close_container(&iter, &dict);
 
@@ -2072,7 +2093,7 @@ static void health_device_destroy(void *data)
                                                device_get_path(device->dev));
 
        remove_channels(device);
-       if (device->ndc) {
+       if (device->ndc != NULL) {
                hdp_channel_unref(device->ndc);
                device->ndc = NULL;
        }
@@ -2107,7 +2128,7 @@ static struct hdp_device *create_health_device(DBusConnection *conn,
        struct hdp_device *dev;
        GSList *l;
 
-       if (!device)
+       if (device == NULL)
                return NULL;
 
        dev = g_new0(struct hdp_device, 1);
@@ -2116,7 +2137,7 @@ static struct hdp_device *create_health_device(DBusConnection *conn,
        health_device_ref(dev);
 
        l = g_slist_find_custom(adapters, adapter, cmp_adapter);
-       if (!l)
+       if (l == NULL)
                goto fail;
 
        dev->hdp_adapter = l->data;
@@ -2144,14 +2165,14 @@ int hdp_device_register(DBusConnection *conn, struct btd_device *device)
        GSList *l;
 
        l = g_slist_find_custom(devices, device, cmp_device);
-       if (l) {
+       if (l != NULL) {
                hdev = l->data;
                hdev->sdp_present = TRUE;
                return 0;
        }
 
        hdev = create_health_device(conn, device);
-       if (!hdev)
+       if (hdev == NULL)
                return -1;
 
        hdev->sdp_present = TRUE;
@@ -2167,7 +2188,7 @@ void hdp_device_unregister(struct btd_device *device)
        GSList *l;
 
        l = g_slist_find_custom(devices, device, cmp_device);
-       if (!l)
+       if (l == NULL)
                return;
 
        hdp_dev = l->data;
@@ -2192,7 +2213,7 @@ int hdp_manager_start(DBusConnection *conn)
        return 0;
 }
 
-void hdp_manager_stop()
+void hdp_manager_stop(void)
 {
        g_dbus_unregister_interface(connection, MANAGER_PATH, HEALTH_MANAGER);
 
index 3cf87ca..39f0441 100644 (file)
@@ -3,9 +3,6 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *  Authors:
- *  Santiago Carot Nemesio <sancane at gmail.com>
- *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
  *
  *  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
@@ -30,6 +27,6 @@ int hdp_device_register(DBusConnection *conn, struct btd_device *device);
 void hdp_device_unregister(struct btd_device *device);
 
 int hdp_manager_start(DBusConnection *conn);
-void hdp_manager_stop();
+void hdp_manager_stop(void);
 
 gboolean hdp_set_mcl_cb(struct hdp_device *device, GError **err);
index b40a37c..9367e73 100644 (file)
@@ -3,9 +3,6 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *  Authors:
- *  Santiago Carot Nemesio <sancane at gmail.com>
- *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
  *
  *  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
index 88b49fc..cccb1a6 100644 (file)
@@ -3,9 +3,6 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *  Authors:
- *  Santiago Carot Nemesio <sancane at gmail.com>
- *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
  *
  *  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
 #include <btio.h>
 #include <adapter.h>
 #include <device.h>
+#include <glib-helper.h>
+#include <log.h>
 
 #include "hdp_types.h"
 
-#include "log.h"
 #include "hdp_manager.h"
 #include "hdp.h"
 
-#include "glib-helper.h"
-
 static DBusConnection *connection = NULL;
 
 static int hdp_adapter_probe(struct btd_adapter *adapter)
@@ -79,7 +75,7 @@ static struct btd_device_driver hdp_device_driver = {
 
 int hdp_manager_init(DBusConnection *conn)
 {
-       if (hdp_manager_start(conn))
+       if (hdp_manager_start(conn) < 0)
                return -1;
 
        connection = dbus_connection_ref(conn);
index b91ef75..d39f190 100644 (file)
@@ -3,9 +3,6 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *  Authors:
- *  Santiago Carot Nemesio <sancane at gmail.com>
- *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
  *
  *  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
index 7d23293..9a6776f 100644 (file)
@@ -3,9 +3,6 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *  Authors:
- *  Santiago Carot Nemesio <sancane at gmail.com>
- *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
  *
  *  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
@@ -84,7 +81,7 @@ struct hdp_application {
        char                    *description;   /* Options description for SDP record */
        uint8_t                 id;             /* The identification is also the mdepid */
        char                    *oname;         /* Name of the owner application */
-       int                     dbus_watcher;   /* Watch for clients disconnection */
+       guint                   dbus_watcher;   /* Watch for clients disconnection */
        gint                    ref;            /* Reference counter */
 };
 
index aefe5f9..3b48e44 100644 (file)
@@ -3,9 +3,6 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *  Authors:
- *  Santiago Carot Nemesio <sancane at gmail.com>
- *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
  *
  *  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
  *
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+
+#include <glib.h>
+
 #include <gdbus.h>
 
 #include <adapter.h>
 #include <device.h>
-#include <stdint.h>
-#include <hdp_types.h>
-#include <hdp_util.h>
-#include <mcap.h>
-#include <hdp.h>
 
 #include <sdpd.h>
-#include <sdp_lib.h>
+#include <bluetooth/sdp_lib.h>
+#include <sdp-client.h>
 #include <glib-helper.h>
 
 #include <btio.h>
-#include <mcap_lib.h>
 
 #include <log.h>
 
+#include "mcap.h"
+#include "mcap_lib.h"
+#include "hdp_types.h"
+#include "hdp.h"
+#include "hdp_util.h"
+
 typedef gboolean (*parse_item_f)(DBusMessageIter *iter, gpointer user_data,
                                                                GError **err);
 
@@ -364,24 +370,24 @@ static gboolean register_service_protocols(struct hdp_adapter *adapter,
        /* set l2cap information */
        sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
        l2cap_list = sdp_list_append(NULL, &l2cap_uuid);
-       if (!l2cap_list) {
+       if (l2cap_list == NULL) {
                ret = FALSE;
                goto end;
        }
 
        psm = sdp_data_alloc(SDP_UINT16, &adapter->ccpsm);
-       if (!psm) {
+       if (psm == NULL) {
                ret = FALSE;
                goto end;
        }
 
-       if (!sdp_list_append(l2cap_list, psm)) {
+       if (sdp_list_append(l2cap_list, psm) == NULL) {
                ret = FALSE;
                goto end;
        }
 
        proto_list = sdp_list_append(NULL, l2cap_list);
-       if (!proto_list) {
+       if (proto_list == NULL) {
                ret = FALSE;
                goto end;
        }
@@ -389,30 +395,30 @@ static gboolean register_service_protocols(struct hdp_adapter *adapter,
        /* set mcap information */
        sdp_uuid16_create(&mcap_c_uuid, MCAP_CTRL_UUID);
        mcap_list = sdp_list_append(NULL, &mcap_c_uuid);
-       if (!mcap_list) {
+       if (mcap_list == NULL) {
                ret = FALSE;
                goto end;
        }
 
        mcap_ver = sdp_data_alloc(SDP_UINT16, &version);
-       if (!mcap_ver) {
+       if (mcap_ver == NULL) {
                ret = FALSE;
                goto end;
        }
 
-       if (!sdp_list_append(mcap_list, mcap_ver)) {
+       if (sdp_list_append(mcap_list, mcap_ver) == NULL) {
                ret = FALSE;
                goto end;
        }
 
-       if (!sdp_list_append(proto_list, mcap_list)) {
+       if (sdp_list_append(proto_list, mcap_list) == NULL) {
                ret = FALSE;
                goto end;
        }
 
        /* attach protocol information to service record */
        access_proto_list = sdp_list_append(NULL, proto_list);
-       if (!access_proto_list) {
+       if (access_proto_list == NULL) {
                ret = FALSE;
                goto end;
        }
@@ -424,17 +430,17 @@ static gboolean register_service_protocols(struct hdp_adapter *adapter,
        ret = TRUE;
 
 end:
-       if (l2cap_list)
+       if (l2cap_list != NULL)
                sdp_list_free(l2cap_list, NULL);
-       if (mcap_list)
+       if (mcap_list != NULL)
                sdp_list_free(mcap_list, NULL);
-       if (proto_list)
+       if (proto_list != NULL)
                sdp_list_free(proto_list, NULL);
-       if (access_proto_list)
+       if (access_proto_list != NULL)
                sdp_list_free(access_proto_list, NULL);
-       if (psm)
+       if (psm != NULL)
                sdp_data_free(psm);
-       if (mcap_ver)
+       if (mcap_ver != NULL)
                sdp_data_free(mcap_ver);
 
        return ret;
@@ -450,7 +456,7 @@ static gboolean register_service_profiles(sdp_record_t *sdp_record)
        sdp_uuid16_create(&hdp_profile.uuid, HDP_SVCLASS_ID);
        hdp_profile.version = HDP_VERSION;
        profile_list = sdp_list_append(NULL, &hdp_profile);
-       if (!profile_list)
+       if (profile_list == NULL)
                return FALSE;
 
        /* set profile descriptor list */
@@ -477,24 +483,24 @@ static gboolean register_service_additional_protocols(
        /* set l2cap information */
        sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
        l2cap_list = sdp_list_append(NULL, &l2cap_uuid);
-       if (!l2cap_list) {
+       if (l2cap_list == NULL) {
                ret = FALSE;
                goto end;
        }
 
        psm = sdp_data_alloc(SDP_UINT16, &adapter->dcpsm);
-       if (!psm) {
+       if (psm == NULL) {
                ret = FALSE;
                goto end;
        }
 
-       if (!sdp_list_append(l2cap_list, psm)) {
+       if (sdp_list_append(l2cap_list, psm) == NULL) {
                ret = FALSE;
                goto end;
        }
 
        proto_list = sdp_list_append(NULL, l2cap_list);
-       if (!proto_list) {
+       if (proto_list == NULL) {
                ret = FALSE;
                goto end;
        }
@@ -502,19 +508,19 @@ static gboolean register_service_additional_protocols(
        /* set mcap information */
        sdp_uuid16_create(&mcap_d_uuid, MCAP_DATA_UUID);
        mcap_list = sdp_list_append(NULL, &mcap_d_uuid);
-       if (!mcap_list) {
+       if (mcap_list == NULL) {
                ret = FALSE;
                goto end;
        }
 
-       if (!sdp_list_append(proto_list, mcap_list)) {
+       if (sdp_list_append(proto_list, mcap_list) == NULL) {
                ret = FALSE;
                goto end;
        }
 
        /* attach protocol information to service record */
        access_proto_list = sdp_list_append(NULL, proto_list);
-       if (!access_proto_list) {
+       if (access_proto_list == NULL) {
                ret = FALSE;
                goto end;
        }
@@ -525,15 +531,15 @@ static gboolean register_service_additional_protocols(
                ret = TRUE;
 
 end:
-       if (l2cap_list)
+       if (l2cap_list != NULL)
                sdp_list_free(l2cap_list, NULL);
-       if (mcap_list)
+       if (mcap_list != NULL)
                sdp_list_free(mcap_list, NULL);
-       if (proto_list)
+       if (proto_list  != NULL)
                sdp_list_free(proto_list, NULL);
-       if (access_proto_list)
+       if (access_proto_list != NULL)
                sdp_list_free(access_proto_list, NULL);
-       if (psm)
+       if (psm != NULL)
                sdp_data_free(psm);
 
        return ret;
@@ -548,49 +554,49 @@ static sdp_list_t *app_to_sdplist(struct hdp_application *app)
        sdp_list_t *f_list = NULL;
 
        mdepid = sdp_data_alloc(SDP_UINT8, &app->id);
-       if (!mdepid)
+       if (mdepid == NULL)
                return NULL;
 
        dtype = sdp_data_alloc(SDP_UINT16, &app->data_type);
-       if (!dtype)
+       if (dtype == NULL)
                goto fail;
 
        role = sdp_data_alloc(SDP_UINT8, &app->role);
-       if (!role)
+       if (role == NULL)
                goto fail;
 
-       if (app->description) {
+       if (app->description != NULL) {
                desc = sdp_data_alloc(SDP_TEXT_STR8, app->description);
-               if (!desc)
+               if (desc == NULL)
                        goto fail;
        }
 
        f_list = sdp_list_append(NULL, mdepid);
-       if (!f_list)
+       if (f_list == NULL)
                goto fail;
 
-       if (!sdp_list_append(f_list, dtype))
+       if (sdp_list_append(f_list, dtype) == NULL)
                goto fail;
 
-       if (!sdp_list_append(f_list, role))
+       if (sdp_list_append(f_list, role) == NULL)
                goto fail;
 
-       if (desc)
-               if (!sdp_list_append(f_list, desc))
+       if (desc != NULL)
+               if (sdp_list_append(f_list, desc) == NULL)
                        goto fail;
 
        return f_list;
 
 fail:
-       if (f_list)
+       if (f_list != NULL)
                sdp_list_free(f_list, NULL);
-       if (mdepid)
+       if (mdepid != NULL)
                sdp_data_free(mdepid);
-       if (dtype)
+       if (dtype != NULL)
                sdp_data_free(dtype);
-       if (role)
+       if (role != NULL)
                sdp_data_free(role);
-       if (desc)
+       if (desc != NULL)
                sdp_data_free(desc);
 
        return NULL;
@@ -602,21 +608,21 @@ static gboolean register_features(struct hdp_application *app,
        sdp_list_t *hdp_feature;
 
        hdp_feature = app_to_sdplist(app);
-       if (!hdp_feature)
+       if (hdp_feature == NULL)
                goto fail;
 
-       if (!*sup_features) {
+       if (*sup_features == NULL) {
                *sup_features = sdp_list_append(NULL, hdp_feature);
-               if (!*sup_features)
+               if (*sup_features == NULL)
                        goto fail;
-       } else if (!sdp_list_append(*sup_features, hdp_feature)) {
+       } else if (sdp_list_append(*sup_features, hdp_feature) == NULL) {
                goto fail;
        }
 
        return TRUE;
 
 fail:
-       if (hdp_feature)
+       if (hdp_feature != NULL)
                sdp_list_free(hdp_feature, (sdp_free_func_t)sdp_data_free);
        return FALSE;
 }
@@ -654,7 +660,7 @@ static gboolean register_data_exchange_spec(sdp_record_t *record)
        /* As by now 11073 is the only supported we set it by default */
 
        spec = sdp_data_alloc(SDP_UINT8, &data_spec);
-       if (!spec)
+       if (spec == NULL)
                return FALSE;
 
        if (sdp_attr_add(record, SDP_ATTR_DATA_EXCHANGE_SPEC, spec) < 0) {
@@ -671,7 +677,7 @@ static gboolean register_mcap_features(sdp_record_t *sdp_record)
        uint8_t mcap_sup_proc = MCAP_SUP_PROC;
 
        mcap_proc = sdp_data_alloc(SDP_UINT8, &mcap_sup_proc);
-       if (!mcap_proc)
+       if (mcap_proc == NULL)
                return FALSE;
 
        if (sdp_attr_add(sdp_record, SDP_ATTR_MCAP_SUPPORTED_PROCEDURES,
@@ -688,19 +694,19 @@ gboolean hdp_update_sdp_record(struct hdp_adapter *adapter, GSList *app_list)
        sdp_record_t *sdp_record;
        bdaddr_t addr;
 
-       if (adapter->sdp_handler)
+       if (adapter->sdp_handler > 0)
                remove_record_from_server(adapter->sdp_handler);
 
-       if (!app_list) {
+       if (app_list == NULL) {
                adapter->sdp_handler = 0;
                return TRUE;
        }
 
        sdp_record = sdp_record_alloc();
-       if (!sdp_record)
+       if (sdp_record == NULL)
                return FALSE;
 
-       if (adapter->sdp_handler)
+       if (adapter->sdp_handler > 0)
                sdp_record->handle = adapter->sdp_handler;
        else
                sdp_record->handle = 0xffffffff; /* Set automatically */
@@ -726,7 +732,7 @@ gboolean hdp_update_sdp_record(struct hdp_adapter *adapter, GSList *app_list)
 
        register_mcap_features(sdp_record);
 
-       if (sdp_set_record_state(sdp_record, adapter->record_state++))
+       if (sdp_set_record_state(sdp_record, adapter->record_state++) < 0)
                goto fail;
 
        adapter_get_address(adapter->btd_adapter, &addr);
@@ -737,7 +743,7 @@ gboolean hdp_update_sdp_record(struct hdp_adapter *adapter, GSList *app_list)
        return TRUE;
 
 fail:
-       if (sdp_record)
+       if (sdp_record != NULL)
                sdp_record_free(sdp_record);
        return FALSE;
 }
@@ -756,13 +762,12 @@ static gboolean get_mdep_from_rec(const sdp_record_t *rec, uint8_t role,
 {
        sdp_data_t *list, *feat;
 
-       if (!desc && !mdep)
+       if (desc == NULL && mdep == NULL)
                return TRUE;
 
        list = sdp_data_get(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST);
-
-       if (list->dtd != SDP_SEQ8 && list->dtd != SDP_SEQ16 &&
-                                                       list->dtd != SDP_SEQ32)
+       if (list == NULL || (list->dtd != SDP_SEQ8 && list->dtd != SDP_SEQ16 &&
+                                                       list->dtd != SDP_SEQ32))
                return FALSE;
 
        for (feat = list->val.dataseq; feat; feat = feat->next) {
@@ -773,15 +778,15 @@ static gboolean get_mdep_from_rec(const sdp_record_t *rec, uint8_t role,
                        continue;
 
                mdepid = feat->val.dataseq;
-               if (!mdepid)
+               if (mdepid == NULL)
                        continue;
 
                data_type = mdepid->next;
-               if (!data_type)
+               if (data_type == NULL)
                        continue;
 
                role_t = data_type->next;
-               if (!role_t)
+               if (role_t == NULL)
                        continue;
 
                desc_t = role_t->next;
@@ -794,10 +799,11 @@ static gboolean get_mdep_from_rec(const sdp_record_t *rec, uint8_t role,
                                        !check_role(role_t->val.uint8, role))
                        continue;
 
-               if (mdep)
+               if (mdep != NULL)
                        *mdep = mdepid->val.uint8;
 
-               if (desc  && desc_t && (desc_t->dtd == SDP_TEXT_STR8 ||
+               if (desc != NULL  && desc_t != NULL  &&
+                                       (desc_t->dtd == SDP_TEXT_STR8 ||
                                        desc_t->dtd == SDP_TEXT_STR16  ||
                                        desc_t->dtd == SDP_TEXT_STR32))
                        *desc = g_strdup(desc_t->val.str);
@@ -814,7 +820,7 @@ static void get_mdep_cb(sdp_list_t *recs, int err, gpointer user_data)
        GError *gerr = NULL;
        uint8_t mdep;
 
-       if (err || !recs) {
+       if (err < 0 || recs == NULL) {
                g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
                                        "Error getting remote SDP records");
                mdep_data->func(0, mdep_data->data, gerr);
@@ -853,7 +859,7 @@ gboolean hdp_get_mdep(struct hdp_device *device, struct hdp_application *app,
        bdaddr_t dst, src;
        uuid_t uuid;
 
-       device_get_address(device->dev, &dst);
+       device_get_address(device->dev, &dst, NULL);
        adapter_get_address(device_get_adapter(device->dev), &src);
 
        mdep_data = g_new0(struct get_mdep_data, 1);
@@ -864,7 +870,7 @@ gboolean hdp_get_mdep(struct hdp_device *device, struct hdp_application *app,
 
        bt_string2uuid(&uuid, HDP_UUID);
        if (bt_search_service(&src, &dst, &uuid, get_mdep_cb, mdep_data,
-                                                       free_mdep_data)) {
+                                                       free_mdep_data) < 0) {
                g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR,
                                                "Can't get remote SDP record");
                g_free(mdep_data);
@@ -879,8 +885,8 @@ static gboolean get_prot_desc_entry(sdp_data_t *entry, int type, guint16 *val)
        sdp_data_t *iter;
        int proto;
 
-       if (!entry || (entry->dtd != SDP_SEQ8 && entry->dtd != SDP_SEQ16 &&
-                                               entry->dtd != SDP_SEQ32))
+       if (entry == NULL || (entry->dtd != SDP_SEQ8 &&
+                       entry->dtd != SDP_SEQ16 && entry->dtd != SDP_SEQ32))
                return FALSE;
 
        iter = entry->val.dataseq;
@@ -891,7 +897,7 @@ static gboolean get_prot_desc_entry(sdp_data_t *entry, int type, guint16 *val)
        if (proto != type)
                return FALSE;
 
-       if (!val)
+       if (val == NULL)
                return TRUE;
 
        iter = iter->next;
@@ -908,12 +914,12 @@ static gboolean hdp_get_prot_desc_list(const sdp_record_t *rec, guint16 *psm,
 {
        sdp_data_t *pdl, *p0, *p1;
 
-       if (!psm && !version)
+       if (psm == NULL && version == NULL)
                return TRUE;
 
        pdl = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST);
-       if (pdl->dtd != SDP_SEQ8 && pdl->dtd != SDP_SEQ16 &&
-                                                       pdl->dtd != SDP_SEQ32)
+       if (pdl == NULL || (pdl->dtd != SDP_SEQ8 && pdl->dtd != SDP_SEQ16 &&
+                                                       pdl->dtd != SDP_SEQ32))
                return FALSE;
 
        p0 = pdl->val.dataseq;
@@ -932,11 +938,11 @@ static gboolean hdp_get_add_prot_desc_list(const sdp_record_t *rec,
 {
        sdp_data_t *pdl, *p0, *p1;
 
-       if (!psm)
+       if (psm == NULL)
                return TRUE;
 
        pdl = sdp_data_get(rec, SDP_ATTR_ADD_PROTO_DESC_LIST);
-       if (pdl->dtd != SDP_SEQ8)
+       if (pdl == NULL || pdl->dtd != SDP_SEQ8)
                return FALSE;
        pdl = pdl->val.dataseq;
        if (pdl->dtd != SDP_SEQ8)
@@ -983,7 +989,7 @@ static gboolean get_dcpsm(sdp_list_t *recs, uint16_t *dcpsm)
 
 static void con_mcl_data_unref(struct conn_mcl_data *conn_data)
 {
-       if (!conn_data)
+       if (conn_data == NULL)
                return;
 
        if (--conn_data->refs > 0)
@@ -1003,7 +1009,7 @@ static void destroy_con_mcl_data(gpointer data)
 
 static struct conn_mcl_data *con_mcl_data_ref(struct conn_mcl_data *conn_data)
 {
-       if (!conn_data)
+       if (conn_data == NULL)
                return NULL;
 
        conn_data->refs++;
@@ -1016,19 +1022,19 @@ static void create_mcl_cb(struct mcap_mcl *mcl, GError *err, gpointer data)
        struct hdp_device *device = conn_data->dev;
        GError *gerr = NULL;
 
-       if (err) {
+       if (err != NULL) {
                conn_data->func(conn_data->data, err);
                return;
        }
 
-       if (!device->mcl)
+       if (device->mcl == NULL)
                device->mcl = mcap_mcl_ref(mcl);
        device->mcl_conn = TRUE;
 
        hdp_set_mcl_cb(device, &gerr);
 
        conn_data->func(conn_data->data, gerr);
-       if (gerr)
+       if (gerr != NULL)
                g_error_free(gerr);
 }
 
@@ -1039,13 +1045,13 @@ static void search_cb(sdp_list_t *recs, int err, gpointer user_data)
        bdaddr_t dst;
        uint16_t ccpsm;
 
-       if (!conn_data->dev->hdp_adapter->mi) {
+       if (conn_data->dev->hdp_adapter->mi == NULL) {
                g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
                                                "Mcap instance released");
                goto fail;
        }
 
-       if (err || !recs) {
+       if (err < 0 || recs == NULL) {
                g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
                                        "Error getting remote SDP records");
                goto fail;
@@ -1059,7 +1065,7 @@ static void search_cb(sdp_list_t *recs, int err, gpointer user_data)
 
        conn_data = con_mcl_data_ref(conn_data);
 
-       device_get_address(conn_data->dev->dev, &dst);
+       device_get_address(conn_data->dev->dev, &dst, NULL);
        if (!mcap_create_mcl(conn_data->dev->hdp_adapter->mi, &dst, ccpsm,
                                                create_mcl_cb, conn_data,
                                                destroy_con_mcl_data, &gerr)) {
@@ -1082,7 +1088,7 @@ gboolean hdp_establish_mcl(struct hdp_device *device,
        bdaddr_t dst, src;
        uuid_t uuid;
 
-       device_get_address(device->dev, &dst);
+       device_get_address(device->dev, &dst, NULL);
        adapter_get_address(device_get_adapter(device->dev), &src);
 
        conn_data = g_new0(struct conn_mcl_data, 1);
@@ -1094,7 +1100,7 @@ gboolean hdp_establish_mcl(struct hdp_device *device,
 
        bt_string2uuid(&uuid, HDP_UUID);
        if (bt_search_service(&src, &dst, &uuid, search_cb, conn_data,
-                                               destroy_con_mcl_data)) {
+                                               destroy_con_mcl_data) < 0) {
                g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR,
                                                "Can't get remote SDP record");
                g_free(conn_data);
@@ -1110,7 +1116,7 @@ static void get_dcpsm_cb(sdp_list_t *recs, int err, gpointer data)
        GError *gerr = NULL;
        uint16_t dcpsm;
 
-       if (err || !recs) {
+       if (err < 0 || recs == NULL) {
                g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR,
                                        "Error getting remote SDP records");
                goto fail;
@@ -1134,7 +1140,7 @@ static void free_dcpsm_data(gpointer data)
 {
        struct get_dcpsm_data *dcpsm_data = data;
 
-       if (!dcpsm_data)
+       if (dcpsm_data == NULL)
                return;
 
        if (dcpsm_data->destroy)
@@ -1152,7 +1158,7 @@ gboolean hdp_get_dcpsm(struct hdp_device *device, hdp_continue_dcpsm_f func,
        bdaddr_t dst, src;
        uuid_t uuid;
 
-       device_get_address(device->dev, &dst);
+       device_get_address(device->dev, &dst, NULL);
        adapter_get_address(device_get_adapter(device->dev), &src);
 
        dcpsm_data = g_new0(struct get_dcpsm_data, 1);
@@ -1162,7 +1168,7 @@ gboolean hdp_get_dcpsm(struct hdp_device *device, hdp_continue_dcpsm_f func,
 
        bt_string2uuid(&uuid, HDP_UUID);
        if (bt_search_service(&src, &dst, &uuid, get_dcpsm_cb, dcpsm_data,
-                                                       free_dcpsm_data)) {
+                                                       free_dcpsm_data) < 0) {
                g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR,
                                                "Can't get remote SDP record");
                g_free(dcpsm_data);
@@ -1174,10 +1180,10 @@ gboolean hdp_get_dcpsm(struct hdp_device *device, hdp_continue_dcpsm_f func,
 
 static void hdp_free_application(struct hdp_application *app)
 {
-       if (app->dbus_watcher)
+       if (app->dbus_watcher > 0)
                g_dbus_remove_watch(app->conn, app->dbus_watcher);
 
-       if (app->conn)
+       if (app->conn != NULL)
                dbus_connection_unref(app->conn);
        g_free(app->oname);
        g_free(app->description);
@@ -1187,7 +1193,7 @@ static void hdp_free_application(struct hdp_application *app)
 
 struct hdp_application *hdp_application_ref(struct hdp_application *app)
 {
-       if (!app)
+       if (app == NULL)
                return NULL;
 
        app->ref++;
@@ -1198,10 +1204,10 @@ struct hdp_application *hdp_application_ref(struct hdp_application *app)
 
 void hdp_application_unref(struct hdp_application *app)
 {
-       if (!app)
+       if (app == NULL)
                return;
 
-       app->ref --;
+       app->ref--;
 
        DBG("health_application_unref(%p): ref=%d", app, app->ref);
        if (app->ref > 0)
index fc59f50..35e1196 100644 (file)
@@ -3,9 +3,6 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *  Authors:
- *  Santiago Carot Nemesio <sancane at gmail.com>
- *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
  *
  *  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
index 81fd8df..4c726b6 100644 (file)
@@ -4,10 +4,6 @@
  *
  *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
  *
- *  Authors:
- *  Santiago Carot-Nemesio <sancane at gmail.com>
- *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
- *
  *  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
  *
  */
 
-#include "log.h"
-#include "error.h"
-
 #include <netinet/in.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <unistd.h>
 
-#include "btio.h"
+#include <glib.h>
+
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/l2cap.h>
+
+#include <btio.h>
+#include <log.h>
+#include <error.h>
+
 #include "mcap.h"
 #include "mcap_lib.h"
 #include "mcap_internal.h"
@@ -685,11 +684,10 @@ gboolean mcap_mdl_abort(struct mcap_mdl *mdl, mcap_mdl_notify_cb abort_cb,
 
 static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr)
 {
-       GSList *l;
        struct mcap_mcl *mcl;
 
-       for (l = list; l; l = l->next) {
-               mcl = l->data;
+       for (; list; list = list->next) {
+               mcl = list->data;
 
                if (!bacmp(&mcl->addr, addr))
                        return mcl;
@@ -792,7 +790,7 @@ static void mcap_cache_mcl(struct mcap_mcl *mcl)
                last->ctrl &= ~MCAP_CTRL_CACHED;
                if (last->ctrl & MCAP_CTRL_CONN) {
                        /* We have to release this MCL if */
-                       /* connection is not succesful    */
+                       /* connection is not successful    */
                        last->ctrl |= MCAP_CTRL_FREE;
                } else {
                        mcap_mcl_release(last);
@@ -1126,6 +1124,7 @@ static void process_md_abort_mdl_req(struct mcap_mcl *mcl, void *cmd,
        req = cmd;
        mdl_id = ntohs(req->mdl);
        mcl->state = MCL_CONNECTED;
+       abrt = NULL;
        for (l = mcl->mdls; l; l = l->next) {
                mdl = l->data;
                if (mdl_id == mdl->mdlid && mdl->state == MDL_WAITING) {
@@ -2062,7 +2061,7 @@ struct mcap_instance *mcap_create_instance(bdaddr_t *src,
        /* Initialize random seed to generate mdlids for this instance */
        srand(time(NULL));
 
-       return mcap_instance_ref(mi);;
+       return mcap_instance_ref(mi);
 }
 
 void mcap_release_instance(struct mcap_instance *mi)
index 81f53f1..34a8382 100644 (file)
@@ -5,11 +5,6 @@
  *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
  *  Copyright (C) 2010 Signove
  *
- *  Authors:
- *  Santiago Carot-Nemesio <sancane at gmail.com>
- *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
- *  Elvis Pfützenreuter <epx at signove.com>
- *
  *  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
index f82e967..7b044ef 100644 (file)
@@ -4,10 +4,6 @@
  *
  *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
  *
- *  Authors:
- *  Santiago Carot-Nemesio <sancane at gmail.com>
- *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
- *
  *  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
index 9c1e508..8fcc141 100644 (file)
@@ -4,10 +4,6 @@
  *
  *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
  *
- *  Authors:
- *  Santiago Carot-Nemesio <sancane at gmail.com>
- *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
- *
  *  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
index f4b005a..6d8d66b 100644 (file)
@@ -5,11 +5,6 @@
  *  Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
  *  Copyright (C) 2010 Signove
  *
- *  Authors:
- *  Santiago Carot-Nemesio <sancane at gmail.com>
- *  Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
- *  Elvis Pfützenreuter <epx at signove.com>
- *
  *  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
  *
  */
 
-#include "btio.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include <stdint.h>
 #include <netinet/in.h>
 #include <time.h>
 #include <stdlib.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/l2cap.h>
-#include "../src/adapter.h"
-#include "../src/manager.h"
 #include <sys/ioctl.h>
 
-#include "config.h"
-#include "log.h"
-
 #include <bluetooth/bluetooth.h>
+#include <bluetooth/l2cap.h>
+#include <adapter.h>
+#include <manager.h>
+#include <btio.h>
+#include <log.h>
+
 #include "mcap.h"
 #include "mcap_lib.h"
 #include "mcap_internal.h"
index 4f5076a..a1ecdd7 100644 (file)
@@ -43,7 +43,6 @@
 #include <gdbus.h>
 
 #include "log.h"
-#include "textfile.h"
 #include "uinput.h"
 
 #include "../src/adapter.h"
@@ -90,14 +89,12 @@ struct input_device {
        GSList                  *connections;
 };
 
-GSList *devices = NULL;
+static GSList *devices = NULL;
 
 static struct input_device *find_device_by_path(GSList *list, const char *path)
 {
-       GSList *l;
-
-       for (l = list; l; l = l->next) {
-               struct input_device *idev = l->data;
+       for (; list; list = list->next) {
+               struct input_device *idev = list->data;
 
                if (!strcmp(idev->path, path))
                        return idev;
@@ -108,10 +105,8 @@ static struct input_device *find_device_by_path(GSList *list, const char *path)
 
 static struct input_conn *find_connection(GSList *list, const char *pattern)
 {
-       GSList *l;
-
-       for (l = list; l; l = l->next) {
-               struct input_conn *iconn = l->data;
+       for (; list; list = list->next) {
+               struct input_conn *iconn = list->data;
 
                if (!strcasecmp(iconn->uuid, pattern))
                        return iconn;
@@ -169,10 +164,10 @@ static int uinput_create(char *name)
                if (fd < 0) {
                        fd = open("/dev/misc/uinput", O_RDWR);
                        if (fd < 0) {
-                               err = errno;
+                               err = -errno;
                                error("Can't open input device: %s (%d)",
-                                                       strerror(err), err);
-                               return -err;
+                                                       strerror(-err), -err);
+                               return err;
                        }
                }
        }
@@ -187,12 +182,11 @@ static int uinput_create(char *name)
        dev.id.version = 0x0000;
 
        if (write(fd, &dev, sizeof(dev)) < 0) {
-               err = errno;
+               err = -errno;
                error("Can't write device information: %s (%d)",
-                                               strerror(err), err);
+                                               strerror(-err), -err);
                close(fd);
-               errno = err;
-               return -err;
+               return err;
        }
 
        ioctl(fd, UI_SET_EVBIT, EV_KEY);
@@ -205,12 +199,11 @@ static int uinput_create(char *name)
        ioctl(fd, UI_SET_KEYBIT, KEY_PAGEDOWN);
 
        if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {
-               err = errno;
+               err = -errno;
                error("Can't create uinput device: %s (%d)",
-                                               strerror(err), err);
+                                               strerror(-err), -err);
                close(fd);
-               errno = err;
-               return -err;
+               return err;
        }
 
        return fd;
@@ -247,17 +240,16 @@ static int decode_key(const char *str)
        return key;
 }
 
-static void send_event(int fd, uint16_t type, uint16_t code, int32_t value)
+static int send_event(int fd, uint16_t type, uint16_t code, int32_t value)
 {
        struct uinput_event event;
-       int err;
 
        memset(&event, 0, sizeof(event));
        event.type      = type;
        event.code      = code;
        event.value     = value;
 
-       err = write(fd, &event, sizeof(event));
+       return write(fd, &event, sizeof(event));
 }
 
 static void send_key(int fd, uint16_t key)
@@ -339,9 +331,11 @@ static void rfcomm_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
         */
        fake->uinput = uinput_create(idev->name);
        if (fake->uinput < 0) {
+               int err = fake->uinput;
+
                g_io_channel_shutdown(chan, TRUE, NULL);
                reply = btd_error_failed(iconn->pending_connect,
-                                                       strerror(errno));
+                                                       strerror(-err));
                goto failed;
        }
 
@@ -540,11 +534,11 @@ static int ioctl_connadd(struct hidp_connadd_req *req)
                return -errno;
 
        if (ioctl(ctl, HIDPCONNADD, req) < 0)
-               err = errno;
+               err = -errno;
 
        close(ctl);
 
-       return -err;
+       return err;
 }
 
 static void encrypt_completed(uint8_t status, gpointer user_data)
@@ -602,8 +596,9 @@ static int hidp_add_connection(const struct input_device *idev,
        extract_hid_record(rec, req);
        sdp_record_free(rec);
 
-       read_device_id(src_addr, dst_addr, NULL,
-                               &req->vendor, &req->product, &req->version);
+       req->vendor = btd_device_get_vendor(idev->device);
+       req->product = btd_device_get_product(idev->device);
+       req->version = btd_device_get_version(idev->device);
 
        fake_hid = get_fake_hid(req->vendor, req->product);
        if (fake_hid) {
@@ -685,7 +680,7 @@ static int connection_disconnect(struct input_conn *iconn, uint32_t flags)
        struct fake_input *fake = iconn->fake;
        struct hidp_conndel_req req;
        struct hidp_conninfo ci;
-       int ctl, err;
+       int ctl, err = 0;
 
        /* Fake input disconnect */
        if (fake) {
@@ -711,7 +706,7 @@ static int connection_disconnect(struct input_conn *iconn, uint32_t flags)
        bacpy(&ci.bdaddr, &idev->dst);
        if ((ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) ||
                                (ci.state != BT_CONNECTED)) {
-               errno = ENOTCONN;
+               err = -ENOTCONN;
                goto fail;
        }
 
@@ -719,21 +714,16 @@ static int connection_disconnect(struct input_conn *iconn, uint32_t flags)
        bacpy(&req.bdaddr, &idev->dst);
        req.flags = flags;
        if (ioctl(ctl, HIDPCONNDEL, &req) < 0) {
+               err = -errno;
                error("Can't delete the HID device: %s(%d)",
-                               strerror(errno), errno);
+                               strerror(-err), -err);
                goto fail;
        }
 
-       close(ctl);
-
-       return 0;
-
 fail:
-       err = errno;
        close(ctl);
-       errno = err;
 
-       return -err;
+       return err;
 }
 
 static int disconnect(struct input_device *idev, uint32_t flags)
index a98a080..ede06be 100644 (file)
@@ -69,7 +69,7 @@ static int hid_device_probe(struct btd_device *device, GSList *uuids)
                return -1;
 
        adapter_get_address(adapter, &src);
-       device_get_address(device, &dst);
+       device_get_address(device, &dst, NULL);
 
        return input_device_register(connection, device, path, &src, &dst,
                                HID_UUID, rec->handle, idle_timeout * 60);
@@ -86,7 +86,7 @@ static int headset_probe(struct btd_device *device, GSList *uuids)
        const gchar *path = device_get_path(device);
        const sdp_record_t *record;
        sdp_list_t *protos;
-       uint8_t ch;
+       int ch;
        bdaddr_t src, dst;
 
        DBG("path %s", path);
@@ -112,7 +112,7 @@ static int headset_probe(struct btd_device *device, GSList *uuids)
        }
 
        adapter_get_address(adapter, &src);
-       device_get_address(device, &dst);
+       device_get_address(device, &dst, NULL);
 
        return fake_input_register(connection, device, path, &src, &dst,
                                HSP_HS_UUID, ch);
index d98018b..cea08d1 100644 (file)
@@ -62,6 +62,7 @@ static void connect_event_cb(GIOChannel *chan, GError *err, gpointer data)
 {
        uint16_t psm;
        bdaddr_t src, dst;
+       char address[18];
        GError *gerr = NULL;
        int ret;
 
@@ -82,17 +83,21 @@ static void connect_event_cb(GIOChannel *chan, GError *err, gpointer data)
                return;
        }
 
-       DBG("Incoming connection on PSM %d", psm);
+       ba2str(&dst, address);
+       DBG("Incoming connection from %s on PSM %d", address, psm);
 
        ret = input_device_set_channel(&src, &dst, psm, chan);
        if (ret == 0)
                return;
 
+       error("Refusing input device connect: %s (%d)", strerror(-ret), -ret);
+
        /* Send unplug virtual cable to unknown devices */
        if (ret == -ENOENT && psm == L2CAP_PSM_HIDP_CTRL) {
                unsigned char unplug = 0x15;
-               int err, sk = g_io_channel_unix_get_fd(chan);
-               err = write(sk, &unplug, sizeof(unplug));
+               int sk = g_io_channel_unix_get_fd(chan);
+               if (write(sk, &unplug, sizeof(unplug)) < 0)
+                       error("Unable to send virtual cable unplug");
        }
 
        g_io_channel_shutdown(chan, TRUE, NULL);
@@ -156,7 +161,11 @@ static void confirm_event_cb(GIOChannel *chan, gpointer user_data)
        }
 
        if (server->confirm) {
-               error("Refusing connection: setup in progress");
+               char address[18];
+
+               ba2str(&dst, address);
+               error("Refusing connection from %s: setup in progress",
+                                                               address);
                goto drop;
        }
 
diff --git a/input/sixpair.c b/input/sixpair.c
new file mode 100644 (file)
index 0000000..5c58b9b
--- /dev/null
@@ -0,0 +1,299 @@
+/* To compile
+ * gcc -g -Wall -I../src -I../lib/ -I../include -DSTORAGEDIR=\"/var/lib/bluetooth\" -o sixpair sixpair.c ../src/storage.c ../common/libhelper.a -I../common `pkg-config --libs --cflags glib-2.0 libusb-1.0` -lbluetooth
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <sdp.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp_lib.h>
+#include <glib.h>
+#include <libusb.h>
+
+#include "storage.h"
+
+/* Vendor and product ID for the Sixaxis PS3 controller */
+#define VENDOR 0x054c
+#define PRODUCT 0x0268
+
+#define PS3_PNP_RECORD "3601920900000A000100000900013503191124090004350D35061901000900113503190011090006350909656E09006A0901000900093508350619112409010009000D350F350D350619010009001335031900110901002513576972656C65737320436F6E74726F6C6C65720901012513576972656C65737320436F6E74726F6C6C6572090102251B536F6E7920436F6D707574657220456E7465727461696E6D656E740902000901000902010901000902020800090203082109020428010902052801090206359A35980822259405010904A101A102850175089501150026FF00810375019513150025013500450105091901291381027501950D0600FF8103150026FF0005010901A10075089504350046FF0009300931093209358102C0050175089527090181027508953009019102750895300901B102C0A1028502750895300901B102C0A10285EE750895300901B102C0A10285EF750895300901B102C0C0090207350835060904090901000902082800090209280109020A280109020B09010009020C093E8009020D280009020E2800"
+
+gboolean option_get_master = TRUE;
+char *option_master= NULL;
+gboolean option_store_info = TRUE;
+const char *option_device = NULL;
+gboolean option_quiet = FALSE;
+
+const GOptionEntry options[] = {
+       { "get-master", '\0', 0, G_OPTION_ARG_NONE, &option_get_master, "Get currently set master address", NULL },
+       { "set-master", '\0', 0, G_OPTION_ARG_STRING, &option_master, "Set master address (\"auto\" for automatic)", NULL },
+       { "store-info", '\0', 0, G_OPTION_ARG_NONE, &option_store_info, "Store the HID info into the input database", NULL },
+       { "device", '\0', 0, G_OPTION_ARG_STRING, &option_device, "Only handle one device (default, all supported", NULL },
+       { "quiet", 'q', 0, G_OPTION_ARG_NONE, &option_quiet, "Quieten the output", NULL },
+       { NULL }
+};
+
+static gboolean
+show_master (libusb_device_handle *devh, int itfnum)
+{
+       unsigned char msg[8];
+       int res;
+
+       res = libusb_control_transfer (devh,
+                                      LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
+                                      0x01, 0x03f5, itfnum,
+                                      (void*) msg, sizeof(msg),
+                                      5000);
+
+       if (res < 0) {
+               g_warning ("Getting the master Bluetooth address failed");
+               return FALSE;
+       }
+       g_print ("Current Bluetooth master: %02X:%02X:%02X:%02X:%02X:%02X\n",
+                msg[2], msg[3], msg[4], msg[5], msg[6], msg[7]);
+
+       return TRUE;
+}
+
+static char *
+get_bdaddr (libusb_device_handle *devh, int itfnum)
+{
+       unsigned char msg[17];
+       char *address;
+       int res;
+
+       res = libusb_control_transfer (devh,
+                                      LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
+                                      0x01, 0x03f2, itfnum,
+                                      (void*) msg, sizeof(msg),
+                                      5000);
+
+       if (res < 0) {
+               g_warning ("Getting the device Bluetooth address failed");
+               return NULL;
+       }
+
+       address = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
+                                  msg[4], msg[5], msg[6], msg[7], msg[8], msg[9]);
+
+       if (option_quiet == FALSE) {
+               g_print ("Device Bluetooth address: %s\n", address);
+       }
+
+       return address;
+}
+
+static gboolean
+set_master_bdaddr (libusb_device_handle *devh, int itfnum, char *host)
+{
+       unsigned char msg[8];
+       int mac[6];
+       int res;
+
+       if (sscanf(host, "%X:%X:%X:%X:%X:%X",
+                  &mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) != 6) {
+               return FALSE;
+       }
+
+       msg[0] = 0x01;
+       msg[1] = 0x00;
+       msg[2] = mac[0];
+       msg[3] = mac[1];
+       msg[4] = mac[2];
+       msg[5] = mac[3];
+       msg[6] = mac[4];
+       msg[7] = mac[5];
+
+       res = libusb_control_transfer (devh,
+                                      LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
+                                      0x09, 0x03f5, itfnum,
+                                      (void*) msg, sizeof(msg),
+                                      5000);
+
+       if (res < 0) {
+               g_warning ("Setting the master Bluetooth address failed");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static char *
+get_host_bdaddr (void)
+{
+       FILE *f;
+       int mac[6];
+
+       //FIXME use dbus to get the default adapter
+
+       f = popen("hcitool dev", "r");
+
+       if (f == NULL) {
+               //FIXME
+               return NULL;
+       }
+       if (fscanf(f, "%*s\n%*s %X:%X:%X:%X:%X:%X",
+                  &mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) != 6) {
+               //FIXME
+               return NULL;
+       }
+
+       return g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+static int
+handle_device (libusb_device *dev, struct libusb_config_descriptor *cfg, int itfnum, const struct libusb_interface_descriptor *alt)
+{
+       libusb_device_handle *devh;
+       int res, retval;
+
+       retval = -1;
+
+       if (libusb_open (dev, &devh) < 0) {
+               g_warning ("Can't open device");
+               goto bail;
+       }
+       libusb_detach_kernel_driver (devh, itfnum);
+
+       res = libusb_claim_interface (devh, itfnum);
+       if (res < 0) {
+               g_warning ("Can't claim interface %d", itfnum);
+               goto bail;
+       }
+
+       if (option_get_master != FALSE) {
+               if (show_master (devh, itfnum) == FALSE)
+                       goto bail;
+               retval = 0;
+       }
+
+       if (option_master != NULL) {
+               if (strcmp (option_master, "auto") == 0) {
+                       g_free (option_master);
+                       option_master = get_host_bdaddr ();
+                       if (option_master == NULL) {
+                               g_warning ("Can't get bdaddr from default device");
+                               retval = -1;
+                               goto bail;
+                       }
+               }
+       } else {
+               option_master = get_host_bdaddr ();
+               if (option_master == NULL) {
+                       g_warning ("Can't get bdaddr from default device");
+                       retval = -1;
+                       goto bail;
+               }
+       }
+
+       if (option_store_info != FALSE) {
+               sdp_record_t *rec;
+               char *device;
+               bdaddr_t dst, src;
+
+               device = get_bdaddr (devh, itfnum);
+               if (device == NULL) {
+                       retval = -1;
+                       goto bail;
+               }
+
+               rec = record_from_string (PS3_PNP_RECORD);
+               store_record(option_master, device, rec);
+               write_trust(option_master, device, "[all]", TRUE);
+               store_device_id(option_master, device, 0xffff, 0x054c, 0x0268, 0);
+               str2ba(option_master, &src);
+               str2ba(device, &dst);
+               write_device_profiles(&src, &dst, "");
+               write_device_name(&src, &dst, "PLAYSTATION(R)3 Controller");
+               sdp_record_free(rec);
+
+               if (set_master_bdaddr (devh, itfnum, option_master) == FALSE) {
+                       retval = -1;
+                       goto bail;
+               }
+       }
+
+bail:
+       libusb_release_interface (devh, itfnum);
+       res = libusb_attach_kernel_driver(devh, itfnum);
+       if (res < 0) {
+               //FIXME sometimes the kernel tells us ENOENT, but succeeds anyway...
+               g_warning ("Reattaching the driver failed: %d", res);
+       }
+       if (devh != NULL)
+               libusb_close (devh);
+
+       return retval;
+}
+
+int main (int argc, char **argv)
+{
+       GOptionContext *context;
+       GError *error = NULL;
+       libusb_device **list;
+       ssize_t num_devices, i;
+
+       context = g_option_context_new ("- Manage Sixaxis PS3 controllers");
+       g_option_context_add_main_entries (context, options, NULL);
+       if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) {
+               g_warning ("Couldn't parse command-line options: %s", error->message);
+               return 1;
+       }
+
+       /* Check that the passed bdaddr is correct */
+       if (option_master != NULL && strcmp (option_master, "auto") != 0) {
+               //FIXME check bdaddr
+       }
+
+       libusb_init (NULL);
+
+       /* Find device(s) */
+       num_devices = libusb_get_device_list (NULL, &list);
+       if (num_devices < 0) {
+               g_warning ("libusb_get_device_list failed");
+               return 1;
+       }
+
+       for (i = 0; i < num_devices; i++) {
+               struct libusb_config_descriptor *cfg;
+               libusb_device *dev = list[i];
+               struct libusb_device_descriptor desc;
+               guint8 j;
+
+               if (libusb_get_device_descriptor (dev, &desc) < 0) {
+                       g_warning ("libusb_get_device_descriptor failed");
+                       continue;
+               }
+
+               /* Here we check for the supported devices */
+               if (desc.idVendor != VENDOR || desc.idProduct != PRODUCT)
+                       continue;
+
+               /* Look for the interface number that interests us */
+               for (j = 0; j < desc.bNumConfigurations; j++) {
+                       struct libusb_config_descriptor *config;
+                       guint8 k;
+
+                       libusb_get_config_descriptor (dev, j, &config);
+
+                       for (k = 0; k < config->bNumInterfaces; k++) {
+                               const struct libusb_interface *itf = &config->interface[k];
+                               int l;
+
+                               for (l = 0; l < itf->num_altsetting ; l++) {
+                                       struct libusb_interface_descriptor alt;
+
+                                       alt = itf->altsetting[l];
+                                       if (alt.bInterfaceClass == 3) {
+                                               handle_device (dev, cfg, l, &alt);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
index 72ee456..cb2e6c1 100644 (file)
@@ -462,6 +462,42 @@ char *bt_compidtostr(int compid)
                return "RDA Microelectronics";
        case 98:
                return "Gibson Guitars";
+       case 99:
+               return "MiCommand Inc.";
+       case 100:
+               return "Band XI International, LLC";
+       case 101:
+               return "Hewlett-Packard Company";
+       case 102:
+               return "9Solutions Oy";
+       case 103:
+               return "GN Netcom A/S";
+       case 104:
+               return "General Motors";
+       case 105:
+               return "A&D Engineering, Inc.";
+       case 106:
+               return "MindTree Ltd.";
+       case 107:
+               return "Polar Electro OY";
+       case 108:
+               return "Beautiful Enterprise Co., Ltd.";
+       case 109:
+               return "BriarTek, Inc.";
+       case 110:
+               return "Summit Data Communications, Inc.";
+       case 111:
+               return "Sound ID";
+       case 112:
+               return "Monster, LLC";
+       case 113:
+               return "connectBlue AB";
+       case 114:
+               return "ShangHai Super Smart Electronics Co. Ltd.";
+       case 115:
+               return "Group Sense Ltd.";
+       case 116:
+               return "Zomm, LLC";
        case 65535:
                return "internal use";
        default:
index 738e07a..5bd4f03 100644 (file)
@@ -93,13 +93,17 @@ enum {
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 #define htobs(d)  (d)
 #define htobl(d)  (d)
+#define htobll(d) (d)
 #define btohs(d)  (d)
 #define btohl(d)  (d)
+#define btohll(d) (d)
 #elif __BYTE_ORDER == __BIG_ENDIAN
 #define htobs(d)  bswap_16(d)
 #define htobl(d)  bswap_32(d)
+#define htobll(d) bswap_64(d)
 #define btohs(d)  bswap_16(d)
 #define btohl(d)  bswap_32(d)
+#define btohll(d) bswap_64(d)
 #else
 #error "Unknown byte order"
 #endif
@@ -121,6 +125,70 @@ do {                                               \
        __p->__v = (val);                       \
 } while(0)
 
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+static inline uint64_t bt_get_le64(void *ptr)
+{
+       return bt_get_unaligned((uint64_t *) ptr);
+}
+
+static inline uint64_t bt_get_be64(void *ptr)
+{
+       return bswap_64(bt_get_unaligned((uint64_t *) ptr));
+}
+
+static inline uint32_t bt_get_le32(void *ptr)
+{
+       return bt_get_unaligned((uint32_t *) ptr);
+}
+
+static inline uint32_t bt_get_be32(void *ptr)
+{
+       return bswap_32(bt_get_unaligned((uint32_t *) ptr));
+}
+
+static inline uint16_t bt_get_le16(void *ptr)
+{
+       return bt_get_unaligned((uint16_t *) ptr);
+}
+
+static inline uint16_t bt_get_be16(void *ptr)
+{
+       return bswap_16(bt_get_unaligned((uint16_t *) ptr));
+}
+#elif __BYTE_ORDER == __BIG_ENDIAN
+static inline uint64_t bt_get_le64(void *ptr)
+{
+       return bswap_64(bt_get_unaligned((uint64_t *) ptr));
+}
+
+static inline uint64_t bt_get_be64(void *ptr)
+{
+       return bt_get_unaligned((uint64_t *) ptr);
+}
+
+static inline uint32_t bt_get_le32(void *ptr)
+{
+       return bswap_32(bt_get_unaligned((uint32_t *) ptr));
+}
+
+static inline uint32_t bt_get_be32(void *ptr)
+{
+       return bt_get_unaligned((uint32_t *) ptr);
+}
+
+static inline uint16_t bt_get_le16(void *ptr)
+{
+       return bswap_16(bt_get_unaligned((uint16_t *) ptr));
+}
+
+static inline uint16_t bt_get_be16(void *ptr)
+{
+       return bt_get_unaligned((uint16_t *) ptr);
+}
+#else
+#error "Unknown byte order"
+#endif
+
 /* BD Address */
 typedef struct {
        uint8_t b[6];
index eb00730..b122313 100644 (file)
--- a/lib/hci.c
+++ b/lib/hci.c
@@ -2291,7 +2291,7 @@ int hci_read_ext_inquiry_response(int dd, uint8_t *fec, uint8_t *data, int to)
        }
 
        *fec = rp.fec;
-       memcpy(data, rp.data, 240);
+       memcpy(data, rp.data, HCI_MAX_EIR_LENGTH);
 
        return 0;
 }
@@ -2304,7 +2304,7 @@ int hci_write_ext_inquiry_response(int dd, uint8_t fec, uint8_t *data, int to)
 
        memset(&cp, 0, sizeof(cp));
        cp.fec = fec;
-       memcpy(cp.data, data, 240);
+       memcpy(cp.data, data, HCI_MAX_EIR_LENGTH);
 
        memset(&rq, 0, sizeof(rq));
        rq.ogf    = OGF_HOST_CTL;
index d2d4f77..48692fa 100644 (file)
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -791,16 +791,18 @@ typedef struct {
 } __attribute__ ((packed)) delete_stored_link_key_rp;
 #define DELETE_STORED_LINK_KEY_RP_SIZE 3
 
+#define HCI_MAX_NAME_LENGTH            248
+
 #define OCF_CHANGE_LOCAL_NAME          0x0013
 typedef struct {
-       uint8_t         name[248];
+       uint8_t         name[HCI_MAX_NAME_LENGTH];
 } __attribute__ ((packed)) change_local_name_cp;
 #define CHANGE_LOCAL_NAME_CP_SIZE 248
 
 #define OCF_READ_LOCAL_NAME            0x0014
 typedef struct {
        uint8_t         status;
-       uint8_t         name[248];
+       uint8_t         name[HCI_MAX_NAME_LENGTH];
 } __attribute__ ((packed)) read_local_name_rp;
 #define READ_LOCAL_NAME_RP_SIZE 249
 
@@ -1071,18 +1073,20 @@ typedef struct {
 } __attribute__ ((packed)) write_afh_mode_rp;
 #define WRITE_AFH_MODE_RP_SIZE 1
 
+#define HCI_MAX_EIR_LENGTH             240
+
 #define OCF_READ_EXT_INQUIRY_RESPONSE  0x0051
 typedef struct {
        uint8_t         status;
        uint8_t         fec;
-       uint8_t         data[240];
+       uint8_t         data[HCI_MAX_EIR_LENGTH];
 } __attribute__ ((packed)) read_ext_inquiry_response_rp;
 #define READ_EXT_INQUIRY_RESPONSE_RP_SIZE 242
 
 #define OCF_WRITE_EXT_INQUIRY_RESPONSE 0x0052
 typedef struct {
        uint8_t         fec;
-       uint8_t         data[240];
+       uint8_t         data[HCI_MAX_EIR_LENGTH];
 } __attribute__ ((packed)) write_ext_inquiry_response_cp;
 #define WRITE_EXT_INQUIRY_RESPONSE_CP_SIZE 241
 typedef struct {
@@ -1378,24 +1382,23 @@ typedef struct {
 #define OCF_READ_LOCAL_AMP_ASSOC       0x000A
 typedef struct {
        uint8_t         handle;
-       uint16_t        length_so_far;
-       uint16_t        assoc_length;
+       uint16_t        len_so_far;
+       uint16_t        max_len;
 } __attribute__ ((packed)) read_local_amp_assoc_cp;
-#define READ_LOCAL_AMP_ASSOC_CP_SIZE 5
+
 typedef struct {
        uint8_t         status;
        uint8_t         handle;
-       uint16_t        length;
-       uint8_t         fragment[248];
+       uint16_t        rem_len;
+       uint8_t         frag[0];
 } __attribute__ ((packed)) read_local_amp_assoc_rp;
-#define READ_LOCAL_AMP_ASSOC_RP_SIZE 252
 
 #define OCF_WRITE_REMOTE_AMP_ASSOC     0x000B
 typedef struct {
        uint8_t         handle;
        uint16_t        length_so_far;
        uint16_t        assoc_length;
-       uint8_t         fragment[248];
+       uint8_t         fragment[HCI_MAX_NAME_LENGTH];
 } __attribute__ ((packed)) write_remote_amp_assoc_cp;
 #define WRITE_REMOTE_AMP_ASSOC_CP_SIZE 253
 typedef struct {
@@ -1722,7 +1725,7 @@ typedef struct {
 typedef struct {
        uint8_t         status;
        bdaddr_t        bdaddr;
-       uint8_t         name[248];
+       uint8_t         name[HCI_MAX_NAME_LENGTH];
 } __attribute__ ((packed)) evt_remote_name_req_complete;
 #define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255
 
@@ -1983,7 +1986,7 @@ typedef struct {
        uint8_t         dev_class[3];
        uint16_t        clock_offset;
        int8_t          rssi;
-       uint8_t         data[240];
+       uint8_t         data[HCI_MAX_EIR_LENGTH];
 } __attribute__ ((packed)) extended_inquiry_info;
 #define EXTENDED_INQUIRY_INFO_SIZE 254
 
index e59cfdd..68593d3 100644 (file)
@@ -83,6 +83,23 @@ struct l2cap_conninfo {
 #define L2CAP_INFO_REQ         0x0a
 #define L2CAP_INFO_RSP         0x0b
 
+/* L2CAP extended feature mask */
+#define L2CAP_FEAT_FLOWCTL     0x00000001
+#define L2CAP_FEAT_RETRANS     0x00000002
+#define L2CAP_FEAT_BIDIR_QOS   0x00000004
+#define L2CAP_FEAT_ERTM                0x00000008
+#define L2CAP_FEAT_STREAMING   0x00000010
+#define L2CAP_FEAT_FCS         0x00000020
+#define L2CAP_FEAT_EXT_FLOW    0x00000040
+#define L2CAP_FEAT_FIXED_CHAN  0x00000080
+#define L2CAP_FEAT_EXT_WINDOW  0x00000100
+#define L2CAP_FEAT_UCD         0x00000200
+
+/* L2CAP fixed channels */
+#define L2CAP_FC_L2CAP         0x02
+#define L2CAP_FC_CONNLESS      0x04
+#define L2CAP_FC_A2MP          0x08
+
 /* L2CAP structures */
 typedef struct {
        uint16_t        len;
@@ -147,6 +164,8 @@ typedef struct {
 #define L2CAP_CONF_UNACCEPT    0x0001
 #define L2CAP_CONF_REJECT      0x0002
 #define L2CAP_CONF_UNKNOWN     0x0003
+#define L2CAP_CONF_PENDING     0x0004
+#define L2CAP_CONF_EFS_REJECT  0x0005
 
 typedef struct {
        uint8_t         type;
@@ -160,6 +179,8 @@ typedef struct {
 #define L2CAP_CONF_QOS         0x03
 #define L2CAP_CONF_RFC         0x04
 #define L2CAP_CONF_FCS         0x05
+#define L2CAP_CONF_EFS         0x06
+#define L2CAP_CONF_EWS         0x07
 
 #define L2CAP_CONF_MAX_SIZE    22
 
@@ -169,6 +190,10 @@ typedef struct {
 #define L2CAP_MODE_ERTM                0x03
 #define L2CAP_MODE_STREAMING   0x04
 
+#define L2CAP_SERVTYPE_NOTRAFFIC       0x00
+#define L2CAP_SERVTYPE_BESTEFFORT      0x01
+#define L2CAP_SERVTYPE_GUARANTEED      0x02
+
 typedef struct {
        uint16_t        dcid;
        uint16_t        scid;
index bd65328..f121b12 100644 (file)
@@ -51,21 +51,32 @@ struct mgmt_rp_read_index_list {
        uint16_t index[0];
 } __packed;
 
+/* Reserve one extra byte for names in management messages so that they
+ * are always guaranteed to be nul-terminated */
+#define MGMT_MAX_NAME_LENGTH           (HCI_MAX_NAME_LENGTH + 1)
+#define MGMT_MAX_SHORT_NAME_LENGTH     (10 + 1)
+
+#define MGMT_SETTING_POWERED           0x00000001
+#define MGMT_SETTING_CONNECTABLE       0x00000002
+#define MGMT_SETTING_FAST_CONNECTABLE  0x00000004
+#define MGMT_SETTING_DISCOVERABLE      0x00000008
+#define MGMT_SETTING_PAIRABLE          0x00000010
+#define MGMT_SETTING_LINK_SECURITY     0x00000020
+#define MGMT_SETTING_SSP               0x00000040
+#define MGMT_SETTING_BREDR             0x00000080
+#define MGMT_SETTING_HS                        0x00000100
+#define MGMT_SETTING_LE                        0x00000200
+
 #define MGMT_OP_READ_INFO              0x0004
 struct mgmt_rp_read_info {
-       uint8_t type;
-       uint8_t powered;
-       uint8_t connectable;
-       uint8_t discoverable;
-       uint8_t pairable;
-       uint8_t sec_mode;
        bdaddr_t bdaddr;
-       uint8_t dev_class[3];
-       uint8_t features[8];
+       uint8_t version;
        uint16_t manufacturer;
-       uint8_t hci_ver;
-       uint16_t hci_rev;
-       uint8_t name[249];
+       uint32_t supported_settings;
+       uint32_t current_settings;
+       uint8_t dev_class[3];
+       uint8_t name[MGMT_MAX_NAME_LENGTH];
+       uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH];
 } __packed;
 
 struct mgmt_mode {
@@ -75,95 +86,125 @@ struct mgmt_mode {
 #define MGMT_OP_SET_POWERED            0x0005
 
 #define MGMT_OP_SET_DISCOVERABLE       0x0006
+struct mgmt_cp_set_discoverable {
+       uint8_t val;
+       uint16_t timeout;
+} __packed;
 
 #define MGMT_OP_SET_CONNECTABLE                0x0007
 
-#define MGMT_OP_SET_PAIRABLE           0x0008
+#define MGMT_OP_SET_FAST_CONNECTABLE   0x0008
 
-#define MGMT_OP_ADD_UUID               0x0009
-struct mgmt_cp_add_uuid {
-       uint8_t uuid[16];
-       uint8_t svc_hint;
-} __packed;
+#define MGMT_OP_SET_PAIRABLE           0x0009
 
-#define MGMT_OP_REMOVE_UUID            0x000A
-struct mgmt_cp_remove_uuid {
-       uint8_t uuid[16];
-} __packed;
+#define MGMT_OP_SET_LINK_SECURITY      0x000A
+
+#define MGMT_OP_SET_SSP                        0x000B
+
+#define MGMT_OP_SET_HS                 0x000C
+
+#define MGMT_OP_SET_LE                 0x000D
 
-#define MGMT_OP_SET_DEV_CLASS          0x000B
+#define MGMT_OP_SET_DEV_CLASS          0x000E
 struct mgmt_cp_set_dev_class {
        uint8_t major;
        uint8_t minor;
 } __packed;
 
-#define MGMT_OP_SET_SERVICE_CACHE      0x000C
-struct mgmt_cp_set_service_cache {
-       uint8_t enable;
+#define MGMT_OP_SET_LOCAL_NAME         0x000F
+struct mgmt_cp_set_local_name {
+       uint8_t name[MGMT_MAX_NAME_LENGTH];
+       uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH];
+} __packed;
+
+#define MGMT_OP_ADD_UUID               0x0010
+struct mgmt_cp_add_uuid {
+       uint8_t uuid[16];
+       uint8_t svc_hint;
+} __packed;
+
+#define MGMT_OP_REMOVE_UUID            0x0011
+struct mgmt_cp_remove_uuid {
+       uint8_t uuid[16];
 } __packed;
 
-struct mgmt_key_info {
+struct mgmt_link_key_info {
        bdaddr_t bdaddr;
        uint8_t type;
        uint8_t val[16];
        uint8_t pin_len;
 } __packed;
 
-#define MGMT_OP_LOAD_KEYS              0x000D
-struct mgmt_cp_load_keys {
+#define MGMT_OP_LOAD_LINK_KEYS         0x0012
+struct mgmt_cp_load_link_keys {
        uint8_t debug_keys;
        uint16_t key_count;
-       struct mgmt_key_info keys[0];
+       struct mgmt_link_key_info keys[0];
 } __packed;
 
-#define MGMT_OP_REMOVE_KEY             0x000E
-struct mgmt_cp_remove_key {
+#define MGMT_OP_REMOVE_KEYS            0x0013
+struct mgmt_cp_remove_keys {
        bdaddr_t bdaddr;
        uint8_t disconnect;
 } __packed;
+struct mgmt_rp_remove_keys {
+       bdaddr_t bdaddr;
+       uint8_t status;
+} __packed;
 
-#define MGMT_OP_DISCONNECT             0x000F
+#define MGMT_OP_DISCONNECT             0x0014
 struct mgmt_cp_disconnect {
        bdaddr_t bdaddr;
 } __packed;
 struct mgmt_rp_disconnect {
        bdaddr_t bdaddr;
+       uint8_t status;
+} __packed;
+
+#define MGMT_ADDR_BREDR                        0x00
+#define MGMT_ADDR_LE_PUBLIC            0x01
+#define MGMT_ADDR_LE_RANDOM            0x02
+#define MGMT_ADDR_INVALID              0xff
+
+struct mgmt_addr_info {
+       bdaddr_t bdaddr;
+       uint8_t type;
 } __packed;
 
-#define MGMT_OP_GET_CONNECTIONS                0x0010
+#define MGMT_OP_GET_CONNECTIONS                0x0015
 struct mgmt_rp_get_connections {
        uint16_t conn_count;
-       bdaddr_t conn[0];
+       struct mgmt_addr_info addr[0];
 } __packed;
 
-#define MGMT_OP_PIN_CODE_REPLY         0x0011
+#define MGMT_OP_PIN_CODE_REPLY         0x0016
 struct mgmt_cp_pin_code_reply {
        bdaddr_t bdaddr;
        uint8_t pin_len;
        uint8_t pin_code[16];
 } __packed;
 
-#define MGMT_OP_PIN_CODE_NEG_REPLY     0x0012
+#define MGMT_OP_PIN_CODE_NEG_REPLY     0x0017
 struct mgmt_cp_pin_code_neg_reply {
        bdaddr_t bdaddr;
 } __packed;
 
-#define MGMT_OP_SET_IO_CAPABILITY      0x0013
+#define MGMT_OP_SET_IO_CAPABILITY      0x0018
 struct mgmt_cp_set_io_capability {
        uint8_t io_capability;
 } __packed;
 
-#define MGMT_OP_PAIR_DEVICE            0x0014
+#define MGMT_OP_PAIR_DEVICE            0x0019
 struct mgmt_cp_pair_device {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        uint8_t io_cap;
 } __packed;
 struct mgmt_rp_pair_device {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        uint8_t status;
 } __packed;
 
-#define MGMT_OP_USER_CONFIRM_REPLY     0x0015
+#define MGMT_OP_USER_CONFIRM_REPLY     0x001A
 struct mgmt_cp_user_confirm_reply {
        bdaddr_t bdaddr;
 } __packed;
@@ -172,11 +213,66 @@ struct mgmt_rp_user_confirm_reply {
        uint8_t status;
 } __packed;
 
-#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x0016
+#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x001B
 
-#define MGMT_OP_SET_LOCAL_NAME         0x0017
-struct mgmt_cp_set_local_name {
-       uint8_t name[249];
+#define MGMT_OP_USER_PASSKEY_REPLY     0x001C
+struct mgmt_cp_user_passkey_reply {
+       bdaddr_t bdaddr;
+       uint32_t passkey;
+} __packed;
+struct mgmt_rp_user_passkey_reply {
+       bdaddr_t bdaddr;
+       uint8_t status;
+} __packed;
+
+#define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x001D
+struct mgmt_cp_user_passkey_neg_reply {
+       bdaddr_t bdaddr;
+} __packed;
+
+#define MGMT_OP_READ_LOCAL_OOB_DATA    0x001E
+struct mgmt_rp_read_local_oob_data {
+       uint8_t hash[16];
+       uint8_t randomizer[16];
+} __packed;
+
+#define MGMT_OP_ADD_REMOTE_OOB_DATA    0x001F
+struct mgmt_cp_add_remote_oob_data {
+       bdaddr_t bdaddr;
+       uint8_t hash[16];
+       uint8_t randomizer[16];
+} __packed;
+
+#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0020
+struct mgmt_cp_remove_remote_oob_data {
+       bdaddr_t bdaddr;
+} __packed;
+
+#define MGMT_OP_START_DISCOVERY                0x0021
+struct mgmt_cp_start_discovery {
+       uint8_t type;
+} __packed;
+
+#define MGMT_OP_STOP_DISCOVERY         0x0022
+
+#define MGMT_OP_CONFIRM_NAME           0x0023
+struct mgmt_cp_confirm_name {
+       bdaddr_t bdaddr;
+       uint8_t name_known;
+} __packed;
+struct mgmt_rp_confirm_name {
+       bdaddr_t bdaddr;
+       uint8_t status;
+} __packed;
+
+#define MGMT_OP_BLOCK_DEVICE           0x0024
+struct mgmt_cp_block_device {
+       bdaddr_t bdaddr;
+} __packed;
+
+#define MGMT_OP_UNBLOCK_DEVICE         0x0025
+struct mgmt_cp_unblock_device {
+       bdaddr_t bdaddr;
 } __packed;
 
 #define MGMT_EV_CMD_COMPLETE           0x0001
@@ -200,54 +296,82 @@ struct mgmt_ev_controller_error {
 
 #define MGMT_EV_INDEX_REMOVED          0x0005
 
-#define MGMT_EV_POWERED                        0x0006
-
-#define MGMT_EV_DISCOVERABLE           0x0007
+#define MGMT_EV_NEW_SETTINGS           0x0006
 
-#define MGMT_EV_CONNECTABLE            0x0008
-
-#define MGMT_EV_PAIRABLE               0x0009
-
-#define MGMT_EV_NEW_KEY                        0x000A
-struct mgmt_ev_new_key {
-       struct mgmt_key_info key;
-       uint8_t old_key_type;
+#define MGMT_EV_CLASS_OF_DEV_CHANGED   0x0007
+struct mgmt_ev_class_of_dev_changed {
+       uint8_t class_of_dev[3];
 } __packed;
 
-#define MGMT_EV_DEVICE_CONNECTED       0x000B
-struct mgmt_ev_device_connected {
-       bdaddr_t bdaddr;
+#define MGMT_EV_LOCAL_NAME_CHANGED     0x0008
+struct mgmt_ev_local_name_changed {
+       uint8_t name[MGMT_MAX_NAME_LENGTH];
+       uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH];
 } __packed;
 
-#define MGMT_EV_DEVICE_DISCONNECTED    0x000C
-struct mgmt_ev_device_disconnected {
-       bdaddr_t bdaddr;
+#define MGMT_EV_NEW_LINK_KEY           0x0009
+struct mgmt_ev_new_link_key {
+       uint8_t store_hint;
+       struct mgmt_link_key_info key;
 } __packed;
 
-#define MGMT_EV_CONNECT_FAILED         0x000D
+#define MGMT_EV_DEVICE_CONNECTED       0x000A
+
+#define MGMT_EV_DEVICE_DISCONNECTED    0x000B
+
+#define MGMT_EV_CONNECT_FAILED         0x000C
 struct mgmt_ev_connect_failed {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        uint8_t status;
 } __packed;
 
-#define MGMT_EV_PIN_CODE_REQUEST       0x000E
+#define MGMT_EV_PIN_CODE_REQUEST       0x000D
 struct mgmt_ev_pin_code_request {
        bdaddr_t bdaddr;
+       uint8_t secure;
 } __packed;
 
-#define MGMT_EV_USER_CONFIRM_REQUEST   0x000F
+#define MGMT_EV_USER_CONFIRM_REQUEST   0x000E
 struct mgmt_ev_user_confirm_request {
        bdaddr_t bdaddr;
+       uint8_t confirm_hint;
        uint32_t value;
 } __packed;
 
+#define MGMT_EV_USER_PASSKEY_REQUEST   0x000F
+struct mgmt_ev_user_passkey_request {
+       bdaddr_t bdaddr;
+} __packed;
+
 #define MGMT_EV_AUTH_FAILED            0x0010
 struct mgmt_ev_auth_failed {
        bdaddr_t bdaddr;
        uint8_t status;
 } __packed;
 
-#define MGMT_EV_LOCAL_NAME_CHANGED     0x0011
-struct mgmt_ev_local_name_changed {
-       uint8_t name[249];
+#define MGMT_EV_DEVICE_FOUND           0x0011
+struct mgmt_ev_device_found {
+       struct mgmt_addr_info addr;
+       uint8_t dev_class[3];
+       int8_t rssi;
+       uint8_t confirm_name;
+       uint8_t eir[HCI_MAX_EIR_LENGTH];
+} __packed;
+
+#define MGMT_EV_REMOTE_NAME            0x0012
+struct mgmt_ev_remote_name {
+       bdaddr_t bdaddr;
+       uint8_t name[MGMT_MAX_NAME_LENGTH];
+} __packed;
+
+#define MGMT_EV_DISCOVERING            0x0013
+
+#define MGMT_EV_DEVICE_BLOCKED         0x0014
+struct mgmt_ev_device_blocked {
+       bdaddr_t bdaddr;
+} __packed;
+
+#define MGMT_EV_DEVICE_UNBLOCKED       0x0015
+struct mgmt_ev_device_unblocked {
+       bdaddr_t bdaddr;
 } __packed;
index e1108e1..a48ee14 100644 (file)
--- a/lib/sdp.c
+++ b/lib/sdp.c
@@ -673,7 +673,7 @@ static int sdp_set_data_type(sdp_buf_t *buf, uint8_t dtd)
        int data_type = 0;
        uint8_t *p = buf->data + buf->data_size;
 
-       *p++ = dtd;
+       *p = dtd;
        data_type = sdp_get_data_type(buf, dtd);
        buf->data_size += data_type;
 
@@ -688,7 +688,6 @@ void sdp_set_attrid(sdp_buf_t *buf, uint16_t attr)
        *p++ = SDP_UINT16;
        buf->data_size = sizeof(uint8_t);
        bt_put_unaligned(htons(attr), (uint16_t *) p);
-       p += sizeof(uint16_t);
        buf->data_size += sizeof(uint16_t);
 }
 
@@ -900,7 +899,7 @@ int sdp_gen_pdu(sdp_buf_t *buf, sdp_data_t *d)
        }
 
        if (!is_seq && !is_alt) {
-               if (src && buf && buf->buf_size >= buf->data_size + data_size) {
+               if (src && buf->buf_size >= buf->data_size + data_size) {
                        memcpy(buf->data + buf->data_size, src, data_size);
                        buf->data_size += data_size;
                } else if (dtd != SDP_DATA_NIL) {
@@ -1021,7 +1020,6 @@ int sdp_uuid_extract(const uint8_t *p, int bufsize, uuid_t *uuid, int *scanned)
                }
                sdp_uuid16_create(uuid, ntohs(bt_get_unaligned((uint16_t *) p)));
                *scanned += sizeof(uint16_t);
-               p += sizeof(uint16_t);
        } else if (type == SDP_UUID32) {
                if (bufsize < (int) sizeof(uint32_t)) {
                        SDPERR("Not enough room for 32-bit UUID");
@@ -1029,7 +1027,6 @@ int sdp_uuid_extract(const uint8_t *p, int bufsize, uuid_t *uuid, int *scanned)
                }
                sdp_uuid32_create(uuid, ntohl(bt_get_unaligned((uint32_t *) p)));
                *scanned += sizeof(uint32_t);
-               p += sizeof(uint32_t);
        } else {
                if (bufsize < (int) sizeof(uint128_t)) {
                        SDPERR("Not enough room for 128-bit UUID");
@@ -1037,7 +1034,6 @@ int sdp_uuid_extract(const uint8_t *p, int bufsize, uuid_t *uuid, int *scanned)
                }
                sdp_uuid128_create(uuid, p);
                *scanned += sizeof(uint128_t);
-               p += sizeof(uint128_t);
        }
        return 0;
 }
@@ -1798,7 +1794,7 @@ sdp_list_t *sdp_list_insert_sorted(sdp_list_t *list, void *d,
        for (q = 0, p = list; p; q = p, p = p->next)
                if (f(p->data, d) >= 0)
                        break;
-       // insert between q and p; if !q insert at head
+       /* insert between q and p; if !q insert at head */
        if (q)
                q->next = n;
        else
@@ -2021,25 +2017,34 @@ int sdp_get_lang_attr(const sdp_record_t *rec, sdp_list_t **langSeq)
        curr_data = sdpdata->val.dataseq;
        while (curr_data) {
                sdp_data_t *pCode = curr_data;
-               sdp_data_t *pEncoding = pCode->next;
-               sdp_data_t *pOffset = pEncoding->next;
-               if (pEncoding && pOffset) {
-                       lang = malloc(sizeof(sdp_lang_attr_t));
-                       if (!lang) {
-                               sdp_list_free(*langSeq, free);
-                               *langSeq = NULL;
-                               return -1;
-                       }
-                       lang->code_ISO639 = pCode->val.uint16;
-                       lang->encoding = pEncoding->val.uint16;
-                       lang->base_offset = pOffset->val.uint16;
-                       SDPDBG("code_ISO639 :  0x%02x\n", lang->code_ISO639);
-                       SDPDBG("encoding :     0x%02x\n", lang->encoding);
-                       SDPDBG("base_offfset : 0x%02x\n", lang->base_offset);
-                       *langSeq = sdp_list_append(*langSeq, lang);
+               sdp_data_t *pEncoding;
+               sdp_data_t *pOffset;
+
+               pEncoding = pCode->next;
+               if (!pEncoding)
+                       break;
+
+               pOffset = pEncoding->next;
+               if (!pOffset)
+                       break;
+
+               lang = malloc(sizeof(sdp_lang_attr_t));
+               if (!lang) {
+                       sdp_list_free(*langSeq, free);
+                       *langSeq = NULL;
+                       return -1;
                }
+               lang->code_ISO639 = pCode->val.uint16;
+               lang->encoding = pEncoding->val.uint16;
+               lang->base_offset = pOffset->val.uint16;
+               SDPDBG("code_ISO639 :  0x%02x\n", lang->code_ISO639);
+               SDPDBG("encoding :     0x%02x\n", lang->encoding);
+               SDPDBG("base_offfset : 0x%02x\n", lang->base_offset);
+               *langSeq = sdp_list_append(*langSeq, lang);
+
                curr_data = pOffset->next;
        }
+
        return 0;
 }
 
@@ -2757,10 +2762,8 @@ void sdp_append_to_buf(sdp_buf_t *dst, uint8_t *data, uint32_t len)
        if (dst->data_size == 0 && dtd == 0) {
                /* create initial sequence */
                *p = SDP_SEQ8;
-               p += sizeof(uint8_t);
                dst->data_size += sizeof(uint8_t);
                /* reserve space for sequence size */
-               p += sizeof(uint8_t);
                dst->data_size += sizeof(uint8_t);
        }
 
@@ -2772,12 +2775,9 @@ void sdp_append_to_buf(sdp_buf_t *dst, uint8_t *data, uint32_t len)
                short offset = sizeof(uint8_t) + sizeof(uint8_t);
                memmove(dst->data + offset + 1, dst->data + offset,
                                                dst->data_size - offset);
-               p = dst->data;
                *p = SDP_SEQ16;
-               p += sizeof(uint8_t);
                dst->data_size += 1;
        }
-       p = dst->data;
        dtd = *(uint8_t *) p;
        p += sizeof(uint8_t);
        switch (dtd) {
@@ -3111,7 +3111,7 @@ int sdp_record_update(sdp_session_t *session, const sdp_record_t *rec)
        return sdp_device_record_update(session, BDADDR_ANY, rec);
 }
 
-sdp_record_t *sdp_record_alloc()
+sdp_record_t *sdp_record_alloc(void)
 {
        sdp_record_t *rec = malloc(sizeof(sdp_record_t));
 
@@ -3196,7 +3196,7 @@ static int gen_dataseq_pdu(uint8_t *dst, const sdp_list_t *seq, uint8_t dtd)
        sdp_buf_t buf;
        int i, seqlen = sdp_list_len(seq);
 
-       // Fill up the value and the dtd arrays
+       /* Fill up the value and the dtd arrays */
        SDPDBG("");
 
        SDPDBG("Seq length : %d\n", seqlen);
@@ -3319,7 +3319,7 @@ int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search,
        uint32_t reqsize = 0, _reqsize;
        uint32_t rspsize = 0, rsplen;
        int seqlen = 0;
-       int total_rec_count, rec_count;
+       int rec_count;
        unsigned scanned, pdata_len;
        uint8_t *pdata, *_pdata;
        uint8_t *reqbuf, *rspbuf;
@@ -3338,16 +3338,16 @@ int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search,
        pdata = reqbuf + sizeof(sdp_pdu_hdr_t);
        reqsize = sizeof(sdp_pdu_hdr_t);
 
-       // add service class IDs for search
+       /* add service class IDs for search */
        seqlen = gen_searchseq_pdu(pdata, search);
 
        SDPDBG("Data seq added : %d\n", seqlen);
 
-       // set the length and increment the pointer
+       /* set the length and increment the pointer */
        reqsize += seqlen;
        pdata += seqlen;
 
-       // specify the maximum svc rec count that client expects
+       /* specify the maximum svc rec count that client expects */
        bt_put_unaligned(htons(max_rec_num), (uint16_t *) pdata);
        reqsize += sizeof(uint16_t);
        pdata += sizeof(uint16_t);
@@ -3357,11 +3357,11 @@ int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search,
        *rsp = NULL;
 
        do {
-               // Add continuation state or NULL (first time)
+               /* Add continuation state or NULL (first time) */
                reqsize = _reqsize + copy_cstate(_pdata,
                                        SDP_REQ_BUFFER_SIZE - _reqsize, cstate);
 
-               // Set the request header's param length
+               /* Set the request header's param length */
                reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));
 
                reqhdr->tid  = htons(sdp_gen_tid(session));
@@ -3397,8 +3397,7 @@ int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search,
                        goto end;
                }
 
-               // net service record match count
-               total_rec_count = ntohs(bt_get_unaligned((uint16_t *) pdata));
+               /* net service record match count */
                pdata += sizeof(uint16_t);
                scanned += sizeof(uint16_t);
                pdata_len -= sizeof(uint16_t);
@@ -3511,17 +3510,17 @@ sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle,
        pdata = reqbuf + sizeof(sdp_pdu_hdr_t);
        reqsize = sizeof(sdp_pdu_hdr_t);
 
-       // add the service record handle
+       /* add the service record handle */
        bt_put_unaligned(htonl(handle), (uint32_t *) pdata);
        reqsize += sizeof(uint32_t);
        pdata += sizeof(uint32_t);
 
-       // specify the response limit
+       /* specify the response limit */
        bt_put_unaligned(htons(65535), (uint16_t *) pdata);
        reqsize += sizeof(uint16_t);
        pdata += sizeof(uint16_t);
 
-       // get attr seq PDU form
+       /* get attr seq PDU form */
        seqlen = gen_attridseq_pdu(pdata, attrids,
                reqtype == SDP_ATTR_REQ_INDIVIDUAL? SDP_UINT16 : SDP_UINT32);
        if (seqlen == -1) {
@@ -3532,18 +3531,18 @@ sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle,
        reqsize += seqlen;
        SDPDBG("Attr list length : %d\n", seqlen);
 
-       // save before Continuation State
+       /* save before Continuation State */
        _pdata = pdata;
        _reqsize = reqsize;
 
        do {
                int status;
 
-               // add NULL continuation state
+               /* add NULL continuation state */
                reqsize = _reqsize + copy_cstate(_pdata,
                                        SDP_REQ_BUFFER_SIZE - _reqsize, cstate);
 
-               // set the request header's param length
+               /* set the request header's param length */
                reqhdr->tid  = htons(sdp_gen_tid(session));
                reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));
 
@@ -3574,7 +3573,10 @@ sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle,
                pdata += sizeof(uint16_t);
                pdata_len -= sizeof(uint16_t);
 
-               // if continuation state set need to re-issue request before parsing
+               /*
+                * if continuation state set need to re-issue request before
+                * parsing
+                */
                if (pdata_len < rsp_count + sizeof(uint8_t)) {
                        SDPERR("Unexpected end of packet: continuation state data missing");
                        goto end;
@@ -3594,7 +3596,7 @@ sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle,
 
                        cstate = cstate_len > 0 ? (sdp_cstate_t *) (pdata + rsp_count) : 0;
 
-                       // build concatenated response buffer
+                       /* build concatenated response buffer */
                        rsp_concat_buf.data = realloc(rsp_concat_buf.data, rsp_concat_buf.data_size + rsp_count);
                        rsp_concat_buf.buf_size = rsp_concat_buf.data_size + rsp_count;
                        targetPtr = rsp_concat_buf.data + rsp_concat_buf.data_size;
@@ -3755,16 +3757,16 @@ int sdp_service_search_async(sdp_session_t *session, const sdp_list_t *search, u
        reqhdr->tid = htons(sdp_gen_tid(session));
        reqhdr->pdu_id = SDP_SVC_SEARCH_REQ;
 
-       // generate PDU
+       /* generate PDU */
        pdata = t->reqbuf + sizeof(sdp_pdu_hdr_t);
        t->reqsize = sizeof(sdp_pdu_hdr_t);
 
-       // add service class IDs for search
+       /* add service class IDs for search */
        seqlen = gen_searchseq_pdu(pdata, search);
 
        SDPDBG("Data seq added : %d\n", seqlen);
 
-       // now set the length and increment the pointer
+       /* now set the length and increment the pointer */
        t->reqsize += seqlen;
        pdata += seqlen;
 
@@ -3772,7 +3774,7 @@ int sdp_service_search_async(sdp_session_t *session, const sdp_list_t *search, u
        t->reqsize += sizeof(uint16_t);
        pdata += sizeof(uint16_t);
 
-       // set the request header's param length
+       /* set the request header's param length */
        cstate_len = copy_cstate(pdata, SDP_REQ_BUFFER_SIZE - t->reqsize, NULL);
        reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t));
 
@@ -3856,21 +3858,21 @@ int sdp_service_attr_async(sdp_session_t *session, uint32_t handle, sdp_attrreq_
        reqhdr->tid = htons(sdp_gen_tid(session));
        reqhdr->pdu_id = SDP_SVC_ATTR_REQ;
 
-       // generate PDU
+       /* generate PDU */
        pdata = t->reqbuf + sizeof(sdp_pdu_hdr_t);
        t->reqsize = sizeof(sdp_pdu_hdr_t);
 
-       // add the service record handle
+       /* add the service record handle */
        bt_put_unaligned(htonl(handle), (uint32_t *) pdata);
        t->reqsize += sizeof(uint32_t);
        pdata += sizeof(uint32_t);
 
-       // specify the response limit
+       /* specify the response limit */
        bt_put_unaligned(htons(65535), (uint16_t *) pdata);
        t->reqsize += sizeof(uint16_t);
        pdata += sizeof(uint16_t);
 
-       // get attr seq PDU form
+       /* get attr seq PDU form */
        seqlen = gen_attridseq_pdu(pdata, attrid_list,
                        reqtype == SDP_ATTR_REQ_INDIVIDUAL? SDP_UINT16 : SDP_UINT32);
        if (seqlen == -1) {
@@ -3878,12 +3880,12 @@ int sdp_service_attr_async(sdp_session_t *session, uint32_t handle, sdp_attrreq_
                goto end;
        }
 
-       // now set the length and increment the pointer
+       /* now set the length and increment the pointer */
        t->reqsize += seqlen;
        pdata += seqlen;
        SDPDBG("Attr list length : %d\n", seqlen);
 
-       // set the request header's param length
+       /* set the request header's param length */
        cstate_len = copy_cstate(pdata, SDP_REQ_BUFFER_SIZE - t->reqsize, NULL);
        reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t));
 
@@ -3968,16 +3970,16 @@ int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *sear
        reqhdr->tid = htons(sdp_gen_tid(session));
        reqhdr->pdu_id = SDP_SVC_SEARCH_ATTR_REQ;
 
-       // generate PDU
+       /* generate PDU */
        pdata = t->reqbuf + sizeof(sdp_pdu_hdr_t);
        t->reqsize = sizeof(sdp_pdu_hdr_t);
 
-       // add service class IDs for search
+       /* add service class IDs for search */
        seqlen = gen_searchseq_pdu(pdata, search);
 
        SDPDBG("Data seq added : %d\n", seqlen);
 
-       // now set the length and increment the pointer
+       /* now set the length and increment the pointer */
        t->reqsize += seqlen;
        pdata += seqlen;
 
@@ -3987,7 +3989,7 @@ int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *sear
 
        SDPDBG("Max attr byte count : %d\n", SDP_MAX_ATTR_LEN);
 
-       // get attr seq PDU form
+       /* get attr seq PDU form */
        seqlen = gen_attridseq_pdu(pdata, attrid_list,
                        reqtype == SDP_ATTR_REQ_INDIVIDUAL ? SDP_UINT16 : SDP_UINT32);
        if (seqlen == -1) {
@@ -3999,7 +4001,7 @@ int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *sear
        SDPDBG("Attr list length : %d\n", seqlen);
        t->reqsize += seqlen;
 
-       // set the request header's param length
+       /* set the request header's param length */
        cstate_len = copy_cstate(pdata, SDP_REQ_BUFFER_SIZE - t->reqsize, NULL);
        reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t));
 
@@ -4164,15 +4166,13 @@ int sdp_process(sdp_session_t *session)
                 */
                plen = sizeof(uint16_t) + rsp_count;
 
-               pdata += sizeof(uint16_t); // points to attribute list
+               pdata += sizeof(uint16_t); /* points to attribute list */
                status = 0x0000;
                break;
        case SDP_ERROR_RSP:
                status = ntohs(bt_get_unaligned((uint16_t *) pdata));
                size = ntohs(rsphdr->plen);
 
-               /* error code + error info */
-               plen = size;
                goto end;
        default:
                t->err = EPROTO;
@@ -4210,13 +4210,13 @@ int sdp_process(sdp_session_t *session)
 
                reqhdr->tid = htons(sdp_gen_tid(session));
 
-               // add continuation state
+               /* add continuation state */
                cstate_len = copy_cstate(t->reqbuf + t->reqsize,
                                SDP_REQ_BUFFER_SIZE - t->reqsize, pcstate);
 
                reqsize = t->reqsize + cstate_len;
 
-               // set the request header's param length
+               /* set the request header's param length */
                reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));
 
                if (sdp_send_req(session, t->reqbuf, reqsize) < 0) {
@@ -4318,11 +4318,11 @@ int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search
        reqhdr = (sdp_pdu_hdr_t *) reqbuf;
        reqhdr->pdu_id = SDP_SVC_SEARCH_ATTR_REQ;
 
-       // generate PDU
+       /* generate PDU */
        pdata = reqbuf + sizeof(sdp_pdu_hdr_t);
        reqsize = sizeof(sdp_pdu_hdr_t);
 
-       // add service class IDs for search
+       /* add service class IDs for search */
        seqlen = gen_searchseq_pdu(pdata, search);
 
        SDPDBG("Data seq added : %d\n", seqlen);
@@ -4391,7 +4391,7 @@ int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search
 
                rsp_count = ntohs(bt_get_unaligned((uint16_t *) pdata));
                attr_list_len += rsp_count;
-               pdata += sizeof(uint16_t);      // pdata points to attribute list
+               pdata += sizeof(uint16_t); /* pdata points to attribute list */
                pdata_len -= sizeof(uint16_t);
 
                if (pdata_len < rsp_count + sizeof(uint8_t)) {
@@ -4630,179 +4630,7 @@ uint16_t sdp_gen_tid(sdp_session_t *session)
 {
        return session->tid++;
 }
-#ifdef __TIZEN_PATCH__
-sdp_data_t *sdp_extract_attr_safe(const uint8_t *p, int bufsize, int *size, sdp_record_t *rec)
-{
-       sdp_data_t *elem;
-       int n = 0;
-       uint8_t dtd;
-
-       if (bufsize < sizeof(uint8_t)) {
-               SDPERR("Unexpected end of packet");
-               return NULL;
-       }
-
-       dtd = *(const uint8_t *)p;
-
-       SDPDBG("extract_attr: dtd=0x%x", dtd);
-       switch (dtd) {
-       case SDP_DATA_NIL:
-       case SDP_BOOL:
-       case SDP_UINT8:
-       case SDP_UINT16:
-       case SDP_UINT32:
-       case SDP_UINT64:
-       case SDP_UINT128:
-       case SDP_INT8:
-       case SDP_INT16:
-       case SDP_INT32:
-       case SDP_INT64:
-       case SDP_INT128:
-               elem = extract_int(p, bufsize, &n);
-               break;
-       case SDP_UUID16:
-       case SDP_UUID32:
-       case SDP_UUID128:
-               elem = extract_uuid(p, bufsize, &n, rec);
-               break;
-       case SDP_TEXT_STR8:
-       case SDP_TEXT_STR16:
-       case SDP_TEXT_STR32:
-       case SDP_URL_STR8:
-       case SDP_URL_STR16:
-       case SDP_URL_STR32:
-               elem = extract_str(p, bufsize, &n);
-               break;
-       case SDP_SEQ8:
-       case SDP_SEQ16:
-       case SDP_SEQ32:
-       case SDP_ALT8:
-       case SDP_ALT16:
-       case SDP_ALT32:
-               elem = extract_seq(p, bufsize, &n, rec);
-               break;
-       default:
-               SDPERR("Unknown data descriptor : 0x%x terminating\n", dtd);
-               return NULL;
-       }
-       *size += n;
-       return elem;
-}
-
 
-int sdp_extract_seqtype_safe(const uint8_t *buf, int bufsize, uint8_t *dtdp, int *size)
-{
-       uint8_t dtd;
-       int scanned = sizeof(uint8_t);
-
-       if (bufsize < sizeof(uint8_t)) {
-               SDPERR("Unexpected end of packet");
-               return 0;
-       }
-
-       dtd = *(uint8_t *) buf;
-       buf += sizeof(uint8_t);
-       bufsize -= sizeof(uint8_t);
-       *dtdp = dtd;
-       switch (dtd) {
-       case SDP_SEQ8:
-       case SDP_ALT8:
-               if (bufsize < sizeof(uint8_t)) {
-                       SDPERR("Unexpected end of packet");
-                       return 0;
-               }
-               *size = *(uint8_t *) buf;
-               scanned += sizeof(uint8_t);
-               break;
-       case SDP_SEQ16:
-       case SDP_ALT16:
-               if (bufsize < sizeof(uint16_t)) {
-                       SDPERR("Unexpected end of packet");
-                       return 0;
-               }
-               *size = ntohs(bt_get_unaligned((uint16_t *) buf));
-               scanned += sizeof(uint16_t);
-               break;
-       case SDP_SEQ32:
-       case SDP_ALT32:
-               if (bufsize < sizeof(uint32_t)) {
-                       SDPERR("Unexpected end of packet");
-                       return 0;
-               }
-               *size = ntohl(bt_get_unaligned((uint32_t *) buf));
-               scanned += sizeof(uint32_t);
-               break;
-       default:
-               SDPERR("Unknown sequence type, aborting\n");
-               return 0;
-       }
-       return scanned;
-}
-
-
-sdp_record_t *sdp_extract_pdu_safe(const uint8_t *buf, int bufsize, int *scanned)
-{
-       int extracted = 0, seqlen = 0;
-       uint8_t dtd;
-       uint16_t attr;
-       sdp_record_t *rec = sdp_record_alloc();
-       const uint8_t *p = buf;
-
-       *scanned = sdp_extract_seqtype_safe(buf, bufsize, &dtd, &seqlen);
-       p += *scanned;
-       bufsize -= *scanned;
-       rec->attrlist = NULL;
-
-       while (extracted < seqlen && bufsize > 0) {
-               int n = sizeof(uint8_t), attrlen = 0;
-               sdp_data_t *data = NULL;
-
-               SDPDBG("Extract PDU, sequenceLength: %d localExtractedLength: %d",
-                                                       seqlen, extracted);
-
-               if (bufsize < n + sizeof(uint16_t)) {
-                       SDPERR("Unexpected end of packet");
-                       break;
-               }
-
-               dtd = *(uint8_t *) p;
-               attr = ntohs(bt_get_unaligned((uint16_t *) (p + n)));
-               n += sizeof(uint16_t);
-
-               SDPDBG("DTD of attrId : %d Attr id : 0x%x \n", dtd, attr);
-
-               data = sdp_extract_attr_safe(p + n, bufsize - n, &attrlen, rec);
-
-               SDPDBG("Attr id : 0x%x attrValueLength : %d\n", attr, attrlen);
-
-               n += attrlen;
-               if (data == NULL) {
-                       SDPDBG("Terminating extraction of attributes");
-                       break;
-               }
-
-               if (attr == SDP_ATTR_RECORD_HANDLE)
-                       rec->handle = data->val.uint32;
-
-               if (attr == SDP_ATTR_SVCLASS_ID_LIST)
-                       extract_svclass_uuid(data, &rec->svclass);
-
-               extracted += n;
-               p += n;
-               bufsize -= n;
-               sdp_attr_replace(rec, attr, data);
-
-               SDPDBG("Extract PDU, seqLength: %d localExtractedLength: %d",
-                                                       seqlen, extracted);
-       }
-#ifdef SDP_DEBUG
-       SDPDBG("Successful extracting of Svc Rec attributes\n");
-       sdp_print_service_attr(rec->attrlist);
-#endif
-       *scanned += seqlen;
-       return rec;
-}
-#endif
 /*
  * Set the supported features
  */
index b5b64a7..5f7d271 100644 (file)
--- a/lib/sdp.h
+++ b/lib/sdp.h
@@ -40,7 +40,6 @@ extern "C" {
 #define SDP_RSP_BUFFER_SIZE    65535
 #define SDP_PDU_CHUNK_SIZE     1024
 
-#define BLUEZ_SDP_DEBUG(format, args...)    printf("%s():%d " format, /*__FILE__,*/ __FUNCTION__, __LINE__, ##args) /*__SYAM__*/
 /*
  * All definitions are based on Bluetooth Assigned Numbers
  * of the Bluetooth Specification
index e506ac1..433e9ef 100644 (file)
@@ -90,7 +90,7 @@ typedef struct {
        int state;
        int local;
        int flags;
-       uint16_t tid;   // Current transaction ID
+       uint16_t tid;   /* Current transaction ID */
        void *priv;
 } sdp_session_t;
 
index 325016a..a3e2a1a 100644 (file)
@@ -74,7 +74,7 @@ void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
 {
        switch (src->type) {
        case BT_UUID128:
-               memcpy(dst, src, sizeof(bt_uuid_t));
+               *dst = *src;
                break;
        case BT_UUID32:
                bt_uuid32_to_uuid128(src, dst);
diff --git a/mgmt/main.c b/mgmt/main.c
new file mode 100644 (file)
index 0000000..20d7bf8
--- /dev/null
@@ -0,0 +1,1566 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <poll.h>
+#include <getopt.h>
+#include <stdbool.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/mgmt.h>
+
+#ifndef NELEM
+#define NELEM(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+static const char *mgmt_op[] = {
+       "<0x0000>",
+       "Read Version",
+       "Read Features",
+       "Read Index List",
+       "Read Controller Info",
+       "Set Powered",
+       "Set Discoverable",
+       "Set Connectable",
+       "Set Pairable",                 /* 0x0008 */
+       "Add UUID",
+       "Remove UUID",
+       "Set Dev Class",
+       "Set Service Cache",
+       "Load Link Keys",
+       "Remove Keys",
+       "Disconnect",
+       "Get Connections",              /* 0x0010 */
+       "PIN Code Reply",
+       "PIN Code Neg Reply",
+       "Set IO Capability",
+       "Pair Device",
+       "User Confirm Reply",
+       "User Confirm Neg Reply",
+       "Set Local Name",
+       "Read Local OOB Data",          /* 0x0018 */
+       "Add Remote OOB Data",
+       "Remove Remove OOB Data",
+       "Start Discoery",
+       "Block Device",
+       "Unblock Device",
+       "Set Fast Connectable",
+};
+
+static const char *mgmt_ev[] = {
+       "<0x0000>",
+       "Command Complete",
+       "Command Status",
+       "Controller Error",
+       "Index Added",
+       "Index Removed",
+       "Powered",
+       "Discoverable",
+       "Connectable",                  /* 0x0008 */
+       "Pairable",
+       "New Link Key",
+       "Device Connected",
+       "Device Disconnected",
+       "Connect Failed",
+       "PIN Code Request",
+       "User Confirm Request",
+       "Authentication Failed",        /* 0x0010 */
+       "Local Name Changed",
+       "Device Found",
+       "Remote Name",
+       "Discovering",
+       "Device Blocked",
+       "Device Unblocked",
+};
+
+static const char *mgmt_status[] = {
+       "Success",
+       "Unknown Command",
+       "Not Connected",
+       "Failed",
+       "Connect Failed",
+       "Authentication Failed",
+       "Not Paired",
+       "No Resources",
+       "Timeout",
+       "Already Connected",
+       "Busy",
+       "Rejected",
+       "Not Supported",
+       "Invalid Parameters",
+       "Disconnected",
+       "Not Powered",
+};
+
+static bool monitor = false;
+static bool discovery = false;
+static bool resolve_names = true;
+
+typedef void (*cmd_cb)(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+                               void *rsp, uint16_t len, void *user_data);
+
+static struct pending_cmd {
+       uint16_t op;
+       uint16_t id;
+       cmd_cb cb;
+       void *user_data;
+       struct pending_cmd *next;
+} *pending = NULL;
+
+static const char *mgmt_opstr(uint16_t op)
+{
+       if (op >= NELEM(mgmt_op))
+               return "<unknown opcode>";
+       return mgmt_op[op];
+}
+
+static const char *mgmt_evstr(uint16_t ev)
+{
+       if (ev >= NELEM(mgmt_ev))
+               return "<unknown event>";
+       return mgmt_ev[ev];
+}
+
+static const char *mgmt_errstr(uint8_t status)
+{
+       if (status >= NELEM(mgmt_status))
+               return "<unknown status>";
+       return mgmt_status[status];
+}
+
+static int mgmt_send_cmd(int mgmt_sk, uint16_t op, uint16_t id, void *data,
+                               size_t len, cmd_cb func, void *user_data)
+{
+       char buf[1024];
+       struct pending_cmd *cmd;
+       struct mgmt_hdr *hdr = (void *) buf;
+
+       if (len + MGMT_HDR_SIZE > sizeof(buf))
+               return -EINVAL;
+
+       cmd = calloc(1, sizeof(struct pending_cmd));
+       if (cmd == NULL)
+               return -errno;
+
+       cmd->op = op;
+       cmd->id = id;
+       cmd->cb = func;
+       cmd->user_data = user_data;
+
+       memset(buf, 0, sizeof(buf));
+       hdr->opcode = htobs(op);
+       hdr->index = htobs(id);
+       hdr->len = htobs(len);
+       memcpy(buf + MGMT_HDR_SIZE, data, len);
+
+       if (write(mgmt_sk, buf, MGMT_HDR_SIZE + len) < 0) {
+               fprintf(stderr, "Unable to write to socket: %s\n",
+                                                       strerror(errno));
+               free(cmd);
+               return -1;
+       }
+
+       cmd->next = pending;
+       pending = cmd;
+
+       return 0;
+}
+
+static int mgmt_open(void)
+{
+       struct sockaddr_hci addr;
+       int sk;
+
+       sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       if (sk < 0) {
+               fprintf(stderr, "socket: %s\n", strerror(errno));
+               return sk;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.hci_family = AF_BLUETOOTH;
+       addr.hci_dev = HCI_DEV_NONE;
+       addr.hci_channel = HCI_CHANNEL_CONTROL;
+
+       if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               fprintf(stderr, "bind: %s\n", strerror(errno));
+               close(sk);
+               return -1;
+       }
+
+       return sk;
+}
+
+static void mgmt_check_pending(int mgmt_sk, uint16_t op, uint16_t index,
+                               uint16_t status, void *data, uint16_t len)
+{
+       struct pending_cmd *c, *prev;
+
+       for (c = pending, prev = NULL; c != NULL; prev = c, c = c->next) {
+               if (c->op != op)
+                       continue;
+               if (c->id != index)
+                       continue;
+
+               if (c == pending)
+                       pending = c->next;
+               else
+                       prev->next = c->next;
+
+               c->cb(mgmt_sk, op, index, status, data, len, c->user_data);
+
+               free(c);
+       }
+}
+
+static int mgmt_cmd_complete(int mgmt_sk, uint16_t index,
+                               struct mgmt_ev_cmd_complete *ev, uint16_t len)
+{
+       uint16_t op;
+
+       if (len < sizeof(*ev)) {
+               fprintf(stderr, "Too short (%u bytes) cmd complete event\n",
+                                                                       len);
+               return -EINVAL;
+       }
+
+       op = bt_get_le16(&ev->opcode);
+
+       len -= sizeof(*ev);
+
+       if (monitor)
+               printf("%s complete, opcode 0x%04x len %u\n", mgmt_opstr(op),
+                                                               op, len);
+
+       mgmt_check_pending(mgmt_sk, op, index, 0, ev->data, len);
+
+       return 0;
+}
+
+static int mgmt_cmd_status(int mgmt_sk, uint16_t index,
+                               struct mgmt_ev_cmd_status *ev, uint16_t len)
+{
+       uint16_t opcode;
+
+       if (len < sizeof(*ev)) {
+               fprintf(stderr, "Too short (%u bytes) cmd status event\n",
+                                                                       len);
+               return -EINVAL;
+       }
+
+       opcode = bt_get_le16(&ev->opcode);
+
+       if (monitor)
+               printf("cmd status, opcode 0x%04x status 0x%02x (%s)\n",
+                               opcode, ev->status, mgmt_errstr(ev->status));
+
+       if (ev->status != 0)
+               mgmt_check_pending(mgmt_sk, opcode, index, ev->status,
+                                                               NULL, 0);
+
+       return 0;
+}
+
+static int mgmt_controller_error(uint16_t index,
+                                       struct mgmt_ev_controller_error *ev,
+                                       uint16_t len)
+{
+       if (len < sizeof(*ev)) {
+               fprintf(stderr,
+                       "Too short (%u bytes) controller error event\n", len);
+               return -EINVAL;
+       }
+
+       if (monitor)
+               printf("hci%u error 0x%02x\n", index, ev->error_code);
+
+       return 0;
+}
+
+static int mgmt_index_added(int mgmt_sk, uint16_t index)
+{
+       if (monitor)
+               printf("hci%u added\n", index);
+       return 0;
+}
+
+static int mgmt_index_removed(int mgmt_sk, uint16_t index)
+{
+       if (monitor)
+               printf("hci%u removed\n", index);
+       return 0;
+}
+
+static const char *settings_str[] = {
+                               "powered",
+                               "connectable",
+                               "fast-connectable",
+                               "discoverable",
+                               "pairable",
+                               "link-security",
+                               "ssp",
+                               "br/edr",
+                               "hs",
+                               "le" ,
+};
+
+static void print_settings(uint32_t settings)
+{
+       unsigned i;
+
+       for (i = 0; i < NELEM(settings_str); i++) {
+               if ((settings & (1 << i)) != 0)
+                       printf("%s ", settings_str[i]);
+       }
+}
+
+static int mgmt_new_settings(int mgmt_sk, uint16_t index,
+                                       uint32_t *ev, uint16_t len)
+{
+       if (len < sizeof(*ev)) {
+               fprintf(stderr, "Too short new_settings event (%u)\n", len);
+               return -EINVAL;
+       }
+
+       if (monitor) {
+               printf("hci%u new_settings: ", index);
+               print_settings(bt_get_le32(ev));
+               printf("\n");
+       }
+
+       return 0;
+}
+
+static int mgmt_discovering(int mgmt_sk, uint16_t index,
+                                       struct mgmt_mode *ev, uint16_t len)
+{
+       if (len < sizeof(*ev)) {
+               fprintf(stderr, "Too short (%u bytes) discovering event\n",
+                                                                       len);
+               return -EINVAL;
+       }
+
+       if (ev->val == 0 && discovery)
+               exit(EXIT_SUCCESS);
+
+       if (monitor)
+               printf("hci%u discovering %s\n", index,
+                                               ev->val ? "on" : "off");
+
+       return 0;
+}
+
+static int mgmt_new_link_key(int mgmt_sk, uint16_t index,
+                               struct mgmt_ev_new_link_key *ev, uint16_t len)
+{
+
+       if (len != sizeof(*ev)) {
+               fprintf(stderr, "Invalid new_link_key length (%u bytes)\n",
+                                                                       len);
+               return -EINVAL;
+       }
+
+       if (monitor) {
+               char addr[18];
+               ba2str(&ev->key.bdaddr, addr);
+               printf("hci%u new_link_key %s type 0x%02x pin_len %d "
+                               "store_hint %u\n", index, addr, ev->key.type,
+                               ev->key.pin_len, ev->store_hint);
+       }
+
+       return 0;
+}
+
+static const char *typestr(uint8_t type)
+{
+       const char *str[] = { "BR/EDR", "LE Public", "LE Random" };
+
+       if (type <= MGMT_ADDR_LE_RANDOM)
+               return str[type];
+
+       return "(unknown)";
+}
+
+static int mgmt_connected(int mgmt_sk, uint16_t index, bool connected,
+                               struct mgmt_addr_info *ev, uint16_t len)
+{
+       const char *ev_name = connected ? "connected" : "disconnected";
+
+       if (len != sizeof(*ev)) {
+               fprintf(stderr,
+                       "Invalid %s event length (%u bytes)\n", ev_name, len);
+               return -EINVAL;
+       }
+
+       if (monitor) {
+               char addr[18];
+               ba2str(&ev->bdaddr, addr);
+               printf("hci%u %s type %s %s\n", index, addr,
+                                               typestr(ev->type), ev_name);
+       }
+
+       return 0;
+}
+
+static int mgmt_conn_failed(int mgmt_sk, uint16_t index,
+                               struct mgmt_ev_connect_failed *ev,
+                               uint16_t len)
+{
+       if (len != sizeof(*ev)) {
+               fprintf(stderr,
+                       "Invalid connect_failed event length (%u bytes)\n", len);
+               return -EINVAL;
+       }
+
+       if (monitor) {
+               char addr[18];
+               ba2str(&ev->addr.bdaddr, addr);
+               printf("hci%u %s type %s connect failed (status 0x%02x, %s)\n",
+                               index, addr, typestr(ev->addr.type), ev->status,
+                               mgmt_errstr(ev->status));
+       }
+
+       return 0;
+}
+
+static int mgmt_auth_failed(int mgmt_sk, uint16_t index,
+                               struct mgmt_ev_auth_failed *ev,
+                               uint16_t len)
+{
+       if (len != sizeof(*ev)) {
+               fprintf(stderr,
+                       "Invalid auth_failed event length (%u bytes)\n", len);
+               return -EINVAL;
+       }
+
+       if (monitor) {
+               char addr[18];
+               ba2str(&ev->bdaddr, addr);
+               printf("hci%u %s auth failed with status 0x%02x (%s)\n",
+                       index, addr, ev->status, mgmt_errstr(ev->status));
+       }
+
+       return 0;
+}
+
+static int mgmt_name_changed(int mgmt_sk, uint16_t index,
+                               struct mgmt_ev_local_name_changed *ev,
+                               uint16_t len)
+{
+       if (len != sizeof(*ev)) {
+               fprintf(stderr,
+                       "Invalid local_name_changed length (%u bytes)\n", len);
+               return -EINVAL;
+       }
+
+       if (monitor)
+               printf("hci%u name changed: %s\n", index, ev->name);
+
+       return 0;
+}
+
+static void confirm_name_rsp(int mgmt_sk, uint16_t op, uint16_t id,
+                               uint8_t status, void *rsp, uint16_t len,
+                               void *user_data)
+{
+       struct mgmt_rp_confirm_name *rp = rsp;
+       char addr[18];
+
+       if (status != 0) {
+               fprintf(stderr,
+                       "hci%u confirm_name failed with status 0x%02x (%s)\n",
+                                       id, status, mgmt_errstr(status));
+               return;
+       }
+
+       if (len != sizeof(*rp)) {
+               fprintf(stderr,
+                       "hci%u confirm_name rsp length %u instead of %zu\n",
+                       id, len, sizeof(*rp));
+               return;
+       }
+
+       ba2str(&rp->bdaddr, addr);
+
+       if (rp->status != 0)
+               fprintf(stderr,
+                       "hci%u confirm_name for %s failed: 0x%02x (%s)\n",
+                       id, addr, rp->status, mgmt_errstr(status));
+       else
+               printf("hci%u confirm_name succeeded for %s\n", id, addr);
+}
+
+static int mgmt_device_found(int mgmt_sk, uint16_t index,
+                               struct mgmt_ev_device_found *ev, uint16_t len)
+{
+       if (len != sizeof(*ev)) {
+               fprintf(stderr,
+                       "Invalid device_found event length (%u bytes)\n", len);
+               return -EINVAL;
+       }
+
+       if (monitor || discovery) {
+               char addr[18];
+               ba2str(&ev->addr.bdaddr, addr);
+               printf("hci%u dev_found: %s type %s class 0x%02x%02x%02x "
+                       "rssi %d confirm_name %u eir (%s)\n", index, addr,
+                       typestr(ev->addr.type),
+                       ev->dev_class[2], ev->dev_class[1], ev->dev_class[0],
+                       ev->rssi, ev->confirm_name,
+                       ev->eir[0] == 0 ? "no" : "yes");
+       }
+
+       if (discovery && ev->confirm_name) {
+               struct mgmt_cp_confirm_name cp;
+
+               memset(&cp, 0, sizeof(cp));
+               bacpy(&cp.bdaddr, &ev->addr.bdaddr);
+               if (resolve_names)
+                       cp.name_known = 0;
+               else
+                       cp.name_known = 1;
+
+               mgmt_send_cmd(mgmt_sk, MGMT_OP_CONFIRM_NAME, index,
+                                       &cp, sizeof(cp), confirm_name_rsp,
+                                       NULL);
+       }
+
+       return 0;
+}
+
+static int mgmt_remote_name(int mgmt_sk, uint16_t index,
+                               struct mgmt_ev_remote_name *ev, uint16_t len)
+{
+       if (len != sizeof(*ev)) {
+               fprintf(stderr,
+                       "Invalid remote_name event length (%u bytes)\n", len);
+               return -EINVAL;
+       }
+
+       if (monitor || discovery) {
+               char addr[18];
+               ba2str(&ev->bdaddr, addr);
+               printf("hci%u %s name %s\n", index, addr, ev->name);
+       }
+
+       return 0;
+}
+
+static void pin_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+                               void *rsp, uint16_t len, void *user_data)
+{
+       if (status != 0) {
+               fprintf(stderr,
+                       "hci%u PIN Code reply failed with status 0x%02x (%s)",
+                                       id, status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       printf("hci%u PIN Reply successful\n", id);
+}
+
+static int mgmt_pin_reply(int mgmt_sk, uint16_t index, bdaddr_t *bdaddr,
+                                               const char *pin, size_t len)
+{
+       struct mgmt_cp_pin_code_reply cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, bdaddr);
+       cp.pin_len = len;
+       memcpy(cp.pin_code, pin, len);
+
+       return mgmt_send_cmd(mgmt_sk, MGMT_OP_PIN_CODE_REPLY, index,
+                                       &cp, sizeof(cp), pin_rsp, NULL);
+}
+
+static void pin_neg_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+                               void *rsp, uint16_t len, void *user_data)
+{
+       if (status != 0) {
+               fprintf(stderr,
+                       "hci%u PIN Neg reply failed with status 0x%02x (%s)",
+                                       id, status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       printf("hci%u PIN Negative Reply successful\n", id);
+}
+
+static int mgmt_pin_neg_reply(int mgmt_sk, uint16_t index, bdaddr_t *bdaddr)
+{
+       struct mgmt_cp_pin_code_neg_reply cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, bdaddr);
+
+       return mgmt_send_cmd(mgmt_sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
+                                       &cp, sizeof(cp), pin_neg_rsp, NULL);
+}
+
+static int mgmt_request_pin(int mgmt_sk, uint16_t index,
+                               struct mgmt_ev_pin_code_request *ev,
+                               uint16_t len)
+{
+       char pin[18];
+       size_t pin_len;
+
+       if (len != sizeof(*ev)) {
+               fprintf(stderr,
+                       "Invalid pin_code request length (%u bytes)\n", len);
+               return -EINVAL;
+       }
+
+       if (monitor) {
+               char addr[18];
+               ba2str(&ev->bdaddr, addr);
+               printf("hci%u %s request PIN\n", index, addr);
+       }
+
+       printf("PIN Request (press enter to reject) >> ");
+       fflush(stdout);
+
+       memset(pin, 0, sizeof(pin));
+
+       if (fgets(pin, sizeof(pin), stdin) == NULL || pin[0] == '\n')
+               return mgmt_pin_neg_reply(mgmt_sk, index, &ev->bdaddr);
+
+       pin_len = strlen(pin);
+       if (pin[pin_len - 1] == '\n') {
+               pin[pin_len - 1] = '\0';
+               pin_len--;
+       }
+
+       return mgmt_pin_reply(mgmt_sk, index, &ev->bdaddr, pin, pin_len);
+}
+
+static void confirm_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+                               void *rsp, uint16_t len, void *user_data)
+{
+       if (status != 0) {
+               fprintf(stderr,
+                       "hci%u User Confirm reply failed. status 0x%02x (%s)",
+                                       id, status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       printf("hci%u User Confirm Reply successful\n", id);
+}
+
+static int mgmt_confirm_reply(int mgmt_sk, uint16_t index, bdaddr_t *bdaddr)
+{
+       struct mgmt_cp_user_confirm_reply cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, bdaddr);
+
+       return mgmt_send_cmd(mgmt_sk, MGMT_OP_USER_CONFIRM_REPLY, index,
+                                       &cp, sizeof(cp), confirm_rsp, NULL);
+}
+
+static void confirm_neg_rsp(int mgmt_sk, uint16_t op, uint16_t id,
+                               uint8_t status, void *rsp, uint16_t len,
+                               void *user_data)
+{
+       if (status != 0) {
+               fprintf(stderr,
+                       "hci%u Confirm Neg reply failed. status 0x%02x (%s)",
+                                       id, status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       printf("hci%u User Confirm Negative Reply successful\n", id);
+}
+
+static int mgmt_confirm_neg_reply(int mgmt_sk, uint16_t index,
+                                                       bdaddr_t *bdaddr)
+{
+       struct mgmt_cp_user_confirm_reply cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, bdaddr);
+
+       return mgmt_send_cmd(mgmt_sk, MGMT_OP_USER_CONFIRM_NEG_REPLY, index,
+                               &cp, sizeof(cp), confirm_neg_rsp, NULL);
+}
+
+
+static int mgmt_user_confirm(int mgmt_sk, uint16_t index,
+                               struct mgmt_ev_user_confirm_request *ev,
+                               uint16_t len)
+{
+       char rsp[5];
+       size_t rsp_len;
+       uint32_t val;
+       char addr[18];
+
+       if (len != sizeof(*ev)) {
+               fprintf(stderr,
+                       "Invalid user_confirm request length (%u)\n", len);
+               return -EINVAL;
+       }
+
+       ba2str(&ev->bdaddr, addr);
+       val = bt_get_le32(&ev->value);
+
+       if (monitor)
+               printf("hci%u %s User Confirm %06u hint %u\n", index, addr,
+                                                       val, ev->confirm_hint);
+
+       if (ev->confirm_hint)
+               printf("Accept pairing with %s (yes/no) >> ", addr);
+       else
+               printf("Confirm value %06u for %s (yes/no) >> ", val, addr);
+
+       fflush(stdout);
+
+       memset(rsp, 0, sizeof(rsp));
+
+       if (fgets(rsp, sizeof(rsp), stdin) == NULL || rsp[0] == '\n')
+               return mgmt_confirm_neg_reply(mgmt_sk, index, &ev->bdaddr);
+
+       rsp_len = strlen(rsp);
+       if (rsp[rsp_len - 1] == '\n') {
+               rsp[rsp_len - 1] = '\0';
+               rsp_len--;
+       }
+
+       if (rsp[0] == 'y' || rsp[0] == 'Y')
+               return mgmt_confirm_reply(mgmt_sk, index, &ev->bdaddr);
+       else
+               return mgmt_confirm_neg_reply(mgmt_sk, index, &ev->bdaddr);
+}
+
+static int mgmt_handle_event(int mgmt_sk, uint16_t ev, uint16_t index,
+                                               void *data, uint16_t len)
+{
+       if (monitor)
+               printf("event: %s\n", mgmt_evstr(ev));
+
+       switch (ev) {
+       case MGMT_EV_CMD_COMPLETE:
+               return mgmt_cmd_complete(mgmt_sk, index, data, len);
+       case MGMT_EV_CMD_STATUS:
+               return mgmt_cmd_status(mgmt_sk, index, data, len);
+       case MGMT_EV_CONTROLLER_ERROR:
+               return mgmt_controller_error(index, data, len);
+       case MGMT_EV_INDEX_ADDED:
+               return mgmt_index_added(mgmt_sk, index);
+       case MGMT_EV_INDEX_REMOVED:
+               return mgmt_index_removed(mgmt_sk, index);
+       case MGMT_EV_NEW_SETTINGS:
+               return mgmt_new_settings(mgmt_sk, index, data, len);
+       case MGMT_EV_DISCOVERING:
+               return mgmt_discovering(mgmt_sk, index, data, len);
+       case MGMT_EV_NEW_LINK_KEY:
+               return mgmt_new_link_key(mgmt_sk, index, data, len);
+       case MGMT_EV_DEVICE_CONNECTED:
+               return mgmt_connected(mgmt_sk, index, true, data, len);
+       case MGMT_EV_DEVICE_DISCONNECTED:
+               return mgmt_connected(mgmt_sk, index, false, data, len);
+       case MGMT_EV_CONNECT_FAILED:
+               return mgmt_conn_failed(mgmt_sk, index, data, len);
+       case MGMT_EV_AUTH_FAILED:
+               return mgmt_auth_failed(mgmt_sk, index, data, len);
+       case MGMT_EV_LOCAL_NAME_CHANGED:
+               return mgmt_name_changed(mgmt_sk, index, data, len);
+       case MGMT_EV_DEVICE_FOUND:
+               return mgmt_device_found(mgmt_sk, index, data, len);
+       case MGMT_EV_REMOTE_NAME:
+               return mgmt_remote_name(mgmt_sk, index, data, len);
+       case MGMT_EV_PIN_CODE_REQUEST:
+               return mgmt_request_pin(mgmt_sk, index, data, len);
+       case MGMT_EV_USER_CONFIRM_REQUEST:
+               return mgmt_user_confirm(mgmt_sk, index, data, len);
+       default:
+               if (monitor)
+                       printf("Unhandled event 0x%04x (%s)\n", ev, mgmt_evstr(ev));
+               return 0;
+       }
+}
+
+static int mgmt_process_data(int mgmt_sk)
+{
+       char buf[1024];
+       struct mgmt_hdr *hdr = (void *) buf;
+       uint16_t len, ev, index;
+       ssize_t ret;
+
+       ret = read(mgmt_sk, buf, sizeof(buf));
+       if (ret < 0) {
+               fprintf(stderr, "read: %s\n", strerror(errno));
+               return ret;
+       }
+
+       if (ret < MGMT_HDR_SIZE) {
+               fprintf(stderr, "Too small mgmt packet (%zd bytes)\n", ret);
+               return 0;
+       }
+
+       ev = bt_get_le16(&hdr->opcode);
+       index = bt_get_le16(&hdr->index);
+       len = bt_get_le16(&hdr->len);
+
+       if (monitor)
+               printf("event 0x%04x len 0x%04x index 0x%04x\n", ev, len, index);
+
+       if (ret != MGMT_HDR_SIZE + len) {
+               fprintf(stderr, "Packet length mismatch. ret %zd len %u",
+                                                               ret, len);
+               return 0;
+       }
+
+       mgmt_handle_event(mgmt_sk, ev, index, buf + MGMT_HDR_SIZE, len);
+
+       return 0;
+}
+
+static void cmd_monitor(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       printf("Monitoring mgmt events...\n");
+       monitor = true;
+}
+
+static void info_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+                               void *rsp, uint16_t len, void *user_data)
+{
+       struct mgmt_rp_read_info *rp = rsp;
+       char addr[18];
+
+       if (status != 0) {
+               fprintf(stderr,
+                       "Reading hci%u info failed with status 0x%02x (%s)\n",
+                                       id, status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       if (len < sizeof(*rp)) {
+               fprintf(stderr, "Too small info reply (%u bytes)\n", len);
+               exit(EXIT_FAILURE);
+       }
+
+       ba2str(&rp->bdaddr, addr);
+       printf("hci%u:\taddr %s version %u manufacturer %u"
+                       " class 0x%02x%02x%02x\n",
+                       id, addr, rp->version, bt_get_le16(&rp->manufacturer),
+                       rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
+
+       printf("\tsupported settings: ");
+       print_settings(bt_get_le32(&rp->supported_settings));
+
+       printf("\n\tcurrent settings: ");
+       print_settings(bt_get_le32(&rp->current_settings));
+
+       printf("\n\tname %s\n", rp->name);
+       printf("\tshort name %s\n", rp->short_name);
+
+       if (pending == NULL)
+               exit(EXIT_SUCCESS);
+}
+
+static void index_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+                               void *rsp, uint16_t len, void *user_data)
+{
+       struct mgmt_rp_read_index_list *rp = rsp;
+       uint16_t count;
+       unsigned int i;
+
+       if (status != 0) {
+               fprintf(stderr,
+                       "Reading index list failed with status 0x%02x (%s)\n",
+                                               status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       if (len < sizeof(*rp)) {
+               fprintf(stderr, "Too small index list reply (%u bytes)\n",
+                                                                       len);
+               exit(EXIT_FAILURE);
+       }
+
+       count = bt_get_le16(&rp->num_controllers);
+
+       if (len < sizeof(*rp) + count * sizeof(uint16_t)) {
+               fprintf(stderr,
+                       "Index count (%u) doesn't match reply length (%u)\n",
+                                                               count, len);
+               exit(EXIT_FAILURE);
+       }
+
+       if (monitor)
+               printf("Index list with %u item%s\n",
+                                               count, count > 1 ? "s" : "");
+
+       if (count == 0)
+               exit(EXIT_SUCCESS);
+
+       if (monitor && count > 0)
+               printf("\t");
+
+       for (i = 0; i < count; i++) {
+               uint16_t index;
+
+               index = bt_get_le16(&rp->index[i]);
+
+               if (monitor)
+                       printf("hci%u ", index);
+
+               if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INFO, index, NULL,
+                                       0, info_rsp, NULL) < 0) {
+                       fprintf(stderr, "Unable to send read_info cmd\n");
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       if (monitor && count > 0)
+               printf("\n");
+}
+
+static void cmd_info(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       if (index == MGMT_INDEX_NONE) {
+               if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INDEX_LIST,
+                                       MGMT_INDEX_NONE, NULL, 0,
+                                       index_rsp, NULL) < 0) {
+                       fprintf(stderr, "Unable to send index_list cmd\n");
+                       exit(EXIT_FAILURE);
+               }
+
+               return;
+       }
+
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INFO, index, NULL,
+                                               0, info_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send read_info cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void setting_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+                               void *rsp, uint16_t len, void *user_data)
+{
+       uint32_t *rp = rsp;
+
+       if (status != 0) {
+               fprintf(stderr,
+                       "%s for hci%u failed with status 0x%02x (%s)\n",
+                       mgmt_opstr(op), id, status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       if (len < sizeof(*rp)) {
+               fprintf(stderr, "Too small %s response (%u bytes)\n",
+                                                       mgmt_opstr(op), len);
+               exit(EXIT_FAILURE);
+       }
+
+       printf("hci%u %s complete, settings: ", id, mgmt_opstr(op));
+       print_settings(bt_get_le32(rp));
+       printf("\n");
+
+       exit(EXIT_SUCCESS);
+}
+
+static void cmd_setting(int mgmt_sk, uint16_t index, uint16_t op,
+                                                       int argc, char **argv)
+{
+       uint8_t val;
+
+       if (argc < 2) {
+               printf("Specify \"on\" or \"off\"\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
+               val = 1;
+       else if (strcasecmp(argv[1], "off") == 0)
+               val = 0;
+       else
+               val = atoi(argv[1]);
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       if (mgmt_send_cmd(mgmt_sk, op, index, &val, sizeof(val),
+                                               setting_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send %s cmd\n", mgmt_opstr(op));
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void cmd_power(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       cmd_setting(mgmt_sk, index, MGMT_OP_SET_POWERED, argc, argv);
+}
+
+static void cmd_discov(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       struct mgmt_cp_set_discoverable cp;
+
+       if (argc < 2) {
+               printf("Usage: btmgmt %s <yes/no> [timeout]\n", argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       memset(&cp, 0, sizeof(cp));
+
+       if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0)
+               cp.val = 1;
+       else if (strcasecmp(argv[1], "off") == 0)
+               cp.val = 0;
+       else
+               cp.val = atoi(argv[1]);
+
+       if (argc > 2)
+               cp.timeout = htobs(atoi(argv[2]));
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DISCOVERABLE, index,
+                               &cp, sizeof(cp), setting_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send set_discoverable cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void cmd_connectable(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       cmd_setting(mgmt_sk, index, MGMT_OP_SET_CONNECTABLE, argc, argv);
+}
+
+static void cmd_pairable(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       cmd_setting(mgmt_sk, index, MGMT_OP_SET_PAIRABLE, argc, argv);
+}
+
+static void class_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+                               void *rsp, uint16_t len, void *user_data)
+{
+       if (status != 0) {
+               fprintf(stderr,
+                       "Setting hci%u class failed with status 0x%02x (%s)",
+                                       id, status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       printf("hci%u class changed\n", id);
+       exit(EXIT_SUCCESS);
+}
+
+static void cmd_class(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       uint8_t class[2];
+
+       if (argc < 3) {
+               printf("Usage: btmgmt %s <major> <minor>\n", argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       class[0] = atoi(argv[1]);
+       class[1] = atoi(argv[2]);
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DEV_CLASS, index,
+                               class, sizeof(class), class_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send set_dev_class cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void disconnect_rsp(int mgmt_sk, uint16_t op, uint16_t id,
+                               uint8_t status, void *rsp, uint16_t len,
+                               void *user_data)
+{
+       struct mgmt_rp_disconnect *rp = rsp;
+       char addr[18];
+
+       if (status != 0) {
+               fprintf(stderr, "Disconnect failed with status 0x%02x (%s)\n",
+                                               status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       if (len != sizeof(*rp)) {
+               fprintf(stderr, "Invalid disconnect response length (%u)\n",
+                                                                       len);
+               exit(EXIT_FAILURE);
+       }
+
+       ba2str(&rp->bdaddr, addr);
+
+       if (rp->status == 0) {
+               printf("%s disconnected\n", addr);
+               exit(EXIT_SUCCESS);
+       } else {
+               fprintf(stderr,
+                       "Disconnecting %s failed with status 0x%02x (%s)\n",
+                               addr, rp->status, mgmt_errstr(rp->status));
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void cmd_disconnect(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       struct mgmt_cp_disconnect cp;
+
+       if (argc < 2) {
+               printf("Usage: btmgmt %s <address>\n", argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       str2ba(argv[1], &cp.bdaddr);
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_DISCONNECT, index,
+                               &cp, sizeof(cp), disconnect_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send disconnect cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void con_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+                               void *rsp, uint16_t len, void *user_data)
+{
+       struct mgmt_rp_get_connections *rp = rsp;
+       uint16_t count, i;
+
+       if (len < sizeof(*rp)) {
+               fprintf(stderr, "Too small (%u bytes) get_connections rsp\n",
+                                                                       len);
+               exit(EXIT_FAILURE);
+       }
+
+       count = bt_get_le16(&rp->conn_count);
+       if (len != sizeof(*rp) + count * sizeof(struct mgmt_addr_info)) {
+               fprintf(stderr, "Invalid get_connections length "
+                                       " (count=%u, len=%u)\n", count, len);
+               exit(EXIT_FAILURE);
+       }
+
+       for (i = 0; i < count; i++) {
+               char addr[18];
+
+               ba2str(&rp->addr[i].bdaddr, addr);
+
+               printf("%s type %s\n", addr, typestr(rp->addr[i].type));
+       }
+
+       exit(EXIT_SUCCESS);
+}
+
+static void cmd_con(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_GET_CONNECTIONS, index, NULL, 0,
+                                                       con_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send get_connections cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void find_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+                               void *rsp, uint16_t len, void *user_data)
+{
+       if (status != 0) {
+               fprintf(stderr,
+                       "Unable to start discovery. status 0x%02x (%s)\n",
+                                               status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       printf("Discovery started\n");
+       discovery = true;
+}
+
+static void cmd_find(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       struct mgmt_cp_start_discovery cp;
+       uint8_t type;
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       type = 0;
+       hci_set_bit(MGMT_ADDR_BREDR, &type);
+       hci_set_bit(MGMT_ADDR_LE_PUBLIC, &type);
+       hci_set_bit(MGMT_ADDR_LE_RANDOM, &type);
+
+       memset(&cp, 0, sizeof(cp));
+       cp.type = type;
+
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_START_DISCOVERY, index,
+                               &cp, sizeof(cp), find_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send start_discovery cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void name_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+                               void *rsp, uint16_t len, void *user_data)
+{
+       if (status != 0) {
+               fprintf(stderr, "Unable to set local name. status 0x%02x (%s)",
+                                               status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       exit(EXIT_SUCCESS);
+}
+
+static void cmd_name(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       struct mgmt_cp_set_local_name cp;
+
+       if (argc < 2) {
+               printf("Usage: btmgmt %s <name>\n", argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       memset(&cp, 0, sizeof(cp));
+       strncpy((char *) cp.name, argv[1], HCI_MAX_NAME_LENGTH);
+
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_LOCAL_NAME, index,
+                                       &cp, sizeof(cp), name_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send set_name cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void pair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+                               void *rsp, uint16_t len, void *user_data)
+{
+       struct mgmt_rp_pair_device *rp = rsp;
+       char addr[18];
+
+       if (status != 0) {
+               fprintf(stderr, "Pairing failed with status 0x%02x (%s)\n",
+                                               status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       if (len != sizeof(*rp)) {
+               fprintf(stderr, "Unexpected pair_rsp len %u\n", len);
+               exit(EXIT_FAILURE);
+       }
+
+       ba2str(&rp->addr.bdaddr, addr);
+
+       if (rp->status != 0) {
+               fprintf(stderr,
+                       "Pairing with %s (%s) failed. status 0x%02x (%s)\n",
+                       addr, typestr(rp->addr.type), rp->status,
+                       mgmt_errstr(rp->status));
+               exit(EXIT_FAILURE);
+       }
+
+       printf("Paired with %s\n", addr);
+
+       exit(EXIT_SUCCESS);
+}
+
+static void pair_usage(void)
+{
+       printf("Usage: btmgmt pair [-c cap] [-t type] <remote address>\n");
+}
+
+static struct option pair_options[] = {
+       { "help",       0, 0, 'h' },
+       { "capability", 1, 0, 'c' },
+       { "type",       1, 0, 't' },
+       { 0, 0, 0, 0 }
+};
+
+static void cmd_pair(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       struct mgmt_cp_pair_device cp;
+       uint8_t cap = 0x01;
+       uint8_t type = MGMT_ADDR_BREDR;
+       int opt;
+
+       while ((opt = getopt_long(argc, argv, "+c:t:h", pair_options,
+                                                               NULL)) != -1) {
+               switch (opt) {
+               case 'c':
+                       cap = strtol(optarg, NULL, 0);
+                       break;
+               case 't':
+                       type = strtol(optarg, NULL, 0);
+                       break;
+               case 'h':
+               default:
+                       pair_usage();
+                       exit(EXIT_SUCCESS);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+       optind = 0;
+
+       if (argc < 1) {
+               pair_usage();
+               exit(EXIT_FAILURE);
+       }
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       memset(&cp, 0, sizeof(cp));
+       str2ba(argv[0], &cp.addr.bdaddr);
+       cp.addr.type = type;
+       cp.io_cap = cap;
+
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_PAIR_DEVICE, index, &cp, sizeof(cp),
+                                                       pair_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send pair_device cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void remove_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+                               void *rsp, uint16_t len, void *user_data)
+{
+       struct mgmt_rp_remove_keys *rp = rsp;
+       char addr[18];
+
+       if (status != 0) {
+               fprintf(stderr, "Remove keys failed with status 0x%02x (%s)\n",
+                                               status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       if (len != sizeof(*rp)) {
+               fprintf(stderr, "Unexpected remove_keys_rsp len %u\n", len);
+               exit(EXIT_FAILURE);
+       }
+
+       ba2str(&rp->bdaddr, addr);
+
+       if (rp->status != 0) {
+               fprintf(stderr,
+                       "Removing keys for %s failed. status 0x%02x (%s)\n",
+                               addr, rp->status, mgmt_errstr(rp->status));
+               exit(EXIT_FAILURE);
+       }
+
+       printf("Removed keys for %s\n", addr);
+
+       exit(EXIT_SUCCESS);
+}
+
+static void cmd_remove(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       struct mgmt_cp_remove_keys cp;
+
+       if (argc < 2) {
+               printf("Usage: btmgmt %s <remote address>\n", argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       memset(&cp, 0, sizeof(cp));
+       str2ba(argv[1], &cp.bdaddr);
+       cp.disconnect = 1;
+
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_REMOVE_KEYS, index, &cp, sizeof(cp),
+                                               remove_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send remove_keys cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void keys_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+                               void *rsp, uint16_t len, void *user_data)
+{
+       if (status != 0) {
+               fprintf(stderr, "Load keys failed with status 0x%02x (%s)\n",
+                                               status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       printf("Keys successfully loaded\n");
+
+       exit(EXIT_SUCCESS);
+}
+
+static void cmd_keys(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       struct mgmt_cp_load_link_keys cp;
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       memset(&cp, 0, sizeof(cp));
+
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_LOAD_LINK_KEYS, index,
+                               &cp, sizeof(cp), keys_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send load_keys cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static struct {
+       char *cmd;
+       void (*func)(int mgmt_sk, uint16_t index, int argc, char **argv);
+       char *doc;
+} command[] = {
+       { "monitor",    cmd_monitor,    "Monitor events"                },
+       { "info",       cmd_info,       "Show controller info"          },
+       { "power",      cmd_power,      "Toggle powered state"          },
+       { "discov",     cmd_discov,     "Toggle discoverable state"     },
+       { "connectable",cmd_connectable,"Toggle connectable state"      },
+       { "pairable",   cmd_pairable,   "Toggle pairable state"         },
+       { "class",      cmd_class,      "Set device major/minor class"  },
+       { "disconnect", cmd_disconnect, "Disconnect device"             },
+       { "con",        cmd_con,        "List connections"              },
+       { "find",       cmd_find,       "Discover nearby devices"       },
+       { "name",       cmd_name,       "Set local name"                },
+       { "pair",       cmd_pair,       "Pair with a remote device"     },
+       { "remove",     cmd_remove,     "Remove pairing (all keys)"     },
+       { "keys",       cmd_keys,       "Load Keys"                     },
+       { NULL, NULL, 0 }
+};
+
+static void usage(void)
+{
+       int i;
+
+       printf("btmgmt ver %s\n", VERSION);
+       printf("Usage:\n"
+               "\tbtmgmt [options] <command> [command parameters]\n");
+
+       printf("Options:\n"
+               "\t--index <id>\tSpecify adapter index\n"
+               "\t--verbose\tEnable extra logging\n"
+               "\t--help\tDisplay help\n");
+
+       printf("Commands:\n");
+       for (i = 0; command[i].cmd; i++)
+               printf("\t%-15s\t%s\n", command[i].cmd, command[i].doc);
+
+       printf("\n"
+               "For more information on the usage of each command use:\n"
+               "\tbtmgmt <command> --help\n" );
+}
+
+static struct option main_options[] = {
+       { "index",      1, 0, 'i' },
+       { "verbose",    0, 0, 'v' },
+       { "help",       0, 0, 'h' },
+       { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+       int opt, i, mgmt_sk;
+       uint16_t index = MGMT_INDEX_NONE;
+       struct pollfd pollfd;
+
+       while ((opt = getopt_long(argc, argv, "+hvi:",
+                                               main_options, NULL)) != -1) {
+               switch (opt) {
+               case 'i':
+                       if (strlen(optarg) > 3 &&
+                                       strncasecmp(optarg, "hci", 3) == 0)
+                               index = atoi(&optarg[4]);
+                       else
+                               index = atoi(optarg);
+                       break;
+               case 'v':
+                       monitor = true;
+                       break;
+               case 'h':
+               default:
+                       usage();
+                       return 0;
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+       optind = 0;
+
+       if (argc < 1) {
+               usage();
+               return 0;
+       }
+
+       mgmt_sk = mgmt_open();
+       if (mgmt_sk < 0) {
+               fprintf(stderr, "Unable to open mgmt socket\n");
+               return -1;
+       }
+
+       for (i = 0; command[i].cmd; i++) {
+               if (strcmp(command[i].cmd, argv[0]) != 0)
+                       continue;
+
+               command[i].func(mgmt_sk, index, argc, argv);
+               break;
+       }
+
+       if (command[i].cmd == NULL) {
+               fprintf(stderr, "Unknown command: %s\n", argv[0]);
+               close(mgmt_sk);
+               return -1;
+       }
+
+       pollfd.fd = mgmt_sk;
+       pollfd.events = POLLIN;
+       pollfd.revents = 0;
+
+       while (poll(&pollfd, 1, -1) >= 0) {
+               if (pollfd.revents & (POLLHUP | POLLERR | POLLNVAL))
+                       break;
+
+               if (pollfd.revents & POLLIN)
+                       mgmt_process_data(mgmt_sk);
+
+               pollfd.revents = 0;
+       }
+
+       close(mgmt_sk);
+
+       return 0;
+}
index 3813205..eb24eda 100644 (file)
@@ -58,18 +58,6 @@ static struct {
        { NULL }
 };
 
-#ifdef  __TIZEN_PATCH__
-struct bnep_data {
-       char *devname;
-       char *script;
-       int pid;
-};
-
-struct bnep_data data;
-#endif
-
-
-
 uint16_t bnep_service_id(const char *svc)
 {
        int i;
@@ -120,10 +108,10 @@ int bnep_init(void)
        ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
 
        if (ctl < 0) {
-               int err = errno;
+               int err = -errno;
                error("Failed to open control socket: %s (%d)",
-                                               strerror(err), err);
-               return -err;
+                                               strerror(-err), -err);
+               return err;
        }
 
        return 0;
@@ -143,10 +131,10 @@ int bnep_kill_connection(bdaddr_t *dst)
        baswap((bdaddr_t *)&req.dst, dst);
        req.flags = 0;
        if (ioctl(ctl, BNEPCONNDEL, &req)) {
-               int err = errno;
+               int err = -errno;
                error("Failed to kill connection: %s (%d)",
-                                               strerror(err), err);
-               return -err;
+                                               strerror(-err), -err);
+               return err;
        }
        return 0;
 }
@@ -162,10 +150,10 @@ int bnep_kill_all_connections(void)
        req.cnum = 7;
        req.ci   = ci;
        if (ioctl(ctl, BNEPGETCONNLIST, &req)) {
-               err = errno;
+               err = -errno;
                error("Failed to get connection list: %s (%d)",
-                                               strerror(err), err);
-               return -err;
+                                               strerror(-err), -err);
+               return err;
        }
 
        for (i = 0; i < req.cnum; i++) {
@@ -189,57 +177,16 @@ int bnep_connadd(int sk, uint16_t role, char *dev)
        req.sock = sk;
        req.role = role;
        if (ioctl(ctl, BNEPCONNADD, &req) < 0) {
-               int err = errno;
+               int err = -errno;
                error("Failed to add device %s: %s(%d)",
-                               dev, strerror(err), err);
-               return -err;
+                               dev, strerror(-err), -err);
+               return err;
        }
 
        strncpy(dev, req.device, 16);
        return 0;
 }
 
-#ifdef  __TIZEN_PATCH__
-static void bnep_child_setup(gpointer data)
-{
-}
-
-void bnep_server_connect(char *devname)
-{
-       // Run bluetooth-ics
-       const char *argv[5];
-       GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH;
-
-       argv[0] = "bluetooth-ics";
-       argv[1] = devname;
-       argv[2] = NULL;
-       argv[3] = NULL;
-
-       if (!g_spawn_async(NULL, (char **) argv, NULL, flags, bnep_child_setup, NULL,
-                               &data.pid, NULL)) {
-               error("Unable to execute %s %s", argv[0], argv[1]);
-       }
-}
-
-void bnep_server_disconnect(void)
-{
-       int err = -1;
-
-       // Kill bluetooth-ics
-       info("data.pid: %d", data.pid);
-
-       if (data.pid > 0)
-       {
-               /* Kill script */
-               err = kill(data.pid, SIGTERM);
-               if (err < 0)
-                       error("kill(%d, SIGTERM): %s (%d)", data.pid, strerror(errno), errno);
-
-               data.pid = 0;
-       }
-}
-#endif
-
 int bnep_if_up(const char *devname)
 {
        struct ifreq ifr;
@@ -282,6 +229,11 @@ int bnep_if_down(const char *devname)
 
        close(sk);
 
+       if (err < 0) {
+               error("Could not bring down %s", devname);
+               return err;
+       }
+
        return 0;
 }
 
@@ -298,7 +250,7 @@ int bnep_add_to_bridge(const char *devname, const char *bridge)
        if (sk < 0)
                return -1;
 
-#ifdef  __TIZEN_PATCH__
+#ifdef  __SAMSUNG_PATCH__
        err = ioctl(sk, SIOCBRADDBR, bridge);
        if (err < 0)
        {
index 47dba9d..fefb754 100644 (file)
@@ -40,8 +40,3 @@ int bnep_connadd(int sk, uint16_t role, char *dev);
 int bnep_if_up(const char *devname);
 int bnep_if_down(const char *devname);
 int bnep_add_to_bridge(const char *devname, const char *bridge);
-
-#ifndef  __TIZEN_PATCH__
-void bnep_server_connect(char *devname);
-void bnep_server_disconnect(void);
-#endif
index 943aca4..ca1f4b2 100644 (file)
@@ -38,7 +38,7 @@
 #include <gdbus.h>
 
 #include "log.h"
-#include "glib-helper.h"
+#include "glib-compat.h"
 #include "btio.h"
 #include "dbus-common.h"
 #include "adapter.h"
@@ -85,10 +85,8 @@ static GSList *peers = NULL;
 
 static struct network_peer *find_peer(GSList *list, const char *path)
 {
-       GSList *l;
-
-       for (l = list; l; l = l->next) {
-               struct network_peer *peer = l->data;
+       for (; list; list = list->next) {
+               struct network_peer *peer = list->data;
 
                if (!strcmp(peer->path, path))
                        return peer;
@@ -99,10 +97,8 @@ static struct network_peer *find_peer(GSList *list, const char *path)
 
 static struct network_conn *find_connection(GSList *list, uint16_t id)
 {
-       GSList *l;
-
-       for (l = list; l; l = l->next) {
-               struct network_conn *nc = l->data;
+       for (; list; list = list->next) {
+               struct network_conn *nc = list->data;
 
                if (nc->id == id)
                        return nc;
@@ -119,11 +115,6 @@ static gboolean bnep_watchdog_cb(GIOChannel *chan, GIOCondition cond,
        if (connection != NULL) {
                gboolean connected = FALSE;
                const char *property = "";
-#ifdef __TIZEN_PATCH__
-               char address[20] = {0};
-               const gchar* paddr = address;
-               ba2str(&nc->peer->dst, address);
-#endif
                emit_property_changed(connection, nc->peer->path,
                                        NETWORK_PEER_INTERFACE, "Connected",
                                        DBUS_TYPE_BOOLEAN, &connected);
@@ -133,11 +124,6 @@ static gboolean bnep_watchdog_cb(GIOChannel *chan, GIOCondition cond,
                emit_property_changed(connection, nc->peer->path,
                                        NETWORK_PEER_INTERFACE, "UUID",
                                        DBUS_TYPE_STRING, &property);
-#ifdef __TIZEN_PATCH__
-               emit_property_changed(connection, nc->peer->path,
-                                       NETWORK_PEER_INTERFACE, "Address",
-                                       DBUS_TYPE_STRING, &paddr);
-#endif
                device_remove_disconnect_watch(nc->peer->device, nc->dc_id);
                nc->dc_id = 0;
                if (nc->watch) {
@@ -209,10 +195,6 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
        int sk;
        const char *pdev, *uuid;
        gboolean connected;
-#ifdef __TIZEN_PATCH__
-       char address[20] = {0};
-       const gchar* paddr = address;
-#endif
 
        if (cond & G_IO_NVAL)
                return FALSE;
@@ -278,9 +260,6 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
                        DBUS_TYPE_INVALID);
 
        connected = TRUE;
-#ifdef __TIZEN_PATCH__
-       ba2str(&nc->peer->dst, address);
-#endif
        emit_property_changed(connection, nc->peer->path,
                                NETWORK_PEER_INTERFACE, "Connected",
                                DBUS_TYPE_BOOLEAN, &connected);
@@ -290,11 +269,7 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
        emit_property_changed(connection, nc->peer->path,
                                NETWORK_PEER_INTERFACE, "UUID",
                                DBUS_TYPE_STRING, &uuid);
-#ifdef __TIZEN_PATCH__
-       emit_property_changed(connection, nc->peer->path,
-                               NETWORK_PEER_INTERFACE, "Address",
-                               DBUS_TYPE_STRING, &paddr);
-#endif
+
        nc->state = CONNECTED;
        nc->dc_id = device_add_disconnect_watch(nc->peer->device, disconnect_cb,
                                                nc, NULL);
@@ -502,8 +477,10 @@ static DBusMessage *connection_get_properties(DBusConnection *conn,
        return reply;
 }
 
-static void connection_free(struct network_conn *nc)
+static void connection_free(void *data)
 {
+       struct network_conn *nc = data;
+
        if (nc->dc_id)
                device_remove_disconnect_watch(nc->peer->device, nc->dc_id);
 
@@ -515,8 +492,7 @@ static void connection_free(struct network_conn *nc)
 
 static void peer_free(struct network_peer *peer)
 {
-       g_slist_foreach(peer->connections, (GFunc) connection_free, NULL);
-       g_slist_free(peer->connections);
+       g_slist_free_full(peer->connections, connection_free);
        btd_device_unref(peer->device);
        g_free(peer->path);
        g_free(peer);
index 321640b..00a55aa 100644 (file)
@@ -80,7 +80,7 @@ static int network_probe(struct btd_device *device, GSList *uuids, uint16_t id)
        DBG("path %s", path);
 
        adapter_get_address(adapter, &src);
-       device_get_address(device, &dst);
+       device_get_address(device, &dst, NULL);
 
        return connection_register(device, path, &src, &dst, id);
 }
index 5c993d7..5048efe 100644 (file)
@@ -46,7 +46,7 @@
 #include "error.h"
 #include "sdpd.h"
 #include "btio.h"
-#include "glib-helper.h"
+#include "glib-compat.h"
 
 #include "common.h"
 #include "server.h"
@@ -79,14 +79,16 @@ struct network_server {
        GSList          *sessions;      /* Active connections */
        struct network_adapter *na;     /* Adapter reference */
        guint           watch_id;       /* Client service watch */
+#ifdef __SAMSUNG_PATCH__
        char            dev[16];        /* Interface name */
+#endif
 };
 
 static DBusConnection *connection = NULL;
 static GSList *adapters = NULL;
 static gboolean security = TRUE;
 
-#ifdef  __TIZEN_PATCH__
+#ifdef  __SAMSUNG_PATCH__
 static gboolean server_disconnected_cb(GIOChannel *chan,
                        GIOCondition cond, gpointer user_data);
 #endif
@@ -94,10 +96,8 @@ static gboolean server_disconnected_cb(GIOChannel *chan,
 static struct network_adapter *find_adapter(GSList *list,
                                        struct btd_adapter *adapter)
 {
-       GSList *l;
-
-       for (l = list; l; l = l->next) {
-               struct network_adapter *na = l->data;
+       for (; list; list = list->next) {
+               struct network_adapter *na = list->data;
 
                if (na->adapter == adapter)
                        return na;
@@ -108,10 +108,8 @@ static struct network_adapter *find_adapter(GSList *list,
 
 static struct network_server *find_server(GSList *list, uint16_t id)
 {
-       GSList *l;
-
-       for (l = list; l; l = l->next) {
-               struct network_server *ns = l->data;
+       for (; list; list = list->next) {
+               struct network_server *ns = list->data;
 
                if (ns->id == id)
                        return ns;
@@ -120,7 +118,7 @@ static struct network_server *find_server(GSList *list, uint16_t id)
        return NULL;
 }
 
-#ifdef  __TIZEN_PATCH__
+#ifdef  __SAMSUNG_PATCH__
 static struct network_session *find_session(GSList *list, GIOChannel *io)
 {
        GSList *l;
@@ -304,7 +302,7 @@ static int server_connadd(struct network_server *ns,
 
        info("Added new connection: %s", devname);
 
-#ifdef  __TIZEN_PATCH__
+#ifdef  __SAMSUNG_PATCH__
        {
                guint watch = 0;
 
@@ -402,7 +400,7 @@ static void setup_destroy(void *user_data)
        session_free(setup);
 }
 
-#ifdef  __TIZEN_PATCH__
+#ifdef  __SAMSUNG_PATCH__
 static gboolean server_disconnected_cb(GIOChannel *chan,
                        GIOCondition cond, gpointer user_data)
 {
@@ -433,8 +431,6 @@ static gboolean server_disconnected_cb(GIOChannel *chan,
                        DBUS_TYPE_STRING, &paddr,
                        DBUS_TYPE_INVALID);
 
-       bnep_server_disconnect();
-
        /* Remove the session info */
        session = find_session(ns->sessions, chan);
        if (session) {
@@ -461,7 +457,7 @@ static gboolean bnep_setup(GIOChannel *chan,
        struct bnep_setup_conn_req *req = (void *) packet;
        uint16_t src_role, dst_role, rsp = BNEP_CONN_NOT_ALLOWED;
        int n, sk;
-#ifdef  __TIZEN_PATCH__
+#ifdef  __SAMSUNG_PATCH__
        gboolean connected = TRUE;
 #endif
 
@@ -527,13 +523,13 @@ static gboolean bnep_setup(GIOChannel *chan,
        if (server_connadd(ns, na->setup, dst_role) < 0)
                goto reply;
 
-#ifndef  __TIZEN_PATCH__
+#ifndef  __SAMSUNG_PATCH__
        na->setup = NULL;
 #endif
 
        rsp = BNEP_SUCCESS;
 
-#ifdef  __TIZEN_PATCH__
+#ifdef  __SAMSUNG_PATCH__
 {
 // Emit connected signal to BT application
        const gchar* adapter_path = adapter_get_path(na->adapter);
@@ -734,7 +730,7 @@ static DBusMessage *register_server(DBusConnection *conn,
        g_free(ns->bridge);
        ns->bridge = g_strdup(bridge);
 
-#ifndef  __TIZEN_PATCH__
+#ifndef  __SAMSUNG_PATCH__
        ns->watch_id = g_dbus_add_disconnect_watch(conn,
                                        dbus_message_get_sender(msg),
                                        server_disconnect, ns, NULL);
@@ -765,7 +761,7 @@ static DBusMessage *unregister_server(DBusConnection *conn,
 
        server_disconnect(conn, ns);
 
-#ifdef  __TIZEN_PATCH__
+#ifdef  __SAMSUNG_PATCH__
        /* Down the bnep interface, and disconnect all connection */
        bnep_kill_all_connections();
        bnep_if_down(ns->dev);
@@ -804,10 +800,7 @@ static void server_free(struct network_server *ns)
        g_free(ns->name);
        g_free(ns->bridge);
 
-       if (ns->sessions) {
-               g_slist_foreach(ns->sessions, (GFunc) session_free, NULL);
-               g_slist_free(ns->sessions);
-       }
+       g_slist_free_full(ns->sessions, session_free);
 
        g_free(ns);
 }
@@ -836,7 +829,7 @@ static GDBusMethodTable server_methods[] = {
        { }
 };
 
-#ifdef  __TIZEN_PATCH__
+#ifdef  __SAMSUNG_PATCH__
 static GDBusSignalTable server_signals[] = {
        { "PeerConnected",      "ss"    },
        { "PeerDisconnected",   "ss"    },
@@ -898,7 +891,7 @@ int server_register(struct btd_adapter *adapter)
 
        path = adapter_get_path(adapter);
 
-#ifndef  __TIZEN_PATCH__
+#ifndef  __SAMSUNG_PATCH__
        if (!g_dbus_register_interface(connection, path, ns->iface,
                                        server_methods, NULL, NULL,
                                        ns, path_unregister)) {
index 87ee15c..ff56920 100644 (file)
@@ -105,7 +105,7 @@ Scripts for testing BlueZ and its functionality
 
 %build
 
-export CFLAGS="${CFLAGS} -D__TIZEN_PATCH__ -D__BROADCOM_PATCH__"
+export CFLAGS="${CFLAGS} -D__SAMSUNG_PATCH__ -D__BROADCOM_PATCH__"
 %reconfigure --disable-static \
                        --localstatedir=/opt/var \
                         --enable-pie \
diff --git a/plugins/adaptername.c b/plugins/adaptername.c
new file mode 100644 (file)
index 0000000..e154e92
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Red Hat, Inc.
+ *  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
+ *
+ *  Author: Bastien Nocera <hadess@hadess.net>
+ *  Marcel Holtmann <marcel@holtmann.org> (for expand_name)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <bluetooth/bluetooth.h>
+
+#include "plugin.h"
+#include "hcid.h" /* For main_opts */
+#include "adapter.h"
+#include "manager.h"
+#include "device.h" /* Needed for storage.h */
+#include "storage.h"
+#include "log.h"
+
+#include <sys/inotify.h>
+#define EVENT_SIZE  (sizeof (struct inotify_event))
+#define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))
+
+#define MACHINE_INFO_DIR "/etc/"
+#define MACHINE_INFO_FILE "machine-info"
+
+static GIOChannel *inotify = NULL;
+static int watch_fd = -1;
+
+/* This file is part of systemd's hostnamed functionality:
+ * http://0pointer.de/public/systemd-man/machine-info.html
+ * http://www.freedesktop.org/wiki/Software/systemd/hostnamed
+ */
+static char *read_pretty_host_name(void)
+{
+       char *contents, *ret;
+       char **lines;
+       guint i;
+
+       if (g_file_get_contents(MACHINE_INFO_DIR MACHINE_INFO_FILE,
+                                       &contents, NULL, NULL) == FALSE)
+               return NULL;
+
+       lines = g_strsplit_set(contents, "\r\n", 0);
+       g_free(contents);
+
+       if (lines == NULL)
+               return NULL;
+
+       ret = NULL;
+       for (i = 0; lines[i] != NULL; i++) {
+               if (g_str_has_prefix(lines[i], "PRETTY_HOSTNAME=")) {
+                       ret = g_strdup(lines[i] + strlen("PRETTY_HOSTNAME="));
+                       break;
+               }
+       }
+
+       g_strfreev(lines);
+
+       return ret;
+}
+
+/*
+ * Device name expansion
+ *   %d - device id
+ *   %h - hostname
+ */
+static char *expand_name(char *dst, int size, char *str, int dev_id)
+{
+       register int sp, np, olen;
+       char *opt, buf[10];
+
+       if (!str || !dst)
+               return NULL;
+
+       sp = np = 0;
+       while (np < size - 1 && str[sp]) {
+               switch (str[sp]) {
+               case '%':
+                       opt = NULL;
+
+                       switch (str[sp+1]) {
+                       case 'd':
+                               sprintf(buf, "%d", dev_id);
+                               opt = buf;
+                               break;
+
+                       case 'h':
+                               opt = main_opts.host_name;
+                               break;
+
+                       case '%':
+                               dst[np++] = str[sp++];
+                               /* fall through */
+                       default:
+                               sp++;
+                               continue;
+                       }
+
+                       if (opt) {
+                               /* substitute */
+                               olen = strlen(opt);
+                               if (np + olen < size - 1)
+                                       memcpy(dst + np, opt, olen);
+                               np += olen;
+                       }
+                       sp += 2;
+                       continue;
+
+               case '\\':
+                       sp++;
+                       /* fall through */
+               default:
+                       dst[np++] = str[sp++];
+                       break;
+               }
+       }
+       dst[np] = '\0';
+       return dst;
+}
+
+static int get_default_adapter_id(void)
+{
+       struct btd_adapter *default_adapter;
+
+       default_adapter = manager_get_default_adapter();
+       if (default_adapter == NULL)
+               return -1;
+
+       return adapter_get_dev_id(default_adapter);
+}
+
+static void set_pretty_name(struct btd_adapter *adapter,
+                                               const char *pretty_hostname)
+{
+       int current_id;
+       int default_adapter;
+
+       default_adapter = get_default_adapter_id();
+       current_id = adapter_get_dev_id(adapter);
+
+       /* Allow us to change the name */
+       adapter_set_allow_name_changes(adapter, TRUE);
+
+       /* If it's the first device, let's assume it will be the
+        * default one, as we're not told when the default adapter
+        * changes */
+       if (default_adapter < 0)
+               default_adapter = current_id;
+
+       if (default_adapter != current_id) {
+               char *str;
+
+               /* +1 because we don't want an adapter called "Foobar's
+                * laptop #0" */
+               str = g_strdup_printf("%s #%d", pretty_hostname,
+                                                       current_id + 1);
+               DBG("Setting name '%s' for device 'hci%d'", str, current_id);
+
+               adapter_set_name(adapter, str);
+               g_free(str);
+       } else {
+               DBG("Setting name '%s' for device 'hci%d'", pretty_hostname,
+                                                               current_id);
+               adapter_set_name(adapter, pretty_hostname);
+       }
+
+       /* And disable the name change now */
+       adapter_set_allow_name_changes(adapter, FALSE);
+}
+
+static int adaptername_probe(struct btd_adapter *adapter)
+{
+       int current_id;
+       char name[MAX_NAME_LENGTH + 1];
+       char *pretty_hostname;
+       bdaddr_t bdaddr;
+
+       pretty_hostname = read_pretty_host_name();
+       if (pretty_hostname != NULL) {
+               set_pretty_name(adapter, pretty_hostname);
+               g_free(pretty_hostname);
+               return 0;
+       }
+
+       adapter_set_allow_name_changes(adapter, TRUE);
+       adapter_get_address(adapter, &bdaddr);
+       current_id = adapter_get_dev_id(adapter);
+
+       if (read_local_name(&bdaddr, name) < 0)
+               expand_name(name, MAX_NAME_LENGTH, main_opts.name, current_id);
+
+       DBG("Setting name '%s' for device 'hci%d'", name, current_id);
+       adapter_set_name(adapter, name);
+
+       return 0;
+}
+
+static gboolean handle_inotify_cb(GIOChannel *channel, GIOCondition cond,
+                                                               gpointer data)
+{
+       char buf[EVENT_BUF_LEN];
+       GIOStatus err;
+       gsize len, i;
+       gboolean changed;
+
+       changed = FALSE;
+
+       err = g_io_channel_read_chars(channel, buf, EVENT_BUF_LEN, &len, NULL);
+       if (err != G_IO_STATUS_NORMAL) {
+               error("Error reading inotify event: %d\n", err);
+               return FALSE;
+       }
+
+       i = 0;
+       while (i < len) {
+               struct inotify_event *pevent = (struct inotify_event *) &buf[i];
+
+               /* check that it's ours */
+               if (pevent->len && pevent->name != NULL &&
+                               strcmp(pevent->name, MACHINE_INFO_FILE) == 0)
+                       changed = TRUE;
+
+               i += EVENT_SIZE + pevent->len;
+       }
+
+       if (changed != FALSE) {
+               DBG(MACHINE_INFO_DIR MACHINE_INFO_FILE
+                               " changed, changing names for adapters");
+               manager_foreach_adapter((adapter_cb) adaptername_probe, NULL);
+       }
+
+       return TRUE;
+}
+
+static void adaptername_remove(struct btd_adapter *adapter)
+{
+}
+
+static struct btd_adapter_driver adaptername_driver = {
+       .name   = "adaptername",
+       .probe  = adaptername_probe,
+       .remove = adaptername_remove,
+};
+
+static int adaptername_init(void)
+{
+       int err;
+       int inot_fd;
+       guint32 mask;
+
+       err = btd_register_adapter_driver(&adaptername_driver);
+       if (err < 0)
+               return err;
+
+       inot_fd = inotify_init();
+       if (inot_fd < 0) {
+               error("Failed to setup inotify");
+               return 0;
+       }
+
+       mask = IN_CLOSE_WRITE;
+       mask |= IN_DELETE;
+       mask |= IN_CREATE;
+       mask |= IN_MOVED_FROM;
+       mask |= IN_MOVED_TO;
+
+       watch_fd = inotify_add_watch(inot_fd, MACHINE_INFO_DIR, mask);
+       if (watch_fd < 0) {
+               error("Failed to setup watch for '%s'", MACHINE_INFO_DIR);
+               close(inot_fd);
+               return 0;
+       }
+
+       inotify = g_io_channel_unix_new(inot_fd);
+       g_io_channel_set_close_on_unref(inotify, TRUE);
+       g_io_channel_set_encoding(inotify, NULL, NULL);
+       g_io_channel_set_flags(inotify, G_IO_FLAG_NONBLOCK, NULL);
+       g_io_add_watch(inotify, G_IO_IN, handle_inotify_cb, NULL);
+
+       return 0;
+}
+
+static void adaptername_exit(void)
+{
+       if (watch_fd >= 0)
+               close(watch_fd);
+       if (inotify != NULL) {
+               g_io_channel_shutdown(inotify, FALSE, NULL);
+               g_io_channel_unref(inotify);
+       }
+
+       btd_unregister_adapter_driver(&adaptername_driver);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(adaptername, VERSION,
+               BLUETOOTH_PLUGIN_PRIORITY_LOW, adaptername_init, adaptername_exit)
diff --git a/plugins/dbusoob.c b/plugins/dbusoob.c
new file mode 100644 (file)
index 0000000..2c03780
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  ST-Ericsson SA
+ *
+ *  Author: Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <gdbus.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/sdp.h>
+
+#include "plugin.h"
+#include "log.h"
+#include "adapter.h"
+#include "device.h"
+#include "manager.h"
+#include "dbus-common.h"
+#include "event.h"
+#include "error.h"
+#include "oob.h"
+
+#define OOB_INTERFACE  "org.bluez.OutOfBand"
+
+struct oob_request {
+       struct btd_adapter *adapter;
+       DBusMessage *msg;
+};
+
+static GSList *oob_requests = NULL;
+static DBusConnection *connection = NULL;
+
+static gint oob_request_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct oob_request *data = a;
+       const struct btd_adapter *adapter = b;
+
+       return data->adapter != adapter;
+}
+
+static struct oob_request *find_oob_request(struct btd_adapter *adapter)
+{
+       GSList *match;
+
+       match = g_slist_find_custom(oob_requests, adapter, oob_request_cmp);
+
+       if (match)
+               return match->data;
+
+       return NULL;
+}
+
+static void read_local_data_complete(struct btd_adapter *adapter, uint8_t *hash,
+                               uint8_t *randomizer)
+{
+       struct DBusMessage *reply;
+       struct oob_request *oob_request;
+
+       oob_request = find_oob_request(adapter);
+       if (!oob_request)
+               return;
+
+       if (hash && randomizer)
+               reply = g_dbus_create_reply(oob_request->msg,
+                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, 16,
+                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, 16,
+                       DBUS_TYPE_INVALID);
+       else
+               reply = btd_error_failed(oob_request->msg,
+                                       "Failed to read local OOB data.");
+
+       oob_requests = g_slist_remove(oob_requests, oob_request);
+       dbus_message_unref(oob_request->msg);
+       g_free(oob_request);
+
+       if (!reply) {
+               error("Couldn't allocate D-Bus message");
+               return;
+       }
+
+       if (!g_dbus_send_message(connection, reply))
+               error("D-Bus send failed");
+}
+
+static DBusMessage *read_local_data(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct btd_adapter *adapter = data;
+       struct oob_request *oob_request;
+
+       if (find_oob_request(adapter))
+               return btd_error_in_progress(msg);
+
+       if (btd_adapter_read_local_oob_data(adapter))
+               return btd_error_failed(msg, "Request failed.");
+
+       oob_request = g_new(struct oob_request, 1);
+       oob_request->adapter = adapter;
+       oob_requests = g_slist_append(oob_requests, oob_request);
+       oob_request->msg = dbus_message_ref(msg);
+
+       return NULL;
+}
+
+static DBusMessage *add_remote_data(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct btd_adapter *adapter = data;
+       uint8_t *hash, *randomizer;
+       int32_t hlen, rlen;
+       const char *addr;
+       bdaddr_t bdaddr;
+
+       if (!dbus_message_get_args(msg, NULL,
+                       DBUS_TYPE_STRING, &addr,
+                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, &hlen,
+                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, &rlen,
+                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       if (hlen != 16 || rlen != 16 || bachk(addr))
+               return btd_error_invalid_args(msg);
+
+       str2ba(addr, &bdaddr);
+
+       if (btd_adapter_add_remote_oob_data(adapter, &bdaddr, hash, randomizer))
+               return btd_error_failed(msg, "Request failed");
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *remove_remote_data(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct btd_adapter *adapter = data;
+       const char *addr;
+       bdaddr_t bdaddr;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr,
+                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       if (bachk(addr))
+               return btd_error_invalid_args(msg);
+
+       str2ba(addr, &bdaddr);
+
+       if (btd_adapter_remove_remote_oob_data(adapter, &bdaddr))
+               return btd_error_failed(msg, "Request failed");
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static GDBusMethodTable oob_methods[] = {
+       {"AddRemoteData",       "sayay",        "",     add_remote_data},
+       {"RemoveRemoteData",    "s",            "",     remove_remote_data},
+       {"ReadLocalData",       "",             "ayay", read_local_data,
+                                               G_DBUS_METHOD_FLAG_ASYNC},
+       {}
+};
+
+static int oob_probe(struct btd_adapter *adapter)
+{
+       const char *path = adapter_get_path(adapter);
+
+       if (!g_dbus_register_interface(connection, path, OOB_INTERFACE,
+                               oob_methods, NULL, NULL, adapter, NULL)) {
+                       error("OOB interface init failed on path %s", path);
+                       return -EIO;
+               }
+
+       return 0;
+}
+
+static void oob_remove(struct btd_adapter *adapter)
+{
+       read_local_data_complete(adapter, NULL, NULL);
+
+       g_dbus_unregister_interface(connection, adapter_get_path(adapter),
+                                                       OOB_INTERFACE);
+}
+
+static struct btd_adapter_driver oob_driver = {
+       .name   = "oob",
+       .probe  = oob_probe,
+       .remove = oob_remove,
+};
+
+static int dbusoob_init(void)
+{
+       DBG("Setup dbusoob plugin");
+
+       connection = get_dbus_connection();
+
+       oob_register_cb(read_local_data_complete);
+
+       return btd_register_adapter_driver(&oob_driver);
+}
+
+static void dbusoob_exit(void)
+{
+       DBG("Cleanup dbusoob plugin");
+
+       manager_foreach_adapter((adapter_cb) oob_remove, NULL);
+
+       btd_unregister_adapter_driver(&oob_driver);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(dbusoob, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                                               dbusoob_init, dbusoob_exit)
diff --git a/plugins/echo.c b/plugins/echo.c
deleted file mode 100644 (file)
index 23f6e49..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <unistd.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-
-#include <glib.h>
-
-#include <gdbus.h>
-
-#include "plugin.h"
-#include "adapter.h"
-#include "log.h"
-
-static gboolean session_event(GIOChannel *chan,
-                                       GIOCondition cond, gpointer data)
-{
-       unsigned char buf[672];
-       gsize len, written;
-       GIOError err;
-
-       if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
-               return FALSE;
-
-       err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
-       if (err == G_IO_ERROR_AGAIN)
-               return TRUE;
-
-       g_io_channel_write(chan, (const gchar *) buf, len, &written);
-
-       return TRUE;
-}
-
-static gboolean connect_event(GIOChannel *chan,
-                                       GIOCondition cond, gpointer data)
-{
-       GIOChannel *io;
-       struct sockaddr_rc addr;
-       socklen_t optlen;
-       char address[18];
-       int sk, nsk;
-
-       sk = g_io_channel_unix_get_fd(chan);
-
-       memset(&addr, 0, sizeof(addr));
-       optlen = sizeof(addr);
-
-       nsk = accept(sk, (struct sockaddr *) &addr, &optlen);
-       if (nsk < 0)
-               return TRUE;
-
-       io = g_io_channel_unix_new(nsk);
-       g_io_channel_set_close_on_unref(io, TRUE);
-
-       ba2str(&addr.rc_bdaddr, address);
-
-       g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                                                       session_event, NULL);
-
-       return TRUE;
-}
-
-static GIOChannel *setup_rfcomm(uint8_t channel)
-{
-       GIOChannel *io;
-       struct sockaddr_rc addr;
-       int sk;
-
-       sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
-       if (sk < 0)
-               return NULL;
-
-       memset(&addr, 0, sizeof(addr));
-       addr.rc_family = AF_BLUETOOTH;
-       bacpy(&addr.rc_bdaddr, BDADDR_ANY);
-       addr.rc_channel = channel;
-
-       if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               close(sk);
-               return NULL;
-       }
-
-       if (listen(sk, 10) < 0) {
-               close(sk);
-               return NULL;
-       }
-
-       io = g_io_channel_unix_new(sk);
-       g_io_channel_set_close_on_unref(io, TRUE);
-
-       g_io_add_watch(io, G_IO_IN, connect_event, NULL);
-
-       return io;
-}
-
-static GIOChannel *chan = NULL;
-
-static int echo_probe(struct btd_adapter *adapter)
-{
-       const char *path = adapter_get_path(adapter);
-
-       DBG("path %s", path);
-
-       chan = setup_rfcomm(23);
-
-       return 0;
-}
-
-static void echo_remove(struct btd_adapter *adapter)
-{
-       const char *path = adapter_get_path(adapter);
-
-       DBG("path %s", path);
-
-       g_io_channel_unref(chan);
-}
-
-static struct btd_adapter_driver echo_server = {
-       .name   = "echo-server",
-       .probe  = echo_probe,
-       .remove = echo_remove,
-};
-
-static int echo_init(void)
-{
-       DBG("Setup echo plugin");
-
-       return btd_register_adapter_driver(&echo_server);
-}
-
-static void echo_exit(void)
-{
-       DBG("Cleanup echo plugin");
-
-       btd_unregister_adapter_driver(&echo_server);
-}
-
-BLUETOOTH_PLUGIN_DEFINE(echo, VERSION,
-               BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, echo_init, echo_exit)
diff --git a/plugins/external-dummy.c b/plugins/external-dummy.c
new file mode 100644 (file)
index 0000000..ff31290
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  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 "plugin.h"
+#include "log.h"
+
+static int dummy_init(void)
+{
+       DBG("");
+
+       return 0;
+}
+
+static void dummy_exit(void)
+{
+       DBG("");
+}
+
+BLUETOOTH_PLUGIN_DEFINE(external_dummy, VERSION,
+               BLUETOOTH_PLUGIN_PRIORITY_LOW, dummy_init, dummy_exit)
index 758d481..0e19ac6 100644 (file)
@@ -73,10 +73,10 @@ static const char *chassis_map[] = {
        "Rack Mount Chassis",    "unknown",
        "Sealed-case PC",        "unknown",
        "Multi-system",          "unknown",
-       "CompactPCI",            "unknonw",
+       "CompactPCI",            "unknown",
        "AdvancedTCA",           "unknown",
        "Blade",                 "server",
-       "Blade Enclosure"        "unknown", /* 0x1D */
+       "Blade Enclosure",       "unknown", /* 0x1D */
        NULL
 };
 
@@ -104,7 +104,7 @@ static int formfactor_probe(struct btd_adapter *adapter)
                return 0;
        }
 
-       formfactor = chassis_map[chassis_type * 2];
+       formfactor = chassis_map[chassis_type * 2 - 1];
        if (formfactor != NULL) {
                if (g_str_equal(formfactor, "laptop") == TRUE)
                        minor |= (1 << 2) | (1 << 3);
diff --git a/plugins/gatt-example.c b/plugins/gatt-example.c
new file mode 100644 (file)
index 0000000..701c1d7
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010  Nokia Corporation
+ *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <bluetooth/uuid.h>
+#include <errno.h>
+#include <adapter.h>
+
+#include "plugin.h"
+#include "hcid.h"
+#include "log.h"
+#include "gattrib.h"
+#include "gatt-service.h"
+#include "att.h"
+#include "attrib-server.h"
+
+/* FIXME: Not defined by SIG? UUID128? */
+#define OPCODES_SUPPORTED_UUID          0xA001
+#define BATTERY_STATE_SVC_UUID         0xA002
+#define BATTERY_STATE_UUID             0xA003
+#define THERM_HUMIDITY_SVC_UUID                0xA004
+#define MANUFACTURER_SVC_UUID          0xA005
+#define TEMPERATURE_UUID               0xA006
+#define FMT_CELSIUS_UUID               0xA007
+#define FMT_OUTSIDE_UUID               0xA008
+#define RELATIVE_HUMIDITY_UUID         0xA009
+#define FMT_PERCENT_UUID               0xA00A
+#define BLUETOOTH_SIG_UUID             0xA00B
+#define MANUFACTURER_NAME_UUID         0xA00C
+#define MANUFACTURER_SERIAL_UUID       0xA00D
+#define VENDOR_SPECIFIC_SVC_UUID       0xA00E
+#define VENDOR_SPECIFIC_TYPE_UUID      0xA00F
+#define FMT_KILOGRAM_UUID              0xA010
+#define FMT_HANGING_UUID               0xA011
+
+struct gatt_example_adapter {
+       struct btd_adapter      *adapter;
+       GSList                  *sdp_handles;
+};
+
+static GSList *adapters = NULL;
+
+static void gatt_example_adapter_free(struct gatt_example_adapter *gadapter)
+{
+       while (gadapter->sdp_handles != NULL) {
+               uint32_t handle = GPOINTER_TO_UINT(gadapter->sdp_handles->data);
+
+               attrib_free_sdp(handle);
+               gadapter->sdp_handles = g_slist_remove(gadapter->sdp_handles,
+                                               gadapter->sdp_handles->data);
+       }
+
+       if (gadapter->adapter != NULL)
+               btd_adapter_unref(gadapter->adapter);
+
+       g_free(gadapter);
+}
+
+static gint adapter_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct gatt_example_adapter *gatt_adapter = a;
+       const struct btd_adapter *adapter = b;
+
+       if (gatt_adapter->adapter == adapter)
+               return 0;
+
+       return -1;
+}
+
+static uint8_t battery_state_read(struct attribute *a, gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       uint8_t value;
+
+       value = 0x04;
+       attrib_db_update(adapter, a->handle, NULL, &value, sizeof(value), NULL);
+
+       return 0;
+}
+
+static gboolean register_battery_service(struct btd_adapter *adapter)
+{
+       return gatt_service_add(adapter, GATT_PRIM_SVC_UUID,
+                       BATTERY_STATE_SVC_UUID,
+                       /* battery state characteristic */
+                       GATT_OPT_CHR_UUID, BATTERY_STATE_UUID,
+                       GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
+                                                       ATT_CHAR_PROPER_NOTIFY,
+                       GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+                                               battery_state_read, adapter,
+
+                       GATT_OPT_INVALID);
+}
+
+static void register_termometer_service(struct gatt_example_adapter *adapter,
+                       const uint16_t manuf1[2], const uint16_t manuf2[2])
+{
+       const char *desc_out_temp = "Outside Temperature";
+       const char *desc_out_hum = "Outside Relative Humidity";
+       uint16_t start_handle, h;
+       const int svc_size = 11;
+       uint32_t sdp_handle;
+       uint8_t atval[256];
+       bt_uuid_t uuid;
+       int len;
+
+       start_handle = attrib_db_find_avail(adapter->adapter, svc_size);
+       if (start_handle == 0) {
+               error("Not enough free handles to register service");
+               return;
+       }
+
+       DBG("start_handle=0x%04x manuf1=0x%04x-0x%04x, manuf2=0x%04x-0x%04x",
+               start_handle, manuf1[0], manuf1[1], manuf2[0], manuf2[1]);
+
+       h = start_handle;
+
+       /* Thermometer: primary service definition */
+       bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+       att_put_u16(THERM_HUMIDITY_SVC_UUID, &atval[0]);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 2);
+
+       bt_uuid16_create(&uuid, GATT_INCLUDE_UUID);
+
+       /* Thermometer: Include */
+       if (manuf1[0] && manuf1[1]) {
+               att_put_u16(manuf1[0], &atval[0]);
+               att_put_u16(manuf1[1], &atval[2]);
+               att_put_u16(MANUFACTURER_SVC_UUID, &atval[4]);
+               attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE,
+                                               ATT_NOT_PERMITTED, atval, 6);
+       }
+
+       /* Thermometer: Include */
+       if (manuf2[0] && manuf2[1]) {
+               att_put_u16(manuf2[0], &atval[0]);
+               att_put_u16(manuf2[1], &atval[2]);
+               att_put_u16(VENDOR_SPECIFIC_SVC_UUID, &atval[4]);
+               attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE,
+                                               ATT_NOT_PERMITTED, atval, 6);
+       }
+
+       /* Thermometer: temperature characteristic */
+       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
+       atval[0] = ATT_CHAR_PROPER_READ;
+       att_put_u16(h + 1, &atval[1]);
+       att_put_u16(TEMPERATURE_UUID, &atval[3]);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 5);
+
+       /* Thermometer: temperature characteristic value */
+       bt_uuid16_create(&uuid, TEMPERATURE_UUID);
+       atval[0] = 0x8A;
+       atval[1] = 0x02;
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 2);
+
+       /* Thermometer: temperature characteristic format */
+       bt_uuid16_create(&uuid, GATT_CHARAC_FMT_UUID);
+       atval[0] = 0x0E;
+       atval[1] = 0xFE;
+       att_put_u16(FMT_CELSIUS_UUID, &atval[2]);
+       atval[4] = 0x01;
+       att_put_u16(FMT_OUTSIDE_UUID, &atval[5]);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 7);
+
+       /* Thermometer: characteristic user description */
+       bt_uuid16_create(&uuid, GATT_CHARAC_USER_DESC_UUID);
+       len = strlen(desc_out_temp);
+       strncpy((char *) atval, desc_out_temp, len);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, len);
+
+       /* Thermometer: relative humidity characteristic */
+       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
+       atval[0] = ATT_CHAR_PROPER_READ;
+       att_put_u16(h + 1, &atval[1]);
+       att_put_u16(RELATIVE_HUMIDITY_UUID, &atval[3]);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 5);
+
+       /* Thermometer: relative humidity value */
+       bt_uuid16_create(&uuid, RELATIVE_HUMIDITY_UUID);
+       atval[0] = 0x27;
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 1);
+
+       /* Thermometer: relative humidity characteristic format */
+       bt_uuid16_create(&uuid, GATT_CHARAC_FMT_UUID);
+       atval[0] = 0x04;
+       atval[1] = 0x00;
+       att_put_u16(FMT_PERCENT_UUID, &atval[2]);
+       att_put_u16(BLUETOOTH_SIG_UUID, &atval[4]);
+       att_put_u16(FMT_OUTSIDE_UUID, &atval[6]);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 8);
+
+       /* Thermometer: characteristic user description */
+       bt_uuid16_create(&uuid, GATT_CHARAC_USER_DESC_UUID);
+       len = strlen(desc_out_hum);
+       strncpy((char *) atval, desc_out_hum, len);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, len);
+
+       g_assert(h - start_handle == svc_size);
+
+       /* Add an SDP record for the above service */
+       sdp_handle = attrib_create_sdp(adapter->adapter, start_handle,
+                                                               "Thermometer");
+       if (sdp_handle)
+               adapter->sdp_handles = g_slist_prepend(adapter->sdp_handles,
+                                               GUINT_TO_POINTER(sdp_handle));
+}
+
+static void register_manuf1_service(struct gatt_example_adapter *adapter,
+                                                       uint16_t range[2])
+{
+       const char *manufacturer_name1 = "ACME Temperature Sensor";
+       const char *serial1 = "237495-3282-A";
+       uint16_t start_handle, h;
+       const int svc_size = 5;
+       uint8_t atval[256];
+       bt_uuid_t uuid;
+       int len;
+
+       start_handle = attrib_db_find_avail(adapter->adapter, svc_size);
+       if (start_handle == 0) {
+               error("Not enough free handles to register service");
+               return;
+       }
+
+       DBG("start_handle=0x%04x", start_handle);
+
+       h = start_handle;
+
+       /* Secondary Service: Manufacturer Service */
+       bt_uuid16_create(&uuid, GATT_SND_SVC_UUID);
+       att_put_u16(MANUFACTURER_SVC_UUID, &atval[0]);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 2);
+
+       /* Manufacturer name characteristic definition */
+       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
+       atval[0] = ATT_CHAR_PROPER_READ;
+       att_put_u16(h + 1, &atval[1]);
+       att_put_u16(MANUFACTURER_NAME_UUID, &atval[3]);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 5);
+
+       /* Manufacturer name characteristic value */
+       bt_uuid16_create(&uuid, MANUFACTURER_NAME_UUID);
+       len = strlen(manufacturer_name1);
+       strncpy((char *) atval, manufacturer_name1, len);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, len);
+
+       /* Manufacturer serial number characteristic */
+       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
+       atval[0] = ATT_CHAR_PROPER_READ;
+       att_put_u16(h + 1, &atval[1]);
+       att_put_u16(MANUFACTURER_SERIAL_UUID, &atval[3]);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 5);
+
+       /* Manufacturer serial number characteristic value */
+       bt_uuid16_create(&uuid, MANUFACTURER_SERIAL_UUID);
+       len = strlen(serial1);
+       strncpy((char *) atval, serial1, len);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, len);
+
+       g_assert(h - start_handle == svc_size);
+
+       range[0] = start_handle;
+       range[1] = start_handle + svc_size - 1;
+}
+
+static void register_manuf2_service(struct gatt_example_adapter *adapter,
+                                                       uint16_t range[2])
+{
+       const char *manufacturer_name2 = "ACME Weighing Scales";
+       const char *serial2 = "11267-2327A00239";
+       uint16_t start_handle, h;
+       const int svc_size = 5;
+       uint8_t atval[256];
+       bt_uuid_t uuid;
+       int len;
+
+       start_handle = attrib_db_find_avail(adapter->adapter, svc_size);
+       if (start_handle == 0) {
+               error("Not enough free handles to register service");
+               return;
+       }
+
+       DBG("start_handle=0x%04x", start_handle);
+
+       h = start_handle;
+
+       /* Secondary Service: Manufacturer Service */
+       bt_uuid16_create(&uuid, GATT_SND_SVC_UUID);
+       att_put_u16(MANUFACTURER_SVC_UUID, &atval[0]);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 2);
+
+       /* Manufacturer name characteristic definition */
+       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
+       atval[0] = ATT_CHAR_PROPER_READ;
+       att_put_u16(h + 1, &atval[1]);
+       att_put_u16(MANUFACTURER_NAME_UUID, &atval[3]);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 5);
+
+       /* Manufacturer name attribute */
+       bt_uuid16_create(&uuid, MANUFACTURER_NAME_UUID);
+       len = strlen(manufacturer_name2);
+       strncpy((char *) atval, manufacturer_name2, len);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, len);
+
+       /* Characteristic: serial number */
+       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
+       atval[0] = ATT_CHAR_PROPER_READ;
+       att_put_u16(h + 1, &atval[1]);
+       att_put_u16(MANUFACTURER_SERIAL_UUID, &atval[3]);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 5);
+
+       /* Serial number characteristic value */
+       bt_uuid16_create(&uuid, MANUFACTURER_SERIAL_UUID);
+       len = strlen(serial2);
+       strncpy((char *) atval, serial2, len);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, len);
+
+       g_assert(h - start_handle == svc_size);
+
+       range[0] = start_handle;
+       range[1] = start_handle + svc_size - 1;
+}
+
+static void register_vendor_service(struct gatt_example_adapter *adapter,
+                                                       uint16_t range[2])
+{
+       uint16_t start_handle, h;
+       const int svc_size = 3;
+       uint8_t atval[256];
+       bt_uuid_t uuid;
+
+       start_handle = attrib_db_find_avail(adapter->adapter, svc_size);
+       if (start_handle == 0) {
+               error("Not enough free handles to register service");
+               return;
+       }
+
+       DBG("start_handle=0x%04x", start_handle);
+
+       h = start_handle;
+
+       /* Secondary Service: Vendor Specific Service */
+       bt_uuid16_create(&uuid, GATT_SND_SVC_UUID);
+       att_put_u16(VENDOR_SPECIFIC_SVC_UUID, &atval[0]);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 2);
+
+       /* Vendor Specific Type characteristic definition */
+       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
+       atval[0] = ATT_CHAR_PROPER_READ;
+       att_put_u16(h + 1, &atval[1]);
+       att_put_u16(VENDOR_SPECIFIC_TYPE_UUID, &atval[3]);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 5);
+
+       /* Vendor Specific Type characteristic value */
+       bt_uuid16_create(&uuid, VENDOR_SPECIFIC_TYPE_UUID);
+       atval[0] = 0x56;
+       atval[1] = 0x65;
+       atval[2] = 0x6E;
+       atval[3] = 0x64;
+       atval[4] = 0x6F;
+       atval[5] = 0x72;
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 6);
+
+       g_assert(h - start_handle == svc_size);
+
+       range[0] = start_handle;
+       range[1] = start_handle + svc_size - 1;
+}
+
+static void register_weight_service(struct gatt_example_adapter *adapter,
+                                               const uint16_t vendor[2])
+{
+       const char *desc_weight = "Rucksack Weight";
+       const uint128_t char_weight_uuid_btorder = {
+               .data = { 0x80, 0x88, 0xF2, 0x18, 0x90, 0x2C, 0x45, 0x0B,
+                         0xB6, 0xC4, 0x62, 0x89, 0x1E, 0x8C, 0x25, 0xE9 } };
+       const uint128_t prim_weight_uuid_btorder = {
+               .data = { 0x4F, 0x0A, 0xC0, 0x96, 0x35, 0xD4, 0x49, 0x11,
+                         0x96, 0x31, 0xDE, 0xA8, 0xDC, 0x74, 0xEE, 0xFE } };
+       uint128_t char_weight_uuid;
+       uint16_t start_handle, h;
+       const int svc_size = 6;
+       uint32_t sdp_handle;
+       uint8_t atval[256];
+       bt_uuid_t uuid;
+       int len;
+
+       btoh128(&char_weight_uuid_btorder, &char_weight_uuid);
+
+       start_handle = attrib_db_find_avail(adapter->adapter, svc_size);
+       if (start_handle == 0) {
+               error("Not enough free handles to register service");
+               return;
+       }
+
+       DBG("start_handle=0x%04x, vendor=0x%04x-0x%04x", start_handle,
+                                                       vendor[0], vendor[1]);
+
+       h = start_handle;
+
+       /* Weight service: primary service definition */
+       bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+       memcpy(atval, &prim_weight_uuid_btorder, 16);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 16);
+
+       if (vendor[0] && vendor[1]) {
+               /* Weight: include */
+               bt_uuid16_create(&uuid, GATT_INCLUDE_UUID);
+               att_put_u16(vendor[0], &atval[0]);
+               att_put_u16(vendor[1], &atval[2]);
+               att_put_u16(MANUFACTURER_SVC_UUID, &atval[4]);
+               attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE,
+                                               ATT_NOT_PERMITTED, atval, 6);
+       }
+
+       /* Weight: characteristic */
+       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
+       atval[0] = ATT_CHAR_PROPER_READ;
+       att_put_u16(h + 1, &atval[1]);
+       memcpy(&atval[3], &char_weight_uuid_btorder, 16);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 19);
+
+       /* Weight: characteristic value */
+       bt_uuid128_create(&uuid, char_weight_uuid);
+       atval[0] = 0x82;
+       atval[1] = 0x55;
+       atval[2] = 0x00;
+       atval[3] = 0x00;
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 4);
+
+       /* Weight: characteristic format */
+       bt_uuid16_create(&uuid, GATT_CHARAC_FMT_UUID);
+       atval[0] = 0x08;
+       atval[1] = 0xFD;
+       att_put_u16(FMT_KILOGRAM_UUID, &atval[2]);
+       att_put_u16(BLUETOOTH_SIG_UUID, &atval[4]);
+       att_put_u16(FMT_HANGING_UUID, &atval[6]);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 8);
+
+       /* Weight: characteristic user description */
+       bt_uuid16_create(&uuid, GATT_CHARAC_USER_DESC_UUID);
+       len = strlen(desc_weight);
+       strncpy((char *) atval, desc_weight, len);
+       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, len);
+
+       g_assert(h - start_handle == svc_size);
+
+       /* Add an SDP record for the above service */
+       sdp_handle = attrib_create_sdp(adapter->adapter, start_handle,
+                                                       "Weight Service");
+       if (sdp_handle)
+               adapter->sdp_handles = g_slist_prepend(adapter->sdp_handles,
+                                               GUINT_TO_POINTER(sdp_handle));
+}
+
+static int gatt_example_adapter_probe(struct btd_adapter *adapter)
+{
+       uint16_t manuf1_range[2] = {0, 0}, manuf2_range[2] = {0, 0};
+       uint16_t vendor_range[2] = {0, 0};
+       struct gatt_example_adapter *gadapter;
+
+       gadapter = g_new0(struct gatt_example_adapter, 1);
+       gadapter->adapter = btd_adapter_ref(adapter);
+
+       if (!register_battery_service(adapter)) {
+               DBG("Battery service could not be registered");
+               gatt_example_adapter_free(gadapter);
+               return -EIO;
+       }
+
+       register_manuf1_service(gadapter, manuf1_range);
+       register_manuf2_service(gadapter, manuf2_range);
+       register_termometer_service(gadapter, manuf1_range, manuf2_range);
+       register_vendor_service(gadapter, vendor_range);
+       register_weight_service(gadapter, vendor_range);
+
+       adapters = g_slist_append(adapters, gadapter);
+
+       return 0;
+}
+
+static void gatt_example_adapter_remove(struct btd_adapter *adapter)
+{
+       struct gatt_example_adapter *gadapter;
+       GSList *l;
+
+       l = g_slist_find_custom(adapters, adapter, adapter_cmp);
+       if (l == NULL)
+               return;
+
+       gadapter = l->data;
+       adapters = g_slist_remove(adapters, gadapter);
+       gatt_example_adapter_free(gadapter);
+}
+
+static struct btd_adapter_driver gatt_example_adapter_driver = {
+       .name   = "gatt-example-adapter-driver",
+       .probe  = gatt_example_adapter_probe,
+       .remove = gatt_example_adapter_remove,
+};
+
+static int gatt_example_init(void)
+{
+       if (!main_opts.attrib_server) {
+               DBG("Attribute server is disabled");
+               return -ENOTSUP;
+       }
+
+       return btd_register_adapter_driver(&gatt_example_adapter_driver);
+}
+
+static void gatt_example_exit(void)
+{
+       if (!main_opts.attrib_server)
+               return;
+
+       btd_unregister_adapter_driver(&gatt_example_adapter_driver);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(gatt_example, VERSION, BLUETOOTH_PLUGIN_PRIORITY_LOW,
+                                       gatt_example_init, gatt_example_exit)
index 163577f..77d2421 100644 (file)
@@ -40,6 +40,7 @@
 
 #include <glib.h>
 
+#include "glib-compat.h"
 #include "hcid.h"
 #include "sdpd.h"
 #include "btio.h"
 #include "storage.h"
 #include "event.h"
 #include "manager.h"
+#include "oob.h"
+#include "eir.h"
+
+#define DISCOV_HALTED 0
+#define DISCOV_INQ 1
+#define DISCOV_SCAN 2
+#define DISCOV_NAMES 3
+
+#define TIMEOUT_BR_LE_SCAN 5120 /* TGAP(100)/2 */
+#define TIMEOUT_LE_SCAN 10240 /* TGAP(gen_disc_scan_min) */
+
+#define LENGTH_BR_INQ 0x08
+#define LENGTH_BR_LE_INQ 0x04
+
+static int start_scanning(int index, int timeout);
 
 static int child_pipe[2] = { -1, -1 };
 
 static guint child_io_id = 0;
 static guint ctl_io_id = 0;
 
+enum adapter_type {
+       BR_EDR,
+       LE_ONLY,
+       BR_EDR_LE,
+       UNKNOWN,
+};
+
 /* Commands sent by kernel on starting an adapter */
 enum {
        PENDING_BDADDR,
@@ -64,11 +87,6 @@ enum {
        PENDING_NAME,
 };
 
-struct uuid_info {
-       uuid_t uuid;
-       uint8_t svc_hint;
-};
-
 struct bt_conn {
        struct dev_info *dev;
        bdaddr_t bdaddr;
@@ -77,23 +95,46 @@ struct bt_conn {
        uint8_t loc_auth;
        uint8_t rem_cap;
        uint8_t rem_auth;
+       uint8_t rem_oob_data;
        gboolean bonding_initiator;
        gboolean secmode3;
        GIOChannel *io; /* For raw L2CAP socket (bonding) */
 };
 
+struct oob_data {
+       bdaddr_t bdaddr;
+       uint8_t hash[16];
+       uint8_t randomizer[16];
+};
+
+enum name_state {
+       NAME_UNKNOWN,
+       NAME_NEEDED,
+       NAME_NOT_NEEDED,
+       NAME_PENDING,
+};
+
+struct found_dev {
+       bdaddr_t bdaddr;
+       int8_t rssi;
+       enum name_state name_state;
+};
+
 static int max_dev = -1;
 static struct dev_info {
        int id;
        int sk;
        bdaddr_t bdaddr;
        char name[249];
-       uint8_t eir[240];
+       uint8_t eir[HCI_MAX_EIR_LENGTH];
        uint8_t features[8];
+       uint8_t extfeatures[8];
        uint8_t ssp_mode;
 
        int8_t tx_power;
 
+       int discov_state;
+
        uint32_t current_cod;
        uint32_t wanted_cod;
        uint32_t pending_cod;
@@ -111,7 +152,7 @@ static struct dev_info {
        uint16_t did_version;
 
        gboolean up;
-       unsigned long pending;
+       uint32_t pending;
 
        GIOChannel *io;
        guint watch_id;
@@ -120,11 +161,145 @@ static struct dev_info {
        GSList *keys;
        uint8_t pin_length;
 
+       GSList *oob_data;
+
        GSList *uuids;
 
        GSList *connections;
+
+       GSList *found_devs;
+       GSList *need_name;
+
+       guint stop_scan_id;
 } *devs = NULL;
 
+static int found_dev_rssi_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct found_dev *d1 = a, *d2 = b;
+       int rssi1, rssi2;
+
+       if (d2->name_state == NAME_NOT_NEEDED)
+               return -1;
+
+       rssi1 = d1->rssi < 0 ? -d1->rssi : d1->rssi;
+       rssi2 = d2->rssi < 0 ? -d2->rssi : d2->rssi;
+
+       return rssi1 - rssi2;
+}
+
+static int found_dev_bda_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct found_dev *d1 = a, *d2 = b;
+
+       return bacmp(&d1->bdaddr, &d2->bdaddr);
+}
+
+static void found_dev_cleanup(struct dev_info *info)
+{
+       g_slist_free_full(info->found_devs, g_free);
+       info->found_devs = NULL;
+
+       g_slist_free_full(info->need_name, g_free);
+       info->need_name = NULL;
+}
+
+static int resolve_name(struct dev_info *info, bdaddr_t *bdaddr)
+{
+       remote_name_req_cp cp;
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%d dba %s", info->id, addr);
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, bdaddr);
+       cp.pscan_rep_mode = 0x02;
+
+       if (hci_send_cmd(info->sk, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ,
+                                       REMOTE_NAME_REQ_CP_SIZE, &cp) < 0)
+               return -errno;
+
+       return 0;
+}
+
+static int resolve_names(struct dev_info *info, struct btd_adapter *adapter)
+{
+       struct found_dev *dev;
+
+       DBG("found_dev %u need_name %u", g_slist_length(info->found_devs),
+                                       g_slist_length(info->need_name));
+
+       if (g_slist_length(info->need_name) == 0)
+               return -ENOENT;
+
+       dev = info->need_name->data;
+       resolve_name(info, &dev->bdaddr);
+       dev->name_state = NAME_PENDING;
+
+       return 0;
+}
+
+static void set_state(int index, int state)
+{
+       struct btd_adapter *adapter;
+       struct dev_info *dev = &devs[index];
+
+       if (dev->discov_state == state)
+               return;
+
+       adapter = manager_find_adapter_by_id(index);
+       if (!adapter) {
+               error("No matching adapter found");
+               return;
+       }
+
+       dev->discov_state = state;
+
+       DBG("hci%d: new state %d", index, dev->discov_state);
+
+       switch (dev->discov_state) {
+       case DISCOV_HALTED:
+               found_dev_cleanup(dev);
+               adapter_set_discovering(adapter, FALSE);
+               break;
+       case DISCOV_INQ:
+       case DISCOV_SCAN:
+               adapter_set_discovering(adapter, TRUE);
+               break;
+       case DISCOV_NAMES:
+               if (resolve_names(dev, adapter) < 0)
+                       set_state(index, DISCOV_HALTED);
+               break;
+       }
+}
+
+static inline gboolean is_le_capable(int index)
+{
+       struct dev_info *dev = &devs[index];
+
+       return (dev->features[4] & LMP_LE &&
+                       dev->extfeatures[0] & LMP_HOST_LE) ? TRUE : FALSE;
+}
+
+static inline gboolean is_bredr_capable(int index)
+{
+       struct dev_info *dev = &devs[index];
+
+       return (dev->features[4] & LMP_NO_BREDR) == 0 ? TRUE : FALSE;
+}
+
+static int get_adapter_type(int index)
+{
+       if (is_le_capable(index) && is_bredr_capable(index))
+               return BR_EDR_LE;
+       else if (is_le_capable(index))
+               return LE_ONLY;
+       else if (is_bredr_capable(index))
+               return BR_EDR;
+
+       return UNKNOWN;
+}
+
 static int ignore_device(struct hci_dev_info *di)
 {
        return hci_test_bit(HCI_RAW, &di->flags) || di->type >> 4 != HCI_BREDR;
@@ -143,6 +318,7 @@ static struct dev_info *init_dev_info(int index, int sk, gboolean registered,
        dev->registered = registered;
        dev->already_up = already_up;
        dev->io_capability = 0x03; /* No Input No Output */
+       dev->discov_state = DISCOV_HALTED;
 
        return dev;
 }
@@ -462,24 +638,13 @@ static void start_adapter(int index)
 static int hciops_stop_inquiry(int index)
 {
        struct dev_info *dev = &devs[index];
-       struct hci_dev_info di;
-       int err;
 
        DBG("hci%d", index);
 
-       if (hci_devinfo(index, &di) < 0)
+       if (hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_INQUIRY_CANCEL, 0, 0) < 0)
                return -errno;
 
-       if (hci_test_bit(HCI_INQUIRY, &di.flags))
-               err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
-                                               OCF_INQUIRY_CANCEL, 0, 0);
-       else
-               err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
-                                       OCF_EXIT_PERIODIC_INQUIRY, 0, 0);
-       if (err < 0)
-               err = -errno;
-
-       return err;
+       return 0;
 }
 
 static gboolean init_adapter(int index)
@@ -504,7 +669,7 @@ static gboolean init_adapter(int index)
                return FALSE;
 
        btd_adapter_get_mode(adapter, &mode, &on_mode, &pairable);
-       DBG("SYAM Mode =  %d, on_mode = %d, pairable = %d", mode, on_mode, pairable);
+
        if (existing_adapter)
                mode = on_mode;
 
@@ -724,6 +889,8 @@ static int disconnect_addr(int index, bdaddr_t *dba, uint8_t reason)
 static void bonding_complete(struct dev_info *dev, struct bt_conn *conn,
                                                                uint8_t status)
 {
+       struct btd_adapter *adapter;
+
        DBG("status 0x%02x", status);
 
        if (conn->io != NULL) {
@@ -736,7 +903,9 @@ static void bonding_complete(struct dev_info *dev, struct bt_conn *conn,
 
        conn->bonding_initiator = FALSE;
 
-       btd_event_bonding_complete(&dev->bdaddr, &conn->bdaddr, status);
+       adapter = manager_find_adapter(&dev->bdaddr);
+       if (adapter)
+               adapter_bonding_complete(adapter, &conn->bdaddr, status);
 }
 
 static int get_auth_info(int index, bdaddr_t *bdaddr, uint8_t *auth)
@@ -863,7 +1032,7 @@ static void link_key_notify(int index, void *ptr)
                /* Some buggy controller combinations generate a changed
                 * combination key for legacy pairing even when there's no
                 * previous key */
-               if ((!conn || conn->rem_auth == 0xff) && old_key_type == 0xff)
+               if (conn->rem_auth == 0xff && old_key_type == 0xff)
                        key_type = 0x00;
                else if (old_key_type != 0xff)
                        key_type = old_key_type;
@@ -1053,14 +1222,42 @@ static void user_passkey_notify(int index, void *ptr)
                                                btohl(req->passkey));
 }
 
-static void remote_oob_data_request(int index, void *ptr)
+static gint oob_bdaddr_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct oob_data *data = a;
+       const bdaddr_t *bdaddr = b;
+
+       return bacmp(&data->bdaddr, bdaddr);
+}
+
+static void remote_oob_data_request(int index, bdaddr_t *bdaddr)
 {
        struct dev_info *dev = &devs[index];
+       GSList *match;
 
        DBG("hci%d", index);
 
-       hci_send_cmd(dev->sk, OGF_LINK_CTL,
-                               OCF_REMOTE_OOB_DATA_NEG_REPLY, 6, ptr);
+       match = g_slist_find_custom(dev->oob_data, bdaddr, oob_bdaddr_cmp);
+
+       if (match) {
+               struct oob_data *data;
+               remote_oob_data_reply_cp cp;
+
+               data = match->data;
+
+               bacpy(&cp.bdaddr, &data->bdaddr);
+               memcpy(cp.hash, data->hash, sizeof(cp.hash));
+               memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer));
+
+               dev->oob_data = g_slist_delete_link(dev->oob_data, match);
+
+               hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_REMOTE_OOB_DATA_REPLY,
+                               REMOTE_OOB_DATA_REPLY_CP_SIZE, &cp);
+
+       } else {
+               hci_send_cmd(dev->sk, OGF_LINK_CTL,
+                               OCF_REMOTE_OOB_DATA_NEG_REPLY, 6, bdaddr);
+       }
 }
 
 static int get_io_cap(int index, bdaddr_t *bdaddr, uint8_t *cap, uint8_t *auth)
@@ -1158,11 +1355,23 @@ static void io_capa_request(int index, void *ptr)
                                        IO_CAPABILITY_NEG_REPLY_CP_SIZE, &cp);
        } else {
                io_capability_reply_cp cp;
+               struct bt_conn *conn;
+               GSList *match;
+
                memset(&cp, 0, sizeof(cp));
                bacpy(&cp.bdaddr, dba);
                cp.capability = cap;
-               cp.oob_data = 0x00;
                cp.authentication = auth;
+
+               conn = find_connection(dev, dba);
+               match = g_slist_find_custom(dev->oob_data, dba, oob_bdaddr_cmp);
+
+               if ((conn->bonding_initiator || conn->rem_oob_data == 0x01) &&
+                               match)
+                       cp.oob_data = 0x01;
+               else
+                       cp.oob_data = 0x00;
+
                hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_IO_CAPABILITY_REPLY,
                                        IO_CAPABILITY_REPLY_CP_SIZE, &cp);
        }
@@ -1182,6 +1391,7 @@ static void io_capa_response(int index, void *ptr)
        if (conn) {
                conn->rem_cap = evt->capability;
                conn->rem_auth = evt->authentication;
+               conn->rem_oob_data = evt->oob_data;
        }
 }
 
@@ -1208,7 +1418,7 @@ static void pin_code_request(int index, bdaddr_t *dba)
                goto reject;
        }
 
-       err = btd_event_request_pin(&dev->bdaddr, dba);
+       err = btd_event_request_pin(&dev->bdaddr, dba, FALSE);
        if (err < 0) {
                error("PIN code negative reply: %s", strerror(-err));
                goto reject;
@@ -1220,56 +1430,6 @@ reject:
        hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, dba);
 }
 
-static void start_inquiry(bdaddr_t *local, uint8_t status, gboolean periodic)
-{
-       struct btd_adapter *adapter;
-       int state;
-
-       /* Don't send the signal if the cmd failed */
-       if (status) {
-               error("Inquiry Failed with status 0x%02x", status);
-               return;
-       }
-
-       adapter = manager_find_adapter(local);
-       if (!adapter) {
-               error("Unable to find matching adapter");
-               return;
-       }
-
-       state = adapter_get_state(adapter);
-
-       if (periodic)
-               state |= STATE_PINQ;
-       else
-               state |= STATE_STDINQ;
-
-       adapter_set_state(adapter, state);
-}
-
-static void inquiry_complete(bdaddr_t *local, uint8_t status,
-                                                       gboolean periodic)
-{
-       struct btd_adapter *adapter;
-       int state;
-
-       /* Don't send the signal if the cmd failed */
-       if (status) {
-               error("Inquiry Failed with status 0x%02x", status);
-               return;
-       }
-
-       adapter = manager_find_adapter(local);
-       if (!adapter) {
-               error("Unable to find matching adapter");
-               return;
-       }
-
-       state = adapter_get_state(adapter);
-       state &= ~(STATE_STDINQ | STATE_PINQ);
-       adapter_set_state(adapter, state);
-}
-
 static inline void remote_features_notify(int index, void *ptr)
 {
        struct dev_info *dev = &devs[index];
@@ -1285,20 +1445,6 @@ static inline void remote_features_notify(int index, void *ptr)
        write_features_info(&dev->bdaddr, &evt->bdaddr, NULL, evt->features);
 }
 
-static void write_le_host_complete(int index, uint8_t status)
-{
-       struct dev_info *dev = &devs[index];
-       uint8_t page_num = 0x01;
-
-       if (status)
-               return;
-
-       if (hci_send_cmd(dev->sk, OGF_INFO_PARAM,
-                               OCF_READ_LOCAL_EXT_FEATURES, 1, &page_num) < 0)
-               error("Unable to read extended local features: %s (%d)",
-                                               strerror(errno), errno);
-}
-
 static void read_local_version_complete(int index,
                                const read_local_version_rp *rp)
 {
@@ -1345,167 +1491,6 @@ static void read_local_features_complete(int index,
                init_adapter(index);
 }
 
-#define SIZEOF_UUID128 16
-
-static void eir_generate_uuid128(GSList *list, uint8_t *ptr, uint16_t *eir_len)
-{
-       int i, k, uuid_count = 0;
-       uint16_t len = *eir_len;
-       uint8_t *uuid128;
-       gboolean truncated = FALSE;
-
-       /* Store UUIDs in place, skip 2 bytes to write type and length later */
-       uuid128 = ptr + 2;
-
-       for (; list; list = list->next) {
-               struct uuid_info *uuid = list->data;
-               uint8_t *uuid128_data = uuid->uuid.value.uuid128.data;
-
-               if (uuid->uuid.type != SDP_UUID128)
-                       continue;
-
-               /* Stop if not enough space to put next UUID128 */
-               if ((len + 2 + SIZEOF_UUID128) > EIR_DATA_LENGTH) {
-                       truncated = TRUE;
-                       break;
-               }
-
-               /* Check for duplicates, EIR data is Little Endian */
-               for (i = 0; i < uuid_count; i++) {
-                       for (k = 0; k < SIZEOF_UUID128; k++) {
-                               if (uuid128[i * SIZEOF_UUID128 + k] !=
-                                       uuid128_data[SIZEOF_UUID128 - 1 - k])
-                                       break;
-                       }
-                       if (k == SIZEOF_UUID128)
-                               break;
-               }
-
-               if (i < uuid_count)
-                       continue;
-
-               /* EIR data is Little Endian */
-               for (k = 0; k < SIZEOF_UUID128; k++)
-                       uuid128[uuid_count * SIZEOF_UUID128 + k] =
-                               uuid128_data[SIZEOF_UUID128 - 1 - k];
-
-               len += SIZEOF_UUID128;
-               uuid_count++;
-       }
-
-       if (uuid_count > 0 || truncated) {
-               /* EIR Data length */
-               ptr[0] = (uuid_count * SIZEOF_UUID128) + 1;
-               /* EIR Data type */
-               ptr[1] = truncated ? EIR_UUID128_SOME : EIR_UUID128_ALL;
-               len += 2;
-               *eir_len = len;
-       }
-}
-
-static void create_ext_inquiry_response(int index, uint8_t *data)
-{
-       struct dev_info *dev = &devs[index];
-       GSList *l;
-       uint8_t *ptr = data;
-       uint16_t eir_len = 0;
-       uint16_t uuid16[EIR_DATA_LENGTH / 2];
-       int i, uuid_count = 0;
-       gboolean truncated = FALSE;
-       size_t name_len;
-
-       name_len = strlen(dev->name);
-
-       if (name_len > 0) {
-               /* EIR Data type */
-               if (name_len > 48) {
-                       name_len = 48;
-                       ptr[1] = EIR_NAME_SHORT;
-               } else
-                       ptr[1] = EIR_NAME_COMPLETE;
-
-               /* EIR Data length */
-               ptr[0] = name_len + 1;
-
-               memcpy(ptr + 2, dev->name, name_len);
-
-               eir_len += (name_len + 2);
-               ptr += (name_len + 2);
-       }
-
-       if (dev->tx_power != 0) {
-               *ptr++ = 2;
-               *ptr++ = EIR_TX_POWER;
-               *ptr++ = (uint8_t) dev->tx_power;
-               eir_len += 3;
-       }
-
-       if (dev->did_vendor != 0x0000) {
-               uint16_t source = 0x0002;
-               *ptr++ = 9;
-               *ptr++ = EIR_DEVICE_ID;
-               *ptr++ = (source & 0x00ff);
-               *ptr++ = (source & 0xff00) >> 8;
-               *ptr++ = (dev->did_vendor & 0x00ff);
-               *ptr++ = (dev->did_vendor & 0xff00) >> 8;
-               *ptr++ = (dev->did_product & 0x00ff);
-               *ptr++ = (dev->did_product & 0xff00) >> 8;
-               *ptr++ = (dev->did_version & 0x00ff);
-               *ptr++ = (dev->did_version & 0xff00) >> 8;
-               eir_len += 10;
-       }
-
-       /* Group all UUID16 types */
-       for (l = dev->uuids; l != NULL; l = g_slist_next(l)) {
-               struct uuid_info *uuid = l->data;
-
-               if (uuid->uuid.type != SDP_UUID16)
-                       continue;
-
-               if (uuid->uuid.value.uuid16 < 0x1100)
-                       continue;
-
-               if (uuid->uuid.value.uuid16 == PNP_INFO_SVCLASS_ID)
-                       continue;
-
-               /* Stop if not enough space to put next UUID16 */
-               if ((eir_len + 2 + sizeof(uint16_t)) > EIR_DATA_LENGTH) {
-                       truncated = TRUE;
-                       break;
-               }
-
-               /* Check for duplicates */
-               for (i = 0; i < uuid_count; i++)
-                       if (uuid16[i] == uuid->uuid.value.uuid16)
-                               break;
-
-               if (i < uuid_count)
-                       continue;
-
-               uuid16[uuid_count++] = uuid->uuid.value.uuid16;
-               eir_len += sizeof(uint16_t);
-       }
-
-       if (uuid_count > 0) {
-               /* EIR Data length */
-               ptr[0] = (uuid_count * sizeof(uint16_t)) + 1;
-               /* EIR Data type */
-               ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
-
-               ptr += 2;
-               eir_len += 2;
-
-               for (i = 0; i < uuid_count; i++) {
-                       *ptr++ = (uuid16[i] & 0x00ff);
-                       *ptr++ = (uuid16[i] & 0xff00) >> 8;
-               }
-       }
-
-       /* Group all UUID128 types */
-       if (eir_len <= EIR_DATA_LENGTH - 2)
-               eir_generate_uuid128(dev->uuids, ptr, &eir_len);
-}
-
 static void update_ext_inquiry_response(int index)
 {
        struct dev_info *dev = &devs[index];
@@ -1524,7 +1509,8 @@ static void update_ext_inquiry_response(int index)
 
        memset(&cp, 0, sizeof(cp));
 
-       create_ext_inquiry_response(index, cp.data);
+       eir_create(dev->name, dev->tx_power, dev->did_vendor, dev->did_product,
+                                       dev->did_version, dev->uuids, cp.data);
 
        if (memcmp(cp.data, dev->eir, sizeof(cp.data)) == 0)
                return;
@@ -1544,7 +1530,7 @@ static void update_name(int index, const char *name)
 
        adapter = manager_find_adapter_by_id(index);
        if (adapter)
-               adapter_update_local_name(adapter, name);
+               adapter_name_changed(adapter, name);
 
        update_ext_inquiry_response(index);
 }
@@ -1569,22 +1555,7 @@ static void read_local_name_complete(int index, read_local_name_rp *rp)
 
        DBG("Got name for hci%d", index);
 
-       /* Even though it shouldn't happen (assuming the kernel behaves
-        * properly) it seems like we might miss the very first
-        * initialization commands that the kernel sends. So check for
-        * it here (since read_local_name is one of the last init
-        * commands) and resend the first ones if we haven't seen
-        * their results yet */
-
-       if (hci_test_bit(PENDING_FEATURES, &dev->pending))
-               hci_send_cmd(dev->sk, OGF_INFO_PARAM,
-                                       OCF_READ_LOCAL_FEATURES, 0, NULL);
-
-       if (hci_test_bit(PENDING_VERSION, &dev->pending))
-               hci_send_cmd(dev->sk, OGF_INFO_PARAM,
-                                       OCF_READ_LOCAL_VERSION, 0, NULL);
-
-       if (!dev->pending)
+       if (!dev->pending && dev->up)
                init_adapter(index);
 }
 
@@ -1607,7 +1578,6 @@ static void read_simple_pairing_mode_complete(int index, void *ptr)
 {
        struct dev_info *dev = &devs[index];
        read_simple_pairing_mode_rp *rp = ptr;
-       struct btd_adapter *adapter;
 
        DBG("hci%d status %u", index, rp->status);
 
@@ -1616,37 +1586,23 @@ static void read_simple_pairing_mode_complete(int index, void *ptr)
 
        dev->ssp_mode = rp->mode;
        update_ext_inquiry_response(index);
-
-       adapter = manager_find_adapter(&dev->bdaddr);
-       if (!adapter) {
-               error("No matching adapter found");
-               return;
-       }
-
-       adapter_update_ssp_mode(adapter, rp->mode);
 }
 
 static void read_local_ext_features_complete(int index,
                                const read_local_ext_features_rp *rp)
 {
-       struct btd_adapter *adapter;
+       struct dev_info *dev = &devs[index];
 
        DBG("hci%d status %u", index, rp->status);
 
        if (rp->status)
                return;
 
-       adapter = manager_find_adapter_by_id(index);
-       if (!adapter) {
-               error("No matching adapter found");
-               return;
-       }
-
        /* Local Extended feature page number is 1 */
        if (rp->page_num != 1)
                return;
 
-       btd_adapter_update_local_ext_features(adapter, rp->features);
+       memcpy(dev->extfeatures, rp->features, sizeof(dev->extfeatures));
 }
 
 static void read_bd_addr_complete(int index, read_bd_addr_rp *rp)
@@ -1671,14 +1627,23 @@ static void read_bd_addr_complete(int index, read_bd_addr_rp *rp)
                init_adapter(index);
 }
 
+static inline void cs_inquiry_evt(int index, uint8_t status)
+{
+       if (status) {
+               error("Inquiry Failed with status 0x%02x", status);
+               return;
+       }
+
+       set_state(index, DISCOV_INQ);
+}
+
 static inline void cmd_status(int index, void *ptr)
 {
-       struct dev_info *dev = &devs[index];
        evt_cmd_status *evt = ptr;
        uint16_t opcode = btohs(evt->opcode);
 
        if (opcode == cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY))
-               start_inquiry(&dev->bdaddr, evt->status, FALSE);
+               cs_inquiry_evt(index, evt->status);
 }
 
 static void read_scan_complete(int index, uint8_t status, void *ptr)
@@ -1763,26 +1728,90 @@ static void write_class_complete(int index, uint8_t status)
        if (dev->pending_cod == 0)
                return;
 
-       dev->current_cod = dev->pending_cod;
-       dev->pending_cod = 0;
-
-       adapter = manager_find_adapter(&dev->bdaddr);
-       if (adapter)
-               btd_adapter_class_changed(adapter, dev->current_cod);
+       dev->current_cod = dev->pending_cod;
+       dev->pending_cod = 0;
+
+       adapter = manager_find_adapter(&dev->bdaddr);
+       if (adapter)
+               btd_adapter_class_changed(adapter, dev->current_cod);
+
+       update_ext_inquiry_response(index);
+
+       if (dev->wanted_cod == dev->current_cod)
+               return;
+
+       if (dev->wanted_cod & LIMITED_BIT &&
+                       !(dev->current_cod & LIMITED_BIT))
+               hciops_set_limited_discoverable(index, TRUE);
+       else if (!(dev->wanted_cod & LIMITED_BIT) &&
+                                       (dev->current_cod & LIMITED_BIT))
+               hciops_set_limited_discoverable(index, FALSE);
+       else
+               write_class(index, dev->wanted_cod);
+}
+
+static void read_local_oob_data_complete(int index, uint8_t status,
+                                               read_local_oob_data_rp *rp)
+{
+       struct btd_adapter *adapter = manager_find_adapter_by_id(index);
+
+       if (!adapter)
+               return;
+
+       if (status)
+               oob_read_local_data_complete(adapter, NULL, NULL);
+       else
+               oob_read_local_data_complete(adapter, rp->hash, rp->randomizer);
+}
+
+static inline void inquiry_complete_evt(int index, uint8_t status)
+{
+       int adapter_type;
+       struct btd_adapter *adapter;
+
+       if (status) {
+               error("Inquiry Failed with status 0x%02x", status);
+               return;
+       }
+
+       adapter = manager_find_adapter_by_id(index);
+       if (!adapter) {
+               error("No matching adapter found");
+               return;
+       }
+
+       adapter_type = get_adapter_type(index);
+
+       if (adapter_type == BR_EDR_LE &&
+                       start_scanning(index, TIMEOUT_BR_LE_SCAN) == 0)
+               return;
+
+       set_state(index, DISCOV_NAMES);
+}
+
+static inline void cc_inquiry_cancel(int index, uint8_t status)
+{
+       if (status) {
+               error("Inquiry Cancel Failed with status 0x%02x", status);
+               return;
+       }
+
+       set_state(index, DISCOV_HALTED);
+}
 
-       update_ext_inquiry_response(index);
+static inline void cc_le_set_scan_enable(int index, uint8_t status)
+{
+       struct dev_info *info = &devs[index];
 
-       if (dev->wanted_cod == dev->current_cod)
+       if (status) {
+               error("LE Set Scan Enable Failed with status 0x%02x", status);
                return;
+       }
 
-       if (dev->wanted_cod & LIMITED_BIT &&
-                       !(dev->current_cod & LIMITED_BIT))
-               hciops_set_limited_discoverable(index, TRUE);
-       else if (!(dev->wanted_cod & LIMITED_BIT) &&
-                                       (dev->current_cod & LIMITED_BIT))
-               hciops_set_limited_discoverable(index, FALSE);
+       if (info->discov_state == DISCOV_SCAN)
+               set_state(index, DISCOV_HALTED);
        else
-               write_class(index, dev->wanted_cod);
+               set_state(index, DISCOV_SCAN);
 }
 
 static inline void cmd_complete(int index, void *ptr)
@@ -1809,20 +1838,11 @@ static inline void cmd_complete(int index, void *ptr)
                ptr += sizeof(evt_cmd_complete);
                read_bd_addr_complete(index, ptr);
                break;
-       case cmd_opcode_pack(OGF_LINK_CTL, OCF_PERIODIC_INQUIRY):
-               start_inquiry(&dev->bdaddr, status, TRUE);
-               break;
-       case cmd_opcode_pack(OGF_LINK_CTL, OCF_EXIT_PERIODIC_INQUIRY):
-               inquiry_complete(&dev->bdaddr, status, TRUE);
-               break;
        case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL):
-               inquiry_complete(&dev->bdaddr, status, FALSE);
-               break;
-       case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_LE_HOST_SUPPORTED):
-               write_le_host_complete(index, status);
+               cc_inquiry_cancel(index, status);
                break;
        case cmd_opcode_pack(OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE):
-               btd_event_le_set_scan_enable_complete(&dev->bdaddr, status);
+               cc_le_set_scan_enable(index, status);
                break;
        case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME):
                if (!status)
@@ -1858,6 +1878,10 @@ static inline void cmd_complete(int index, void *ptr)
                ptr += sizeof(evt_cmd_complete);
                read_tx_power_complete(index, ptr);
                break;
+       case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_OOB_DATA):
+               ptr += sizeof(evt_cmd_complete);
+               read_local_oob_data_complete(index, status, ptr);
+               break;
        };
 }
 
@@ -1865,16 +1889,43 @@ static inline void remote_name_information(int index, void *ptr)
 {
        struct dev_info *dev = &devs[index];
        evt_remote_name_req_complete *evt = ptr;
+       struct btd_adapter *adapter;
        char name[MAX_NAME_LENGTH + 1];
+       struct found_dev *found;
+
+       GSList *match;
 
        DBG("hci%d status %u", index, evt->status);
 
        memset(name, 0, sizeof(name));
 
-       if (!evt->status)
+       if (evt->status == 0) {
                memcpy(name, evt->name, MAX_NAME_LENGTH);
+               btd_event_remote_name(&dev->bdaddr, &evt->bdaddr, name);
+       }
+
+       adapter = manager_find_adapter_by_id(index);
+       if (!adapter) {
+               error("No matching adapter found");
+               return;
+       }
+
+       match = g_slist_find_custom(dev->need_name, &evt->bdaddr,
+                                                       found_dev_bda_cmp);
+       if (match == NULL)
+               return;
+
+       found = match->data;
+       found->name_state = NAME_NOT_NEEDED;
+
+       dev->need_name = g_slist_remove_link(dev->need_name, match);
+
+       match->next = dev->found_devs;
+       dev->found_devs = match;
+       dev->found_devs = g_slist_sort(dev->found_devs, found_dev_rssi_cmp);
 
-       btd_event_remote_name(&dev->bdaddr, &evt->bdaddr, evt->status, name);
+       if (resolve_names(dev, adapter) < 0)
+               set_state(index, DISCOV_HALTED);
 }
 
 static inline void remote_version_information(int index, void *ptr)
@@ -1897,6 +1948,34 @@ static inline void remote_version_information(int index, void *ptr)
                                btohs(evt->lmp_subver));
 }
 
+static void dev_found(struct dev_info *info, bdaddr_t *dba, addr_type_t type,
+                               uint32_t cod, int8_t rssi, uint8_t cfm_name,
+                               uint8_t *eir, uint8_t eir_len)
+{
+       struct found_dev *dev;
+       GSList *match;
+
+       match = g_slist_find_custom(info->found_devs, dba, found_dev_bda_cmp);
+       if (match != NULL) {
+               cfm_name = 0;
+               goto event;
+       }
+
+       dev = g_new0(struct found_dev, 1);
+       bacpy(&dev->bdaddr, dba);
+       dev->rssi = rssi;
+       if (cfm_name)
+               dev->name_state = NAME_UNKNOWN;
+       else
+               dev->name_state = NAME_NOT_NEEDED;
+
+       info->found_devs = g_slist_prepend(info->found_devs, dev);
+
+event:
+       btd_event_device_found(&info->bdaddr, dba, type, cod, rssi, cfm_name,
+                                                               eir, eir_len);
+}
+
 static inline void inquiry_result(int index, int plen, void *ptr)
 {
        struct dev_info *dev = &devs[index];
@@ -1909,8 +1988,8 @@ static inline void inquiry_result(int index, int plen, void *ptr)
                                                (info->dev_class[1] << 8) |
                                                (info->dev_class[2] << 16);
 
-               btd_event_device_found(&dev->bdaddr, &info->bdaddr, class,
-                                                               0, NULL);
+               dev_found(dev, &info->bdaddr, ADDR_TYPE_BREDR, class, 0, 1,
+                                                               NULL, 0);
                ptr += INQUIRY_INFO_SIZE;
        }
 }
@@ -1931,8 +2010,8 @@ static inline void inquiry_result_with_rssi(int index, int plen, void *ptr)
                                                | (info->dev_class[1] << 8)
                                                | (info->dev_class[2] << 16);
 
-                       btd_event_device_found(&dev->bdaddr, &info->bdaddr,
-                                               class, info->rssi, NULL);
+                       dev_found(dev, &info->bdaddr, ADDR_TYPE_BREDR, class,
+                                               info->rssi, 1, NULL, 0);
                        ptr += INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE;
                }
        } else {
@@ -1942,8 +2021,8 @@ static inline void inquiry_result_with_rssi(int index, int plen, void *ptr)
                                                | (info->dev_class[1] << 8)
                                                | (info->dev_class[2] << 16);
 
-                       btd_event_device_found(&dev->bdaddr, &info->bdaddr,
-                                               class, info->rssi, NULL);
+                       dev_found(dev, &info->bdaddr, ADDR_TYPE_BREDR, class,
+                                               info->rssi, 1, NULL, 0);
                        ptr += INQUIRY_INFO_WITH_RSSI_SIZE;
                }
        }
@@ -1960,9 +2039,16 @@ static inline void extended_inquiry_result(int index, int plen, void *ptr)
                uint32_t class = info->dev_class[0]
                                        | (info->dev_class[1] << 8)
                                        | (info->dev_class[2] << 16);
+               gboolean cfm_name;
+
+               if (eir_has_complete_name(info->data, sizeof(info->data)))
+                       cfm_name = FALSE;
+               else
+                       cfm_name = TRUE;
 
-               btd_event_device_found(&dev->bdaddr, &info->bdaddr, class,
-                                               info->rssi, info->data);
+               dev_found(dev, &info->bdaddr, ADDR_TYPE_BREDR, class,
+                                       info->rssi, cfm_name,
+                                       info->data, sizeof(info->data));
                ptr += EXTENDED_INQUIRY_INFO_SIZE;
        }
 }
@@ -2177,23 +2263,41 @@ static inline void conn_request(int index, void *ptr)
        btd_event_remote_class(&dev->bdaddr, &evt->bdaddr, class);
 }
 
+static inline addr_type_t le_addr_type(uint8_t bdaddr_type)
+{
+       switch (bdaddr_type) {
+       case LE_RANDOM_ADDRESS:
+               return ADDR_TYPE_LE_RANDOM;
+       case LE_PUBLIC_ADDRESS:
+       default:
+               return ADDR_TYPE_LE_PUBLIC;
+       }
+}
+
 static inline void le_advertising_report(int index, evt_le_meta_event *meta)
 {
        struct dev_info *dev = &devs[index];
        le_advertising_info *info;
-       uint8_t num_reports;
+       uint8_t num_reports, rssi;
        const uint8_t RSSI_SIZE = 1;
 
        num_reports = meta->data[0];
 
        info = (le_advertising_info *) &meta->data[1];
-       btd_event_advertising_report(&dev->bdaddr, info);
+       rssi = *(info->data + info->length);
+
+       dev_found(dev, &info->bdaddr, le_addr_type(info->bdaddr_type), 0, rssi,
+                                               0, info->data, info->length);
+
        num_reports--;
 
        while (num_reports--) {
                info = (le_advertising_info *) (info->data + info->length +
                                                                RSSI_SIZE);
-               btd_event_advertising_report(&dev->bdaddr, info);
+               rssi = *(info->data + info->length);
+
+               dev_found(dev, &info->bdaddr, le_addr_type(info->bdaddr_type),
+                               0, rssi, 0, info->data, info->length);
        }
 }
 
@@ -2226,19 +2330,17 @@ static void stop_hci_dev(int index)
        if (dev->watch_id > 0)
                g_source_remove(dev->watch_id);
 
+       if (dev->stop_scan_id > 0)
+               g_source_remove(dev->stop_scan_id);
+
        if (dev->io != NULL)
                g_io_channel_unref(dev->io);
 
        hci_close_dev(dev->sk);
 
-       g_slist_foreach(dev->keys, (GFunc) g_free, NULL);
-       g_slist_free(dev->keys);
-
-       g_slist_foreach(dev->uuids, (GFunc) g_free, NULL);
-       g_slist_free(dev->uuids);
-
-       g_slist_foreach(dev->connections, (GFunc) conn_free, NULL);
-       g_slist_free(dev->connections);
+       g_slist_free_full(dev->keys, g_free);
+       g_slist_free_full(dev->uuids, g_free);
+       g_slist_free_full(dev->connections, g_free);
 
        init_dev_info(index, -1, dev->registered, dev->already_up);
 }
@@ -2313,7 +2415,7 @@ static gboolean io_security_event(GIOChannel *chan, GIOCondition cond,
 
        case EVT_INQUIRY_COMPLETE:
                evt = (evt_cmd_status *) ptr;
-               inquiry_complete(&dev->bdaddr, evt->status, FALSE);
+               inquiry_complete_evt(index, evt->status);
                break;
 
        case EVT_INQUIRY_RESULT:
@@ -2387,7 +2489,7 @@ static gboolean io_security_event(GIOChannel *chan, GIOCondition cond,
                break;
 
        case EVT_REMOTE_OOB_DATA_REQUEST:
-               remote_oob_data_request(index, ptr);
+               remote_oob_data_request(index, (bdaddr_t *) ptr);
                break;
        }
 
@@ -2497,6 +2599,13 @@ static void device_devup_setup(int index)
        bacpy(&dev->bdaddr, &di.bdaddr);
        memcpy(dev->features, di.features, 8);
 
+       if (dev->features[7] & LMP_EXT_FEAT) {
+               uint8_t page_num = 0x01;
+
+               hci_send_cmd(dev->sk, OGF_INFO_PARAM,
+                               OCF_READ_LOCAL_EXT_FEATURES, 1, &page_num);
+       }
+
        /* Set page timeout */
        if ((main_opts.flags & (1 << HCID_SET_PAGETO))) {
                write_page_timeout_cp cp;
@@ -2511,8 +2620,31 @@ static void device_devup_setup(int index)
        hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_STORED_LINK_KEY,
                                        READ_STORED_LINK_KEY_CP_SIZE, &cp);
 
-       if (!dev->pending)
+       if (!dev->pending) {
                init_adapter(index);
+               return;
+       }
+
+       /* Even though it shouldn't happen (assuming the kernel behaves
+        * properly) it seems like we might miss the very first
+        * initialization commands that the kernel sends. So check for
+        * it here and resend the ones we haven't seen their results yet */
+
+       if (hci_test_bit(PENDING_FEATURES, &dev->pending))
+               hci_send_cmd(dev->sk, OGF_INFO_PARAM,
+                                       OCF_READ_LOCAL_FEATURES, 0, NULL);
+
+       if (hci_test_bit(PENDING_VERSION, &dev->pending))
+               hci_send_cmd(dev->sk, OGF_INFO_PARAM,
+                                       OCF_READ_LOCAL_VERSION, 0, NULL);
+
+       if (hci_test_bit(PENDING_NAME, &dev->pending))
+               hci_send_cmd(dev->sk, OGF_HOST_CTL,
+                                       OCF_READ_LOCAL_NAME, 0, 0);
+
+       if (hci_test_bit(PENDING_BDADDR, &dev->pending))
+               hci_send_cmd(dev->sk, OGF_INFO_PARAM,
+                                       OCF_READ_BD_ADDR, 0, NULL);
 }
 
 static void init_pending(int index)
@@ -2597,7 +2729,7 @@ static void init_conn_list(int index)
        struct dev_info *dev = &devs[index];
        struct hci_conn_list_req *cl;
        struct hci_conn_info *ci;
-       int err, i;
+       int i;
 
        DBG("hci%d", index);
 
@@ -2623,8 +2755,6 @@ static void init_conn_list(int index)
                conn->handle = ci->handle;
        }
 
-       err = 0;
-
 failed:
        g_free(cl);
 }
@@ -2655,6 +2785,7 @@ static void device_event(int event, int index)
                devs[index].up = FALSE;
                devs[index].pending_cod = 0;
                devs[index].cache_enable = TRUE;
+               devs[index].discov_state = DISCOV_HALTED;
                if (!devs[index].pending) {
                        struct btd_adapter *adapter;
 
@@ -2916,43 +3047,24 @@ static int hciops_set_dev_class(int index, uint8_t major, uint8_t minor)
        return err;
 }
 
-static int hciops_start_inquiry(int index, uint8_t length, gboolean periodic)
+static int start_inquiry(int index, uint8_t length)
 {
        struct dev_info *dev = &devs[index];
        uint8_t lap[3] = { 0x33, 0x8b, 0x9e };
-       int err;
-
-       DBG("hci%d length %u periodic %d", index, length, periodic);
-
-       if (periodic) {
-               periodic_inquiry_cp cp;
-
-               memset(&cp, 0, sizeof(cp));
-               memcpy(&cp.lap, lap, 3);
-               cp.max_period = htobs(24);
-               cp.min_period = htobs(16);
-               cp.length  = length;
-               cp.num_rsp = 0x00;
-
-               err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
-                                               OCF_PERIODIC_INQUIRY,
-                                               PERIODIC_INQUIRY_CP_SIZE, &cp);
-       } else {
-               inquiry_cp inq_cp;
+       inquiry_cp inq_cp;
 
-               memset(&inq_cp, 0, sizeof(inq_cp));
-               memcpy(&inq_cp.lap, lap, 3);
-               inq_cp.length = length;
-               inq_cp.num_rsp = 0x00;
+       DBG("hci%d length %u", index, length);
 
-               err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
-                                       OCF_INQUIRY, INQUIRY_CP_SIZE, &inq_cp);
-       }
+       memset(&inq_cp, 0, sizeof(inq_cp));
+       memcpy(&inq_cp.lap, lap, 3);
+       inq_cp.length = length;
+       inq_cp.num_rsp = 0x00;
 
-       if (err < 0)
-               err = -errno;
+       if (hci_send_cmd(dev->sk, OGF_LINK_CTL,
+                       OCF_INQUIRY, INQUIRY_CP_SIZE, &inq_cp) < 0)
+               return -errno;
 
-       return err;
+       return 0;
 }
 
 static int le_set_scan_enable(int index, uint8_t enable)
@@ -2973,10 +3085,25 @@ static int le_set_scan_enable(int index, uint8_t enable)
        return 0;
 }
 
-static int hciops_start_scanning(int index)
+static gboolean stop_le_scan_cb(gpointer user_data)
+{
+       struct dev_info *dev = user_data;
+       int err;
+
+       err = le_set_scan_enable(dev->id, 0);
+       if (err < 0)
+               return TRUE;
+
+       dev->stop_scan_id = 0;
+
+       return FALSE;
+}
+
+static int start_scanning(int index, int timeout)
 {
        struct dev_info *dev = &devs[index];
        le_set_scan_parameters_cp cp;
+       int err;
 
        DBG("hci%d", index);
 
@@ -2993,34 +3120,28 @@ static int hciops_start_scanning(int index)
                                LE_SET_SCAN_PARAMETERS_CP_SIZE, &cp) < 0)
                return -errno;
 
-       return le_set_scan_enable(index, 1);
-}
+       err = le_set_scan_enable(index, 1);
+       if (err < 0)
+               return err;
 
-static int hciops_stop_scanning(int index)
-{
-       DBG("hci%d", index);
+       /* Schedule a le scan disable in 'timeout' milliseconds */
+       dev->stop_scan_id = g_timeout_add(timeout, stop_le_scan_cb, dev);
 
-       return le_set_scan_enable(index, 0);
+       return 0;
 }
 
-static int hciops_resolve_name(int index, bdaddr_t *bdaddr)
+static int hciops_stop_scanning(int index)
 {
        struct dev_info *dev = &devs[index];
-       remote_name_req_cp cp;
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d dba %s", index, addr);
 
-       memset(&cp, 0, sizeof(cp));
-       bacpy(&cp.bdaddr, bdaddr);
-       cp.pscan_rep_mode = 0x02;
+       DBG("hci%d", index);
 
-       if (hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ,
-                                       REMOTE_NAME_REQ_CP_SIZE, &cp) < 0)
-               return -errno;
+       if (dev->stop_scan_id > 0) {
+               g_source_remove(dev->stop_scan_id);
+               dev->stop_scan_id = 0;
+       }
 
-       return 0;
+       return le_set_scan_enable(index, 0);
 }
 
 static int hciops_set_name(int index, const char *name)
@@ -3043,26 +3164,75 @@ static int hciops_set_name(int index, const char *name)
        return 0;
 }
 
-static int hciops_cancel_resolve_name(int index, bdaddr_t *bdaddr)
+static int cancel_resolve_name(int index)
 {
-       struct dev_info *dev = &devs[index];
+       struct dev_info *info = &devs[index];
+       struct found_dev *dev;
        remote_name_req_cancel_cp cp;
-       char addr[18];
+       struct btd_adapter *adapter;
 
-       ba2str(bdaddr, addr);
-       DBG("hci%d dba %s", index, addr);
+       DBG("hci%d", index);
+
+       if (g_slist_length(info->need_name) == 0)
+               return 0;
+
+       dev = info->need_name->data;
+       if (dev->name_state != NAME_PENDING)
+               return 0;
 
        memset(&cp, 0, sizeof(cp));
-       bacpy(&cp.bdaddr, bdaddr);
+       bacpy(&cp.bdaddr, &dev->bdaddr);
+
+       adapter = manager_find_adapter_by_id(index);
+       if (adapter)
+               adapter_set_discovering(adapter, FALSE);
+
+       found_dev_cleanup(info);
 
-       if (hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ_CANCEL,
+       if (hci_send_cmd(info->sk, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ_CANCEL,
                                REMOTE_NAME_REQ_CANCEL_CP_SIZE, &cp) < 0)
                return -errno;
 
        return 0;
 }
 
-static int hciops_fast_connectable(int index, gboolean enable)
+static int hciops_start_discovery(int index)
+{
+       int adapter_type = get_adapter_type(index);
+
+       DBG("hci%u", index);
+
+       switch (adapter_type) {
+       case BR_EDR_LE:
+               return start_inquiry(index, LENGTH_BR_LE_INQ);
+       case BR_EDR:
+               return start_inquiry(index, LENGTH_BR_INQ);
+       case LE_ONLY:
+               return start_scanning(index, TIMEOUT_LE_SCAN);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int hciops_stop_discovery(int index)
+{
+       struct dev_info *dev = &devs[index];
+
+       DBG("index %d", index);
+
+       switch (dev->discov_state) {
+       case DISCOV_INQ:
+               return hciops_stop_inquiry(index);
+       case DISCOV_SCAN:
+               return hciops_stop_scanning(index);
+       case DISCOV_NAMES:
+               cancel_resolve_name(index);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int hciops_set_fast_connectable(int index, gboolean enable)
 {
        struct dev_info *dev = &devs[index];
        write_page_activity_cp cp;
@@ -3171,28 +3341,6 @@ static int hciops_get_conn_list(int index, GSList **conns)
        return 0;
 }
 
-static int hciops_read_local_version(int index, struct hci_version *ver)
-{
-       struct dev_info *dev = &devs[index];
-
-       DBG("hci%d", index);
-
-       memcpy(ver, &dev->ver, sizeof(*ver));
-
-       return 0;
-}
-
-static int hciops_read_local_features(int index, uint8_t *features)
-{
-       struct dev_info *dev = &devs[index];
-
-       DBG("hci%d", index);
-
-       memcpy(features, dev->features, 8);
-
-       return  0;
-}
-
 static int hciops_disconnect(int index, bdaddr_t *bdaddr)
 {
        DBG("hci%d", index);
@@ -3227,7 +3375,8 @@ static int hciops_remove_bonding(int index, bdaddr_t *bdaddr)
        return 0;
 }
 
-static int hciops_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin)
+static int hciops_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin,
+                                                               size_t pin_len)
 {
        struct dev_info *dev = &devs[index];
        char addr[18];
@@ -3238,14 +3387,13 @@ static int hciops_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin)
 
        if (pin) {
                pin_code_reply_cp pr;
-               size_t len = strlen(pin);
 
-               dev->pin_length = len;
+               dev->pin_length = pin_len;
 
                memset(&pr, 0, sizeof(pr));
                bacpy(&pr.bdaddr, bdaddr);
-               memcpy(pr.pin_code, pin, len);
-               pr.pin_len = len;
+               memcpy(pr.pin_code, pin, pin_len);
+               pr.pin_len = pin_len;
                err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
                                                OCF_PIN_CODE_REPLY,
                                                PIN_CODE_REPLY_CP_SIZE, &pr);
@@ -3288,27 +3436,6 @@ static int hciops_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey)
        return err;
 }
 
-static int hciops_enable_le(int index)
-{
-       struct dev_info *dev = &devs[index];
-       write_le_host_supported_cp cp;
-
-       DBG("hci%d", index);
-
-       if (!(dev->features[4] & LMP_LE))
-               return -ENOTSUP;
-
-       cp.le = 0x01;
-       cp.simul = (dev->features[6] & LMP_LE_BREDR) ? 0x01 : 0x00;
-
-       if (hci_send_cmd(dev->sk, OGF_HOST_CTL,
-                               OCF_WRITE_LE_HOST_SUPPORTED,
-                               WRITE_LE_HOST_SUPPORTED_CP_SIZE, &cp) < 0)
-               return -errno;
-
-       return 0;
-}
-
 static uint8_t generate_service_class(int index)
 {
        struct dev_info *dev = &devs[index];
@@ -3555,6 +3682,101 @@ static int hciops_cancel_bonding(int index, bdaddr_t *bdaddr)
        return 0;
 }
 
+static int hciops_read_local_oob_data(int index)
+{
+       struct dev_info *dev = &devs[index];
+
+       DBG("hci%d", index);
+
+       if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_LOCAL_OOB_DATA, 0, 0)
+                                                                       < 0)
+               return -errno;
+
+       return 0;
+}
+
+static int hciops_add_remote_oob_data(int index, bdaddr_t *bdaddr,
+                                       uint8_t *hash, uint8_t *randomizer)
+{
+       char addr[18];
+       struct dev_info *dev = &devs[index];
+       GSList *match;
+       struct oob_data *data;
+
+       ba2str(bdaddr, addr);
+       DBG("hci%d bdaddr %s", index, addr);
+
+       match = g_slist_find_custom(dev->oob_data, bdaddr, oob_bdaddr_cmp);
+
+       if (match) {
+               data = match->data;
+       } else {
+               data = g_new(struct oob_data, 1);
+               bacpy(&data->bdaddr, bdaddr);
+               dev->oob_data = g_slist_prepend(dev->oob_data, data);
+       }
+
+       memcpy(data->hash, hash, sizeof(data->hash));
+       memcpy(data->randomizer, randomizer, sizeof(data->randomizer));
+
+       return 0;
+}
+
+static int hciops_remove_remote_oob_data(int index, bdaddr_t *bdaddr)
+{
+       char addr[18];
+       struct dev_info *dev = &devs[index];
+       GSList *match;
+
+       ba2str(bdaddr, addr);
+       DBG("hci%d bdaddr %s", index, addr);
+
+       match = g_slist_find_custom(dev->oob_data, bdaddr, oob_bdaddr_cmp);
+
+       if (!match)
+               return -ENOENT;
+
+       g_free(match->data);
+       dev->oob_data = g_slist_delete_link(dev->oob_data, match);
+
+       return 0;
+}
+
+static int hciops_confirm_name(int index, bdaddr_t *bdaddr,
+                                                       gboolean name_known)
+{
+       struct dev_info *info = &devs[index];
+       struct found_dev *dev;
+       GSList *match;
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%u %s name_known %u", index, addr, name_known);
+
+       match = g_slist_find_custom(info->found_devs, bdaddr,
+                                               found_dev_bda_cmp);
+       if (match == NULL)
+               return -ENOENT;
+
+       dev = match->data;
+
+       if (name_known) {
+               dev->name_state = NAME_NOT_NEEDED;
+               info->found_devs = g_slist_sort(info->found_devs,
+                                                       found_dev_rssi_cmp);
+               return 0;
+       }
+
+       dev->name_state = NAME_NEEDED;
+       info->found_devs = g_slist_remove_link(info->found_devs, match);
+
+       match->next = info->need_name;
+       info->need_name = match;
+       info->need_name = g_slist_sort(info->need_name, found_dev_rssi_cmp);
+
+       return 0;
+}
+
 static struct btd_adapter_ops hci_ops = {
        .setup = hciops_setup,
        .cleanup = hciops_cleanup,
@@ -3562,28 +3784,21 @@ static struct btd_adapter_ops hci_ops = {
        .set_discoverable = hciops_set_discoverable,
        .set_pairable = hciops_set_pairable,
        .set_limited_discoverable = hciops_set_limited_discoverable,
-       .start_inquiry = hciops_start_inquiry,
-       .stop_inquiry = hciops_stop_inquiry,
-       .start_scanning = hciops_start_scanning,
-       .stop_scanning = hciops_stop_scanning,
-       .resolve_name = hciops_resolve_name,
-       .cancel_resolve_name = hciops_cancel_resolve_name,
+       .start_discovery = hciops_start_discovery,
+       .stop_discovery = hciops_stop_discovery,
        .set_name = hciops_set_name,
        .set_dev_class = hciops_set_dev_class,
-       .set_fast_connectable = hciops_fast_connectable,
+       .set_fast_connectable = hciops_set_fast_connectable,
        .read_clock = hciops_read_clock,
        .read_bdaddr = hciops_read_bdaddr,
        .block_device = hciops_block_device,
        .unblock_device = hciops_unblock_device,
        .get_conn_list = hciops_get_conn_list,
-       .read_local_version = hciops_read_local_version,
-       .read_local_features = hciops_read_local_features,
        .disconnect = hciops_disconnect,
        .remove_bonding = hciops_remove_bonding,
        .pincode_reply = hciops_pincode_reply,
        .confirm_reply = hciops_confirm_reply,
        .passkey_reply = hciops_passkey_reply,
-       .enable_le = hciops_enable_le,
        .encrypt_link = hciops_encrypt_link,
        .set_did = hciops_set_did,
        .add_uuid = hciops_add_uuid,
@@ -3594,6 +3809,10 @@ static struct btd_adapter_ops hci_ops = {
        .set_io_capability = hciops_set_io_capability,
        .create_bonding = hciops_create_bonding,
        .cancel_bonding = hciops_cancel_bonding,
+       .read_local_oob_data = hciops_read_local_oob_data,
+       .add_remote_oob_data = hciops_add_remote_oob_data,
+       .remove_remote_oob_data = hciops_remove_remote_oob_data,
+       .confirm_name = hciops_confirm_name,
 };
 
 static int hciops_init(void)
index 56f2664..6c34116 100644 (file)
 #define MCE_RADIO_STATES_CHANGE_REQ    "req_radio_states_change"
 #define MCE_RADIO_STATES_GET           "get_radio_states"
 #define MCE_RADIO_STATES_SIG           "radio_states_ind"
+#define MCE_TKLOCK_MODE_SIG            "tklock_mode_ind"
 
 static guint watch_id;
+static guint tklock_watch_id;
 static DBusConnection *conn = NULL;
 static gboolean mce_bt_set = FALSE;
-static gboolean collision = FALSE;
+static gboolean mce_bt_on = FALSE;
+
+static gboolean mce_tklock_mode_cb(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       DBusMessageIter args;
+       const char *sigvalue;
+
+       if (!dbus_message_iter_init(message, &args)) {
+               error("message has no arguments");
+       } else if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING) {
+               error("argument is not string");
+       } else {
+
+               dbus_message_iter_get_basic(&args, &sigvalue);
+               DBG("got signal with value %s", sigvalue);
+
+               if (g_strcmp0("unlocked", sigvalue) == 0 && mce_bt_on)
+                       btd_adapter_enable_auto_connect(adapter);
+       }
+
+       return TRUE;
+}
 
 static gboolean mce_signal_callback(DBusConnection *connection,
                                        DBusMessage *message, void *user_data)
@@ -58,6 +83,7 @@ static gboolean mce_signal_callback(DBusConnection *connection,
        DBusMessageIter args;
        uint32_t sigvalue;
        struct btd_adapter *adapter = user_data;
+       int err;
 
        DBG("received mce signal");
 
@@ -71,13 +97,16 @@ static gboolean mce_signal_callback(DBusConnection *connection,
 
                /* set the adapter according to the mce signal
                   and remember the value */
-               mce_bt_set = sigvalue & MCE_RADIO_STATE_BLUETOOTH ?
-                                                               TRUE : FALSE;
+               mce_bt_on = sigvalue & MCE_RADIO_STATE_BLUETOOTH ? TRUE : FALSE;
 
-               if (mce_bt_set)
-                       btd_adapter_switch_online(adapter);
+               if (mce_bt_on)
+                       err = btd_adapter_switch_online(adapter);
                else
-                       btd_adapter_switch_offline(adapter);
+                       err = btd_adapter_switch_offline(adapter);
+
+               if (err == 0)
+                       mce_bt_set = TRUE;
+
        }
 
        return TRUE;
@@ -85,46 +114,43 @@ static gboolean mce_signal_callback(DBusConnection *connection,
 
 static void read_radio_states_cb(DBusPendingCall *call, void *user_data)
 {
-       DBusError err;
+       DBusError derr;
        DBusMessage *reply;
        dbus_uint32_t radio_states;
        struct btd_adapter *adapter = user_data;
+       int err;
 
        reply = dbus_pending_call_steal_reply(call);
 
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
+       dbus_error_init(&derr);
+       if (dbus_set_error_from_message(&derr, reply)) {
                error("mce replied with an error: %s, %s",
-                               err.name, err.message);
-               dbus_error_free(&err);
+                               derr.name, derr.message);
+               dbus_error_free(&derr);
                goto done;
        }
 
-       dbus_error_init(&err);
-       if (dbus_message_get_args(reply, &err,
+       dbus_error_init(&derr);
+       if (dbus_message_get_args(reply, &derr,
                                DBUS_TYPE_UINT32, &radio_states,
                                DBUS_TYPE_INVALID) == FALSE) {
                error("unable to parse get_radio_states reply: %s, %s",
-                                                       err.name, err.message);
-               dbus_error_free(&err);
+                                                       derr.name, derr.message);
+               dbus_error_free(&derr);
                goto done;
        }
 
        DBG("radio_states: %d", radio_states);
 
-       mce_bt_set = radio_states & MCE_RADIO_STATE_BLUETOOTH ? TRUE : FALSE;
+       mce_bt_on = radio_states & MCE_RADIO_STATE_BLUETOOTH ? TRUE : FALSE;
 
-       /* check if the adapter has not completed the initial power
-        * cycle, if so delay action to mce_notify_powered */
-       collision = mce_bt_set && adapter_powering_down(adapter);
-
-       if (collision)
-               goto done;
-
-       if (mce_bt_set)
-               btd_adapter_switch_online(adapter);
+       if (mce_bt_on)
+               err = btd_adapter_switch_online(adapter);
        else
-               btd_adapter_switch_offline(adapter);
+               err = btd_adapter_switch_offline(adapter);
+
+       if (err == 0)
+               mce_bt_set = TRUE;
 
 done:
        dbus_message_unref(reply);
@@ -133,77 +159,80 @@ done:
 static void adapter_powered(struct btd_adapter *adapter, gboolean powered)
 {
        DBusMessage *msg;
-       dbus_uint32_t radio_states = 0;
-       dbus_uint32_t radio_mask = MCE_RADIO_STATE_BLUETOOTH;
        static gboolean startup = TRUE;
 
        DBG("adapter_powered called with %d", powered);
 
        if (startup) {
+               DBusPendingCall *call;
+
+               /* Initialization: sync adapter state and MCE radio state */
+
+               DBG("Startup: reading MCE Bluetooth radio state...");
                startup = FALSE;
-               return;
-       }
 
-       /* check if the plugin got the get_radio_states reply from the
-        * mce when the adapter was not yet down during the power
-        * cycling when bluetoothd is started */
-       if (collision) {
-               error("maemo6: powered state collision");
-               collision = FALSE;
+               msg = dbus_message_new_method_call(MCE_SERVICE,
+                                       MCE_REQUEST_PATH, MCE_REQUEST_IF,
+                                       MCE_RADIO_STATES_GET);
 
-               if (mce_bt_set)
-                       btd_adapter_switch_online(adapter);
+               if (!dbus_connection_send_with_reply(conn, msg, &call, -1)) {
+                       error("calling %s failed", MCE_RADIO_STATES_GET);
+                       dbus_message_unref(msg);
+                       return;
+               }
 
+               dbus_pending_call_set_notify(call, read_radio_states_cb,
+                                                               adapter, NULL);
+               dbus_pending_call_unref(call);
+               dbus_message_unref(msg);
                return;
        }
 
-       /* nothing to do if the states match */
-       if (mce_bt_set == powered)
+       /* MCE initiated operation */
+       if (mce_bt_set == TRUE) {
+               mce_bt_set = FALSE;
                return;
+       }
 
-       /* set the mce value according to the state of the adapter */
-       msg = dbus_message_new_method_call(MCE_SERVICE, MCE_REQUEST_PATH,
-                               MCE_REQUEST_IF, MCE_RADIO_STATES_CHANGE_REQ);
+       /* Non MCE operation: set MCE according to adapter state */
+       if (mce_bt_on != powered) {
+               dbus_uint32_t radio_states;
+               dbus_uint32_t radio_mask = MCE_RADIO_STATE_BLUETOOTH;
 
-       if (powered)
-               radio_states = MCE_RADIO_STATE_BLUETOOTH;
+               msg = dbus_message_new_method_call(MCE_SERVICE,
+                                       MCE_REQUEST_PATH, MCE_REQUEST_IF,
+                                       MCE_RADIO_STATES_CHANGE_REQ);
 
-       dbus_message_append_args(msg, DBUS_TYPE_UINT32, &radio_states,
-                               DBUS_TYPE_UINT32, &radio_mask,
-                               DBUS_TYPE_INVALID);
+               radio_states = (powered ? MCE_RADIO_STATE_BLUETOOTH : 0);
 
-       if (dbus_connection_send(conn, msg, NULL))
-               mce_bt_set = powered;
-       else
-               error("calling %s failed", MCE_RADIO_STATES_CHANGE_REQ);
+               DBG("Changing MCE Bluetooth radio state to: %d", radio_states);
+
+               dbus_message_append_args(msg, DBUS_TYPE_UINT32, &radio_states,
+                                       DBUS_TYPE_UINT32, &radio_mask,
+                                       DBUS_TYPE_INVALID);
 
-       dbus_message_unref(msg);
+               if (dbus_connection_send(conn, msg, NULL))
+                       mce_bt_on = powered;
+               else
+                       error("calling %s failed", MCE_RADIO_STATES_CHANGE_REQ);
+
+               dbus_message_unref(msg);
+       }
 }
 
 static int mce_probe(struct btd_adapter *adapter)
 {
-       DBusMessage *msg;
-       DBusPendingCall *call;
 
        DBG("path %s", adapter_get_path(adapter));
 
-       msg = dbus_message_new_method_call(MCE_SERVICE, MCE_REQUEST_PATH,
-                                       MCE_REQUEST_IF, MCE_RADIO_STATES_GET);
-
-       if (!dbus_connection_send_with_reply(conn, msg, &call, -1)) {
-               error("calling %s failed", MCE_RADIO_STATES_GET);
-               dbus_message_unref(msg);
-               return -1;
-       }
-
-       dbus_pending_call_set_notify(call, read_radio_states_cb, adapter, NULL);
-       dbus_pending_call_unref(call);
-       dbus_message_unref(msg);
-
        watch_id = g_dbus_add_signal_watch(conn, NULL, MCE_SIGNAL_PATH,
                                        MCE_SIGNAL_IF, MCE_RADIO_STATES_SIG,
                                        mce_signal_callback, adapter, NULL);
 
+       tklock_watch_id = g_dbus_add_signal_watch(conn, NULL, MCE_SIGNAL_PATH,
+                                       MCE_SIGNAL_IF, MCE_TKLOCK_MODE_SIG,
+                                       mce_tklock_mode_cb, adapter, NULL);
+
        btd_adapter_register_powered_callback(adapter, adapter_powered);
 
        return 0;
@@ -216,6 +245,9 @@ static void mce_remove(struct btd_adapter *adapter)
        if (watch_id > 0)
                g_dbus_remove_watch(conn, watch_id);
 
+       if (tklock_watch_id > 0)
+               g_dbus_remove_watch(conn, tklock_watch_id);
+
        btd_adapter_unregister_powered_callback(adapter, adapter_powered);
 }
 
index 0c376f7..23dc552 100644 (file)
@@ -47,6 +47,7 @@
 #include "manager.h"
 #include "device.h"
 #include "event.h"
+#include "oob.h"
 
 #define MGMT_BUF_SIZE 1024
 
@@ -54,18 +55,12 @@ static int max_index = -1;
 static struct controller_info {
        gboolean valid;
        gboolean notified;
-       uint8_t type;
        bdaddr_t bdaddr;
-       uint8_t features[8];
-       uint8_t dev_class[3];
+       uint8_t version;
        uint16_t manufacturer;
-       uint8_t hci_ver;
-       uint16_t hci_rev;
-       gboolean enabled;
-       gboolean connectable;
-       gboolean discoverable;
-       gboolean pairable;
-       uint8_t sec_mode;
+       uint32_t supported_settings;
+       uint32_t current_settings;
+       uint8_t dev_class[3];
        GSList *connections;
 } *controllers = NULL;
 
@@ -192,8 +187,23 @@ static int mgmt_set_connectable(int index, gboolean connectable)
 
 static int mgmt_set_discoverable(int index, gboolean discoverable)
 {
+       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_discoverable)];
+       struct mgmt_hdr *hdr = (void *) buf;
+       struct mgmt_cp_set_discoverable *cp = (void *) &buf[sizeof(*hdr)];
+
        DBG("index %d discoverable %d", index, discoverable);
-       return mgmt_set_mode(index, MGMT_OP_SET_DISCOVERABLE, discoverable);
+
+       memset(buf, 0, sizeof(buf));
+       hdr->opcode = htobs(MGMT_OP_SET_DISCOVERABLE);
+       hdr->index = htobs(index);
+       hdr->len = htobs(sizeof(*cp));
+
+       cp->val = discoverable;
+
+       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
+               return -errno;
+
+       return 0;
 }
 
 static int mgmt_set_pairable(int index, gboolean pairable)
@@ -202,33 +212,71 @@ static int mgmt_set_pairable(int index, gboolean pairable)
        return mgmt_set_mode(index, MGMT_OP_SET_PAIRABLE, pairable);
 }
 
-static int mgmt_update_powered(int index, uint8_t powered)
+static inline int mgmt_powered(uint32_t settings)
 {
-       struct controller_info *info;
-       struct btd_adapter *adapter;
-       gboolean pairable, discoverable;
-       uint8_t on_mode;
+       return (settings & MGMT_SETTING_POWERED) != 0;
+}
 
-       if (index > max_index) {
-               error("Unexpected index %u", index);
-               return -ENODEV;
-       }
+static inline int mgmt_connectable(uint32_t settings)
+{
+       return (settings & MGMT_SETTING_CONNECTABLE) != 0;
+}
 
-       info = &controllers[index];
+static inline int mgmt_fast_connectable(uint32_t settings)
+{
+       return (settings & MGMT_SETTING_FAST_CONNECTABLE) != 0;
+}
 
-       info->enabled = powered;
+static inline int mgmt_discoverable(uint32_t settings)
+{
+       return (settings & MGMT_SETTING_DISCOVERABLE) != 0;
+}
 
-       adapter = manager_find_adapter(&info->bdaddr);
-       if (adapter == NULL) {
-               DBG("Adapter not found");
-               return -ENODEV;
-       }
+static inline int mgmt_pairable(uint32_t settings)
+{
+       return (settings & MGMT_SETTING_PAIRABLE) != 0;
+}
+
+static inline int mgmt_ssp(uint32_t settings)
+{
+       return (settings & MGMT_SETTING_SSP) != 0;
+}
+
+static inline int mgmt_bredr(uint32_t settings)
+{
+       return (settings & MGMT_SETTING_BREDR) != 0;
+}
+
+static inline int mgmt_high_speed(uint32_t settings)
+{
+       return (settings & MGMT_SETTING_HS) != 0;
+}
+
+static inline int mgmt_low_energy(uint32_t settings)
+{
+       return (settings & MGMT_SETTING_LE) != 0;
+}
 
-       if (!powered) {
-               info->connectable = FALSE;
-               info->pairable = FALSE;
-               info->discoverable = FALSE;
+static uint8_t create_mode(uint32_t settings)
+{
+       uint8_t mode = 0;
+
+       if (mgmt_connectable(settings))
+               mode |= SCAN_PAGE;
+
+       if (mgmt_discoverable(settings))
+               mode |= SCAN_INQUIRY;
+
+       return mode;
+}
+
+static int mgmt_update_powered(struct btd_adapter *adapter, uint32_t settings)
+{
+       gboolean pairable;
+       uint8_t on_mode;
+       uint16_t index;
 
+       if (!mgmt_powered(settings)) {
                btd_adapter_stop(adapter);
                return 0;
        }
@@ -237,151 +285,84 @@ static int mgmt_update_powered(int index, uint8_t powered)
 
        btd_adapter_get_mode(adapter, NULL, &on_mode, &pairable);
 
-       discoverable = (on_mode == MODE_DISCOVERABLE);
+       index = adapter_get_dev_id(adapter);
 
-       if (on_mode == MODE_DISCOVERABLE && !info->discoverable)
+       if (on_mode == MODE_DISCOVERABLE && !mgmt_discoverable(settings))
                mgmt_set_discoverable(index, TRUE);
-       else if (on_mode == MODE_CONNECTABLE && !info->connectable)
+       else if (on_mode == MODE_CONNECTABLE && !mgmt_connectable(settings))
                mgmt_set_connectable(index, TRUE);
-       else {
-               uint8_t mode = 0;
-
-               if (info->connectable)
-                       mode |= SCAN_PAGE;
-               if (info->discoverable)
-                       mode |= SCAN_INQUIRY;
-
-               adapter_mode_changed(adapter, mode);
-       }
+       else
+               adapter_mode_changed(adapter, create_mode(settings));
 
-       if (info->pairable != pairable)
+       if (mgmt_pairable(settings) != pairable)
                mgmt_set_pairable(index, pairable);
 
        return 0;
 }
 
-static void mgmt_powered(int sk, uint16_t index, void *buf, size_t len)
+static int mode_changed(uint32_t s1, uint32_t s2)
 {
-       struct mgmt_mode *ev = buf;
+       if (mgmt_connectable(s1) != mgmt_connectable(s2))
+               return 1;
 
-       if (len < sizeof(*ev)) {
-               error("Too small powered event");
-               return;
-       }
-
-       DBG("Controller %u powered %u", index, ev->val);
+       if (mgmt_discoverable(s1) != mgmt_discoverable(s2))
+               return 1;
 
-       mgmt_update_powered(index, ev->val);
+       return 0;
 }
 
-static void mgmt_discoverable(int sk, uint16_t index, void *buf, size_t len)
+static void mgmt_new_settings(int sk, uint16_t index, void *buf, size_t len)
 {
-       struct mgmt_mode *ev = buf;
+       uint32_t settings, *ev = buf;
        struct controller_info *info;
        struct btd_adapter *adapter;
-       uint8_t mode;
 
        if (len < sizeof(*ev)) {
-               error("Too small discoverable event");
+               error("Too small new settings event");
                return;
        }
 
-       DBG("Controller %u discoverable %u", index, ev->val);
+       DBG("hci%u new settings", index);
 
        if (index > max_index) {
-               error("Unexpected index %u in discoverable event", index);
+               error("Unexpected index %u in new_settings event", index);
                return;
        }
 
        info = &controllers[index];
 
-       info->discoverable = ev->val ? TRUE : FALSE;
-
        adapter = manager_find_adapter(&info->bdaddr);
-       if (!adapter)
-               return;
-
-       if (info->connectable)
-               mode = SCAN_PAGE;
-       else
-               mode = 0;
-
-       if (info->discoverable)
-               mode |= SCAN_INQUIRY;
-
-       adapter_mode_changed(adapter, mode);
-}
-
-static void mgmt_connectable(int sk, uint16_t index, void *buf, size_t len)
-{
-       struct mgmt_mode *ev = buf;
-       struct controller_info *info;
-       struct btd_adapter *adapter;
-       uint8_t mode;
-
-       if (len < sizeof(*ev)) {
-               error("Too small connectable event");
-               return;
-       }
-
-       DBG("Controller %u connectable %u", index, ev->val);
-
-       if (index > max_index) {
-               error("Unexpected index %u in connectable event", index);
+       if (adapter == NULL) {
+               DBG("Adapter not found");
                return;
        }
 
-       info = &controllers[index];
-
-       info->connectable = ev->val ? TRUE : FALSE;
-
-       adapter = manager_find_adapter(&info->bdaddr);
-       if (!adapter)
-               return;
+       settings = bt_get_le32(ev);
 
-       if (info->discoverable)
-               mode = SCAN_INQUIRY;
-       else
-               mode = 0;
+       if (mgmt_powered(settings) != mgmt_powered(info->current_settings))
+               mgmt_update_powered(adapter, settings);
+       else if (mode_changed(settings, info->current_settings))
+               adapter_mode_changed(adapter, create_mode(settings));
 
-       if (info->connectable)
-               mode |= SCAN_PAGE;
+       if (mgmt_pairable(settings) != mgmt_pairable(info->current_settings))
+               btd_adapter_pairable_changed(adapter, mgmt_pairable(settings));
 
-       adapter_mode_changed(adapter, mode);
+       info->current_settings = settings;
 }
 
-static void mgmt_pairable(int sk, uint16_t index, void *buf, size_t len)
+static void bonding_complete(struct controller_info *info, bdaddr_t *bdaddr,
+                                                               uint8_t status)
 {
-       struct mgmt_mode *ev = buf;
-       struct controller_info *info;
        struct btd_adapter *adapter;
 
-       if (len < sizeof(*ev)) {
-               error("Too small pairable event");
-               return;
-       }
-
-       DBG("Controller %u pairable %u", index, ev->val);
-
-       if (index > max_index) {
-               error("Unexpected index %u in pairable event", index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       info->pairable = ev->val ? TRUE : FALSE;
-
        adapter = manager_find_adapter(&info->bdaddr);
-       if (!adapter)
-               return;
-
-       btd_adapter_pairable_changed(adapter, info->pairable);
+       if (adapter != NULL)
+               adapter_bonding_complete(adapter, bdaddr, status);
 }
 
-static void mgmt_new_key(int sk, uint16_t index, void *buf, size_t len)
+static void mgmt_new_link_key(int sk, uint16_t index, void *buf, size_t len)
 {
-       struct mgmt_ev_new_key *ev = buf;
+       struct mgmt_ev_new_link_key *ev = buf;
        struct controller_info *info;
 
        if (len != sizeof(*ev)) {
@@ -406,16 +387,17 @@ static void mgmt_new_key(int sk, uint16_t index, void *buf, size_t len)
 
        info = &controllers[index];
 
-       btd_event_link_key_notify(&info->bdaddr, &ev->key.bdaddr,
-                                       ev->key.val, ev->key.type,
-                                       ev->key.pin_len);
+       if (ev->store_hint)
+               btd_event_link_key_notify(&info->bdaddr, &ev->key.bdaddr,
+                                               ev->key.val, ev->key.type,
+                                               ev->key.pin_len);
 
-       btd_event_bonding_complete(&info->bdaddr, &ev->key.bdaddr, 0);
+       bonding_complete(info, &ev->key.bdaddr, 0);
 }
 
 static void mgmt_device_connected(int sk, uint16_t index, void *buf, size_t len)
 {
-       struct mgmt_ev_device_connected *ev = buf;
+       struct mgmt_addr_info *ev = buf;
        struct controller_info *info;
        char addr[18];
 
@@ -441,7 +423,7 @@ static void mgmt_device_connected(int sk, uint16_t index, void *buf, size_t len)
 static void mgmt_device_disconnected(int sk, uint16_t index, void *buf,
                                                                size_t len)
 {
-       struct mgmt_ev_device_disconnected *ev = buf;
+       struct mgmt_addr_info *ev = buf;
        struct controller_info *info;
        char addr[18];
 
@@ -475,7 +457,7 @@ static void mgmt_connect_failed(int sk, uint16_t index, void *buf, size_t len)
                return;
        }
 
-       ba2str(&ev->bdaddr, addr);
+       ba2str(&ev->addr.bdaddr, addr);
 
        DBG("hci%u %s status %u", index, addr, ev->status);
 
@@ -486,13 +468,14 @@ static void mgmt_connect_failed(int sk, uint16_t index, void *buf, size_t len)
 
        info = &controllers[index];
 
-       btd_event_conn_failed(&info->bdaddr, &ev->bdaddr, ev->status);
+       btd_event_conn_failed(&info->bdaddr, &ev->addr.bdaddr, ev->status);
 
        /* In the case of security mode 3 devices */
-       btd_event_bonding_complete(&info->bdaddr, &ev->bdaddr, ev->status);
+       bonding_complete(info, &ev->addr.bdaddr, ev->status);
 }
 
-static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin)
+static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin,
+                                                               size_t pin_len)
 {
        char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_pin_code_reply)];
        struct mgmt_hdr *hdr = (void *) buf;
@@ -500,7 +483,7 @@ static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin)
        char addr[18];
 
        ba2str(bdaddr, addr);
-       DBG("index %d addr %s pin %s", index, addr, pin ? pin : "<none>");
+       DBG("index %d addr %s pinlen %zu", index, addr, pin_len);
 
        memset(buf, 0, sizeof(buf));
 
@@ -517,9 +500,7 @@ static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin)
                buf_len = sizeof(*hdr) + sizeof(*cp);
        } else {
                struct mgmt_cp_pin_code_reply *cp;
-               size_t pin_len;
 
-               pin_len = strlen(pin);
                if (pin_len > 16)
                        return -EINVAL;
 
@@ -564,10 +545,10 @@ static void mgmt_pin_code_request(int sk, uint16_t index, void *buf, size_t len)
 
        info = &controllers[index];
 
-       err = btd_event_request_pin(&info->bdaddr, &ev->bdaddr);
+       err = btd_event_request_pin(&info->bdaddr, &ev->bdaddr, ev->secure);
        if (err < 0) {
                error("btd_event_request_pin: %s", strerror(-err));
-               mgmt_pincode_reply(index, &ev->bdaddr, NULL);
+               mgmt_pincode_reply(index, &ev->bdaddr, NULL, 0);
        }
 }
 
@@ -600,6 +581,98 @@ static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success)
        return 0;
 }
 
+static int mgmt_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey)
+{
+       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_user_passkey_reply)];
+       struct mgmt_hdr *hdr = (void *) buf;
+       size_t buf_len;
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("index %d addr %s passkey %06u", index, addr, passkey);
+
+       memset(buf, 0, sizeof(buf));
+
+       hdr->index = htobs(index);
+       if (passkey == INVALID_PASSKEY) {
+               struct mgmt_cp_user_passkey_neg_reply *cp;
+
+               hdr->opcode = htobs(MGMT_OP_USER_PASSKEY_NEG_REPLY);
+               hdr->len = htobs(sizeof(*cp));
+
+               cp = (void *) &buf[sizeof(*hdr)];
+               bacpy(&cp->bdaddr, bdaddr);
+
+               buf_len = sizeof(*hdr) + sizeof(*cp);
+       } else {
+               struct mgmt_cp_user_passkey_reply *cp;
+
+               hdr->opcode = htobs(MGMT_OP_USER_PASSKEY_REPLY);
+               hdr->len = htobs(sizeof(*cp));
+
+               cp = (void *) &buf[sizeof(*hdr)];
+               bacpy(&cp->bdaddr, bdaddr);
+               cp->passkey = htobl(passkey);
+
+               buf_len = sizeof(*hdr) + sizeof(*cp);
+       }
+
+       if (write(mgmt_sock, buf, buf_len) < 0)
+               return -errno;
+
+       return 0;
+}
+
+static void mgmt_passkey_request(int sk, uint16_t index, void *buf, size_t len)
+{
+       struct mgmt_ev_user_passkey_request *ev = buf;
+       struct controller_info *info;
+       char addr[18];
+       int err;
+
+       if (len < sizeof(*ev)) {
+               error("Too small passkey_request event");
+               return;
+       }
+
+       ba2str(&ev->bdaddr, addr);
+
+       DBG("hci%u %s", index, addr);
+
+       if (index > max_index) {
+               error("Unexpected index %u in passkey_request event", index);
+               return;
+       }
+
+       info = &controllers[index];
+
+       err = btd_event_user_passkey(&info->bdaddr, &ev->bdaddr);
+       if (err < 0) {
+               error("btd_event_user_passkey: %s", strerror(-err));
+               mgmt_passkey_reply(index, &ev->bdaddr, INVALID_PASSKEY);
+       }
+}
+
+struct confirm_data {
+       int index;
+       bdaddr_t bdaddr;
+};
+
+static gboolean confirm_accept(gpointer user_data)
+{
+       struct confirm_data *data = user_data;
+       struct controller_info *info = &controllers[data->index];
+
+       DBG("auto-accepting incoming pairing request");
+
+       if (data->index > max_index || !info->valid)
+               return FALSE;
+
+       mgmt_confirm_reply(data->index, &data->bdaddr, TRUE);
+
+       return FALSE;
+}
+
 static void mgmt_user_confirm_request(int sk, uint16_t index, void *buf,
                                                                size_t len)
 {
@@ -615,7 +688,7 @@ static void mgmt_user_confirm_request(int sk, uint16_t index, void *buf,
 
        ba2str(&ev->bdaddr, addr);
 
-       DBG("hci%u %s", index, addr);
+       DBG("hci%u %s confirm_hint %u", index, addr, ev->confirm_hint);
 
        if (index > max_index) {
                error("Unexpected index %u in user_confirm_request event",
@@ -623,6 +696,18 @@ static void mgmt_user_confirm_request(int sk, uint16_t index, void *buf,
                return;
        }
 
+       if (ev->confirm_hint) {
+               struct confirm_data *data;
+
+               data = g_new0(struct confirm_data, 1);
+               data->index = index;
+               bacpy(&data->bdaddr, &ev->bdaddr);
+
+               g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, 1,
+                                               confirm_accept, data, g_free);
+               return;
+       }
+
        info = &controllers[index];
 
        err = btd_event_user_confirm(&info->bdaddr, &ev->bdaddr,
@@ -649,6 +734,7 @@ static int mgmt_add_uuid(int index, uuid_t *uuid, uint8_t svc_hint)
        struct mgmt_hdr *hdr = (void *) buf;
        struct mgmt_cp_add_uuid *cp = (void *) &buf[sizeof(*hdr)];
        uuid_t uuid128;
+       uint128_t uint128;
 
        DBG("index %d", index);
 
@@ -659,7 +745,9 @@ static int mgmt_add_uuid(int index, uuid_t *uuid, uint8_t svc_hint)
        hdr->len = htobs(sizeof(*cp));
        hdr->index = htobs(index);
 
-       memcpy(cp->uuid, uuid128.value.uuid128.data, 16);
+       ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
+       htob128(&uint128, (uint128_t *) cp->uuid);
+
        cp->svc_hint = svc_hint;
 
        if (write(mgmt_sock, buf, sizeof(buf)) < 0)
@@ -674,6 +762,7 @@ static int mgmt_remove_uuid(int index, uuid_t *uuid)
        struct mgmt_hdr *hdr = (void *) buf;
        struct mgmt_cp_remove_uuid *cp = (void *) &buf[sizeof(*hdr)];
        uuid_t uuid128;
+       uint128_t uint128;
 
        DBG("index %d", index);
 
@@ -684,7 +773,8 @@ static int mgmt_remove_uuid(int index, uuid_t *uuid)
        hdr->len = htobs(sizeof(*cp));
        hdr->index = htobs(index);
 
-       memcpy(cp->uuid, uuid128.value.uuid128.data, 16);
+       ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
+       htob128(&uint128, (uint128_t *) cp->uuid);
 
        if (write(mgmt_sock, buf, sizeof(buf)) < 0)
                return -errno;
@@ -755,32 +845,26 @@ static void read_info_complete(int sk, uint16_t index, void *buf, size_t len)
                return;
        }
 
-       mgmt_set_mode(index, MGMT_OP_SET_SERVICE_CACHE, 1);
-
        info = &controllers[index];
-       info->type = rp->type;
-       info->enabled = rp->powered;
-       info->connectable = rp->connectable;
-       info->discoverable = rp->discoverable;
-       info->pairable = rp->pairable;
-       info->sec_mode = rp->sec_mode;
+
        bacpy(&info->bdaddr, &rp->bdaddr);
-       memcpy(info->dev_class, rp->dev_class, 3);
-       memcpy(info->features, rp->features, 8);
+       info->version = rp->version;
        info->manufacturer = btohs(bt_get_unaligned(&rp->manufacturer));
-       info->hci_ver = rp->hci_ver;
-       info->hci_rev = btohs(bt_get_unaligned(&rp->hci_rev));
+
+       memcpy(&info->supported_settings, &rp->supported_settings,
+                                       sizeof(info->supported_settings));
+       memcpy(&info->current_settings, &rp->current_settings,
+                                       sizeof(info->current_settings));
+
+       memcpy(info->dev_class, rp->dev_class, sizeof(info->dev_class));
 
        ba2str(&info->bdaddr, addr);
-       DBG("hci%u type %u addr %s", index, info->type, addr);
-       DBG("hci%u class 0x%02x%02x%02x", index,
+       DBG("hci%u addr %s version %u manufacturer %u class 0x%02x%02x%02x\n",
+               index, addr, info->version, info->manufacturer,
                info->dev_class[2], info->dev_class[1], info->dev_class[0]);
-       DBG("hci%u manufacturer %d HCI ver %d:%d", index, info->manufacturer,
-                                               info->hci_ver, info->hci_rev);
-       DBG("hci%u enabled %u discoverable %u pairable %u sec_mode %u", index,
-                                       info->enabled, info->discoverable,
-                                       info->pairable, info->sec_mode);
+       DBG("hci%u settings", index);
        DBG("hci%u name %s", index, (char *) rp->name);
+       DBG("hci%u short name %s", index, (char *) rp->short_name);
 
        adapter = btd_manager_register_adapter(index);
        if (adapter == NULL) {
@@ -794,239 +878,178 @@ static void read_info_complete(int sk, uint16_t index, void *buf, size_t len)
                return;
        }
 
-       if (info->enabled)
-               mgmt_update_powered(index, TRUE);
+       if (mgmt_powered(info->current_settings))
+               mgmt_update_powered(adapter, info->current_settings);
        else
                mgmt_set_powered(index, TRUE);
 
-       adapter_update_local_name(adapter, (char *) rp->name);
+       adapter_name_changed(adapter, (char *) rp->name);
 
        btd_adapter_unref(adapter);
 }
 
-static void set_powered_complete(int sk, uint16_t index, void *buf, size_t len)
+static void disconnect_complete(int sk, uint16_t index, void *buf, size_t len)
 {
-       struct mgmt_mode *rp = buf;
+       struct mgmt_rp_disconnect *rp = buf;
+       struct controller_info *info;
+       char addr[18];
 
        if (len < sizeof(*rp)) {
-               error("Too small set powered complete event");
+               error("Too small disconnect complete event");
                return;
        }
 
-       DBG("hci%d powered %u", index, rp->val);
-
-       mgmt_update_powered(index, rp->val);
-}
-
-static void set_discoverable_complete(int sk, uint16_t index, void *buf,
-                                                               size_t len)
-{
-       struct mgmt_mode *rp = buf;
-       struct controller_info *info;
-       struct btd_adapter *adapter;
-       uint8_t mode;
+       ba2str(&rp->bdaddr, addr);
 
-       if (len < sizeof(*rp)) {
-               error("Too small set discoverable complete event");
+       if (rp->status != 0) {
+               error("Disconnecting %s failed with status %u",
+                                                       addr, rp->status);
                return;
        }
 
-       DBG("hci%d discoverable %u", index, rp->val);
+       DBG("hci%d %s disconnected", index, addr);
 
        if (index > max_index) {
-               error("Unexpected index %u in discoverable complete", index);
+               error("Unexpected index %u in disconnect complete", index);
                return;
        }
 
        info = &controllers[index];
 
-       info->discoverable = rp->val ? TRUE : FALSE;
-
-       adapter = manager_find_adapter(&info->bdaddr);
-       if (!adapter)
-               return;
-
-       /* set_discoverable will always also change page scanning */
-       mode = SCAN_PAGE;
-
-       if (info->discoverable)
-               mode |= SCAN_INQUIRY;
+       btd_event_disconn_complete(&info->bdaddr, &rp->bdaddr);
 
-       adapter_mode_changed(adapter, mode);
+       bonding_complete(info, &rp->bdaddr, HCI_CONNECTION_TERMINATED);
 }
 
-static void set_connectable_complete(int sk, uint16_t index, void *buf,
-                                                               size_t len)
+static void pair_device_complete(int sk, uint16_t index, void *buf, size_t len)
 {
-       struct mgmt_mode *rp = buf;
+       struct mgmt_rp_pair_device *rp = buf;
        struct controller_info *info;
-       struct btd_adapter *adapter;
+       char addr[18];
 
        if (len < sizeof(*rp)) {
-               error("Too small set connectable complete event");
+               error("Too small pair_device complete event");
                return;
        }
 
-       DBG("hci%d connectable %u", index, rp->val);
+       ba2str(&rp->addr.bdaddr, addr);
+
+       DBG("hci%d %s pairing complete status %u", index, addr, rp->status);
 
        if (index > max_index) {
-               error("Unexpected index %u in connectable complete", index);
+               error("Unexpected index %u in pair_device complete", index);
                return;
        }
 
        info = &controllers[index];
 
-       info->connectable = rp->val ? TRUE : FALSE;
-
-       adapter = manager_find_adapter(&info->bdaddr);
-       if (adapter)
-               adapter_mode_changed(adapter, rp->val ? SCAN_PAGE : 0);
+       bonding_complete(info, &rp->addr.bdaddr, rp->status);
 }
 
-static void set_pairable_complete(int sk, uint16_t index, void *buf,
+static void get_connections_complete(int sk, uint16_t index, void *buf,
                                                                size_t len)
 {
-       struct mgmt_mode *rp = buf;
+       struct mgmt_rp_get_connections *rp = buf;
        struct controller_info *info;
-       struct btd_adapter *adapter;
+       int i;
 
        if (len < sizeof(*rp)) {
-               error("Too small set pairable complete event");
+               error("Too small get_connections complete event");
                return;
        }
 
-       DBG("hci%d pairable %u", index, rp->val);
+       if (len < (sizeof(*rp) + (rp->conn_count * sizeof(bdaddr_t)))) {
+               error("Too small get_connections complete event");
+               return;
+       }
 
        if (index > max_index) {
-               error("Unexpected index %u in pairable complete", index);
+               error("Unexpected index %u in get_connections complete",
+                                                               index);
                return;
        }
 
        info = &controllers[index];
 
-       info->pairable = rp->val ? TRUE : FALSE;
-
-       adapter = manager_find_adapter(&info->bdaddr);
-       if (!adapter)
-               return;
+       for (i = 0; i < rp->conn_count; i++) {
+               bdaddr_t *bdaddr = g_memdup(&rp->addr[i], sizeof(bdaddr_t));
+               info->connections = g_slist_append(info->connections, bdaddr);
+       }
 
-       btd_adapter_pairable_changed(adapter, info->pairable);
+       read_info(sk, index);
 }
 
-static void disconnect_complete(int sk, uint16_t index, void *buf, size_t len)
+static void set_local_name_complete(int sk, uint16_t index, void *buf,
+                                                               size_t len)
 {
-       struct mgmt_rp_disconnect *rp = buf;
+       struct mgmt_cp_set_local_name *rp = buf;
        struct controller_info *info;
-       char addr[18];
+       struct btd_adapter *adapter;
 
        if (len < sizeof(*rp)) {
-               error("Too small disconnect complete event");
+               error("Too small set_local_name complete event");
                return;
        }
 
-       ba2str(&rp->bdaddr, addr);
-
-       DBG("hci%d %s disconnected", index, addr);
+       DBG("hci%d name %s", index, (char *) rp->name);
 
        if (index > max_index) {
-               error("Unexpected index %u in disconnect complete", index);
+               error("Unexpected index %u in set_local_name complete", index);
                return;
        }
 
        info = &controllers[index];
 
-       btd_event_disconn_complete(&info->bdaddr, &rp->bdaddr);
-
-       btd_event_bonding_complete(&info->bdaddr, &rp->bdaddr,
-                                               HCI_CONNECTION_TERMINATED);
-}
-
-static void pair_device_complete(int sk, uint16_t index, void *buf, size_t len)
-{
-       struct mgmt_rp_pair_device *rp = buf;
-       struct controller_info *info;
-       char addr[18];
-
-       if (len < sizeof(*rp)) {
-               error("Too small pair_device complete event");
-               return;
-       }
-
-       ba2str(&rp->bdaddr, addr);
-
-       DBG("hci%d %s pairing complete status %u", index, addr, rp->status);
-
-       if (index > max_index) {
-               error("Unexpected index %u in pair_device complete", index);
+       adapter = manager_find_adapter(&info->bdaddr);
+       if (adapter == NULL) {
+               DBG("Adapter not found");
                return;
        }
 
-       info = &controllers[index];
-
-       btd_event_bonding_complete(&info->bdaddr, &rp->bdaddr, rp->status);
+       adapter_name_changed(adapter, (char *) rp->name);
 }
 
-static void get_connections_complete(int sk, uint16_t index, void *buf,
+static void read_local_oob_data_complete(int sk, uint16_t index, void *buf,
                                                                size_t len)
 {
-       struct mgmt_rp_get_connections *rp = buf;
-       struct controller_info *info;
-       int i;
-
-       if (len < sizeof(*rp)) {
-               error("Too small get_connections complete event");
-               return;
-       }
+       struct mgmt_rp_read_local_oob_data *rp = buf;
+       struct btd_adapter *adapter;
 
-       if (len < (sizeof(*rp) + (rp->conn_count * sizeof(bdaddr_t)))) {
-               error("Too small get_connections complete event");
+       if (len != sizeof(*rp)) {
+               error("Wrong read_local_oob_data_complete event size");
                return;
        }
 
        if (index > max_index) {
-               error("Unexpected index %u in get_connections complete",
+               error("Unexpected index %u in read_local_oob_data_complete",
                                                                index);
                return;
        }
 
-       info = &controllers[index];
+       DBG("hci%u", index);
 
-       for (i = 0; i < rp->conn_count; i++) {
-               bdaddr_t *bdaddr = g_memdup(&rp->conn[i], sizeof(bdaddr_t));
-               info->connections = g_slist_append(info->connections, bdaddr);
-       }
+       adapter = manager_find_adapter_by_id(index);
 
-       read_info(sk, index);
+       if (adapter)
+               oob_read_local_data_complete(adapter, rp->hash, rp->randomizer);
 }
 
-static void set_local_name_complete(int sk, uint16_t index, void *buf,
-                                                               size_t len)
+static void read_local_oob_data_failed(int sk, uint16_t index)
 {
-       struct mgmt_cp_set_local_name *rp = buf;
-       struct controller_info *info;
        struct btd_adapter *adapter;
 
-       if (len < sizeof(*rp)) {
-               error("Too small set_local_name complete event");
-               return;
-       }
-
-       DBG("hci%d name %s", index, (char *) rp->name);
-
        if (index > max_index) {
-               error("Unexpected index %u in set_local_name complete", index);
+               error("Unexpected index %u in read_local_oob_data_failed",
+                                                               index);
                return;
        }
 
-       info = &controllers[index];
+       DBG("hci%u", index);
 
-       adapter = manager_find_adapter(&info->bdaddr);
-       if (adapter == NULL) {
-               DBG("Adapter not found");
-               return;
-       }
+       adapter = manager_find_adapter_by_id(index);
 
-       adapter_update_local_name(adapter, (char *) rp->name);
+       if (adapter)
+               oob_read_local_data_complete(adapter, NULL, NULL);
 }
 
 static void mgmt_cmd_complete(int sk, uint16_t index, void *buf, size_t len)
@@ -1056,16 +1079,16 @@ static void mgmt_cmd_complete(int sk, uint16_t index, void *buf, size_t len)
                read_info_complete(sk, index, ev->data, len);
                break;
        case MGMT_OP_SET_POWERED:
-               set_powered_complete(sk, index, ev->data, len);
+               mgmt_new_settings(sk, index, ev->data, len);
                break;
        case MGMT_OP_SET_DISCOVERABLE:
-               set_discoverable_complete(sk, index, ev->data, len);
+               mgmt_new_settings(sk, index, ev->data, len);
                break;
        case MGMT_OP_SET_CONNECTABLE:
-               set_connectable_complete(sk, index, ev->data, len);
+               mgmt_new_settings(sk, index, ev->data, len);
                break;
        case MGMT_OP_SET_PAIRABLE:
-               set_pairable_complete(sk, index, ev->data, len);
+               mgmt_new_settings(sk, index, ev->data, len);
                break;
        case MGMT_OP_ADD_UUID:
                DBG("add_uuid complete");
@@ -1076,14 +1099,11 @@ static void mgmt_cmd_complete(int sk, uint16_t index, void *buf, size_t len)
        case MGMT_OP_SET_DEV_CLASS:
                DBG("set_dev_class complete");
                break;
-       case MGMT_OP_SET_SERVICE_CACHE:
-               DBG("set_service_cache complete");
+       case MGMT_OP_LOAD_LINK_KEYS:
+               DBG("load_link_keys complete");
                break;
-       case MGMT_OP_LOAD_KEYS:
-               DBG("load_keys complete");
-               break;
-       case MGMT_OP_REMOVE_KEY:
-               DBG("remove_key complete");
+       case MGMT_OP_REMOVE_KEYS:
+               DBG("remove_keys complete");
                break;
        case MGMT_OP_DISCONNECT:
                DBG("disconnect complete");
@@ -1113,6 +1133,30 @@ static void mgmt_cmd_complete(int sk, uint16_t index, void *buf, size_t len)
        case MGMT_OP_SET_LOCAL_NAME:
                set_local_name_complete(sk, index, ev->data, len);
                break;
+       case MGMT_OP_READ_LOCAL_OOB_DATA:
+               read_local_oob_data_complete(sk, index, ev->data, len);
+               break;
+       case MGMT_OP_ADD_REMOTE_OOB_DATA:
+               DBG("add_remote_oob_data complete");
+               break;
+       case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
+               DBG("remove_remote_oob_data complete");
+               break;
+       case MGMT_OP_BLOCK_DEVICE:
+               DBG("block_device complete");
+               break;
+       case MGMT_OP_UNBLOCK_DEVICE:
+               DBG("unblock_device complete");
+               break;
+       case MGMT_OP_SET_FAST_CONNECTABLE:
+               DBG("set_fast_connectable complete");
+               break;
+       case MGMT_OP_START_DISCOVERY:
+               DBG("start_discovery complete");
+               break;
+       case MGMT_OP_STOP_DISCOVERY:
+               DBG("stop_discovery complete");
+               break;
        default:
                error("Unknown command complete for opcode %u", opcode);
                break;
@@ -1132,6 +1176,12 @@ static void mgmt_cmd_status(int sk, uint16_t index, void *buf, size_t len)
        opcode = btohs(bt_get_unaligned(&ev->opcode));
 
        DBG("status %u opcode %u (index %u)", ev->status, opcode, index);
+
+       switch (opcode) {
+       case MGMT_OP_READ_LOCAL_OOB_DATA:
+               read_local_oob_data_failed(sk, index);
+               break;
+       }
 }
 
 static void mgmt_controller_error(int sk, uint16_t index, void *buf, size_t len)
@@ -1165,7 +1215,7 @@ static void mgmt_auth_failed(int sk, uint16_t index, void *buf, size_t len)
 
        info = &controllers[index];
 
-       btd_event_bonding_complete(&info->bdaddr, &ev->bdaddr, ev->status);
+       bonding_complete(info, &ev->bdaddr, ev->status);
 }
 
 static void mgmt_local_name_changed(int sk, uint16_t index, void *buf, size_t len)
@@ -1190,7 +1240,160 @@ static void mgmt_local_name_changed(int sk, uint16_t index, void *buf, size_t le
 
        adapter = manager_find_adapter(&info->bdaddr);
        if (adapter)
-               adapter_update_local_name(adapter, (char *) ev->name);
+               adapter_name_changed(adapter, (char *) ev->name);
+}
+
+static inline addr_type_t mgmt_addr_type(uint8_t mgmt_addr_type)
+{
+       switch (mgmt_addr_type) {
+       case MGMT_ADDR_BREDR:
+               return ADDR_TYPE_BREDR;
+       case MGMT_ADDR_LE_PUBLIC:
+               return ADDR_TYPE_LE_PUBLIC;
+       case MGMT_ADDR_LE_RANDOM:
+               return ADDR_TYPE_LE_RANDOM;
+       default:
+               return ADDR_TYPE_BREDR;
+       }
+}
+
+static void mgmt_device_found(int sk, uint16_t index, void *buf, size_t len)
+{
+       struct mgmt_ev_device_found *ev = buf;
+       struct controller_info *info;
+       char addr[18];
+       uint8_t *eir;
+       uint32_t cls;
+
+       if (len != sizeof(*ev)) {
+               error("mgmt_device_found length %zu instead of expected %zu",
+                                                       len, sizeof(*ev));
+               return;
+       }
+
+       if (index > max_index) {
+               error("Unexpected index %u in device_found event", index);
+               return;
+       }
+
+       info = &controllers[index];
+
+       cls = ev->dev_class[0] | (ev->dev_class[1] << 8) |
+                                               (ev->dev_class[2] << 16);
+
+       if (ev->eir[0] == 0)
+               eir = NULL;
+       else
+               eir = ev->eir;
+
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("hci%u addr %s, class %u rssi %d cfm_name %u %s", index, addr, cls,
+                                               ev->rssi, ev->confirm_name,
+                                               eir ? "eir" : "");
+
+       btd_event_device_found(&info->bdaddr, &ev->addr.bdaddr,
+                                       mgmt_addr_type(ev->addr.type), cls,
+                                       ev->rssi, ev->confirm_name,
+                                       eir, HCI_MAX_EIR_LENGTH);
+}
+
+static void mgmt_remote_name(int sk, uint16_t index, void *buf, size_t len)
+{
+       struct mgmt_ev_remote_name *ev = buf;
+       struct controller_info *info;
+       char addr[18];
+
+       if (len < sizeof(*ev)) {
+               error("Too small mgmt_remote_name packet");
+               return;
+       }
+
+       if (index > max_index) {
+               error("Unexpected index %u in remote_name event", index);
+               return;
+       }
+
+       info = &controllers[index];
+
+       ba2str(&ev->bdaddr, addr);
+       DBG("hci%u addr %s, name %s", index, addr, ev->name);
+
+       btd_event_remote_name(&info->bdaddr, &ev->bdaddr, (char *) ev->name);
+}
+
+static void mgmt_discovering(int sk, uint16_t index, void *buf, size_t len)
+{
+       struct mgmt_mode *ev = buf;
+       struct controller_info *info;
+       struct btd_adapter *adapter;
+
+       if (len < sizeof(*ev)) {
+               error("Too small discovering event");
+               return;
+       }
+
+       DBG("Controller %u discovering %u", index, ev->val);
+
+       if (index > max_index) {
+               error("Unexpected index %u in discovering event", index);
+               return;
+       }
+
+       info = &controllers[index];
+
+       adapter = manager_find_adapter(&info->bdaddr);
+       if (!adapter)
+               return;
+
+       adapter_set_discovering(adapter, ev->val);
+}
+
+static void mgmt_device_blocked(int sk, uint16_t index, void *buf, size_t len)
+{
+       struct controller_info *info;
+       struct mgmt_ev_device_blocked *ev = buf;
+       char addr[18];
+
+       if (len < sizeof(*ev)) {
+               error("Too small mgmt_device_blocked event packet");
+               return;
+       }
+
+       ba2str(&ev->bdaddr, addr);
+       DBG("Device blocked, index %u, addr %s", index, addr);
+
+       if (index > max_index) {
+               error("Unexpected index %u in device_blocked event", index);
+               return;
+       }
+
+       info = &controllers[index];
+
+       btd_event_device_blocked(&info->bdaddr, &ev->bdaddr);
+}
+
+static void mgmt_device_unblocked(int sk, uint16_t index, void *buf, size_t len)
+{
+       struct controller_info *info;
+       struct mgmt_ev_device_unblocked *ev = buf;
+       char addr[18];
+
+       if (len < sizeof(*ev)) {
+               error("Too small mgmt_device_unblocked event packet");
+               return;
+       }
+
+       ba2str(&ev->bdaddr, addr);
+       DBG("Device unblocked, index %u, addr %s", index, addr);
+
+       if (index > max_index) {
+               error("Unexpected index %u in device_unblocked event", index);
+               return;
+       }
+
+       info = &controllers[index];
+
+       btd_event_device_unblocked(&info->bdaddr, &ev->bdaddr);
 }
 
 static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data)
@@ -1252,20 +1455,11 @@ static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data
        case MGMT_EV_INDEX_REMOVED:
                mgmt_index_removed(sk, index);
                break;
-       case MGMT_EV_POWERED:
-               mgmt_powered(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_DISCOVERABLE:
-               mgmt_discoverable(sk, index, buf + MGMT_HDR_SIZE, len);
+       case MGMT_EV_NEW_SETTINGS:
+               mgmt_new_settings(sk, index, buf + MGMT_HDR_SIZE, len);
                break;
-       case MGMT_EV_CONNECTABLE:
-               mgmt_connectable(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_PAIRABLE:
-               mgmt_pairable(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_NEW_KEY:
-               mgmt_new_key(sk, index, buf + MGMT_HDR_SIZE, len);
+       case MGMT_EV_NEW_LINK_KEY:
+               mgmt_new_link_key(sk, index, buf + MGMT_HDR_SIZE, len);
                break;
        case MGMT_EV_DEVICE_CONNECTED:
                mgmt_device_connected(sk, index, buf + MGMT_HDR_SIZE, len);
@@ -1288,6 +1482,24 @@ static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data
        case MGMT_EV_LOCAL_NAME_CHANGED:
                mgmt_local_name_changed(sk, index, buf + MGMT_HDR_SIZE, len);
                break;
+       case MGMT_EV_DEVICE_FOUND:
+               mgmt_device_found(sk, index, buf + MGMT_HDR_SIZE, len);
+               break;
+       case MGMT_EV_REMOTE_NAME:
+               mgmt_remote_name(sk, index, buf + MGMT_HDR_SIZE, len);
+               break;
+       case MGMT_EV_DISCOVERING:
+               mgmt_discovering(sk, index, buf + MGMT_HDR_SIZE, len);
+               break;
+       case MGMT_EV_DEVICE_BLOCKED:
+               mgmt_device_blocked(sk, index, buf + MGMT_HDR_SIZE, len);
+               break;
+       case MGMT_EV_DEVICE_UNBLOCKED:
+               mgmt_device_unblocked(sk, index, buf + MGMT_HDR_SIZE, len);
+               break;
+       case MGMT_EV_USER_PASSKEY_REQUEST:
+               mgmt_passkey_request(sk, index, buf + MGMT_HDR_SIZE, len);
+               break;
        default:
                error("Unknown Management opcode %u (index %u)", opcode, index);
                break;
@@ -1387,38 +1599,43 @@ static int mgmt_set_limited_discoverable(int index, gboolean limited)
        return -ENOSYS;
 }
 
-static int mgmt_start_inquiry(int index, uint8_t length, gboolean periodic)
+static int mgmt_start_discovery(int index)
 {
-       DBG("index %d length %u periodic %d", index, length, periodic);
-       return -ENOSYS;
-}
+       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_start_discovery)];
+       struct mgmt_hdr *hdr = (void *) buf;
+       struct mgmt_cp_start_discovery *cp = (void *) &buf[sizeof(*hdr)];
 
-static int mgmt_stop_inquiry(int index)
-{
        DBG("index %d", index);
-       return -ENOSYS;
-}
 
-static int mgmt_start_scanning(int index)
-{
-       DBG("index %d", index);
-       return -ENOSYS;
+       memset(buf, 0, sizeof(buf));
+       hdr->opcode = htobs(MGMT_OP_START_DISCOVERY);
+       hdr->len = htobs(sizeof(*cp));
+       hdr->index = htobs(index);
+
+       hci_set_bit(MGMT_ADDR_BREDR, &cp->type);
+       hci_set_bit(MGMT_ADDR_LE_PUBLIC, &cp->type);
+       hci_set_bit(MGMT_ADDR_LE_RANDOM, &cp->type);
+
+       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
+               return -errno;
+
+       return 0;
 }
 
-static int mgmt_stop_scanning(int index)
+static int mgmt_stop_discovery(int index)
 {
+       struct mgmt_hdr hdr;
+
        DBG("index %d", index);
-       return -ENOSYS;
-}
 
-static int mgmt_resolve_name(int index, bdaddr_t *bdaddr)
-{
-       char addr[18];
+       memset(&hdr, 0, sizeof(hdr));
+       hdr.opcode = htobs(MGMT_OP_STOP_DISCOVERY);
+       hdr.index = htobs(index);
 
-       ba2str(bdaddr, addr);
-       DBG("index %d addr %s", index, addr);
+       if (write(mgmt_sock, &hdr, sizeof(hdr)) < 0)
+               return -errno;
 
-       return -ENOSYS;
+       return 0;
 }
 
 static int mgmt_set_name(int index, const char *name)
@@ -1442,20 +1659,25 @@ static int mgmt_set_name(int index, const char *name)
        return 0;
 }
 
-static int mgmt_cancel_resolve_name(int index, bdaddr_t *bdaddr)
+static int mgmt_set_fast_connectable(int index, gboolean enable)
 {
-       char addr[18];
+       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_mode)];
+       struct mgmt_hdr *hdr = (void *) buf;
+       struct mgmt_mode *cp = (void *) &buf[sizeof(*hdr)];
 
-       ba2str(bdaddr, addr);
-       DBG("index %d addr %s", index, addr);
+       DBG("index %d enable %d", index, enable);
 
-       return -ENOSYS;
-}
+       memset(buf, 0, sizeof(buf));
+       hdr->opcode = htobs(MGMT_OP_SET_FAST_CONNECTABLE);
+       hdr->len = htobs(sizeof(*cp));
+       hdr->index = htobs(index);
 
-static int mgmt_fast_connectable(int index, gboolean enable)
-{
-       DBG("index %d enable %d", index, enable);
-       return -ENOSYS;
+       cp->val = enable;
+
+       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
+               return -errno;
+
+       return 0;
 }
 
 static int mgmt_read_clock(int index, bdaddr_t *bdaddr, int which, int timeout,
@@ -1488,63 +1710,68 @@ static int mgmt_read_bdaddr(int index, bdaddr_t *bdaddr)
 
 static int mgmt_block_device(int index, bdaddr_t *bdaddr)
 {
+       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_block_device)];
+       struct mgmt_hdr *hdr = (void *) buf;
+       struct mgmt_cp_block_device *cp;
+       size_t buf_len;
        char addr[18];
 
        ba2str(bdaddr, addr);
        DBG("index %d addr %s", index, addr);
 
-       return -ENOSYS;
+       memset(buf, 0, sizeof(buf));
+
+       hdr->opcode = htobs(MGMT_OP_BLOCK_DEVICE);
+       hdr->len = htobs(sizeof(*cp));
+       hdr->index = htobs(index);
+
+       cp = (void *) &buf[sizeof(*hdr)];
+       bacpy(&cp->bdaddr, bdaddr);
+
+       buf_len = sizeof(*hdr) + sizeof(*cp);
+
+       if (write(mgmt_sock, buf, buf_len) < 0)
+               return -errno;
+
+       return 0;
 }
 
 static int mgmt_unblock_device(int index, bdaddr_t *bdaddr)
 {
+       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_unblock_device)];
+       struct mgmt_hdr *hdr = (void *) buf;
+       struct mgmt_cp_unblock_device *cp;
+       size_t buf_len;
        char addr[18];
 
        ba2str(bdaddr, addr);
        DBG("index %d addr %s", index, addr);
 
-       return -ENOSYS;
-}
-
-static int mgmt_get_conn_list(int index, GSList **conns)
-{
-       struct controller_info *info = &controllers[index];
-
-       DBG("index %d", index);
-
-       *conns = info->connections;
-       info->connections = NULL;
+       memset(buf, 0, sizeof(buf));
 
-       return 0;
-}
+       hdr->opcode = htobs(MGMT_OP_UNBLOCK_DEVICE);
+       hdr->len = htobs(sizeof(*cp));
+       hdr->index = htobs(index);
 
-static int mgmt_read_local_version(int index, struct hci_version *ver)
-{
-       struct controller_info *info = &controllers[index];
+       cp = (void *) &buf[sizeof(*hdr)];
+       bacpy(&cp->bdaddr, bdaddr);
 
-       DBG("index %d", index);
+       buf_len = sizeof(*hdr) + sizeof(*cp);
 
-       if (!info->valid)
-               return -ENODEV;
-
-       memset(ver, 0, sizeof(*ver));
-       ver->manufacturer = info->manufacturer;
-       ver->hci_ver = info->hci_ver;
-       ver->hci_rev = info->hci_rev;
+       if (write(mgmt_sock, buf, buf_len) < 0)
+               return -errno;
 
        return 0;
 }
 
-static int mgmt_read_local_features(int index, uint8_t *features)
+static int mgmt_get_conn_list(int index, GSList **conns)
 {
        struct controller_info *info = &controllers[index];
 
        DBG("index %d", index);
 
-       if (!info->valid)
-               return -ENODEV;
-
-       memcpy(features, info->features, 8);
+       *conns = info->connections;
+       info->connections = NULL;
 
        return 0;
 }
@@ -1574,16 +1801,16 @@ static int mgmt_disconnect(int index, bdaddr_t *bdaddr)
 
 static int mgmt_remove_bonding(int index, bdaddr_t *bdaddr)
 {
-       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_remove_key)];
+       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_remove_keys)];
        struct mgmt_hdr *hdr = (void *) buf;
-       struct mgmt_cp_remove_key *cp = (void *) &buf[sizeof(*hdr)];
+       struct mgmt_cp_remove_keys *cp = (void *) &buf[sizeof(*hdr)];
        char addr[18];
 
        ba2str(bdaddr, addr);
        DBG("index %d addr %s", index, addr);
 
        memset(buf, 0, sizeof(buf));
-       hdr->opcode = htobs(MGMT_OP_REMOVE_KEY);
+       hdr->opcode = htobs(MGMT_OP_REMOVE_KEYS);
        hdr->len = htobs(sizeof(*cp));
        hdr->index = htobs(index);
 
@@ -1596,22 +1823,6 @@ static int mgmt_remove_bonding(int index, bdaddr_t *bdaddr)
        return 0;
 }
 
-static int mgmt_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey)
-{
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("index %d addr %s passkey %06u", index, addr, passkey);
-
-       return -ENOSYS;
-}
-
-static int mgmt_enable_le(int index)
-{
-       DBG("index %d", index);
-       return -ENOSYS;
-}
-
 static int mgmt_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb,
                                                        gpointer user_data)
 {
@@ -1634,7 +1845,9 @@ static int mgmt_set_did(int index, uint16_t vendor, uint16_t product,
 static int mgmt_disable_cod_cache(int index)
 {
        DBG("index %d", index);
-       return mgmt_set_mode(index, MGMT_OP_SET_SERVICE_CACHE, 0);
+
+       /* The cache control is handled automatically for mgmt */
+       return 0;
 }
 
 static int mgmt_restore_powered(int index)
@@ -1643,12 +1856,12 @@ static int mgmt_restore_powered(int index)
        return -ENOSYS;
 }
 
-static int mgmt_load_keys(int index, GSList *keys, gboolean debug_keys)
+static int mgmt_load_link_keys(int index, GSList *keys, gboolean debug_keys)
 {
        char *buf;
        struct mgmt_hdr *hdr;
-       struct mgmt_cp_load_keys *cp;
-       struct mgmt_key_info *key;
+       struct mgmt_cp_load_link_keys *cp;
+       struct mgmt_link_key_info *key;
        size_t key_count, cp_size;
        GSList *l;
        int err;
@@ -1666,7 +1879,7 @@ static int mgmt_load_keys(int index, GSList *keys, gboolean debug_keys)
        memset(buf, 0, sizeof(buf));
 
        hdr = (void *) buf;
-       hdr->opcode = htobs(MGMT_OP_LOAD_KEYS);
+       hdr->opcode = htobs(MGMT_OP_LOAD_LINK_KEYS);
        hdr->len = htobs(cp_size);
        hdr->index = htobs(index);
 
@@ -1729,7 +1942,7 @@ static int mgmt_create_bonding(int index, bdaddr_t *bdaddr, uint8_t io_cap)
        hdr->len = htobs(sizeof(*cp));
        hdr->index = htobs(index);
 
-       bacpy(&cp->bdaddr, bdaddr);
+       bacpy(&cp->addr.bdaddr, bdaddr);
        cp->io_cap = io_cap;
 
        if (write(mgmt_sock, &buf, sizeof(buf)) < 0)
@@ -1748,6 +1961,98 @@ static int mgmt_cancel_bonding(int index, bdaddr_t *bdaddr)
        return -ENOSYS;
 }
 
+static int mgmt_read_local_oob_data(int index)
+{
+       struct mgmt_hdr hdr;
+
+       DBG("hci%d", index);
+
+       hdr.opcode = htobs(MGMT_OP_READ_LOCAL_OOB_DATA);
+       hdr.len = 0;
+       hdr.index = htobs(index);
+
+       if (write(mgmt_sock, &hdr, sizeof(hdr)) < 0)
+               return -errno;
+
+       return 0;
+}
+
+static int mgmt_add_remote_oob_data(int index, bdaddr_t *bdaddr,
+                                       uint8_t *hash, uint8_t *randomizer)
+{
+       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_add_remote_oob_data)];
+       struct mgmt_hdr *hdr = (void *) buf;
+       struct mgmt_cp_add_remote_oob_data *cp = (void *) &buf[sizeof(*hdr)];
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%d bdaddr %s", index, addr);
+
+       memset(buf, 0, sizeof(buf));
+
+       hdr->opcode = htobs(MGMT_OP_ADD_REMOTE_OOB_DATA);
+       hdr->index = htobs(index);
+       hdr->len = htobs(sizeof(*cp));
+
+       bacpy(&cp->bdaddr, bdaddr);
+       memcpy(cp->hash, hash, 16);
+       memcpy(cp->randomizer, randomizer, 16);
+
+       if (write(mgmt_sock, &buf, sizeof(buf)) < 0)
+               return -errno;
+
+       return 0;
+}
+
+static int mgmt_remove_remote_oob_data(int index, bdaddr_t *bdaddr)
+{
+       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_remove_remote_oob_data)];
+       struct mgmt_hdr *hdr = (void *) buf;
+       struct mgmt_cp_remove_remote_oob_data *cp = (void *) &buf[sizeof(*hdr)];
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%d bdaddr %s", index, addr);
+
+       memset(buf, 0, sizeof(buf));
+
+       hdr->opcode = htobs(MGMT_OP_REMOVE_REMOTE_OOB_DATA);
+       hdr->index = htobs(index);
+       hdr->len = htobs(sizeof(*cp));
+
+       bacpy(&cp->bdaddr, bdaddr);
+
+       if (write(mgmt_sock, &buf, sizeof(buf)) < 0)
+               return -errno;
+
+       return 0;
+}
+
+static int mgmt_confirm_name(int index, bdaddr_t *bdaddr, gboolean name_known)
+{
+       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_confirm_name)];
+       struct mgmt_hdr *hdr = (void *) buf;
+       struct mgmt_cp_confirm_name *cp = (void *) &buf[sizeof(*hdr)];
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%d bdaddr %s name_known %u", index, addr, name_known);
+
+       memset(buf, 0, sizeof(buf));
+
+       hdr->opcode = htobs(MGMT_OP_CONFIRM_NAME);
+       hdr->index = htobs(index);
+       hdr->len = htobs(sizeof(*cp));
+
+       bacpy(&cp->bdaddr, bdaddr);
+       cp->name_known = name_known;
+
+       if (write(mgmt_sock, &buf, sizeof(buf)) < 0)
+               return -errno;
+
+       return 0;
+}
+
 static struct btd_adapter_ops mgmt_ops = {
        .setup = mgmt_setup,
        .cleanup = mgmt_cleanup,
@@ -1755,38 +2060,35 @@ static struct btd_adapter_ops mgmt_ops = {
        .set_discoverable = mgmt_set_discoverable,
        .set_pairable = mgmt_set_pairable,
        .set_limited_discoverable = mgmt_set_limited_discoverable,
-       .start_inquiry = mgmt_start_inquiry,
-       .stop_inquiry = mgmt_stop_inquiry,
-       .start_scanning = mgmt_start_scanning,
-       .stop_scanning = mgmt_stop_scanning,
-       .resolve_name = mgmt_resolve_name,
-       .cancel_resolve_name = mgmt_cancel_resolve_name,
+       .start_discovery = mgmt_start_discovery,
+       .stop_discovery = mgmt_stop_discovery,
        .set_name = mgmt_set_name,
        .set_dev_class = mgmt_set_dev_class,
-       .set_fast_connectable = mgmt_fast_connectable,
+       .set_fast_connectable = mgmt_set_fast_connectable,
        .read_clock = mgmt_read_clock,
        .read_bdaddr = mgmt_read_bdaddr,
        .block_device = mgmt_block_device,
        .unblock_device = mgmt_unblock_device,
        .get_conn_list = mgmt_get_conn_list,
-       .read_local_version = mgmt_read_local_version,
-       .read_local_features = mgmt_read_local_features,
        .disconnect = mgmt_disconnect,
        .remove_bonding = mgmt_remove_bonding,
        .pincode_reply = mgmt_pincode_reply,
        .confirm_reply = mgmt_confirm_reply,
        .passkey_reply = mgmt_passkey_reply,
-       .enable_le = mgmt_enable_le,
        .encrypt_link = mgmt_encrypt_link,
        .set_did = mgmt_set_did,
        .add_uuid = mgmt_add_uuid,
        .remove_uuid = mgmt_remove_uuid,
        .disable_cod_cache = mgmt_disable_cod_cache,
        .restore_powered = mgmt_restore_powered,
-       .load_keys = mgmt_load_keys,
+       .load_keys = mgmt_load_link_keys,
        .set_io_capability = mgmt_set_io_capability,
        .create_bonding = mgmt_create_bonding,
        .cancel_bonding = mgmt_cancel_bonding,
+       .read_local_oob_data = mgmt_read_local_oob_data,
+       .add_remote_oob_data = mgmt_add_remote_oob_data,
+       .remove_remote_oob_data = mgmt_remove_remote_oob_data,
+       .confirm_name = mgmt_confirm_name,
 };
 
 static int mgmt_init(void)
index d3414f5..14a5cb6 100644 (file)
@@ -436,7 +436,6 @@ static DBusMessage *update_xml_record(DBusConnection *conn,
        sdp_record = sdp_xml_parse_record(record, len);
        if (!sdp_record) {
                error("Parsing of XML service record failed");
-               sdp_record_free(sdp_record);
                return btd_error_failed(msg,
                                        "Parsing of XML service record failed");
        }
@@ -588,12 +587,6 @@ static DBusMessage *request_authorization(DBusConnection *conn,
        sender = dbus_message_get_sender(msg);
        if (find_pending_by_sender(serv_adapter, sender))
                return btd_error_does_not_exist(msg);
-#ifdef __TIZEN_PATCH__
-
-
-       info("handle %x\n", handle);
-       if(1 != handle)
-       {
 
        user_record = find_record(serv_adapter, handle, sender);
        if (!user_record) {
@@ -624,59 +617,12 @@ static DBusMessage *request_authorization(DBusConnection *conn,
                return btd_error_not_authorized(msg);
        }
        bt_free(uuid128);
-       }
-#else
-       user_record = find_record(serv_adapter, handle, sender);
-       if (!user_record) {
-               user_record = find_record(serv_adapter_any, handle, sender);
-               if (!user_record)
-                       return not_authorized(msg);
-       }
-
-       record = sdp_record_find(user_record->handle);
-       if (record == NULL)
-               return not_authorized(msg);
-
-       if (sdp_get_service_classes(record, &services) < 0) {
-               sdp_record_free(record);
-               return not_authorized(msg);
-       }
 
-       if (services == NULL)
-               return not_authorized(msg);
-
-       uuid = services->data;
-       uuid128 = sdp_uuid_to_uuid128(uuid);
-
-       sdp_list_free(services, bt_free);
-
-       if (sdp_uuid2strn(uuid128, uuid_str, MAX_LEN_UUID_STR) < 0) {
-               bt_free(uuid128);
-               return not_authorized(msg);
-       }
-       bt_free(uuid128);
-#endif
        auth = g_new0(struct pending_auth, 1);
        auth->msg = dbus_message_ref(msg);
        auth->conn = dbus_connection_ref(connection);
-#ifdef __TIZEN_PATCH__
-       if(1 != handle)
-       {
-               auth->sender = user_record->sender;
-               memcpy(auth->uuid, uuid_str, MAX_LEN_UUID_STR);
-       }
-       else
-       {
-               auth->sender = (char *)sender;
-               char* uuid_l2cap = "00000100-0000-1000-8000-00805f9b34fb";
-               memset(auth->uuid, 0, MAX_LEN_UUID_STR);
-               memcpy(auth->uuid, uuid_l2cap, strlen(uuid_l2cap));
-       }
-#else
        auth->sender = user_record->sender;
        memcpy(auth->uuid, uuid_str, MAX_LEN_UUID_STR);
-
-#endif
        str2ba(address, &auth->dst);
 
        serv_adapter->pending_list = g_slist_append(serv_adapter->pending_list,
@@ -750,852 +696,6 @@ done:
        return dbus_message_new_method_return(msg);
 }
 
-#ifdef __TIZEN_PATCH__
-extern sdp_session_t *g_cached_session;
-
-static DBusMessage *siso_add_service_record_pdu(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       info("siso_add_service_record_pdu() +\n");
-       DBusMessage *reply;
-       const char *sender, *record;
-       uint32_t len;
-       dbus_uint32_t handle;
-       int err;
-       sdp_record_t *sdp_record;
-       int scanned;
-       int ret = -1;
-       DBusMessageIter iter, array;
-       dbus_message_iter_init(msg, &iter);
-       dbus_message_iter_recurse(&iter, &array);
-       dbus_message_iter_get_fixed_array(&array, &record, &len);
-       if (len <= 0) {
-               info("Error!!!! ... Invalid args....\n");
-               return btd_error_invalid_args(msg);
-       }
-       info("\n");
-       sdp_record = (sdp_record_t *)sdp_extract_pdu_safe(record, len, &scanned);
-       if (!sdp_record) {
-               info("Error!!! ---------Parsing of service record failed--------\n");
-               return btd_error_invalid_args(msg);
-       }
-       if (scanned != len) {
-               info("Warning!!!! Size mismatch of service record, scanned = %d, len = %d\n",
-                                                       scanned, len);
-               /*The JSRapp service record seesm to be wrong!!!!.
-                * Hence its returning the value 49 and 35.
-                * Its a missmatch. Once its is corrected uncomment below code.*/
-               /* sdp_record_free(sdp_record);
-                  return -1;
-                */
-       }
-
-       if (sdp_record->handle < 0x10000) {
-               DBG("Invalid record handle 0x%05x", sdp_record->handle);
-               sdp_record_free(sdp_record);
-               return btd_error_invalid_args(msg);
-       }
-
-       if (add_record_to_server(BDADDR_ANY, sdp_record) < 0) {
-               info("Error !!!!!!!!      add_record_to_server() \n");
-               info("Failed to register service record for handle 0x%x\n", sdp_record->handle);
-               sdp_record_free(sdp_record);
-               return btd_error_invalid_args(msg);
-       }
-
-       handle = sdp_record->handle;
-
-       info("Received handler = 0x%x\n", handle);
-
-
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply) {
-               info("Error in reply\n");
-               return btd_error_invalid_args(msg);
-       }
-
-       dbus_message_append_args(reply, DBUS_TYPE_UINT32, &handle,
-                                                       DBUS_TYPE_INVALID);
-       info("-\n");
-
-       return reply;
-
-}
-
-
-static DBusMessage *siso_remove_service_record(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       info("\n\n\n\n++++++++++++++++++ (RX) siso_remove_service_record +++++++++++++++++++++++\n\n\n\n");
-       struct service_adapter *serv_adapter = data;
-       dbus_uint32_t handle;
-       sdp_record_t *rec;
-       DBusMessage *reply;
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &handle,
-                                               DBUS_TYPE_INVALID) == FALSE)
-       {
-               info("\nError!!!! ---------------- Invalid arguments ................................\n");
-               return btd_error_invalid_args(msg);
-       }
-       DBG("RRemoving record with handle 0x%05x", handle);
-
-       rec = sdp_record_find(handle);
-       if (!rec)
-       {
-               info("\n---------------- Record Not found for the handler 0x%x-----------\n", handle);
-               return btd_error_invalid_args(msg);
-       }
-       if (sdp_record_remove(handle) == 0) {
-               update_db_timestamp();
-               update_svclass_list(BDADDR_ANY);
-       }
-
-       sdp_record_free(rec);
-       info("\nFreed SDP record\n");
-
-//     return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-       {
-               info("Error in reply\n");
-               return btd_error_invalid_args(msg);
-       }
-       info("-\n");
-
-       return reply;
-
-}
-
-static volatile sig_atomic_t __io_finished;
-
-static void __dbus_sdp_callback_multiple_handle_complete__cb(uint8_t type, uint16_t status,
-                               uint8_t *rsp, size_t size, void *udata)
-{
-       unsigned int i;
-       int err = -1;
-       int tsrc, csrc, tsrc_count, index_count = 0;
-       uint32_t s_handle;
-       DBusConnection  *conn;
-       //DBusMessage *reply;
-       //DBusMessageIter iter, array_iter;
-       service_dbus_ctxt_t* ctxt = (service_dbus_ctxt_t*)udata;
-
-       info("__dbus_sdp_callback_multiple_handle_complete__cb.. +\n");
-#if 0 //Service search
-      if( SDP_ERROR_RSP == status)
-       {
-               info(" sdp timed out \n");
-               __io_finished = 1;
-               return failed_strerror(ctxt->msg, err);
-       }
-       printf("\n");
-
-       if (type == SDP_ERROR_RSP) {
-               __io_finished = 1; /* We have to come of the loop when type == SDP_ERROR_RSP */
-               return failed_strerror(ctxt->msg, err);
-       }
-
-       info(" after  SDP_ERROR_RSP check \n");
-
-       if(NULL == udata)
-       {
-                    info(" sdp search is over \n");
-
-       }
-      else
-       {
-               info(" sdp search continues \n");
-       reply = dbus_message_new_method_return(ctxt->msg);
-               info( " sdp got a reply \n");
-
-               if(reply)
-               {
-       dbus_message_iter_init_append(reply, &iter);
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                               DBUS_TYPE_UINT32_AS_STRING, &array_iter);
-               }
-               else
-               {
-                       info(" reply is NULL \n");
-               }
-       }
-
-       info(" after  iteration \n");
-#else
-       info("type!!!!!!!!!    %d\n",type);
-       printf("\n");
-       if(type == 0 )
-       {
-               info("timed outttttttt\n");
-
-          __io_finished =1;
-              return;
-       }
-
-       if (type == SDP_ERROR_RSP) {
-               __io_finished = 1;
-        err = -EIO;
-               info("Dbus Failed err =%d\n", err);
-               return;
-       }
-
-#endif
-       uint8_t *pdata = rsp;
-       tsrc = ntohs(bt_get_unaligned((uint16_t *) pdata));
-       if ( tsrc <= 0)
-       {
-               info("tsrc not found");
-//             s_handle = 0xFE000000; /*Record not found*/
-               goto done;
-       }
-       else
-       {
-
-
-               pdata += sizeof(uint16_t);
-               csrc = ntohs(bt_get_unaligned((uint16_t *) pdata));
-               if ( csrc <= 0)
-               {
-                       info("csrc not found");
-//                     s_handle = 0xFE000000; /*Record not found*/
-                       goto done;
-
-               }
-               else
-               {
-                       info("Total service record found = %d, CSR = %d", tsrc, tsrc);
-                       pdata += sizeof(uint16_t);
-                       tsrc_count = tsrc;
-                       index_count = 0;
-                       do
-                       {
-                               s_handle = ntohl(bt_get_unaligned((uint32_t*)pdata));
-                               pdata += sizeof(uint32_t);
-#if 0 //Service search
-                               dbus_message_iter_append_basic(&array_iter,
-                                                               DBUS_TYPE_UINT32, &s_handle);
-#else
-                               dbus_message_iter_append_basic(ctxt->array_iter,
-                                                               DBUS_TYPE_UINT32, &s_handle);
-#endif
-                               ++index_count;
-                               DBG("got handle 0x%x count %d", s_handle, index_count);
-                               if(index_count >= MAX_REMOTE_SERVICES) break;
-                       }while(--tsrc_count);
-
-               }
-       }
-
-
-
-       info( "********Received handles = 0X%X ***********, total rx size = %d\n", index_count, size);
-
-
-done:
-       __io_finished = 1;
-#if 0 //Service search
-       dbus_message_iter_close_container(&iter, &array_iter);
-       dbus_connection_send(ctxt->conn, reply, NULL);
-       dbus_message_unref(reply);
-
-       if(ctxt != NULL)
-       {
-               //dbus_connection_unref(ctxt->conn);
-               dbus_message_unref(ctxt->msg);
-               free(ctxt);
-               ctxt = NULL;
-
-       }
-#endif
-
-       info( "__socket_sdp_callback_multiple_handle_complete__cb -\n");
-       return;
-}
-
-
-static void get_remote_service_cb(sdp_list_t *recs, int err, gpointer user_data)
-{
-       sdp_list_t *seq;
-       int ii = 0, index_count=0;
-       int struct_len;
-       DBusMessage *reply;
-       DBusMessageIter iter, array_iter;
-
-       service_dbus_ctxt_t* service_search_ctxt = (service_dbus_ctxt_t*) user_data;
-
-       info("get_remote_service_cb+");
-
-       if (err < 0) {
-               error("Unable to get service record: %s (%d)", strerror(-err), -err);
-               goto fail;
-       }
-
-       if (!recs || !recs->data) {
-               info("No records found\n");
-               //error("No records found");
-               //goto fail;
-       }
-
-       reply = dbus_message_new_method_return(service_search_ctxt->msg);
-
-       if(reply)
-       {
-               dbus_message_iter_init_append(reply, &iter);
-               dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32_AS_STRING, &array_iter);
-       }
-       else
-       {
-               info(" reply is NULL \n");
-               goto fail;
-       }
-
-       for (seq = recs; seq; seq = seq->next)
-       {
-               sdp_record_t *rec = (sdp_record_t *) seq->data;
-               GString *result;
-
-               if (!rec)
-                       break;
-
-               dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_UINT32, &rec->handle);
-
-               ++index_count;
-       }
-
-
-       info( "********Received handles = 0X%X ***********\n", index_count);
-
-
-done:
-       dbus_message_iter_close_container(&iter, &array_iter);
-       dbus_connection_send(service_search_ctxt->conn, reply, NULL);
-       dbus_message_unref(reply);
-
-fail:
-       if(service_search_ctxt != NULL)
-       {
-               //dbus_connection_unref(service_search_ctxt->conn);
-               dbus_message_unref(service_search_ctxt->msg);
-               free(service_search_ctxt);
-               service_search_ctxt = NULL;
-       }
-
-       info("get_remote_service_cb-");
-       return;
-
-}
-
-
-static DBusMessage *get_remote_service_handles(DBusConnection *conn, DBusMessage *msg, void *data)
-{
-       int err = 0;
-       uuid_t uuid;
-       char * addr, *match;
-       bdaddr_t bdadd;
-       service_dbus_ctxt_t* service_search_ctxt = NULL;
-
-
-       info("get_remote_service_handles");
-
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr, DBUS_TYPE_STRING, &match,
-                                               DBUS_TYPE_INVALID) == FALSE)
-       {
-               info("\n---------------- Invalid arguments ................................\n");
-               return btd_error_invalid_args(msg);
-       }
-       info( "Addr: %s\n", addr);
-       info( "UUID: %s\n", match);
-       str2ba(addr, &bdadd);
-
-       if (strlen(match) > 0)
-       {
-               if (bt_string2uuid(&uuid, match) < 0)
-               {
-                       error("Invalid service class name");
-                       return btd_error_invalid_args(msg);
-               }
-               sdp_uuid128_to_uuid(&uuid);
-       }
-
-       service_search_ctxt = g_try_malloc0(sizeof(service_dbus_ctxt_t));
-       if (!service_search_ctxt) {
-               info("malloc() failed");
-               return btd_error_failed(msg, "No Memory");
-       }
-       service_search_ctxt->conn = conn;
-       service_search_ctxt->msg = dbus_message_ref(msg);
-
-       err = bt_search_service(BDADDR_ANY, &bdadd, &uuid, get_remote_service_cb, service_search_ctxt, NULL);
-       if (err < 0)
-       {
-                       error("Invalid service class name");
-                       return btd_error_failed(msg, "Invalid service class name");
-       }
-       return NULL;
-}
-
-static DBusMessage *siso_get_remote_service_handles(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       info("\n\n\n\n++++++++++++++++++ (RX) siso_get_remote_service_handles +++++++++++++++++++++++\n\n\n\n");
-       struct service_adapter *serv_adapter = data;
-       dbus_uint32_t handle;
-       sdp_record_t *rec;
-       DBusMessage *reply;
-
-       char * addr, *match;
-       bdaddr_t bdadd;
-       sdp_list_t *search, *attrids;
-       uint32_t range = 0x0000ffff;
-       uuid_t uuid;
-       service_dbus_ctxt_t* ctxt = NULL;
-       DBusMessageIter iter, array_iter;
-
-
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr, DBUS_TYPE_STRING, &match,
-                                               DBUS_TYPE_INVALID) == FALSE)
-       {
-               info("\nError!!!! ---------------- Invalid arguments ................................\n");
-               return btd_error_invalid_args(msg);
-       }
-       info( "Before sdp_connect with bdaddr %s\n", addr);
-       str2ba(addr, &bdadd);
-       if (strlen(match) > 0)
-       {
-               if (bt_string2uuid(&uuid, match) < 0)
-               {
-                       error("Invalid service class name");
-                       return btd_error_invalid_args(msg);
-               }
-       }
-
-       if(NULL == g_cached_session)
-       {
-               g_cached_session = sdp_connect(BDADDR_ANY, &bdadd, 0);
-               if (!g_cached_session)
-               {
-                       info("Can't connect to SDP service\n");
-                       goto error_done;
-                       //break;
-               }
-       }
-
-       info( "Before sdp_set_notify\n");
-       __io_finished = 0;
-       ctxt = malloc(sizeof(service_dbus_ctxt_t));
-
-       if(NULL == ctxt)
-       {
-               info("!!!!!Memory allocation failed for ctxt\n");
-
-               goto error_done;
-       }
-
-       ctxt->conn = conn;
-       ctxt->msg = dbus_message_ref(msg);
-
-       reply = dbus_message_new_method_return(ctxt->msg);
-       dbus_message_iter_init_append(reply, &iter);
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                               DBUS_TYPE_UINT32_AS_STRING, &array_iter);
-
-       ctxt->array_iter = &array_iter;
-
-       sdp_set_notify(g_cached_session, __dbus_sdp_callback_multiple_handle_complete__cb, ctxt);
-
-
-       search = sdp_list_append(NULL, &uuid);
-
-       info( "Before sdp_list_append\n");
-
-       attrids = sdp_list_append(NULL, &range);
-
-       info( "Before sdp_service_search_async\n");
-
-       if(0 != sdp_service_search_async(g_cached_session, search, 0xffff))
-       {
-               error("Error : sdp_service_search_async()");
-               goto error_done;
-       }
-
-       info( "Before sdp_list_free\n");
-
-       sdp_list_free(attrids, NULL);
-
-       info( "Before sdp_list_free\n");
-
-       sdp_list_free(search, NULL);
-
-       while (!__io_finished)
-       {
-               printf(". ");
-               info(" calling sdp_process [ enter] : %d\n", __io_finished);
-                if (sdp_process(g_cached_session) == -1)
-                {
-                       info( "Search Completed : error\n");
-
-                }
-
-                info(" calling sdp_process [leave]: %d\n", __io_finished);
-       }
-       dbus_message_iter_close_container(&iter, &array_iter);
-
-       free(ctxt);
-
-       return reply;
-error_done:
-       info( "Error done .. before ctx free\n");
-
-       if(ctxt != NULL)
-       {
-               free(ctxt);
-               ctxt = NULL;
-       }
-
-       info( "Error done .. After ctx free\n");
-
-       info("-\n");
-
-       return btd_error_invalid_args(msg);
-}
-
-static void __sdp_callback_xml_complete_dbus__cb(uint8_t type, uint16_t err, uint8_t *rsp, size_t size, void *udata)
-{
-       info("__sdp_callback_xml_complete_dbus__cb() +\n");
-       service_dbus_ctxt_t *ctxt = (service_dbus_ctxt_t*) udata;
-       sdp_record_t *rec;
-       int scanned;
-       GString *result;
-       DBusMessage *reply, *msg;
-       DBusMessageIter iter, array_iter;
-
-       reply = dbus_message_new_method_return(ctxt->msg);
-
-       if (err == 0xffff)
-       {
-               error("Invalid session!");
-               goto failed;
-       }
-       if (type == SDP_ERROR_RSP)
-       {
-               error("SDP_ERROR_RSP!");
-               goto failed;
-       }
-
-       /* check response PDU ID */
-       if (type != SDP_SVC_ATTR_RSP)
-       {
-               error("SDP_SVC_ATTR_RSP!");
-               goto failed;
-       }
-
-       rec = (sdp_record_t *)sdp_extract_pdu_safe(rsp, size, &scanned);
-       if (rec == NULL || size != scanned)
-       {
-               error("Invalid service record!");
-               goto failed;
-       }
-
-       result = g_string_new(NULL);
-
-       DBG("size %d\n", size);
-
-       convert_sdp_record_to_xml(rec, result, (void *) g_string_append);
-
-       sdp_record_free(rec);
-
-       info( "XML Converted buffer length %d\n", result->len);
-
-       dbus_message_append_args(reply,
-                       DBUS_TYPE_STRING, result->str,
-                       DBUS_TYPE_INVALID);
-       g_string_free(result, TRUE);
-
-       dbus_connection_send(ctxt->conn, reply, NULL);
-       dbus_message_unref(reply);
-
-       if(NULL != ctxt)
-       {
-               free(ctxt);
-               ctxt = NULL;
-       }
-       __io_finished = 1;
-       info("__sdp_callback_xml_complete_dbus__cb-\n");
-       return;
-failed:
-
-       dbus_connection_send(ctxt->conn, reply, NULL);
-       dbus_message_unref(reply);
-
-       if(ctxt != NULL)
-       {
-               dbus_connection_unref(ctxt->conn);
-               dbus_message_unref(ctxt->msg);
-               free(ctxt);
-               ctxt = NULL;
-
-       }
-}
-
-static DBusMessage * siso_adapter_get_remote_svc_xml(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       info( "siso_adapter_get_remote_svc_xml() +\n");
-       sdp_session_t *session;
-       sdp_list_t *attrids;
-       uint32_t range = 0x0000ffff;
-       const char *dst;
-       uint32_t handle;
-       int err;
-       bdaddr_t  bdadd;
-       DBusMessage *reply;
-       service_dbus_ctxt_t* ctxt = NULL;
-
-       if (!dbus_message_get_args(msg, NULL,
-                       DBUS_TYPE_STRING, &dst,
-                       DBUS_TYPE_UINT32, &handle,
-                       DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       str2ba(dst, &bdadd);
-
-       session = sdp_connect(BDADDR_ANY, &bdadd, 0);
-       if (!session)
-       {
-                   info("Can't connect to SDP service\n");
-                   goto error_done;
-       }
-       ctxt = malloc(sizeof(service_dbus_ctxt_t));
-
-       if(NULL == ctxt)
-       {
-               info("!!!!!Memory allocation failed for ctxt\n");
-               goto error_done;
-       }
-
-       ctxt->conn = conn;
-       ctxt->msg = dbus_message_ref(msg);
-
-       info( "Before sdp_set_notify +++\n");
-       if (sdp_set_notify(session, __sdp_callback_xml_complete_dbus__cb, ctxt) < 0)
-       {
-                sdp_close(session);
-               goto error_done;
-       }
-
-       attrids = sdp_list_append(NULL, &range);
-       if (sdp_service_attr_async(session, handle, SDP_ATTR_REQ_RANGE, attrids) < 0)
-       {
-               sdp_list_free(attrids, NULL);
-                sdp_close(session);
-               goto error_done;
-       }
-       sdp_list_free(attrids, NULL);
-       __io_finished = 0;
-           while (!__io_finished)
-           {
-                       printf(". ");
-                       sdp_process(session);
-           }
-
-           sdp_close(session);
-           return 0;
-
-error_done:
-       if(ctxt != NULL)
-       {
-               free(ctxt);
-               ctxt = NULL;
-       }
-       info("-\n");
-
-       return btd_error_invalid_args(msg);
-
-}
-
-static void sdp_get_pdu_by_handle_dbus_rsp(uint8_t type, uint16_t err,
-                       uint8_t *rsp, size_t size, void *udata)
-{
-       sdp_record_t *rec;
-       int scanned;
-       DBusMessage *reply, *msg;
-       DBusMessageIter iter, array_iter;
-       service_dbus_ctxt_t* ctxt = NULL;
-       info("sdp_get_pdu_by_handle_rsp+\n");
-
-       if (err == 0xffff)
-       {
-               error("Invalid session!");
-               goto failed;
-       }
-
-       if (type == SDP_ERROR_RSP)
-       {
-               error("SDP_ERROR_RSP!");
-               goto failed;
-       }
-
-       /* check response PDU ID */
-       if (type != SDP_SVC_ATTR_RSP)
-       {
-               error("SDP_SVC_ATTR_RSP!");
-               goto failed;
-       }
-
-       ctxt = (service_dbus_ctxt_t*)udata;
-       rec = (sdp_record_t *)sdp_extract_pdu_safe(rsp, size, &scanned);
-       if (rec == NULL || size != scanned) {
-               error("Invalid service record!");
-               goto failed;
-       }
-
-       //sdp_store_record(ctxt->src, ctxt->dst, rec->handle, rsp, size);
-
-       sdp_record_free(rec);
-
-       DBG("size %d", size);
-       dbus_message_iter_append_fixed_array(ctxt->array_iter,
-                       DBUS_TYPE_BYTE, &rsp, size);
-
-       __io_finished = 1;
-       info("sdp_get_pdu_by_handle_rsp -\n");
-
-       return;
-
-failed:
-       info("Failed to get the service record");
-
-       __io_finished = 1;
-       return;
-}
-
-static DBusMessage *adapter_get_remote_svc(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-
-       //sdp_session_t *session;
-       sdp_list_t *attrids;
-       uint32_t range = 0x0000ffff;
-       const char *dst;
-       uint32_t handle;
-       bdaddr_t bdadd;
-       int struct_len;
-       service_dbus_ctxt_t* ctxt = NULL;
-#if 0 //Service search
-#else
-       DBusMessage *reply;
-       DBusMessageIter iter, array_iter;
-#endif
-       info("...__get_sdp_record_by_handle_send_response....\n");
-
-       if (!dbus_message_get_args(msg, NULL,
-                       DBUS_TYPE_STRING, &dst,
-                       DBUS_TYPE_UINT32, &handle,
-                       DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       info("address %s, handle %d", dst, handle);
-
-       str2ba(dst, &bdadd);
-
-       if(NULL == g_cached_session)
-       {
-               g_cached_session = sdp_connect(BDADDR_ANY, &bdadd, 0);
-               if (!g_cached_session)
-               {
-                       info("Can't connect to SDP service\n");
-                       goto error_done;
-                       //break;
-               }
-       }
-       info( "Before sdp_set_notify,,,,,......\n");
-
-       ctxt = malloc(sizeof(service_dbus_ctxt_t));
-
-       if(NULL == ctxt)
-       {
-               goto error_done;
-       }
-       __io_finished = 0;
-       ctxt->conn = conn;
-       ctxt->msg = dbus_message_ref(msg);
-       reply = dbus_message_new_method_return(ctxt->msg);
-       dbus_message_iter_init_append(reply, &iter);
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_TYPE_BYTE_AS_STRING, &array_iter);
-
-       ctxt->array_iter = &array_iter;
-       if (sdp_set_notify(g_cached_session, sdp_get_pdu_by_handle_dbus_rsp, ctxt) < 0)
-               goto error_done;
-
-
-       attrids = sdp_list_append(NULL, &range);
-
-       if (sdp_service_attr_async(g_cached_session, handle,
-                               SDP_ATTR_REQ_RANGE, attrids) < 0) {
-               sdp_list_free(attrids, NULL);
-               goto error_done;
-       }
-
-       sdp_list_free(attrids, NULL);
-
-       while (!__io_finished)
-       {
-               printf(". ");
-               sdp_process(g_cached_session);
-       }
-       dbus_message_iter_close_container(&iter, &array_iter);
-
-       free(ctxt);
-       return reply;
-
-
-error_done:
-       if(ctxt != NULL)
-       {
-               free(ctxt);
-               ctxt =  NULL;
-       }
-       info("__get_sdp_record_by_handle_send_response failed");
-
-       return btd_error_invalid_args(msg);
-
-}
-
-static DBusMessage *close_sdp_session(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       info("close_sdp_session");
-       if(NULL != g_cached_session)
-       {
-               info("closing sdp cached session");
-               sdp_close(g_cached_session);
-               g_cached_session = NULL;
-       }
-
-       return dbus_message_new_method_return(msg);
-}
-
-
-static GDBusMethodTable service_methods[] = {
-       { "AddRecord",          "s",    "u",    add_service_record      },
-       { "AddServiceRecord",           "ay",   "u",    siso_add_service_record_pdu     },
-       { "RemoveServiceRecord",        "u",    "",     siso_remove_service_record      },
-       {"GetRemoteServiceHandles", "ss",    "ay",      siso_get_remote_service_handles, G_DBUS_METHOD_FLAG_ASYNC},
-//     {"GetRemoteServiceHandles", "ss",    "ay",      get_remote_service_handles, G_DBUS_METHOD_FLAG_ASYNC},
-       { "GetRemoteServiceRecord",             "su",   "ay", adapter_get_remote_svc, G_DBUS_METHOD_FLAG_ASYNC},
-       { "CloseSdpSession",    "",     "",     close_sdp_session},
-       { "GetRemoteServiceRecordAsXML",        "su",   "s",    siso_adapter_get_remote_svc_xml,        G_DBUS_METHOD_FLAG_ASYNC        },
-       { "UpdateRecord",       "us",   "",     update_service_record   },
-       { "RemoveRecord",       "u",    "",     remove_service_record   },
-       { "RequestAuthorization","su",  "",     request_authorization,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "CancelAuthorization", "",    "",     cancel_authorization    },
-       { }
-};
-#else
 static GDBusMethodTable service_methods[] = {
        { "AddRecord",          "s",    "u",    add_service_record      },
        { "UpdateRecord",       "us",   "",     update_service_record   },
@@ -1606,7 +706,6 @@ static GDBusMethodTable service_methods[] = {
        { }
 };
 
-#endif
 static void path_unregister(void *data)
 {
        struct service_adapter *serv_adapter = data;
@@ -1626,7 +725,6 @@ static void path_unregister(void *data)
 
 static int register_interface(const char *path, struct btd_adapter *adapter)
 {
-       info("\nEntering register_interface()... +\n");
        struct service_adapter *serv_adapter;
 
        DBG("path %s", path);
diff --git a/plugins/wiimote.c b/plugins/wiimote.c
new file mode 100644 (file)
index 0000000..1ae638b
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  David Herrmann <dh.herrmann@googlemail.com>
+ *
+ *
+ *  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 <bluetooth/bluetooth.h>
+
+#include "plugin.h"
+#include "adapter.h"
+#include "device.h"
+#include "log.h"
+#include "storage.h"
+
+/*
+ * Nintendo Wii Remote devices require the bdaddr of the host as pin input for
+ * authentication. This plugin registers a pin-callback and forces this pin
+ * to be used for authentication.
+ *
+ * There are two ways to place the wiimote into discoverable mode.
+ *  - Pressing the red-sync button on the back of the wiimote. This module
+ *    supports pairing via this method. Auto-reconnect should be possible after
+ *    the device was paired once.
+ *  - Pressing the 1+2 buttons on the front of the wiimote. This module does
+ *    not support this method since this method never enables auto-reconnect.
+ *    Hence, pairing is not needed. Use it without pairing if you want.
+ * After connecting the wiimote you should immediately connect to the input
+ * service of the wiimote. If you don't, the wiimote will close the connection.
+ * The wiimote waits about 5 seconds until it turns off again.
+ * Auto-reconnect is only enabled when pairing with the wiimote via the red
+ * sync-button and then connecting to the input service. If you do not connect
+ * to the input service, then auto-reconnect is not enabled.
+ * If enabled, the wiimote connects to the host automatically when any button
+ * is pressed.
+ */
+
+static ssize_t wii_pincb(struct btd_adapter *adapter, struct btd_device *device,
+                                                               char *pinbuf)
+{
+       uint16_t vendor, product;
+       bdaddr_t sba, dba;
+       char addr[18];
+
+       adapter_get_address(adapter, &sba);
+       device_get_address(device, &dba, NULL);
+       ba2str(&dba, addr);
+
+       vendor = btd_device_get_vendor(device);
+       if (vendor != 0x057e)
+               return 0;
+
+       product = btd_device_get_product(device);
+       if (product == 0x0306) {
+               DBG("Forcing fixed pin on detected wiimote %s", addr);
+               memcpy(pinbuf, &sba, 6);
+               return 6;
+       }
+
+       return 0;
+}
+
+static int wii_probe(struct btd_adapter *adapter)
+{
+       btd_adapter_register_pin_cb(adapter, wii_pincb);
+
+       return 0;
+}
+
+static void wii_remove(struct btd_adapter *adapter)
+{
+       btd_adapter_unregister_pin_cb(adapter, wii_pincb);
+}
+
+static struct btd_adapter_driver wii_driver = {
+       .name   = "wiimote",
+       .probe  = wii_probe,
+       .remove = wii_remove,
+};
+
+static int wii_init(void)
+{
+       return btd_register_adapter_driver(&wii_driver);
+}
+
+static void wii_exit(void)
+{
+       btd_unregister_adapter_driver(&wii_driver);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(wiimote, VERSION,
+               BLUETOOTH_PLUGIN_PRIORITY_LOW, wii_init, wii_exit)
diff --git a/proximity/main.c b/proximity/main.c
new file mode 100644 (file)
index 0000000..5f0fc12
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "log.h"
+#include "plugin.h"
+#include "manager.h"
+
+static DBusConnection *connection = NULL;
+static GKeyFile *config = NULL;
+
+static GKeyFile *open_config_file(const char *file)
+{
+       GError *gerr = NULL;
+       GKeyFile *keyfile;
+
+       keyfile = g_key_file_new();
+
+       g_key_file_set_list_separator(keyfile, ',');
+
+       if (!g_key_file_load_from_file(keyfile, file, 0, &gerr)) {
+               error("Parsing %s failed: %s", file, gerr->message);
+               g_error_free(gerr);
+               g_key_file_free(keyfile);
+               return NULL;
+       }
+
+       return keyfile;
+}
+
+static int proximity_init(void)
+{
+
+       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+       if (connection == NULL)
+               return -EIO;
+
+       config = open_config_file(CONFIGDIR "/proximity.conf");
+
+       if (proximity_manager_init(connection, config) < 0) {
+               dbus_connection_unref(connection);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static void proximity_exit(void)
+{
+       if (config)
+               g_key_file_free(config);
+
+       proximity_manager_exit();
+       dbus_connection_unref(connection);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(proximity, VERSION,
+                       BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                       proximity_init, proximity_exit)
diff --git a/proximity/manager.c b/proximity/manager.c
new file mode 100644 (file)
index 0000000..a767554
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <gdbus.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "att.h"
+#include "monitor.h"
+#include "reporter.h"
+#include "manager.h"
+
+#define IMMEDIATE_ALERT_UUID   "00001802-0000-1000-8000-00805f9b34fb"
+#define LINK_LOSS_UUID         "00001803-0000-1000-8000-00805f9b34fb"
+#define TX_POWER_UUID          "00001804-0000-1000-8000-00805f9b34fb"
+
+static DBusConnection *connection = NULL;
+
+static struct enabled enabled  = {
+       .linkloss = TRUE,
+       .pathloss = TRUE,
+       .findme = TRUE,
+};
+
+static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct att_primary *prim = a;
+       const char *uuid = b;
+
+       return g_strcmp0(prim->uuid, uuid);
+}
+
+static int attio_device_probe(struct btd_device *device, GSList *uuids)
+{
+       struct att_primary *linkloss, *txpower, *immediate;
+       GSList *l, *primaries;
+
+       primaries = btd_device_get_primaries(device);
+
+       l = g_slist_find_custom(primaries, IMMEDIATE_ALERT_UUID,
+                       primary_uuid_cmp);
+       immediate = (l ? l->data : NULL);
+
+       l = g_slist_find_custom(primaries, TX_POWER_UUID, primary_uuid_cmp);
+       txpower = (l ? l->data : NULL);
+
+       l = g_slist_find_custom(primaries, LINK_LOSS_UUID, primary_uuid_cmp);
+       linkloss = (l ? l->data : NULL);
+
+       return monitor_register(connection, device, linkloss, txpower,
+                                                       immediate, &enabled);
+}
+
+static void attio_device_remove(struct btd_device *device)
+{
+       monitor_unregister(connection, device);
+}
+
+static struct btd_device_driver monitor_driver = {
+       .name = "Proximity GATT Driver",
+       .uuids = BTD_UUIDS(IMMEDIATE_ALERT_UUID, LINK_LOSS_UUID, TX_POWER_UUID),
+       .probe = attio_device_probe,
+       .remove = attio_device_remove,
+};
+
+static void load_config_file(GKeyFile *config)
+{
+       char **list;
+       int i;
+
+       if (config == NULL)
+               return;
+
+       list = g_key_file_get_string_list(config, "General", "Disable",
+                                                               NULL, NULL);
+       for (i = 0; list && list[i] != NULL; i++) {
+               if (g_str_equal(list[i], "FindMe"))
+                       enabled.findme = FALSE;
+               else if (g_str_equal(list[i], "LinkLoss"))
+                       enabled.linkloss = FALSE;
+               else if (g_str_equal(list[i], "PathLoss"))
+                       enabled.pathloss = FALSE;
+       }
+
+       g_strfreev(list);
+}
+
+int proximity_manager_init(DBusConnection *conn, GKeyFile *config)
+{
+       int ret;
+
+       load_config_file(config);
+
+       /* TODO: Register Proximity Monitor/Reporter drivers */
+       ret = btd_register_device_driver(&monitor_driver);
+       if (ret < 0)
+               return ret;
+
+       connection = dbus_connection_ref(conn);
+
+       return reporter_init();
+}
+
+void proximity_manager_exit(void)
+{
+       reporter_exit();
+       btd_unregister_device_driver(&monitor_driver);
+       dbus_connection_unref(connection);
+}
diff --git a/proximity/manager.h b/proximity/manager.h
new file mode 100644 (file)
index 0000000..b0fe7c8
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int proximity_manager_init(DBusConnection *conn, GKeyFile *conf);
+void proximity_manager_exit(void);
diff --git a/proximity/monitor.c b/proximity/monitor.c
new file mode 100644 (file)
index 0000000..76020ee
--- /dev/null
@@ -0,0 +1,663 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <gdbus.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/uuid.h>
+
+#include "dbus-common.h"
+#include "adapter.h"
+#include "device.h"
+#include "error.h"
+#include "log.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "attio.h"
+#include "monitor.h"
+#include "textfile.h"
+
+#define PROXIMITY_INTERFACE "org.bluez.Proximity"
+
+#define ALERT_LEVEL_CHR_UUID 0x2A06
+#define POWER_LEVEL_CHR_UUID 0x2A07
+
+#define IMMEDIATE_TIMEOUT      5
+
+enum {
+       ALERT_NONE = 0,
+       ALERT_MILD,
+       ALERT_HIGH,
+};
+
+struct monitor {
+       struct btd_device *device;
+       GAttrib *attrib;
+       DBusConnection *conn;
+       struct att_range *linkloss;
+       struct att_range *txpower;
+       struct att_range *immediate;
+       struct enabled enabled;
+       char *linklosslevel;            /* Link Loss Alert Level */
+       char *fallbacklevel;            /* Immediate fallback alert level */
+       char *immediatelevel;           /* Immediate Alert Level */
+       char *signallevel;              /* Path Loss RSSI level */
+       uint16_t linklosshandle;        /* Link Loss Characteristic
+                                        * Value Handle */
+       uint16_t txpowerhandle;         /* Tx Characteristic Value Handle */
+       uint16_t immediatehandle;       /* Immediate Alert Value Handle */
+       guint immediateto;              /* Reset Immediate Alert to "none" */
+       guint attioid;
+};
+
+static inline int create_filename(char *buf, size_t size,
+                               const bdaddr_t *bdaddr, const char *name)
+{
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+
+       return create_name(buf, size, STORAGEDIR, addr, name);
+}
+
+static int write_proximity_config(bdaddr_t *sba, bdaddr_t *dba,
+                                       const char *alert, const char *level)
+{
+       char filename[PATH_MAX + 1], addr[18], key[38];
+
+       create_filename(filename, PATH_MAX, sba, "proximity");
+
+       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+       ba2str(dba, addr);
+
+       snprintf(key, sizeof(key), "%17s#%s", addr, alert);
+
+       return textfile_put(filename, key, level);
+}
+
+static char *read_proximity_config(bdaddr_t *sba, bdaddr_t *dba,
+                                                       const char *alert)
+{
+       char filename[PATH_MAX + 1], addr[18], key[38];
+       char *str, *strnew;
+
+       create_filename(filename, PATH_MAX, sba, "proximity");
+
+       ba2str(dba, addr);
+       snprintf(key, sizeof(key), "%17s#%s", addr, alert);
+
+       str = textfile_caseget(filename, key);
+       if (str == NULL)
+               return NULL;
+
+       strnew = g_strdup(str);
+       free(str);
+
+       return strnew;
+}
+
+static uint8_t str2level(const char *level)
+{
+       if (g_strcmp0("high", level) == 0)
+               return ALERT_HIGH;
+       else if (g_strcmp0("mild", level) == 0)
+               return ALERT_MILD;
+
+       return ALERT_NONE;
+}
+
+static void linkloss_written(guint8 status, const guint8 *pdu, guint16 plen,
+                                                       gpointer user_data)
+{
+       struct monitor *monitor = user_data;
+       struct btd_device *device = monitor->device;
+       const char *path = device_get_path(device);
+
+       if (status != 0) {
+               error("Link Loss Write Request failed: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       if (!dec_write_resp(pdu, plen)) {
+               error("Link Loss Write Request: protocol error");
+               return;
+       }
+
+       DBG("Link Loss Alert Level written");
+
+       emit_property_changed(monitor->conn, path,
+                               PROXIMITY_INTERFACE, "LinkLossAlertLevel",
+                               DBUS_TYPE_STRING, &monitor->linklosslevel);
+}
+
+static void char_discovered_cb(GSList *characteristics, guint8 status,
+                                                       gpointer user_data)
+{
+       struct monitor *monitor = user_data;
+       struct att_char *chr;
+       uint8_t value = str2level(monitor->linklosslevel);
+
+       if (status) {
+               error("Discover Link Loss handle: %s", att_ecode2str(status));
+               return;
+       }
+
+       DBG("Setting alert level \"%s\" on Reporter", monitor->linklosslevel);
+
+       /* Assume there is a single Alert Level characteristic */
+       chr = characteristics->data;
+       monitor->linklosshandle = chr->value_handle;
+
+       gatt_write_char(monitor->attrib, monitor->linklosshandle, &value, 1,
+                                               linkloss_written, monitor);
+}
+
+static int write_alert_level(struct monitor *monitor)
+{
+       struct att_range *linkloss = monitor->linkloss;
+       bt_uuid_t uuid;
+
+       if (monitor->linklosshandle) {
+               uint8_t value = str2level(monitor->linklosslevel);
+
+               gatt_write_char(monitor->attrib, monitor->linklosshandle,
+                                       &value, 1, linkloss_written, monitor);
+               return 0;
+       }
+
+       bt_uuid16_create(&uuid, ALERT_LEVEL_CHR_UUID);
+
+       /* FIXME: use cache (requires service changed support) ? */
+       gatt_discover_char(monitor->attrib, linkloss->start, linkloss->end,
+                                       &uuid, char_discovered_cb, monitor);
+
+       return 0;
+}
+
+static void tx_power_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
+                                                       gpointer user_data)
+{
+       uint8_t value[ATT_MAX_MTU];
+       int vlen;
+
+       if (status != 0) {
+               DBG("Tx Power Level read failed: %s", att_ecode2str(status));
+               return;
+       }
+
+       if (!dec_read_resp(pdu, plen, value, &vlen)) {
+               DBG("Protocol error");
+               return;
+       }
+
+       if (vlen != 1) {
+               DBG("Invalid length for TX Power value: %d", vlen);
+               return;
+       }
+
+       DBG("Tx Power Level: %02x", (int8_t) value[0]);
+}
+
+static void tx_power_handle_cb(GSList *characteristics, guint8 status,
+                                                       gpointer user_data)
+{
+       struct monitor *monitor = user_data;
+       struct att_char *chr;
+
+       if (status) {
+               error("Discover Tx Power handle: %s", att_ecode2str(status));
+               return;
+       }
+
+       chr = characteristics->data;
+       monitor->txpowerhandle = chr->value_handle;
+
+       DBG("Tx Power handle: 0x%04x", monitor->txpowerhandle);
+
+       gatt_read_char(monitor->attrib, monitor->txpowerhandle, 0,
+                                                       tx_power_read_cb, monitor);
+}
+
+static void read_tx_power(struct monitor *monitor)
+{
+       struct att_range *txpower = monitor->txpower;
+       bt_uuid_t uuid;
+
+       if (monitor->txpowerhandle != 0) {
+               gatt_read_char(monitor->attrib, monitor->txpowerhandle, 0,
+                                               tx_power_read_cb, monitor);
+               return;
+       }
+
+       bt_uuid16_create(&uuid, POWER_LEVEL_CHR_UUID);
+
+       gatt_discover_char(monitor->attrib, txpower->start, txpower->end,
+                               &uuid, tx_power_handle_cb, monitor);
+}
+
+static gboolean immediate_timeout(gpointer user_data)
+{
+       struct monitor *monitor = user_data;
+       const char *path = device_get_path(monitor->device);
+
+       monitor->immediateto = 0;
+
+       if (g_strcmp0(monitor->immediatelevel, "none") == 0)
+               return FALSE;
+
+       if (monitor->attrib) {
+               uint8_t value = ALERT_NONE;
+               gatt_write_cmd(monitor->attrib, monitor->immediatehandle,
+                               &value, 1, NULL, NULL);
+       }
+
+       g_free(monitor->immediatelevel);
+       monitor->immediatelevel = g_strdup("none");
+       emit_property_changed(monitor->conn, path, PROXIMITY_INTERFACE,
+                                       "ImmediateAlertLevel", DBUS_TYPE_STRING,
+                                       &monitor->immediatelevel);
+
+       return FALSE;
+}
+
+static void immediate_written(gpointer user_data)
+{
+       struct monitor *monitor = user_data;
+       const char *path = device_get_path(monitor->device);
+
+       g_free(monitor->fallbacklevel);
+       monitor->fallbacklevel = NULL;
+
+       emit_property_changed(monitor->conn, path, PROXIMITY_INTERFACE,
+                               "ImmediateAlertLevel",
+                               DBUS_TYPE_STRING, &monitor->immediatelevel);
+
+       monitor->immediateto = g_timeout_add_seconds(IMMEDIATE_TIMEOUT,
+                                               immediate_timeout, monitor);
+}
+
+static void write_immediate_alert(struct monitor *monitor)
+{
+       uint8_t value = str2level(monitor->immediatelevel);
+
+       gatt_write_cmd(monitor->attrib, monitor->immediatehandle, &value, 1,
+                                               immediate_written, monitor);
+}
+
+static void immediate_handle_cb(GSList *characteristics, guint8 status,
+                                                       gpointer user_data)
+{
+       struct monitor *monitor = user_data;
+       struct att_char *chr;
+
+       if (status) {
+               error("Discover Immediate Alert handle: %s",
+                                               att_ecode2str(status));
+               return;
+       }
+
+       chr = characteristics->data;
+       monitor->immediatehandle = chr->value_handle;
+
+       DBG("Immediate Alert handle: 0x%04x", monitor->immediatehandle);
+
+       if (monitor->fallbacklevel)
+               write_immediate_alert(monitor);
+}
+
+static void discover_immediate_handle(struct monitor *monitor)
+{
+       struct att_range *immediate = monitor->immediate;
+       bt_uuid_t uuid;
+
+       bt_uuid16_create(&uuid, ALERT_LEVEL_CHR_UUID);
+
+       gatt_discover_char(monitor->attrib, immediate->start, immediate->end,
+                                       &uuid, immediate_handle_cb, monitor);
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+       struct monitor *monitor = user_data;
+
+       monitor->attrib = g_attrib_ref(attrib);
+
+       if (monitor->enabled.linkloss)
+               write_alert_level(monitor);
+
+       if (monitor->enabled.pathloss)
+               read_tx_power(monitor);
+
+       if (monitor->immediatehandle == 0) {
+               if(monitor->enabled.pathloss || monitor->enabled.findme)
+                       discover_immediate_handle(monitor);
+       } else if (monitor->fallbacklevel)
+               write_immediate_alert(monitor);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+       struct monitor *monitor = user_data;
+       const char *path = device_get_path(monitor->device);
+
+       g_attrib_unref(monitor->attrib);
+       monitor->attrib = NULL;
+
+       if (monitor->immediateto == 0)
+               return;
+
+       g_source_remove(monitor->immediateto);
+       monitor->immediateto = 0;
+
+       if (g_strcmp0(monitor->immediatelevel, "none") == 0)
+               return;
+
+       g_free(monitor->immediatelevel);
+       monitor->immediatelevel = g_strdup("none");
+       emit_property_changed(monitor->conn, path, PROXIMITY_INTERFACE,
+                                       "ImmediateAlertLevel", DBUS_TYPE_STRING,
+                                       &monitor->immediatelevel);
+}
+
+static gboolean level_is_valid(const char *level)
+{
+       return (g_str_equal("none", level) ||
+                       g_str_equal("mild", level) ||
+                       g_str_equal("high", level));
+}
+
+static DBusMessage *set_link_loss_alert(DBusConnection *conn, DBusMessage *msg,
+                                               const char *level, void *data)
+{
+       struct monitor *monitor = data;
+       struct btd_device *device = monitor->device;
+       bdaddr_t sba, dba;
+
+       if (!level_is_valid(level))
+               return btd_error_invalid_args(msg);
+
+       if (g_strcmp0(monitor->linklosslevel, level) == 0)
+               return dbus_message_new_method_return(msg);
+
+       g_free(monitor->linklosslevel);
+       monitor->linklosslevel = g_strdup(level);
+
+       adapter_get_address(device_get_adapter(device), &sba);
+       device_get_address(device, &dba, NULL);
+
+       write_proximity_config(&sba, &dba, "LinkLossAlertLevel", level);
+
+       if (monitor->attrib)
+               write_alert_level(monitor);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *set_immediate_alert(DBusConnection *conn, DBusMessage *msg,
+                                               const char *level, void *data)
+{
+       struct monitor *monitor = data;
+
+       if (!level_is_valid(level))
+               return btd_error_invalid_args(msg);
+
+       if (g_strcmp0(monitor->immediatelevel, level) == 0)
+               return dbus_message_new_method_return(msg);
+
+       if (monitor->immediateto) {
+               g_source_remove(monitor->immediateto);
+               monitor->immediateto = 0;
+       }
+
+       /* Previous Immediate Alert level if connection/write fails */
+       g_free(monitor->fallbacklevel);
+       monitor->fallbacklevel = monitor->immediatelevel;
+
+       monitor->immediatelevel = g_strdup(level);
+
+       /*
+        * Means that Link/Path Loss are disabled or there is a pending
+        * writting for Find Me(Immediate Alert characteristic value).
+        * If enabled, Path Loss always registers a connection callback
+        * when the Proximity Monitor starts.
+        */
+       if (monitor->attioid == 0)
+               monitor->attioid = btd_device_add_attio_callback(monitor->device,
+                                                       attio_connected_cb,
+                                                       attio_disconnected_cb,
+                                                       monitor);
+       else if (monitor->attrib)
+               write_immediate_alert(monitor);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *get_properties(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
+{
+       struct monitor *monitor = data;
+       DBusMessageIter iter;
+       DBusMessageIter dict;
+       DBusMessage *reply;
+
+       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);
+
+       if (monitor->enabled.linkloss)
+               dict_append_entry(&dict, "LinkLossAlertLevel",
+                               DBUS_TYPE_STRING, &monitor->linklosslevel);
+
+       if (monitor->enabled.findme || monitor->enabled.pathloss)
+               dict_append_entry(&dict, "ImmediateAlertLevel",
+                               DBUS_TYPE_STRING, &monitor->immediatelevel);
+
+       if (monitor->enabled.pathloss)
+               dict_append_entry(&dict, "SignalLevel",
+                               DBUS_TYPE_STRING, &monitor->signallevel);
+
+       dbus_message_iter_close_container(&iter, &dict);
+
+       return reply;
+}
+
+static DBusMessage *set_property(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
+{
+       struct monitor *monitor = data;
+       const char *property;
+       DBusMessageIter iter;
+       DBusMessageIter sub;
+       const char *level;
+
+       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);
+
+       if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
+               return btd_error_invalid_args(msg);
+
+       dbus_message_iter_get_basic(&sub, &level);
+
+       if (g_str_equal("ImmediateAlertLevel", property)) {
+               if (monitor->enabled.findme == FALSE &&
+                               monitor->enabled.pathloss == FALSE)
+                       return btd_error_not_available(msg);
+
+               return set_immediate_alert(conn, msg, level, data);
+       } else if (g_str_equal("LinkLossAlertLevel", property)) {
+               if (monitor->enabled.linkloss == FALSE)
+                       return btd_error_not_available(msg);
+
+               return set_link_loss_alert(conn, msg, level, data);
+       }
+
+       return btd_error_invalid_args(msg);
+}
+
+static GDBusMethodTable monitor_methods[] = {
+       { "GetProperties",      "",     "a{sv}",        get_properties  },
+       { "SetProperty",        "sv",   "",             set_property,
+                                               G_DBUS_METHOD_FLAG_ASYNC},
+       { }
+};
+
+static GDBusSignalTable monitor_signals[] = {
+       { "PropertyChanged",    "sv"    },
+       { }
+};
+
+static void monitor_destroy(gpointer user_data)
+{
+       struct monitor *monitor = user_data;
+
+       if (monitor->immediateto)
+               g_source_remove(monitor->immediateto);
+
+       if (monitor->attioid)
+               btd_device_remove_attio_callback(monitor->device,
+                                               monitor->attioid);
+       if (monitor->attrib)
+               g_attrib_unref(monitor->attrib);
+
+       dbus_connection_unref(monitor->conn);
+       btd_device_unref(monitor->device);
+       g_free(monitor->linkloss);
+       g_free(monitor->immediate);
+       g_free(monitor->txpower);
+       g_free(monitor->linklosslevel);
+       g_free(monitor->immediatelevel);
+       g_free(monitor->signallevel);
+       g_free(monitor);
+}
+
+int monitor_register(DBusConnection *conn, struct btd_device *device,
+               struct att_primary *linkloss, struct att_primary *txpower,
+               struct att_primary *immediate, struct enabled *enabled)
+{
+       const char *path = device_get_path(device);
+       struct monitor *monitor;
+       bdaddr_t sba, dba;
+       char *level;
+
+       adapter_get_address(device_get_adapter(device), &sba);
+       device_get_address(device, &dba, NULL);
+
+       level = read_proximity_config(&sba, &dba, "LinkLossAlertLevel");
+
+       monitor = g_new0(struct monitor, 1);
+       monitor->device = btd_device_ref(device);
+       monitor->conn = dbus_connection_ref(conn);
+       monitor->linklosslevel = (level ? : g_strdup("high"));
+       monitor->signallevel = g_strdup("unknown");
+       monitor->immediatelevel = g_strdup("none");
+
+       if (g_dbus_register_interface(conn, path,
+                               PROXIMITY_INTERFACE,
+                               monitor_methods, monitor_signals,
+                               NULL, monitor, monitor_destroy) == FALSE) {
+               error("D-Bus failed to register %s interface",
+                                               PROXIMITY_INTERFACE);
+               monitor_destroy(monitor);
+               return -1;
+       }
+
+       DBG("Registered interface %s on path %s", PROXIMITY_INTERFACE, path);
+
+       if (linkloss && enabled->linkloss) {
+               monitor->linkloss = g_new0(struct att_range, 1);
+               monitor->linkloss->start = linkloss->start;
+               monitor->linkloss->end = linkloss->end;
+
+               monitor->enabled.linkloss = TRUE;
+       }
+
+       if (immediate) {
+               if (txpower && enabled->pathloss) {
+                       monitor->txpower = g_new0(struct att_range, 1);
+                       monitor->txpower->start = txpower->start;
+                       monitor->txpower->end = txpower->end;
+
+                       monitor->enabled.pathloss = TRUE;
+               }
+
+               if (enabled->pathloss || enabled->findme) {
+                       monitor->immediate = g_new0(struct att_range, 1);
+                       monitor->immediate->start = immediate->start;
+                       monitor->immediate->end = immediate->end;
+               }
+
+               monitor->enabled.findme = enabled->findme;
+       }
+
+       DBG("Link Loss: %s, Path Loss: %s, FindMe: %s",
+                               monitor->enabled.linkloss ? "TRUE" : "FALSE",
+                               monitor->enabled.pathloss ? "TRUE" : "FALSE",
+                               monitor->enabled.findme ? "TRUE" : "FALSE");
+
+       if (monitor->enabled.linkloss || monitor->enabled.pathloss)
+               monitor->attioid = btd_device_add_attio_callback(device,
+                                                       attio_connected_cb,
+                                                       attio_disconnected_cb,
+                                                       monitor);
+
+       return 0;
+}
+
+void monitor_unregister(DBusConnection *conn, struct btd_device *device)
+{
+       const char *path = device_get_path(device);
+
+       g_dbus_unregister_interface(conn, path, PROXIMITY_INTERFACE);
+}
diff --git a/proximity/monitor.h b/proximity/monitor.h
new file mode 100644 (file)
index 0000000..fb79e26
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+struct enabled {
+       gboolean linkloss;
+       gboolean pathloss;
+       gboolean findme;
+};
+
+int monitor_register(DBusConnection *conn, struct btd_device *device,
+               struct att_primary *linkloss, struct att_primary *txpower,
+               struct att_primary *immediate, struct enabled *enabled);
+void monitor_unregister(DBusConnection *conn, struct btd_device *device);
diff --git a/proximity/proximity.conf b/proximity/proximity.conf
new file mode 100644 (file)
index 0000000..417610f
--- /dev/null
@@ -0,0 +1,9 @@
+# Configuration file for the proximity service
+
+# This section contains options which are not specific to any
+# particular interface
+[General]
+
+# Configuration to allow disabling Proximity services
+# Allowed values: LinkLoss,PathLoss,FindMe
+Disable=PathLoss
diff --git a/proximity/reporter.c b/proximity/reporter.c
new file mode 100644 (file)
index 0000000..a139c7c
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <bluetooth/uuid.h>
+#include <adapter.h>
+
+#include "log.h"
+
+#include "hcid.h"
+#include "att.h"
+#include "gattrib.h"
+#include "attrib-server.h"
+#include "reporter.h"
+
+#define IMMEDIATE_ALERT_SVC_UUID       0x1802
+#define LINK_LOSS_SVC_UUID             0x1803
+#define TX_POWER_SVC_UUID              0x1804
+#define ALERT_LEVEL_CHR_UUID           0x2A06
+#define POWER_LEVEL_CHR_UUID           0x2A07
+
+enum {
+       NO_ALERT = 0x00,
+       MILD_ALERT = 0x01,
+       HIGH_ALERT = 0x02,
+};
+
+static uint16_t tx_power_handle;
+
+static void register_link_loss(void)
+{
+       uint16_t start_handle, h;
+       const int svc_size = 3;
+       uint8_t atval[256];
+       bt_uuid_t uuid;
+
+       /* FIXME: Provide the adapter in next function */
+       start_handle = attrib_db_find_avail(NULL, svc_size);
+       if (start_handle == 0) {
+               error("Not enough free handles to register service");
+               return;
+       }
+
+       DBG("start_handle=0x%04x", start_handle);
+
+       h = start_handle;
+
+       /* Primary service definition */
+       bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+       att_put_u16(LINK_LOSS_SVC_UUID, &atval[0]);
+       /* FIXME: Provide the adapter in next function */
+       attrib_db_add(NULL, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
+
+       /* Alert level characteristic */
+       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
+       atval[0] = ATT_CHAR_PROPER_READ | ATT_CHAR_PROPER_WRITE;
+       att_put_u16(h + 1, &atval[1]);
+       att_put_u16(ALERT_LEVEL_CHR_UUID, &atval[3]);
+       /* FIXME: Provide the adapter in next function */
+       attrib_db_add(NULL, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
+
+       /* Alert level value */
+       bt_uuid16_create(&uuid, ALERT_LEVEL_CHR_UUID);
+       att_put_u8(NO_ALERT, &atval[0]);
+       /* FIXME: Provide the adapter in next function */
+       attrib_db_add(NULL, h++, &uuid, ATT_NONE, ATT_NONE, atval, 1);
+
+       g_assert(h - start_handle == svc_size);
+}
+
+static void register_tx_power(void)
+{
+       uint16_t start_handle, h;
+       const int svc_size = 4;
+       uint8_t atval[256];
+       bt_uuid_t uuid;
+
+       /* FIXME: Provide the adapter in next function */
+       start_handle = attrib_db_find_avail(NULL, svc_size);
+       if (start_handle == 0) {
+               error("Not enough free handles to register service");
+               return;
+       }
+
+       DBG("start_handle=0x%04x", start_handle);
+
+       h = start_handle;
+
+       /* Primary service definition */
+       bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+       att_put_u16(TX_POWER_SVC_UUID, &atval[0]);
+       /* FIXME: Provide the adapter in next function */
+       attrib_db_add(NULL, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
+
+       /* Power level characteristic */
+       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
+       atval[0] = ATT_CHAR_PROPER_READ | ATT_CHAR_PROPER_NOTIFY;
+       att_put_u16(h + 1, &atval[1]);
+       att_put_u16(POWER_LEVEL_CHR_UUID, &atval[3]);
+       /* FIXME: Provide the adapter in next function */
+       attrib_db_add(NULL, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
+
+       /* Power level value */
+       bt_uuid16_create(&uuid, POWER_LEVEL_CHR_UUID);
+       att_put_u8(0x00, &atval[0]);
+       tx_power_handle = h;
+       /* FIXME: Provide the adapter in next function */
+       attrib_db_add(NULL, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 1);
+
+       /* Client characteristic configuration */
+       bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
+       atval[0] = 0x00;
+       atval[1] = 0x00;
+       /* FIXME: Provide the adapter in next function */
+       attrib_db_add(NULL, h++, &uuid, ATT_NONE, ATT_NONE, atval, 2);
+
+       g_assert(h - start_handle == svc_size);
+}
+
+static void register_immediate_alert(void)
+{
+       uint16_t start_handle, h;
+       const int svc_size = 3;
+       uint8_t atval[256];
+       bt_uuid_t uuid;
+
+       /* FIXME: Provide the adapter in next function */
+       start_handle = attrib_db_find_avail(NULL, svc_size);
+       if (start_handle == 0) {
+               error("Not enough free handles to register service");
+               return;
+       }
+
+       DBG("start_handle=0x%04x", start_handle);
+
+       h = start_handle;
+
+       /* Primary service definition */
+       bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+       att_put_u16(IMMEDIATE_ALERT_SVC_UUID, &atval[0]);
+       /* FIXME: Provide the adapter in next function */
+       attrib_db_add(NULL, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
+
+       /* Alert level characteristic */
+       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
+       atval[0] = ATT_CHAR_PROPER_WRITE_WITHOUT_RESP;
+       att_put_u16(h + 1, &atval[1]);
+       att_put_u16(ALERT_LEVEL_CHR_UUID, &atval[3]);
+       /* FIXME: Provide the adapter in next function */
+       attrib_db_add(NULL, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
+
+       /* Alert level value */
+       bt_uuid16_create(&uuid, ALERT_LEVEL_CHR_UUID);
+       att_put_u8(NO_ALERT, &atval[0]);
+       /* FIXME: Provide the adapter in next function */
+       attrib_db_add(NULL, h++, &uuid, ATT_NONE, ATT_NONE, atval, 1);
+
+       g_assert(h - start_handle == svc_size);
+}
+
+int reporter_init(void)
+{
+       if (!main_opts.attrib_server) {
+               DBG("Attribute server is disabled");
+               return -1;
+       }
+
+       DBG("Proximity Reporter");
+
+       register_link_loss();
+       register_tx_power();
+       register_immediate_alert();
+
+       return 0;
+}
+
+void reporter_exit(void)
+{
+}
similarity index 81%
rename from attrib/manager.h
rename to proximity/reporter.h
index fabf342..ea6b83d 100644 (file)
@@ -2,8 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2010  Nokia Corporation
- *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -22,5 +22,5 @@
  *
  */
 
-int attrib_manager_init(DBusConnection *conn);
-void attrib_manager_exit(void);
+int reporter_init(void);
+void reporter_exit(void);
index b433ba3..acdec77 100644 (file)
@@ -2,6 +2,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2010 ST-Ericsson SA
+ *  Copyright (C) 2011 Tieto Poland
  *
  *  Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
  *          for ST-Ericsson
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <glib.h>
+#include <gdbus.h>
+
 #include "log.h"
 #include "sap.h"
 
+#define SAP_DUMMY_IFACE "org.bluez.SimAccessTest"
+#define SAP_DUMMY_PATH "/org/bluez/test"
+
+enum {
+       SIM_DISCONNECTED= 0x00,
+       SIM_CONNECTED   = 0x01,
+       SIM_POWERED_OFF = 0x02,
+       SIM_MISSING     = 0x03
+};
+
+static DBusConnection *connection = NULL;
+
+static int sim_card_conn_status = SIM_DISCONNECTED;
+static void *sap_data = NULL;  /* SAP server private data.*/
+static gboolean ongoing_call_status = FALSE;
+static int max_msg_size_supported = 512;
+
 void sap_connect_req(void *sap_device, uint16_t maxmsgsize)
 {
-       sap_connect_rsp(sap_device, SAP_STATUS_OK, maxmsgsize);
-       sap_status_ind(sap_device, SAP_STATUS_CHANGE_CARD_RESET);
+       DBG("status: %d", sim_card_conn_status);
+
+       if (sim_card_conn_status != SIM_DISCONNECTED) {
+               sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED,
+                                                               maxmsgsize);
+               return;
+       } else if (max_msg_size_supported > maxmsgsize) {
+               sap_connect_rsp(sap_device, SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL,
+                                               max_msg_size_supported);
+               return;
+       } else if (max_msg_size_supported < maxmsgsize) {
+               sap_connect_rsp(sap_device,
+                               SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED,
+                               max_msg_size_supported);
+               return;
+       } else if (ongoing_call_status) {
+               sap_connect_rsp(sap_device, SAP_STATUS_OK_ONGOING_CALL,
+                                               max_msg_size_supported);
+               return;
+       } else {
+               sim_card_conn_status = SIM_CONNECTED;
+               sap_data = sap_device;
+
+               sap_connect_rsp(sap_device, SAP_STATUS_OK, maxmsgsize);
+               sap_status_ind(sap_device, SAP_STATUS_CHANGE_CARD_RESET);
+       }
 }
 
 void sap_disconnect_req(void *sap_device, uint8_t linkloss)
 {
+       sim_card_conn_status = SIM_DISCONNECTED;
+       sap_data = NULL;
+       ongoing_call_status = FALSE;
+
+       DBG("status: %d", sim_card_conn_status);
+
+       if (linkloss)
+               return;
+
        sap_disconnect_rsp(sap_device);
 }
 
 void sap_transfer_apdu_req(void *sap_device, struct sap_parameter *param)
 {
-       sap_transfer_apdu_rsp(sap_device, SAP_RESULT_OK, NULL, 0);
+       char apdu[] = "APDU response!";
+
+       DBG("status: %d", sim_card_conn_status);
+
+       if (sim_card_conn_status == SIM_MISSING)
+               sap_transfer_apdu_rsp(sap_device,
+                               SAP_RESULT_ERROR_CARD_REMOVED, NULL, 0);
+       else if (sim_card_conn_status == SIM_POWERED_OFF)
+               sap_transfer_apdu_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF,
+                                                               NULL, 0);
+       else if (sim_card_conn_status != SIM_CONNECTED)
+               sap_transfer_apdu_rsp(sap_device,
+                       SAP_RESULT_ERROR_NOT_ACCESSIBLE, NULL, 0);
+       else
+               sap_transfer_apdu_rsp(sap_device, SAP_RESULT_OK,
+                                               (uint8_t*)&apdu, sizeof(apdu));
 }
 
 void sap_transfer_atr_req(void *sap_device)
 {
-       sap_transfer_atr_rsp(sap_device, SAP_RESULT_OK, NULL, 0);
+       char atr[] = "ATR response!";
+
+       DBG("status: %d", sim_card_conn_status);
+
+       if (sim_card_conn_status == SIM_MISSING)
+               sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_CARD_REMOVED,
+                                                               NULL, 0);
+       else if (sim_card_conn_status == SIM_POWERED_OFF)
+               sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF,
+                                                               NULL, 0);
+       else if (sim_card_conn_status != SIM_CONNECTED)
+               sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON,
+                                                               NULL, 0);
+       else
+               sap_transfer_atr_rsp(sap_device, SAP_RESULT_OK,
+                                               (uint8_t*)&atr, sizeof(atr));
 }
 
 void sap_power_sim_off_req(void *sap_device)
 {
-       sap_power_sim_off_rsp(sap_device, SAP_RESULT_OK);
+       DBG("status: %d", sim_card_conn_status);
+
+       if (sim_card_conn_status == SIM_MISSING) {
+               sap_power_sim_off_rsp(sap_device,
+                                       SAP_RESULT_ERROR_CARD_REMOVED);
+       } else if (sim_card_conn_status == SIM_POWERED_OFF) {
+               sap_power_sim_off_rsp(sap_device,
+                                       SAP_RESULT_ERROR_POWERED_OFF);
+       } else if (sim_card_conn_status != SIM_CONNECTED) {
+               sap_power_sim_off_rsp(sap_device,
+                                       SAP_RESULT_ERROR_NO_REASON);
+       } else {
+               sap_power_sim_off_rsp(sap_device, SAP_RESULT_OK);
+               sim_card_conn_status = SIM_POWERED_OFF;
+       }
 }
 
 void sap_power_sim_on_req(void *sap_device)
 {
-       sap_power_sim_on_rsp(sap_device, SAP_RESULT_OK);
+       DBG("status: %d", sim_card_conn_status);
+
+       if (sim_card_conn_status == SIM_MISSING) {
+               sap_power_sim_on_rsp(sap_device,
+                                       SAP_RESULT_ERROR_CARD_REMOVED);
+       } else if (sim_card_conn_status == SIM_POWERED_OFF) {
+               sap_power_sim_on_rsp(sap_device, SAP_RESULT_OK);
+               sim_card_conn_status = SIM_CONNECTED;
+               return;
+       } else if (sim_card_conn_status != SIM_CONNECTED) {
+               sap_power_sim_on_rsp(sap_device,
+                                       SAP_RESULT_ERROR_NOT_ACCESSIBLE);
+       } else {
+               sap_power_sim_on_rsp(sap_device,
+                                       SAP_RESULT_ERROR_NO_REASON);
+       }
 }
 
 void sap_reset_sim_req(void *sap_device)
 {
-       sap_reset_sim_rsp(sap_device, SAP_RESULT_OK);
-       sap_status_ind(sap_device, SAP_STATUS_CHANGE_CARD_RESET);
+       DBG("status: %d", sim_card_conn_status);
+
+       if (sim_card_conn_status == SIM_MISSING) {
+               sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_CARD_REMOVED);
+       } else if (sim_card_conn_status == SIM_POWERED_OFF) {
+               sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF);
+       } else if (sim_card_conn_status != SIM_CONNECTED) {
+               sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
+       } else {
+               sap_reset_sim_rsp(sap_device, SAP_RESULT_OK);
+       }
 }
 
 void sap_transfer_card_reader_status_req(void *sap_device)
 {
-       sap_transfer_card_reader_status_rsp(sap_device, SAP_RESULT_OK,
-                                               ICC_READER_CARD_POWERED_ON);
+       DBG("status: %d", sim_card_conn_status);
+
+       if (sim_card_conn_status != SIM_CONNECTED) {
+               sap_transfer_card_reader_status_rsp(sap_device,
+                                       SAP_RESULT_ERROR_NO_REASON, 0xF1);
+               return;
+       }
+
+       sap_transfer_card_reader_status_rsp(sap_device, SAP_RESULT_OK, 0xF1);
 }
 
 void sap_set_transport_protocol_req(void *sap_device,
@@ -73,13 +209,137 @@ void sap_set_transport_protocol_req(void *sap_device,
        sap_transport_protocol_rsp(sap_device, SAP_RESULT_NOT_SUPPORTED);
 }
 
+static inline DBusMessage *invalid_args(DBusMessage *msg)
+{
+       return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
+                                       "Invalid arguments in method call");
+}
+
+static DBusMessage *ongoing_call(DBusConnection *conn, DBusMessage *msg,
+                                               void *data)
+{
+       dbus_bool_t ongoing;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &ongoing,
+                                               DBUS_TYPE_INVALID))
+               return invalid_args(msg);
+
+       if (ongoing_call_status && !ongoing) {
+               /* An ongoing call has finished. Continue connection.*/
+               sap_status_ind(sap_data, SAP_STATUS_CHANGE_CARD_RESET);
+               ongoing_call_status = ongoing;
+       } else if (!ongoing_call_status && ongoing) {
+               /* An ongoing call has started.*/
+               ongoing_call_status = ongoing;
+       }
+
+       DBG("OngoingCall status set to %d", ongoing_call_status);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *max_msg_size(DBusConnection *conn, DBusMessage *msg,
+                                               void *data)
+{
+       dbus_uint32_t size;
+
+       if (sim_card_conn_status == SIM_CONNECTED)
+               return g_dbus_create_error(msg, "org.bluez.Error.Failed",
+                               "Can't change msg size when connected.");
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &size,
+                                                       DBUS_TYPE_INVALID))
+               return invalid_args(msg);
+
+       max_msg_size_supported = size;
+
+       DBG("MaxMessageSize set to %d", max_msg_size_supported);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *disconnect_immediate(DBusConnection *conn, DBusMessage *msg,
+                                               void *data)
+{
+       if (sim_card_conn_status == SIM_DISCONNECTED)
+               return g_dbus_create_error(msg, "org.bluez.Error.Failed",
+                               "Already disconnected.");
+
+       sim_card_conn_status = SIM_DISCONNECTED;
+       sap_disconnect_ind(sap_data, SAP_DISCONNECTION_TYPE_IMMEDIATE);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *card_status(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       dbus_uint32_t status;
+
+       DBG("status %d", sim_card_conn_status);
+
+       if (sim_card_conn_status != SIM_CONNECTED)
+               return g_dbus_create_error(msg, "org.bluez.Error.Failed",
+                               "Can't change msg size when not connected.");
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &status,
+                                                       DBUS_TYPE_INVALID))
+               return invalid_args(msg);
+
+       switch (status) {
+       case 0: /* card removed */
+               sim_card_conn_status = SIM_MISSING;
+               sap_status_ind(sap_data, SAP_STATUS_CHANGE_CARD_REMOVED);
+               break;
+
+       case 1: /* card inserted */
+               if (sim_card_conn_status == SIM_MISSING) {
+                       sim_card_conn_status = SIM_CONNECTED;
+                       sap_status_ind(sap_data,
+                                       SAP_STATUS_CHANGE_CARD_INSERTED);
+               }
+               break;
+
+       case 2: /* card not longer available*/
+               sim_card_conn_status = SIM_POWERED_OFF;
+               sap_status_ind(sap_data, SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE);
+               break;
+
+       default:
+               return g_dbus_create_error(msg, "org.bluez.Error.Failed",
+                               "Unknown card status. Use 0, 1 or 2.");
+       }
+
+       DBG("Card status changed to %d", status);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static GDBusMethodTable dummy_methods[] = {
+       { "OngoingCall", "b", "", ongoing_call},
+       { "MaxMessageSize", "u", "", max_msg_size},
+       { "DisconnectImmediate", "", "", disconnect_immediate},
+       { "CardStatus", "u", "", card_status},
+       { }
+};
+
 int sap_init(void)
 {
-       DBG("SAP driver init.");
+       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+
+       if (g_dbus_register_interface(connection, SAP_DUMMY_PATH,
+                               SAP_DUMMY_IFACE, dummy_methods, NULL, NULL,
+                               NULL, NULL) == FALSE) {
+               error("sap-dummy interface %s init failed on path %s",
+                                       SAP_DUMMY_IFACE, SAP_DUMMY_PATH);
+               return -1;
+       }
+
        return 0;
 }
 
 void sap_exit(void)
 {
-       DBG("SAP driver exit.");
+       dbus_connection_unref(connection);
+       connection = NULL;
 }
diff --git a/sap/sap-u8500.c b/sap/sap-u8500.c
new file mode 100644 (file)
index 0000000..ef7d95c
--- /dev/null
@@ -0,0 +1,761 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  SAP Driver for ST-Ericsson U8500 platform
+ *
+ *  Copyright (C) 2010-2011 ST-Ericsson SA
+ *
+ *  Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> for
+ *  ST-Ericsson.
+ *
+ *  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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <glib.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "log.h"
+#include "sap.h"
+
+#define STE_SIMD_SOCK  "/dev/socket/catd_a"
+#define STE_CLIENT_TAG 0x0000
+
+#ifdef STE_SAP_DEBUG
+#define DBG_VERBOSE(fmt, arg...) DBG(fmt, arg)
+#else
+#define DBG_VERBOSE(fmt...)
+#endif
+
+#define sap_error(fmt, arg...) do { \
+       error("STE U8500 SAP: " fmt, ## arg); \
+       } while (0)
+
+#define sap_info(fmt, arg...) do { \
+       info("STE U8500 SAP: " fmt, ## arg); \
+       } while (0)
+
+struct ste_message {
+       uint16_t len;
+       uint16_t id;
+       uint32_t client_tag;
+       uint8_t payload[0];
+} __attribute__((packed));
+
+#define STE_MSG_PAYLOAD_SIZE(msg) (msg->len - sizeof(*msg) + sizeof(msg->len))
+
+enum ste_protocol {
+       STE_START_SAP_REQ       = 0x2D01,
+       STE_START_SAP_RSP       = 0x2E01,
+       STE_END_SAP_REQ         = 0x2D02,
+       STE_END_SAP_RSP         = 0x2E02,
+       STE_POWER_OFF_REQ       = 0x2D03,
+       STE_POWER_OFF_RSP       = 0x2E03,
+       STE_POWER_ON_REQ        = 0x2D04,
+       STE_POWER_ON_RSP        = 0x2E04,
+       STE_RESET_REQ           = 0x2D05,
+       STE_RESET_RSP           = 0x2E05,
+       STE_SEND_APDU_REQ       = 0x2D06,
+       STE_SEND_APDU_RSP       = 0x2E06,
+       STE_GET_ATR_REQ         = 0x2D07,
+       STE_GET_ATR_RSP         = 0x2E07,
+       STE_GET_STATUS_REQ      = 0x2D08,
+       STE_GET_STATUS_RSP      = 0x2E08,
+       STE_STATUS_IND          = 0x2F02,
+       STE_SIM_READY_IND       = 0x2F03,
+};
+
+enum ste_msg {
+       STE_SEND_APDU_MSG,
+       STE_GET_ATR_MSG,
+       STE_POWER_OFF_MSG,
+       STE_POWER_ON_MSG,
+       STE_RESET_MSG,
+       STE_GET_STATUS_MSG,
+       STE_MSG_MAX,
+};
+
+enum ste_status {
+       STE_STATUS_OK           = 0x00000000,
+       STE_STATUS_FAILURE      = 0x00000001,
+       STE_STATUS_BUSY_CALL    = 0x00000002,
+};
+
+enum ste_card_status {
+       STE_CARD_STATUS_UNKNOWN         = 0x00,
+       STE_CARD_STATUS_ACTIVE          = 0x01,
+       STE_CARD_STATUS_NOT_ACTIVE      = 0x02,
+       STE_CARD_STATUS_MISSING         = 0x03,
+       STE_CARD_STATUS_INVALID         = 0x04,
+       STE_CARD_STATUS_DISCONNECTED    = 0x05,
+};
+
+/* Card reader status bits as described in GSM 11.14, Section 12.33
+ * Bits 0-2 are for card reader identity and always zeros. */
+#define ICC_READER_REMOVABLE   (1 << 3)
+#define ICC_READER_PRESENT     (1 << 4)
+#define ICC_READER_ID1         (1 << 5)
+#define ICC_READER_CARD_PRESENT        (1 << 6)
+#define ICC_READER_CARD_POWERED        (1 << 7)
+
+enum ste_state {
+       STE_DISABLED,           /* Reader not present or removed */
+       STE_POWERED_OFF,        /* Card in the reader but powered off */
+       STE_NO_CARD,            /* No card in the reader */
+       STE_ENABLED,            /* Card in the reader and powered on */
+       STE_SIM_BUSY,           /* Modem is busy with ongoing call.*/
+       STE_STATE_MAX
+};
+
+struct ste_u8500 {
+       GIOChannel *io;
+       enum ste_state state;
+       void *sap_data;
+};
+
+typedef int(*recv_state_change_cb)(void *sap, uint8_t result);
+typedef int(*recv_pdu_cb)(void *sap, uint8_t result, uint8_t *data,
+                                                               uint16_t len);
+
+static struct ste_u8500 u8500;
+
+static const uint8_t sim2sap_result[STE_MSG_MAX][STE_STATE_MAX] = {
+       /* SAP results for SEND APDU message */
+       {
+               SAP_RESULT_ERROR_NOT_ACCESSIBLE,        /* STE_DISABLED */
+               SAP_RESULT_ERROR_POWERED_OFF,           /* STE_POWERED_OFF */
+               SAP_RESULT_ERROR_CARD_REMOVED,          /* STE_NO_CARD */
+               SAP_RESULT_ERROR_NO_REASON              /* STE_ENABLED */
+       },
+
+       /* SAP results for GET_ATR message */
+       {
+               SAP_RESULT_ERROR_NO_REASON,
+               SAP_RESULT_ERROR_POWERED_OFF,
+               SAP_RESULT_ERROR_CARD_REMOVED,
+               SAP_RESULT_ERROR_NO_REASON
+       },
+
+       /* SAP results POWER OFF message */
+       {
+               SAP_RESULT_ERROR_NO_REASON,
+               SAP_RESULT_ERROR_POWERED_OFF,
+               SAP_RESULT_ERROR_CARD_REMOVED,
+               SAP_RESULT_ERROR_NO_REASON
+       },
+
+       /* SAP results POWER ON message */
+       {
+               SAP_RESULT_ERROR_NO_REASON,
+               SAP_RESULT_ERROR_NOT_ACCESSIBLE,
+               SAP_RESULT_ERROR_CARD_REMOVED,
+               SAP_RESULT_ERROR_POWERED_ON
+       },
+
+       /* SAP results SIM RESET message */
+       {
+               SAP_RESULT_ERROR_NO_REASON,
+               SAP_RESULT_ERROR_POWERED_OFF,
+               SAP_RESULT_ERROR_CARD_REMOVED,
+               SAP_RESULT_ERROR_NOT_ACCESSIBLE
+       },
+
+       /* SAP results GET STATUS message */
+       {
+               SAP_RESULT_ERROR_NO_REASON,
+               SAP_RESULT_ERROR_NO_REASON,
+               SAP_RESULT_ERROR_NO_REASON,
+               SAP_RESULT_ERROR_NO_REASON
+       }
+};
+
+static uint8_t get_sap_result(enum ste_msg msg, uint32_t status)
+{
+       if (!u8500.io)
+               return SAP_RESULT_ERROR_NO_REASON;
+
+       switch (status) {
+       case STE_STATUS_OK:
+               return SAP_RESULT_OK;
+
+       case STE_STATUS_FAILURE:
+               return sim2sap_result[msg][u8500.state];
+
+       default:
+               DBG("Can't convert a result (status %u)", status);
+               return SAP_RESULT_ERROR_NO_REASON;
+       }
+}
+
+static int get_sap_reader_status(uint32_t card_status, uint8_t *icc_status)
+{
+       /* Card reader is present, not removable and not ID-1 size. */
+       *icc_status = ICC_READER_PRESENT;
+
+       switch (card_status) {
+       case STE_CARD_STATUS_ACTIVE:
+               *icc_status |= ICC_READER_CARD_POWERED;
+
+       case STE_CARD_STATUS_NOT_ACTIVE:
+       case STE_CARD_STATUS_INVALID:
+               *icc_status |= ICC_READER_CARD_PRESENT;
+
+       case STE_CARD_STATUS_MISSING:
+       case STE_CARD_STATUS_DISCONNECTED:
+               return 0;
+
+       default:
+               DBG("Can't convert reader status %u", card_status);
+
+       case STE_CARD_STATUS_UNKNOWN:
+               return -1;
+       }
+}
+
+static uint8_t get_sap_status_change(uint32_t card_status)
+{
+       if (!u8500.io)
+               return SAP_STATUS_CHANGE_UNKNOWN_ERROR;
+
+       switch (card_status) {
+       case STE_CARD_STATUS_UNKNOWN:
+               return SAP_STATUS_CHANGE_UNKNOWN_ERROR;
+
+       case STE_CARD_STATUS_ACTIVE:
+               u8500.state = STE_ENABLED;
+               return SAP_STATUS_CHANGE_CARD_RESET;
+
+       case STE_CARD_STATUS_NOT_ACTIVE:
+               u8500.state = STE_DISABLED;
+               return SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE;
+
+       case STE_CARD_STATUS_MISSING:
+               u8500.state = STE_DISABLED;
+               return SAP_STATUS_CHANGE_CARD_REMOVED;
+
+       case STE_CARD_STATUS_INVALID:
+               u8500.state = STE_DISABLED;
+               return SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE;
+
+       default:
+               DBG("Can't convert status change %u", card_status);
+               return SAP_STATUS_CHANGE_UNKNOWN_ERROR;
+       }
+}
+
+static int send_message(GIOChannel *io, void *buf, size_t size)
+{
+       gsize written;
+
+       DBG_VERBOSE("io %p, size %zu", io, size);
+
+       if (g_io_channel_write_chars(io, buf, size, &written, NULL) !=
+                                                       G_IO_STATUS_NORMAL)
+               return -EIO;
+
+       return written;
+}
+
+static int send_request(GIOChannel *io, uint16_t id,
+                                               struct sap_parameter *param)
+{
+       int ret;
+       struct ste_message *msg;
+       size_t size = sizeof(*msg);
+
+       DBG_VERBOSE("io %p", io);
+
+       if (param)
+               size += param->len;
+
+       msg = g_try_malloc0(size);
+       if (!msg) {
+               sap_error("sending request failed: %s", strerror(ENOMEM));
+               return -ENOMEM;
+       }
+
+       msg->len = size - sizeof(msg->len);
+       msg->id = id;
+       msg->client_tag = STE_CLIENT_TAG;
+
+       if (param)
+               memcpy(msg->payload, param->val, param->len);
+
+       ret = send_message(io, msg, size);
+       if (ret < 0) {
+               sap_error("sending request failed: %s", strerror(-ret));
+       } else if (ret != (int) size) {
+               sap_error("sending request failed: %d out of %zu bytes sent",
+                                                               ret, size);
+               ret = -EIO;
+       }
+
+       g_free(msg);
+
+       return ret;
+}
+
+static void recv_status(uint32_t status)
+{
+       sap_status_ind(u8500.sap_data, get_sap_status_change(status));
+}
+
+static void recv_card_status(uint32_t status, uint8_t *param)
+{
+       uint32_t *card_status;
+       uint8_t result;
+       uint8_t iccrs;
+
+       if (status != STE_STATUS_OK)
+               return;
+
+       card_status = (uint32_t *)param;
+
+       if (get_sap_reader_status(*card_status, &iccrs) < 0)
+               result = SAP_RESULT_ERROR_NO_REASON;
+       else
+               result = get_sap_result(STE_GET_STATUS_MSG, status);
+
+       sap_transfer_card_reader_status_rsp(u8500.sap_data, result, iccrs);
+}
+
+static void recv_state_change(uint32_t ste_msg, uint32_t status,
+                       uint32_t new_state, recv_state_change_cb callback)
+{
+       if (status != STE_STATUS_OK)
+               return;
+
+       u8500.state = new_state;
+
+       if (callback)
+               callback(u8500.sap_data, get_sap_result(ste_msg, status));
+}
+
+static void recv_pdu(uint32_t ste_msg, struct ste_message *msg, uint32_t status,
+                                       uint8_t *param, recv_pdu_cb callback)
+{
+       uint8_t *data = NULL;
+       uint8_t result;
+       int size = 0;
+
+       if (status == STE_STATUS_OK) {
+               data = param;
+               size = STE_MSG_PAYLOAD_SIZE(msg) - sizeof(status);
+       }
+
+       result = get_sap_result(ste_msg, status);
+
+       if (callback)
+               callback(u8500.sap_data, result, data, size);
+}
+
+static void simd_close(void)
+{
+       DBG("io %p", u8500.io);
+
+       if (u8500.io) {
+               g_io_channel_shutdown(u8500.io, TRUE, NULL);
+               g_io_channel_unref(u8500.io);
+       }
+
+       u8500.state = STE_DISABLED;
+       u8500.io = NULL;
+       u8500.sap_data = NULL;
+}
+
+static void recv_sim_ready()
+{
+       sap_info("sim is ready. Try to connect again");
+
+       if (send_request(u8500.io, STE_START_SAP_REQ, NULL) < 0) {
+               sap_connect_rsp(u8500.sap_data, SAP_STATUS_CONNECTION_FAILED,
+                                                               SAP_BUF_SIZE);
+               simd_close();
+       }
+}
+
+static void recv_connect_rsp(uint32_t status)
+{
+       switch (status) {
+       case STE_STATUS_OK:
+               if (u8500.state != STE_SIM_BUSY)
+                       sap_connect_rsp(u8500.sap_data,
+                                       SAP_STATUS_OK, 0);
+               break;
+       case STE_STATUS_BUSY_CALL:
+               if (u8500.state != STE_SIM_BUSY) {
+                       sap_connect_rsp(u8500.sap_data,
+                               SAP_STATUS_OK_ONGOING_CALL,
+                               SAP_BUF_SIZE);
+
+                       u8500.state = STE_SIM_BUSY;
+               }
+               break;
+       default:
+               sap_connect_rsp(u8500.sap_data,
+                               SAP_STATUS_CONNECTION_FAILED, 0);
+               simd_close();
+               break;
+       }
+}
+
+static void recv_response(struct ste_message *msg)
+{
+       uint32_t status;
+       uint8_t *param;
+
+       DBG_VERBOSE("msg_id 0x%x", msg->id);
+
+       if (msg->id == STE_END_SAP_RSP) {
+               sap_disconnect_rsp(u8500.sap_data);
+               simd_close();
+               return;
+       }
+
+       param = msg->payload;
+       status = *(uint32_t *)param;
+       param += sizeof(status);
+
+       DBG_VERBOSE("status 0x%x", status);
+
+       switch (msg->id) {
+       case STE_START_SAP_RSP:
+               recv_connect_rsp(status);
+               break;
+       case STE_SEND_APDU_RSP:
+               recv_pdu(STE_SEND_APDU_MSG, msg, status, param,
+                                                       sap_transfer_apdu_rsp);
+               break;
+
+       case STE_GET_ATR_RSP:
+               recv_pdu(STE_GET_ATR_MSG, msg, status, param,
+                                                       sap_transfer_atr_rsp);
+               break;
+
+       case STE_POWER_OFF_RSP:
+               recv_state_change(STE_POWER_OFF_MSG, status, STE_POWERED_OFF,
+                                                       sap_power_sim_off_rsp);
+               break;
+
+       case STE_POWER_ON_RSP:
+               recv_state_change(STE_POWER_ON_MSG, status, STE_ENABLED,
+                                                       sap_power_sim_on_rsp);
+               break;
+
+       case STE_RESET_RSP:
+               recv_state_change(STE_RESET_MSG, status, STE_ENABLED,
+                                                       sap_reset_sim_rsp);
+               break;
+
+       case STE_GET_STATUS_RSP:
+               recv_card_status(status, param);
+               break;
+
+       case STE_STATUS_IND:
+               recv_status(status);
+               break;
+
+       case STE_SIM_READY_IND:
+               recv_sim_ready();
+               break;
+
+       default:
+               sap_error("unsupported message received (id 0x%x)", msg->id);
+       }
+}
+
+static int recv_message(void *buf, size_t size)
+{
+       uint8_t *iter = buf;
+       struct ste_message *msg = buf;
+
+       do {
+               DBG_VERBOSE("size %zu msg->len %u.", size, msg->len);
+
+               if (size < sizeof(*msg)) {
+                       sap_error("invalid message received (%zu bytes)", size);
+                       return -EBADMSG;
+               }
+
+               /* Message must be complete. */
+               if (size < (msg->len + sizeof(msg->len))) {
+                       sap_error("incomplete message received (%zu bytes)",
+                                                                       size);
+                       return -EBADMSG;
+               }
+
+               recv_response(msg);
+
+               /* Reduce total buffer size by just handled frame size. */
+               size -= msg->len + sizeof(msg->len);
+
+               /* Move msg pointer to the next message if any. */
+               iter += msg->len + sizeof(msg->len);
+               msg = (struct ste_message *)iter;
+       } while (size > 0);
+
+       return 0;
+}
+
+static gboolean simd_data_cb(GIOChannel *io, GIOCondition cond, gpointer data)
+{
+       char buf[SAP_BUF_SIZE];
+       gsize bytes_read;
+       GIOStatus gstatus;
+
+       if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
+               DBG("Error condition on sim socket (0x%x)", cond);
+               return FALSE;
+       }
+
+       gstatus = g_io_channel_read_chars(io, buf, sizeof(buf), &bytes_read,
+                                                                       NULL);
+       if (gstatus != G_IO_STATUS_NORMAL) {
+               sap_error("error while reading from channel (%d)", gstatus);
+               return TRUE;
+       }
+
+       if (recv_message(buf, bytes_read) < 0)
+               sap_error("error while parsing STE Sim message");
+
+       return TRUE;
+}
+
+static void simd_watch(int sock, void *sap_data)
+{
+       GIOChannel *io;
+
+       DBG("sock %d, sap_data %p ", sock, sap_data);
+
+       io = g_io_channel_unix_new(sock);
+
+       g_io_channel_set_close_on_unref(io, TRUE);
+       g_io_channel_set_encoding(io, NULL, NULL);
+       g_io_channel_set_buffered(io, FALSE);
+
+       u8500.io = io;
+       u8500.sap_data = sap_data;
+       u8500.state = STE_DISABLED;
+
+       g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
+                       G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+                       simd_data_cb, NULL, NULL);
+}
+
+static int simd_connect(void *sap_data)
+{
+       struct sockaddr_un addr;
+       int sock;
+       int err;
+
+       /* Already connected to simd */
+       if (u8500.io)
+               return -EALREADY;
+
+       sock = socket(PF_UNIX, SOCK_STREAM, 0);
+       if (sock < 0) {
+               err = -errno;
+               sap_error("creating socket failed: %s", strerror(-err));
+               return err;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       memcpy(addr.sun_path, STE_SIMD_SOCK, sizeof(STE_SIMD_SOCK) - 1);
+
+       if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               err = -errno;
+               sap_error("connect to the socket failed: %s", strerror(-err));
+               goto failed;
+       }
+
+       if (fcntl(sock, F_SETFL, O_NONBLOCK) > 0) {
+               err = -errno;
+               sap_error("setting up socket failed: %s", strerror(-err));
+               goto failed;
+       }
+
+       simd_watch(sock, sap_data);
+
+       return 0;
+
+failed:
+       close(sock);
+       return err;
+}
+
+void sap_connect_req(void *sap_device, uint16_t maxmsgsize)
+{
+       DBG("sap_device %p maxmsgsize %u", sap_device, maxmsgsize);
+
+       sap_info("connect request");
+
+       if (simd_connect(sap_device) < 0) {
+               sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED, 0);
+               return;
+       }
+
+       if (send_request(u8500.io, STE_START_SAP_REQ, NULL) < 0) {
+               sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED,
+                                                               SAP_BUF_SIZE);
+               simd_close();
+       }
+}
+
+void sap_disconnect_req(void *sap_device, uint8_t linkloss)
+{
+       DBG("sap_device %p linkloss %u", sap_device, linkloss);
+
+       sap_info("disconnect request %s", linkloss ? "by link loss" : "");
+
+       if (u8500.state == STE_DISABLED) {
+               sap_disconnect_rsp(sap_device);
+               simd_close();
+               return;
+       }
+
+       if (linkloss) {
+               simd_close();
+               return;
+       }
+
+       if (send_request(u8500.io, STE_END_SAP_REQ, NULL) < 0) {
+               sap_disconnect_rsp(sap_device);
+               return;
+       }
+}
+
+void sap_transfer_apdu_req(void *sap_device, struct sap_parameter *param)
+{
+       uint8_t result;
+
+       DBG_VERBOSE("sap_device %p param %p", sap_device, param);
+
+       if (u8500.state != STE_ENABLED) {
+               result = get_sap_result(STE_SEND_APDU_MSG, STE_STATUS_FAILURE);
+               sap_transfer_apdu_rsp(sap_device, result, NULL, 0);
+               return;
+       }
+
+       if (send_request(u8500.io, STE_SEND_APDU_REQ, param) < 0)
+               sap_transfer_apdu_rsp(sap_device, SAP_RESULT_ERROR_NO_DATA,
+                                                               NULL, 0);
+}
+
+void sap_transfer_atr_req(void *sap_device)
+{
+       uint8_t result;
+
+       DBG("sap_device %p", sap_device);
+
+       if (u8500.state != STE_ENABLED) {
+               result = get_sap_result(STE_GET_ATR_MSG, STE_STATUS_FAILURE);
+               sap_transfer_atr_rsp(sap_device, result, NULL, 0);
+               return;
+       }
+
+       if (send_request(u8500.io, STE_GET_ATR_REQ, NULL) < 0)
+               sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_NO_DATA, NULL,
+                                                                       0);
+}
+
+void sap_power_sim_off_req(void *sap_device)
+{
+       uint8_t result;
+
+       DBG("sap_device %p", sap_device);
+
+       if (u8500.state != STE_ENABLED) {
+               result = get_sap_result(STE_POWER_OFF_MSG, STE_STATUS_FAILURE);
+               sap_power_sim_off_rsp(sap_device, result);
+               return;
+       }
+
+       if (send_request(u8500.io, STE_POWER_OFF_REQ, NULL) < 0)
+               sap_power_sim_off_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
+}
+
+void sap_power_sim_on_req(void *sap_device)
+{
+       uint8_t result;
+
+       DBG("sap_device %p", sap_device);
+
+       if (u8500.state != STE_POWERED_OFF) {
+               result = get_sap_result(STE_POWER_ON_MSG, STE_STATUS_FAILURE);
+               sap_power_sim_on_rsp(sap_device, result);
+               return;
+       }
+
+       if (send_request(u8500.io, STE_POWER_ON_REQ, NULL) < 0)
+               sap_power_sim_on_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
+}
+
+void sap_reset_sim_req(void *sap_device)
+{
+       uint8_t result;
+
+       DBG("sap_device %p", sap_device);
+
+       if (u8500.state != STE_ENABLED) {
+               result = get_sap_result(STE_RESET_MSG, STE_STATUS_FAILURE);
+               sap_reset_sim_rsp(sap_device, result);
+               return;
+       }
+
+       if (send_request(u8500.io, STE_RESET_REQ, NULL) < 0)
+               sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
+}
+
+void sap_transfer_card_reader_status_req(void *sap_device)
+{
+       uint8_t result;
+
+       DBG("sap_device %p", sap_device);
+
+       if (u8500.state == STE_DISABLED) {
+               result = get_sap_result(STE_GET_STATUS_MSG, STE_STATUS_FAILURE);
+               sap_transfer_card_reader_status_rsp(sap_device, result, 0);
+               return;
+       }
+
+       if (send_request(u8500.io, STE_GET_STATUS_REQ, NULL) < 0)
+               sap_transfer_card_reader_status_rsp(sap_device,
+                                               SAP_RESULT_ERROR_NO_DATA, 0);
+}
+
+void sap_set_transport_protocol_req(void *sap_device,
+                                               struct sap_parameter *param)
+{
+       DBG("sap_device %p", sap_device);
+
+       sap_transport_protocol_rsp(sap_device, SAP_RESULT_NOT_SUPPORTED);
+}
+
+int sap_init(void)
+{
+       u8500.state = STE_DISABLED;
+       info("STE U8500 SAP driver initialized");
+       return 0;
+}
+
+void sap_exit(void)
+{
+}
index bd0f06d..1dbb235 100644 (file)
--- a/sap/sap.h
+++ b/sap/sap.h
@@ -84,17 +84,6 @@ struct sap_message {
        struct sap_parameter param[0];
 } __attribute__((packed));
 
-enum {
-       ICC_READER_UNSPECIFIED_ERROR, /* No further information available */
-       ICC_READER_NOT_PRESENT,       /* Card Reader removed or not present */
-       ICC_READER_BUSY,              /* Card Reader in use */
-       ICC_READER_CARD_POWERED_ON,   /* Card in reader and is powered on */
-       ICC_READER_DEACTIVATED,       /* Card Reader deactivated */
-       ICC_READER_CARD_POWERED_OFF,  /* Card in reader, but powered off */
-       ICC_READER_NO_CARD,           /* No card in reader */
-       ICC_READER_LAST
-};
-
 #define SAP_BUF_SIZE           512
 #define SAP_MSG_HEADER_SIZE    4
 
@@ -143,7 +132,7 @@ enum sap_param_id {
 #define SAP_PARAM_ID_DISCONNECT_IND_LEN                0x01
 #define SAP_PARAM_ID_CARD_READER_STATUS_LEN    0x01
 #define SAP_PARAM_ID_STATUS_CHANGE_LEN         0x01
-#define SAP_PARAM_ID_TRANSPORT_PROTOCOL_LEN    0x01
+#define SAP_PARAM_ID_TRANSPORT_PROTO_LEN       0x01
 
 /* Transport Protocol - SAP v1.1 section 5.2.9 */
 enum sap_transport_protocol {
@@ -184,3 +173,4 @@ int sap_transport_protocol_rsp(void *sap_device, uint8_t result);
 
 /* Event indication. Implemented by server.c*/
 int sap_status_ind(void *sap_device, uint8_t status_change);
+int sap_disconnect_ind(void *sap_device, uint8_t disc_type);
index 1c62a3e..b8aa8a5 100644 (file)
 #define SAP_SERVER_INTERFACE   "org.bluez.SimAccess"
 #define SAP_UUID               "0000112D-0000-1000-8000-00805F9B34FB"
 #define SAP_SERVER_CHANNEL     8
-#define SAP_BUF_SIZE           512
+
+#define PADDING4(x) ((4 - (x & 0x03)) & 0x03)
+#define PARAMETER_SIZE(x) (sizeof(struct sap_parameter) + x + PADDING4(x))
+
+#define SAP_NO_REQ 0xFF
+
+#define SAP_TIMER_GRACEFUL_DISCONNECT 30
+#define SAP_TIMER_NO_ACTIVITY 30
 
 enum {
        SAP_STATE_DISCONNECTED,
+       SAP_STATE_CONNECT_IN_PROGRESS,
+       SAP_STATE_CONNECT_MODEM_BUSY,
        SAP_STATE_CONNECTED,
+       SAP_STATE_GRACEFUL_DISCONNECT,
+       SAP_STATE_IMMEDIATE_DISCONNECT,
+       SAP_STATE_CLIENT_DISCONNECT
 };
 
 struct sap_connection {
        GIOChannel *io;
        uint32_t state;
+       uint8_t processing_req;
+       guint timer_id;
 };
 
 struct sap_server {
@@ -71,6 +85,110 @@ struct sap_server {
 static DBusConnection *connection;
 static struct sap_server *server;
 
+static void start_guard_timer(struct sap_connection *conn, guint interval);
+static void stop_guard_timer(struct sap_connection *conn);
+static gboolean guard_timeout(gpointer data);
+
+static size_t add_result_parameter(uint8_t result,
+                                       struct sap_parameter *param)
+{
+       param->id = SAP_PARAM_ID_RESULT_CODE;
+       param->len = htons(SAP_PARAM_ID_RESULT_CODE_LEN);
+       *param->val = result;
+
+       return PARAMETER_SIZE(SAP_PARAM_ID_RESULT_CODE_LEN);
+}
+
+static int is_power_sim_off_req_allowed(uint8_t processing_req)
+{
+       switch (processing_req) {
+       case SAP_NO_REQ:
+       case SAP_TRANSFER_APDU_REQ:
+       case SAP_TRANSFER_ATR_REQ:
+       case SAP_POWER_SIM_ON_REQ:
+       case SAP_RESET_SIM_REQ:
+       case SAP_TRANSFER_CARD_READER_STATUS_REQ:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static int is_reset_sim_req_allowed(uint8_t processing_req)
+{
+       switch (processing_req) {
+       case SAP_NO_REQ:
+       case SAP_TRANSFER_APDU_REQ:
+       case SAP_TRANSFER_ATR_REQ:
+       case SAP_TRANSFER_CARD_READER_STATUS_REQ:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static int check_msg(struct sap_message *msg)
+{
+       if (!msg)
+               return -EINVAL;
+
+       switch (msg->id) {
+       case SAP_CONNECT_REQ:
+               if (msg->nparam != 0x01)
+                       return -EBADMSG;
+
+               if (msg->param->id != SAP_PARAM_ID_MAX_MSG_SIZE)
+                       return -EBADMSG;
+
+               if (ntohs(msg->param->len) != SAP_PARAM_ID_MAX_MSG_SIZE_LEN)
+                       return -EBADMSG;
+
+               break;
+
+       case SAP_TRANSFER_APDU_REQ:
+               if (msg->nparam != 0x01)
+                       return -EBADMSG;
+
+               if (msg->param->id != SAP_PARAM_ID_COMMAND_APDU)
+                       if ( msg->param->id != SAP_PARAM_ID_COMMAND_APDU7816)
+                               return -EBADMSG;
+
+               if (msg->param->len == 0x00)
+                       return -EBADMSG;
+
+               break;
+
+       case SAP_SET_TRANSPORT_PROTOCOL_REQ:
+               if (msg->nparam != 0x01)
+                       return -EBADMSG;
+
+               if (msg->param->id != SAP_PARAM_ID_TRANSPORT_PROTOCOL)
+                       return -EBADMSG;
+
+               if (ntohs(msg->param->len) != SAP_PARAM_ID_TRANSPORT_PROTO_LEN)
+                       return -EBADMSG;
+
+               if (*msg->param->val != SAP_TRANSPORT_PROTOCOL_T0)
+                       if (*msg->param->val != SAP_TRANSPORT_PROTOCOL_T1)
+                               return -EBADMSG;
+
+               break;
+
+       case SAP_DISCONNECT_REQ:
+       case SAP_TRANSFER_ATR_REQ:
+       case SAP_POWER_SIM_OFF_REQ:
+       case SAP_POWER_SIM_ON_REQ:
+       case SAP_RESET_SIM_REQ:
+       case SAP_TRANSFER_CARD_READER_STATUS_REQ:
+               if (msg->nparam != 0x00)
+                       return -EBADMSG;
+
+               break;
+       }
+
+       return 0;
+}
+
 static sdp_record_t *create_sap_record(uint8_t channel)
 {
        sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id;
@@ -83,6 +201,7 @@ static sdp_record_t *create_sap_record(uint8_t channel)
        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);
@@ -126,127 +245,779 @@ static sdp_record_t *create_sap_record(uint8_t channel)
        return record;
 }
 
+static int send_message(struct sap_connection *conn, void *buf, size_t size)
+{
+       size_t written = 0;
+       GError *gerr = NULL;
+       GIOStatus gstatus;
+
+       if (!conn || !buf)
+               return -EINVAL;
+
+       DBG("conn %p, size %zu", conn, size);
+
+       gstatus = g_io_channel_write_chars(conn->io, buf, size, &written,
+                                                                       &gerr);
+       if (gstatus != G_IO_STATUS_NORMAL) {
+               if (gerr)
+                       g_error_free(gerr);
+
+               error("write error (0x%02x).", gstatus);
+               return -EIO;
+       }
+
+       if (written != size) {
+               error("written %zu bytes out of %zu", written, size);
+               return -EIO;
+       }
+
+       return written;
+}
+
+static int disconnect_ind(void *sap_device, uint8_t disc_type)
+{
+       struct sap_connection *conn = sap_device;
+       char buf[SAP_BUF_SIZE];
+       struct sap_message *msg = (struct sap_message *) buf;
+       struct sap_parameter *param = (struct sap_parameter *) msg->param;
+       size_t size = sizeof(struct sap_message);
+
+       if (!conn)
+               return -EINVAL;
+
+       DBG("data %p state %d disc_type 0x%02x", conn, conn->state, disc_type);
+
+       if (conn->state != SAP_STATE_GRACEFUL_DISCONNECT &&
+                       conn->state != SAP_STATE_IMMEDIATE_DISCONNECT) {
+               error("Processing error (state %d pr 0x%02x)", conn->state,
+                                                       conn->processing_req);
+               return -EPERM;
+       }
+
+       memset(buf, 0, sizeof(buf));
+       msg->id = SAP_DISCONNECT_IND;
+       msg->nparam = 0x01;
+
+       /* Add disconnection type param. */
+       param->id  = SAP_PARAM_ID_DISCONNECT_IND;
+       param->len = htons(SAP_PARAM_ID_DISCONNECT_IND_LEN);
+       *param->val = disc_type;
+       size += PARAMETER_SIZE(SAP_PARAM_ID_DISCONNECT_IND_LEN);
+
+       return send_message(sap_device, buf, size);
+}
+
 static void connect_req(struct sap_connection *conn,
-                                       struct sap_parameter *param)
+                               struct sap_parameter *param)
 {
-       DBG("SAP_CONNECT_REQUEST");
+       uint16_t maxmsgsize, *val;
+
+       DBG("conn %p state %d", conn, conn->state);
+
+       if (!param)
+               goto error_rsp;
+
+       if (conn->state != SAP_STATE_DISCONNECTED)
+               goto error_rsp;
+
+       stop_guard_timer(conn);
+
+       val = (uint16_t *) &param->val;
+       maxmsgsize = ntohs(*val);
+
+       DBG("Connect MaxMsgSize: 0x%04x", maxmsgsize);
+
+       conn->state = SAP_STATE_CONNECT_IN_PROGRESS;
+
+       if (maxmsgsize <= SAP_BUF_SIZE) {
+               conn->processing_req = SAP_CONNECT_REQ;
+               sap_connect_req(conn, maxmsgsize);
+       } else {
+               sap_connect_rsp(conn, SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED,
+                                                               SAP_BUF_SIZE);
+       }
+
+       return;
+
+error_rsp:
+       sap_error_rsp(conn);
 }
 
 static int disconnect_req(struct sap_connection *conn, uint8_t disc_type)
 {
-       DBG("SAP_DISCONNECT_REQUEST");
-       return 0;
+       DBG("conn %p state %d disc_type 0x%02x", conn, conn->state, disc_type);
+
+       switch (disc_type) {
+       case SAP_DISCONNECTION_TYPE_GRACEFUL:
+               if (conn->state == SAP_STATE_DISCONNECTED ||
+                               conn->state == SAP_STATE_CONNECT_IN_PROGRESS ||
+                               conn->state == SAP_STATE_CONNECT_MODEM_BUSY)
+                       return -EPERM;
+
+               if (conn->state == SAP_STATE_CONNECTED) {
+                       conn->state = SAP_STATE_GRACEFUL_DISCONNECT;
+                       conn->processing_req = SAP_NO_REQ;
+
+                       disconnect_ind(conn, disc_type);
+                       /* Timer will disconnect if client won't do.*/
+                       start_guard_timer(conn, SAP_TIMER_GRACEFUL_DISCONNECT);
+               }
+
+               return 0;
+
+       case SAP_DISCONNECTION_TYPE_IMMEDIATE:
+               if (conn->state == SAP_STATE_DISCONNECTED ||
+                               conn->state == SAP_STATE_CONNECT_IN_PROGRESS ||
+                               conn->state == SAP_STATE_CONNECT_MODEM_BUSY)
+                       return -EPERM;
+
+               if (conn->state == SAP_STATE_CONNECTED ||
+                               conn->state == SAP_STATE_GRACEFUL_DISCONNECT) {
+                       conn->state = SAP_STATE_IMMEDIATE_DISCONNECT;
+                       conn->processing_req = SAP_NO_REQ;
+
+                       stop_guard_timer(conn);
+                       disconnect_ind(conn, disc_type);
+                       sap_disconnect_req(conn, 0);
+               }
+
+               return 0;
+
+       case SAP_DISCONNECTION_TYPE_CLIENT:
+               if (conn->state != SAP_STATE_CONNECTED &&
+                               conn->state != SAP_STATE_GRACEFUL_DISCONNECT) {
+                       sap_error_rsp(conn);
+                       return -EPERM;
+               }
+
+               conn->state = SAP_STATE_CLIENT_DISCONNECT;
+               conn->processing_req = SAP_NO_REQ;
+
+               stop_guard_timer(conn);
+               sap_disconnect_req(conn, 0);
+
+               return 0;
+
+       default:
+               error("Unknown disconnection type (0x%02x).", disc_type);
+               return -EINVAL;
+       }
 }
 
 static void transfer_apdu_req(struct sap_connection *conn,
                                        struct sap_parameter *param)
 {
-       DBG("SAP_APDU_REQUEST");
+       DBG("conn %p state %d", conn, conn->state);
+
+       if (!param)
+               goto error_rsp;
+
+       param->len = ntohs(param->len);
+
+       if (conn->state != SAP_STATE_CONNECTED &&
+                       conn->state != SAP_STATE_GRACEFUL_DISCONNECT)
+               goto error_rsp;
+
+       if (conn->processing_req != SAP_NO_REQ)
+               goto error_rsp;
+
+       conn->processing_req = SAP_TRANSFER_APDU_REQ;
+       sap_transfer_apdu_req(conn, param);
+
+       return;
+
+error_rsp:
+       sap_error_rsp(conn);
 }
 
 static void transfer_atr_req(struct sap_connection *conn)
 {
-       DBG("SAP_ATR_REQUEST");
+       DBG("conn %p state %d", conn, conn->state);
+
+       if (conn->state != SAP_STATE_CONNECTED)
+               goto error_rsp;
+
+       if (conn->processing_req != SAP_NO_REQ)
+               goto error_rsp;
+
+       conn->processing_req = SAP_TRANSFER_ATR_REQ;
+       sap_transfer_atr_req(conn);
+
+       return;
+
+error_rsp:
+       sap_error_rsp(conn);
 }
 
 static void power_sim_off_req(struct sap_connection *conn)
 {
-       DBG("SAP_SIM_OFF_REQUEST");
+       DBG("conn %p state %d", conn, conn->state);
+
+       if (conn->state != SAP_STATE_CONNECTED)
+               goto error_rsp;
+
+       if (!is_power_sim_off_req_allowed(conn->processing_req))
+               goto error_rsp;
+
+       conn->processing_req = SAP_POWER_SIM_OFF_REQ;
+       sap_power_sim_off_req(conn);
+
+       return;
+
+error_rsp:
+       sap_error_rsp(conn);
 }
 
 static void power_sim_on_req(struct sap_connection *conn)
 {
-       DBG("SAP_SIM_ON_REQUEST");
+       DBG("conn %p state %d", conn, conn->state);
+
+       if (conn->state != SAP_STATE_CONNECTED)
+               goto error_rsp;
+
+       if (conn->processing_req != SAP_NO_REQ)
+               goto error_rsp;
+
+       conn->processing_req = SAP_POWER_SIM_ON_REQ;
+       sap_power_sim_on_req(conn);
+
+       return;
+
+error_rsp:
+       sap_error_rsp(conn);
 }
 
 static void reset_sim_req(struct sap_connection *conn)
 {
-       DBG("SAP_RESET_SIM_REQUEST");
+       DBG("conn %p state %d", conn, conn->state);
+
+       if (conn->state != SAP_STATE_CONNECTED)
+               goto error_rsp;
+
+       if (!is_reset_sim_req_allowed(conn->processing_req))
+               goto error_rsp;
+
+       conn->processing_req = SAP_RESET_SIM_REQ;
+       sap_reset_sim_req(conn);
+
+       return;
+
+error_rsp:
+       sap_error_rsp(conn);
 }
 
 static void transfer_card_reader_status_req(struct sap_connection *conn)
 {
-       DBG("SAP_TRANSFER_CARD_READER_STATUS_REQUEST");
+       DBG("conn %p state %d", conn, conn->state);
+
+       if (conn->state != SAP_STATE_CONNECTED)
+               goto error_rsp;
+
+       if (conn->processing_req != SAP_NO_REQ)
+               goto error_rsp;
+
+       conn->processing_req = SAP_TRANSFER_CARD_READER_STATUS_REQ;
+       sap_transfer_card_reader_status_req(conn);
+
+       return;
+
+error_rsp:
+       sap_error_rsp(conn);
 }
 
 static void set_transport_protocol_req(struct sap_connection *conn,
                                        struct sap_parameter *param)
 {
-       DBG("SAP_SET_TRANSPORT_PROTOCOL_REQUEST");
+       if (!param)
+               goto error_rsp;
+
+       DBG("conn %p state %d param %p", conn, conn->state, param);
+
+       if (conn->state != SAP_STATE_CONNECTED)
+               goto error_rsp;
+
+       if (conn->processing_req != SAP_NO_REQ)
+               goto error_rsp;
+
+       conn->processing_req = SAP_SET_TRANSPORT_PROTOCOL_REQ;
+       sap_set_transport_protocol_req(conn, param);
+
+       return;
+
+error_rsp:
+       sap_error_rsp(conn);
+}
+
+static void start_guard_timer(struct sap_connection *conn, guint interval)
+{
+       if (!conn)
+               return;
+
+       if (!conn->timer_id)
+               conn->timer_id = g_timeout_add_seconds(interval, guard_timeout,
+                                                                       conn);
+       else
+               error("Timer is already active.");
+}
+
+static void stop_guard_timer(struct sap_connection *conn)
+{
+       if (conn  && conn->timer_id) {
+               g_source_remove(conn->timer_id);
+               conn->timer_id = 0;
+       }
+}
+
+static gboolean guard_timeout(gpointer data)
+{
+       struct sap_connection *conn = data;
+
+       if (!conn)
+               return FALSE;
+
+       DBG("conn %p state %d pr 0x%02x", conn, conn->state,
+                                               conn->processing_req);
+
+       conn->timer_id = 0;
+
+       switch (conn->state) {
+       case SAP_STATE_DISCONNECTED:
+               /* Client opened RFCOMM channel but didn't send CONNECT_REQ,
+                * in fixed time or client disconnected SAP connection but
+                * didn't closed RFCOMM channel in fixed time.*/
+               if (conn->io) {
+                       g_io_channel_shutdown(conn->io, TRUE, NULL);
+                       g_io_channel_unref(conn->io);
+               }
+               break;
+
+       case SAP_STATE_GRACEFUL_DISCONNECT:
+               /* Client didn't disconnect SAP connection in fixed time,
+                * so close SAP connection immediately. */
+               disconnect_req(conn, SAP_DISCONNECTION_TYPE_IMMEDIATE);
+               break;
+
+       default:
+               error("Unexpected state (%d).", conn->state);
+               break;
+       }
+
+       return FALSE;
+}
+
+static void sap_set_connected(struct sap_connection *conn)
+{
+       gboolean connected = TRUE;
+
+       emit_property_changed(connection, server->path,
+                                       SAP_SERVER_INTERFACE,
+               "Connected", DBUS_TYPE_BOOLEAN, &connected);
+
+       conn->state = SAP_STATE_CONNECTED;
 }
 
 int sap_connect_rsp(void *sap_device, uint8_t status, uint16_t maxmsgsize)
 {
-       return 0;
+       struct sap_connection *conn = sap_device;
+       char buf[SAP_BUF_SIZE];
+       struct sap_message *msg = (struct sap_message *) buf;
+       struct sap_parameter *param = (struct sap_parameter *) msg->param;
+       size_t size = sizeof(struct sap_message);
+
+       if (!conn)
+               return -EINVAL;
+
+       DBG("state %d pr 0x%02x status 0x%02x", conn->state,
+                                               conn->processing_req, status);
+
+       if (conn->state != SAP_STATE_CONNECT_IN_PROGRESS)
+               return -EPERM;
+
+       memset(buf, 0, sizeof(buf));
+       msg->id = SAP_CONNECT_RESP;
+       msg->nparam = 0x01;
+
+       /* Add connection status */
+       param->id = SAP_PARAM_ID_CONN_STATUS;
+       param->len = htons(SAP_PARAM_ID_CONN_STATUS_LEN);
+       *param->val = status;
+       size += PARAMETER_SIZE(SAP_PARAM_ID_CONN_STATUS_LEN);
+
+       /* Add MaxMsgSize */
+       if (maxmsgsize) {
+               uint16_t *len;
+
+               msg->nparam++;
+               param = (struct sap_parameter *) &buf[size];
+               param->id = SAP_PARAM_ID_MAX_MSG_SIZE;
+               param->len = htons(SAP_PARAM_ID_MAX_MSG_SIZE_LEN);
+               len = (uint16_t *) &param->val;
+               *len = htons(maxmsgsize);
+               size += PARAMETER_SIZE(SAP_PARAM_ID_MAX_MSG_SIZE_LEN);
+       }
+
+       if (status == SAP_STATUS_OK) {
+               sap_set_connected(conn);
+       } else if (status == SAP_STATUS_OK_ONGOING_CALL) {
+               DBG("ongoing call. Wait for reset indication!");
+               conn->state = SAP_STATE_CONNECT_MODEM_BUSY;
+       } else {
+               conn->state = SAP_STATE_DISCONNECTED;
+
+               /* Timer will shutdown channel if client doesn't send
+                * CONNECT_REQ or doesn't shutdown channel itself.*/
+               start_guard_timer(conn, SAP_TIMER_NO_ACTIVITY);
+       }
+
+       conn->processing_req = SAP_NO_REQ;
+
+       return send_message(sap_device, buf, size);
 }
 
 int sap_disconnect_rsp(void *sap_device)
 {
+       struct sap_connection *conn = sap_device;
+       struct sap_message msg;
+
+       if (!conn)
+               return -EINVAL;
+
+       DBG("state %d pr 0x%02x", conn->state, conn->processing_req);
+
+       switch (conn->state) {
+       case SAP_STATE_CLIENT_DISCONNECT:
+               memset(&msg, 0, sizeof(msg));
+               msg.id = SAP_DISCONNECT_RESP;
+
+               conn->state = SAP_STATE_DISCONNECTED;
+               conn->processing_req = SAP_NO_REQ;
+
+               /* Timer will close channel if client doesn't do it.*/
+               start_guard_timer(conn, SAP_TIMER_NO_ACTIVITY);
+
+               return send_message(sap_device, &msg, sizeof(msg));
+
+       case SAP_STATE_IMMEDIATE_DISCONNECT:
+               conn->state = SAP_STATE_DISCONNECTED;
+               conn->processing_req = SAP_NO_REQ;
+
+               if (conn->io) {
+                       g_io_channel_shutdown(conn->io, TRUE, NULL);
+                       g_io_channel_unref(conn->io);
+               }
+
+               return 0;
+
+       default:
+               break;
+       }
+
        return 0;
 }
 
 int sap_transfer_apdu_rsp(void *sap_device, uint8_t result, uint8_t *apdu,
                                        uint16_t length)
 {
-       return 0;
+       struct sap_connection *conn = sap_device;
+       char buf[SAP_BUF_SIZE];
+       struct sap_message *msg = (struct sap_message *) buf;
+       struct sap_parameter *param = (struct sap_parameter *) msg->param;
+       size_t size = sizeof(struct sap_message);
+
+       if (!conn)
+               return -EINVAL;
+
+       DBG("state %d pr 0x%02x", conn->state, conn->processing_req);
+
+       if (conn->processing_req != SAP_TRANSFER_APDU_REQ)
+               return 0;
+
+       if (result == SAP_RESULT_OK && (!apdu || (apdu && length == 0x00)))
+               return -EINVAL;
+
+       memset(buf, 0, sizeof(buf));
+       msg->id = SAP_TRANSFER_APDU_RESP;
+       msg->nparam = 0x01;
+       size += add_result_parameter(result, param);
+
+       /* Add APDU response. */
+       if (result == SAP_RESULT_OK) {
+               msg->nparam++;
+               param = (struct sap_parameter *) &buf[size];
+               param->id = SAP_PARAM_ID_RESPONSE_APDU;
+               param->len = htons(length);
+
+               size += PARAMETER_SIZE(length);
+
+               if (size > SAP_BUF_SIZE)
+                       return -EOVERFLOW;
+
+               memcpy(param->val, apdu, length);
+       }
+
+       conn->processing_req = SAP_NO_REQ;
+
+       return send_message(sap_device, buf, size);
 }
 
 int sap_transfer_atr_rsp(void *sap_device, uint8_t result, uint8_t *atr,
                                        uint16_t length)
 {
-       return 0;
+       struct sap_connection *conn = sap_device;
+       char buf[SAP_BUF_SIZE];
+       struct sap_message *msg = (struct sap_message *) buf;
+       struct sap_parameter *param = (struct sap_parameter *) msg->param;
+       size_t size = sizeof(struct sap_message);
+
+       if (!conn)
+               return -EINVAL;
+
+       DBG("result 0x%02x state %d pr 0x%02x len %d", result, conn->state,
+                       conn->processing_req, length);
+
+       if (conn->processing_req != SAP_TRANSFER_ATR_REQ)
+               return 0;
+
+       if (result == SAP_RESULT_OK && (!atr || (atr && length == 0x00)))
+               return -EINVAL;
+
+       memset(buf, 0, sizeof(buf));
+       msg->id = SAP_TRANSFER_ATR_RESP;
+       msg->nparam = 0x01;
+       size += add_result_parameter(result, param);
+
+       /* Add ATR response */
+       if (result == SAP_RESULT_OK) {
+               msg->nparam++;
+               param = (struct sap_parameter *) &buf[size];
+               param->id = SAP_PARAM_ID_ATR;
+               param->len = htons(length);
+               size += PARAMETER_SIZE(length);
+
+               if (size > SAP_BUF_SIZE)
+                       return -EOVERFLOW;
+
+               memcpy(param->val, atr, length);
+       }
+
+       conn->processing_req = SAP_NO_REQ;
+
+       return send_message(sap_device, buf, size);
 }
 
 int sap_power_sim_off_rsp(void *sap_device, uint8_t result)
 {
-       return 0;
+       struct sap_connection *conn = sap_device;
+       char buf[SAP_BUF_SIZE];
+       struct sap_message *msg = (struct sap_message *) buf;
+       size_t size = sizeof(struct sap_message);
+
+       if (!conn)
+               return -EINVAL;
+
+       DBG("state %d pr 0x%02x", conn->state, conn->processing_req);
+
+       if (conn->processing_req != SAP_POWER_SIM_OFF_REQ)
+               return 0;
+
+       memset(buf, 0, sizeof(buf));
+       msg->id = SAP_POWER_SIM_OFF_RESP;
+       msg->nparam = 0x01;
+       size += add_result_parameter(result, msg->param);
+
+       conn->processing_req = SAP_NO_REQ;
+
+       return send_message(sap_device, buf, size);
 }
 
 int sap_power_sim_on_rsp(void *sap_device, uint8_t result)
 {
-       return 0;
+       struct sap_connection *conn = sap_device;
+       char buf[SAP_BUF_SIZE];
+       struct sap_message *msg = (struct sap_message *) buf;
+       size_t size = sizeof(struct sap_message);
+
+       if (!conn)
+               return -EINVAL;
+
+       DBG("state %d pr 0x%02x", conn->state, conn->processing_req);
+
+       if (conn->processing_req != SAP_POWER_SIM_ON_REQ)
+               return 0;
+
+       memset(buf, 0, sizeof(buf));
+       msg->id = SAP_POWER_SIM_ON_RESP;
+       msg->nparam = 0x01;
+       size += add_result_parameter(result, msg->param);
+
+       conn->processing_req = SAP_NO_REQ;
+
+       return send_message(sap_device, buf, size);
 }
 
 int sap_reset_sim_rsp(void *sap_device, uint8_t result)
 {
-       return 0;
+       struct sap_connection *conn = sap_device;
+       char buf[SAP_BUF_SIZE];
+       struct sap_message *msg = (struct sap_message *) buf;
+       size_t size = sizeof(struct sap_message);
+
+       if (!conn)
+               return -EINVAL;
+
+       DBG("state %d pr 0x%02x result 0x%02x", conn->state,
+                                       conn->processing_req, result);
+
+       if (conn->processing_req != SAP_RESET_SIM_REQ)
+               return 0;
+
+       memset(buf, 0, sizeof(buf));
+       msg->id = SAP_RESET_SIM_RESP;
+       msg->nparam = 0x01;
+       size += add_result_parameter(result, msg->param);
+
+       conn->processing_req = SAP_NO_REQ;
+
+       return send_message(sap_device, buf, size);
 }
 
 int sap_transfer_card_reader_status_rsp(void *sap_device, uint8_t result,
                                                uint8_t status)
 {
-       return 0;
+       struct sap_connection *conn = sap_device;
+       char buf[SAP_BUF_SIZE];
+       struct sap_message *msg = (struct sap_message *) buf;
+       struct sap_parameter *param = (struct sap_parameter *) msg->param;
+       size_t size = sizeof(struct sap_message);
+
+       if (!conn)
+               return -EINVAL;
+
+       DBG("state %d pr 0x%02x result 0x%02x", conn->state,
+                                       conn->processing_req, result);
+
+       if (conn->processing_req != SAP_TRANSFER_CARD_READER_STATUS_REQ)
+               return 0;
+
+       memset(buf, 0, sizeof(buf));
+       msg->id = SAP_TRANSFER_CARD_READER_STATUS_RESP;
+       msg->nparam = 0x01;
+       size += add_result_parameter(result, param);
+
+       /* Add card reader status. */
+       if (result == SAP_RESULT_OK) {
+               msg->nparam++;
+               param = (struct sap_parameter *) &buf[size];
+               param->id = SAP_PARAM_ID_CARD_READER_STATUS;
+               param->len = htons(SAP_PARAM_ID_CARD_READER_STATUS_LEN);
+               *param->val = status;
+               size += PARAMETER_SIZE(SAP_PARAM_ID_CARD_READER_STATUS_LEN);
+       }
+
+       conn->processing_req = SAP_NO_REQ;
+
+       return send_message(sap_device, buf, size);
 }
 
 int sap_transport_protocol_rsp(void *sap_device, uint8_t result)
 {
-       return 0;
+       struct sap_connection *conn = sap_device;
+       char buf[SAP_BUF_SIZE];
+       struct sap_message *msg = (struct sap_message *) buf;
+       size_t size = sizeof(struct sap_message);
+
+       if (!conn)
+               return -EINVAL;
+
+       DBG("state %d pr 0x%02x result 0x%02x", conn->state,
+                                       conn->processing_req, result);
+
+       if (conn->processing_req != SAP_SET_TRANSPORT_PROTOCOL_REQ)
+               return 0;
+
+       memset(buf, 0, sizeof(buf));
+       msg->id = SAP_SET_TRANSPORT_PROTOCOL_RESP;
+       msg->nparam = 0x01;
+       size += add_result_parameter(result, msg->param);
+
+       conn->processing_req = SAP_NO_REQ;
+
+       return send_message(sap_device, buf, size);
 }
 
 int sap_error_rsp(void *sap_device)
 {
-       return 0;
+       struct sap_message msg;
+       struct sap_connection *conn = sap_device;
+
+       memset(&msg, 0, sizeof(msg));
+       msg.id = SAP_ERROR_RESP;
+
+       error("SAP error (state %d pr 0x%02x).", conn->state,
+                                                       conn->processing_req);
+
+       return send_message(conn, &msg, sizeof(msg));
 }
 
 int sap_status_ind(void *sap_device, uint8_t status_change)
 {
-       return 0;
+       struct sap_connection *conn = sap_device;
+       char buf[SAP_BUF_SIZE];
+       struct sap_message *msg = (struct sap_message *) buf;
+       struct sap_parameter *param = (struct sap_parameter *) msg->param;
+       size_t size = sizeof(struct sap_message);
+
+       if (!conn)
+               return -EINVAL;
+
+       DBG("state %d pr 0x%02x sc 0x%02x", conn->state, conn->processing_req,
+                               status_change);
+
+       /* Might be need to change state to connected after ongoing call.*/
+       if (conn->state == SAP_STATE_CONNECT_MODEM_BUSY &&
+                       status_change == SAP_STATUS_CHANGE_CARD_RESET)
+               sap_set_connected(conn);
+
+       if (conn->state != SAP_STATE_CONNECTED &&
+                       conn->state != SAP_STATE_GRACEFUL_DISCONNECT)
+               return 0;
+
+       memset(buf, 0, sizeof(buf));
+       msg->id = SAP_STATUS_IND;
+       msg->nparam = 0x01;
+
+       /* Add status change. */
+       param->id  = SAP_PARAM_ID_STATUS_CHANGE;
+       param->len = htons(SAP_PARAM_ID_STATUS_CHANGE_LEN);
+       *param->val = status_change;
+       size += PARAMETER_SIZE(SAP_PARAM_ID_STATUS_CHANGE_LEN);
+
+       return send_message(sap_device, buf, size);
 }
 
-static int handle_cmd(void *data, void *buf, size_t size)
+int sap_disconnect_ind(void *sap_device, uint8_t disc_type)
+{
+       struct sap_connection *conn = sap_device;
+
+       return disconnect_req(conn, SAP_DISCONNECTION_TYPE_IMMEDIATE);
+}
+
+static int handle_cmd(struct sap_connection *conn, void *buf, size_t size)
 {
        struct sap_message *msg = buf;
-       struct sap_connection *conn = data;
 
        if (!conn)
                return -EINVAL;
 
        if (size < sizeof(struct sap_message))
-               return -EINVAL;
+               goto error_rsp;
 
        if (msg->nparam != 0 && size < (sizeof(struct sap_message) +
                                        sizeof(struct sap_parameter) + 4))
-               return -EBADMSG;
+               goto error_rsp;
+
+       if (check_msg(msg) < 0)
+               goto error_rsp;
 
        switch (msg->id) {
        case SAP_CONNECT_REQ:
@@ -277,11 +1048,14 @@ static int handle_cmd(void *data, void *buf, size_t size)
                set_transport_protocol_req(conn, msg->param);
                return 0;
        default:
-               DBG("SAP unknown message.");
-               return -ENOMSG;
+               DBG("Unknown SAP message id 0x%02x.", msg->id);
+               break;
        }
 
-       return -1;
+error_rsp:
+       DBG("Invalid SAP message format.");
+       sap_error_rsp(conn);
+       return -EBADMSG;
 }
 
 static void sap_conn_remove(struct sap_connection *conn)
@@ -303,12 +1077,14 @@ static void sap_conn_remove(struct sap_connection *conn)
 
 static gboolean sap_io_cb(GIOChannel *io, GIOCondition cond, gpointer data)
 {
+       struct sap_connection *conn = data;
+
        char buf[SAP_BUF_SIZE];
        size_t bytes_read = 0;
        GError *gerr = NULL;
        GIOStatus gstatus;
 
-       DBG("io %p", io);
+       DBG("conn %p io %p", conn, io);
 
        if (cond & G_IO_NVAL) {
                DBG("ERR (G_IO_NVAL) on rfcomm socket.");
@@ -326,7 +1102,7 @@ static gboolean sap_io_cb(GIOChannel *io, GIOCondition cond, gpointer data)
        }
 
        gstatus = g_io_channel_read_chars(io, buf, sizeof(buf) - 1,
-                               &bytes_read, &gerr);
+                                                       &bytes_read, &gerr);
        if (gstatus != G_IO_STATUS_NORMAL) {
                if (gerr)
                        g_error_free(gerr);
@@ -334,8 +1110,8 @@ static gboolean sap_io_cb(GIOChannel *io, GIOCondition cond, gpointer data)
                return TRUE;
        }
 
-       if (handle_cmd(data, buf, bytes_read) < 0)
-               error("Invalid SAP message.");
+       if (handle_cmd(conn, buf, bytes_read) < 0)
+               error("SAP protocol processing failure.");
 
        return TRUE;
 }
@@ -347,7 +1123,22 @@ static void sap_io_destroy(void *data)
        DBG("conn %p", conn);
 
        if (conn && conn->io) {
-               conn->io = NULL;
+               gboolean connected = FALSE;
+
+               stop_guard_timer(conn);
+
+               if (conn->state != SAP_STATE_CONNECT_IN_PROGRESS &&
+                               conn->state != SAP_STATE_CONNECT_MODEM_BUSY)
+                       emit_property_changed(connection, server->path,
+                                       SAP_SERVER_INTERFACE, "Connected",
+                                       DBUS_TYPE_BOOLEAN, &connected);
+
+               if (conn->state == SAP_STATE_CONNECT_IN_PROGRESS ||
+                               conn->state == SAP_STATE_CONNECT_MODEM_BUSY ||
+                               conn->state == SAP_STATE_CONNECTED ||
+                               conn->state == SAP_STATE_GRACEFUL_DISCONNECT)
+                       sap_disconnect_req(NULL, 1);
+
                sap_conn_remove(conn);
        }
 }
@@ -356,11 +1147,15 @@ static void sap_connect_cb(GIOChannel *io, GError *gerr, gpointer data)
 {
        struct sap_connection *conn = data;
 
-       DBG("io %p gerr %p data %p ", io, gerr, data);
+       DBG("conn %p, io %p", conn, io);
 
        if (!conn)
                return;
 
+       /* Timer will shutdown the channel in case of lack of client
+          activity */
+       start_guard_timer(conn, SAP_TIMER_NO_ACTIVITY);
+
        g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
                        G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
                        sap_io_cb, conn, sap_io_destroy);
@@ -371,13 +1166,13 @@ static void connect_auth_cb(DBusError *derr, void *data)
        struct sap_connection *conn = data;
        GError *gerr = NULL;
 
-       DBG("derr %p data %p ", derr, data);
+       DBG("conn %p", conn);
 
        if (!conn)
                return;
 
        if (derr && dbus_error_is_set(derr)) {
-               error("Access denied: %s", derr->message);
+               error("Access has been denied (%s)", derr->message);
                sap_conn_remove(conn);
                return;
        }
@@ -389,7 +1184,7 @@ static void connect_auth_cb(DBusError *derr, void *data)
                return;
        }
 
-       DBG("Client has been authorized.");
+       DBG("Access has been granted.");
 }
 
 static void connect_confirm_cb(GIOChannel *io, gpointer data)
@@ -397,14 +1192,16 @@ static void connect_confirm_cb(GIOChannel *io, gpointer data)
        struct sap_connection *conn = server->conn;
        GError *gerr = NULL;
        bdaddr_t src, dst;
+       char dstaddr[18];
        int err;
 
-       DBG("io %p data %p ", io, data);
+       DBG("conn %p io %p", conn, io);
 
        if (!io)
                return;
 
        if (conn) {
+               DBG("Another SAP connection already exists.");
                g_io_channel_shutdown(io, TRUE, NULL);
                return;
        }
@@ -434,23 +1231,24 @@ static void connect_confirm_cb(GIOChannel *io, gpointer data)
                return;
        }
 
-       err = btd_request_authorization(&src, &dst, SAP_UUID,
-                                       connect_auth_cb, conn);
+       ba2str(&dst, dstaddr);
+
+       err = btd_request_authorization(&src, &dst, SAP_UUID, connect_auth_cb,
+                                                                       conn);
        if (err < 0) {
-               DBG("Authorization denied: %d %s", err,  strerror(err));
+               error("Authorization failure (err %d)", err);
                sap_conn_remove(conn);
                return;
        }
 
-       DBG("SAP incoming connection (sock %d) authorization.",
-                               g_io_channel_unix_get_fd(io));
+       DBG("Authorizing incomming SAP connection from %s", dstaddr);
 }
 
 static inline DBusMessage *message_failed(DBusMessage *msg,
                                        const char *description)
 {
-       return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
-                               "%s", description);
+       return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "%s",
+                                                               description);
 }
 
 static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg,
@@ -458,8 +1256,6 @@ static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg,
 {
        struct sap_server *server = data;
 
-       DBG("server %p", server);
-
        if (!server)
                return message_failed(msg, "Server internal error.");
 
@@ -468,6 +1264,10 @@ static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg,
        if (!server->conn)
                return message_failed(msg, "Client already disconnected");
 
+       if (disconnect_req(server->conn, SAP_DISCONNECTION_TYPE_GRACEFUL) < 0)
+               return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+                                       "There is no active connection");
+
        return dbus_message_new_method_return(msg);
 }
 
@@ -494,7 +1294,8 @@ static DBusMessage *get_properties(DBusConnection *c,
                        DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
                        DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
 
-       connected = (conn->state == SAP_STATE_CONNECTED);
+       connected = (conn->state == SAP_STATE_CONNECTED ||
+                               conn->state == SAP_STATE_GRACEFUL_DISCONNECT);
        dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &connected);
 
        dbus_message_iter_close_container(&iter, &dict);
@@ -521,14 +1322,15 @@ static void server_free(struct sap_server *server)
        sap_conn_remove(server->conn);
        g_free(server->path);
        g_free(server);
+       server = NULL;
 }
 
 static void destroy_sap_interface(void *data)
 {
        struct sap_server *server = data;
 
-       DBG("Unregistered interface %s on path %s",
-                       SAP_SERVER_INTERFACE, server->path);
+       DBG("Unregistered interface %s on path %s", SAP_SERVER_INTERFACE,
+                                                               server->path);
 
        server_free(server);
 }
@@ -586,10 +1388,10 @@ int sap_server_register(const char *path, bdaddr_t *src)
        server->conn = NULL;
 
        if (!g_dbus_register_interface(connection, path, SAP_SERVER_INTERFACE,
-                               server_methods, server_signals, NULL,
-                               server, destroy_sap_interface)) {
+                                       server_methods, server_signals, NULL,
+                                       server, destroy_sap_interface)) {
                error("D-Bus failed to register %s interface",
-                                               SAP_SERVER_INTERFACE);
+                                                       SAP_SERVER_INTERFACE);
                goto server_err;
        }
 
@@ -599,7 +1401,6 @@ server_err:
        remove_record_from_server(server->record_id);
 sdp_err:
        server_free(server);
-       server = NULL;
        sap_exit();
 
        return -1;
@@ -623,8 +1424,6 @@ int sap_server_unregister(const char *path)
 
        g_dbus_unregister_interface(connection, path, SAP_SERVER_INTERFACE);
 
-       server_free(server);
-       server = NULL;
        sap_exit();
 
        return 0;
index 77fcc5d..c5015ab 100644 (file)
--- a/sbc/sbc.c
+++ b/sbc/sbc.c
@@ -383,7 +383,7 @@ static int sbc_unpack_frame(const uint8_t *data, struct sbc_frame *frame,
        int crc_pos = 0;
        int32_t temp;
 
-       int audio_sample;
+       uint32_t audio_sample;
        int ch, sb, blk, bit;   /* channel, subband, block and bit standard
                                   counters */
        int bits[2][8];         /* bits distribution */
@@ -493,23 +493,30 @@ static int sbc_unpack_frame(const uint8_t *data, struct sbc_frame *frame,
        for (blk = 0; blk < frame->blocks; blk++) {
                for (ch = 0; ch < frame->channels; ch++) {
                        for (sb = 0; sb < frame->subbands; sb++) {
-                               if (levels[ch][sb] > 0) {
-                                       audio_sample = 0;
-                                       for (bit = 0; bit < bits[ch][sb]; bit++) {
-                                               if (consumed > len * 8)
-                                                       return -1;
+                               uint32_t shift;
 
-                                               if ((data[consumed >> 3] >> (7 - (consumed & 0x7))) & 0x01)
-                                                       audio_sample |= 1 << (bits[ch][sb] - bit - 1);
+                               if (levels[ch][sb] == 0) {
+                                       frame->sb_sample[blk][ch][sb] = 0;
+                                       continue;
+                               }
 
-                                               consumed++;
-                                       }
+                               shift = frame->scale_factor[ch][sb] +
+                                               1 + SBCDEC_FIXED_EXTRA_BITS;
 
-                                       frame->sb_sample[blk][ch][sb] =
-                                               (((audio_sample << 1) | 1) << frame->scale_factor[ch][sb]) /
-                                               levels[ch][sb] - (1 << frame->scale_factor[ch][sb]);
-                               } else
-                                       frame->sb_sample[blk][ch][sb] = 0;
+                               audio_sample = 0;
+                               for (bit = 0; bit < bits[ch][sb]; bit++) {
+                                       if (consumed > len * 8)
+                                               return -1;
+
+                                       if ((data[consumed >> 3] >> (7 - (consumed & 0x7))) & 0x01)
+                                               audio_sample |= 1 << (bits[ch][sb] - bit - 1);
+
+                                       consumed++;
+                               }
+
+                               frame->sb_sample[blk][ch][sb] = (int32_t)
+                                       (((((uint64_t) audio_sample << 1) | 1) << shift) /
+                                       levels[ch][sb]) - (1 << shift);
                        }
                }
        }
index 9f126c6..5476860 100644 (file)
@@ -48,7 +48,7 @@ typedef int32_t sbc_fixed_t;
 
 #define SBC_FIXED_0(val) { val = 0; }
 #define MUL(a, b)        ((a) * (b))
-#ifdef __arm__
+#if defined(__arm__) && (!defined(__thumb__) || defined(__thumb2__))
 #define MULA(a, b, res) ({                             \
                int tmp = res;                  \
                __asm__(                                \
index 9586098..b321272 100644 (file)
@@ -41,7 +41,7 @@
 static void __attribute__((naked)) sbc_analyze_four_armv6()
 {
        /* r0 = in, r1 = out, r2 = consts */
-       asm volatile (
+       __asm__ volatile (
                "push   {r1, r4-r7, lr}\n"
                "push   {r8-r11}\n"
                "ldrd   r4,  r5,  [r0, #0]\n"
@@ -112,7 +112,7 @@ static void __attribute__((naked)) sbc_analyze_four_armv6()
 static void __attribute__((naked)) sbc_analyze_eight_armv6()
 {
        /* r0 = in, r1 = out, r2 = consts */
-       asm volatile (
+       __asm__ volatile (
                "push   {r1, r4-r7, lr}\n"
                "push   {r8-r11}\n"
                "ldrd   r4,  r5,  [r0, #24]\n"
index 1862aed..6a9efe5 100644 (file)
@@ -40,8 +40,8 @@
 
 #if !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15) && \
        defined(__GNUC__) && defined(SBC_HAVE_ARMV6) && \
-       defined(__ARM_EABI__) && !defined(__thumb__) && \
-       !defined(__ARM_NEON__)
+       defined(__ARM_EABI__) && !defined(__ARM_NEON__) && \
+       (!defined(__thumb__) || defined(__thumb2__))
 
 #define SBC_BUILD_WITH_ARMV6_SUPPORT
 
index 213967e..e0bd060 100644 (file)
@@ -42,7 +42,7 @@
 static inline void sbc_analyze_four_iwmmxt(const int16_t *in, int32_t *out,
                                        const FIXED_T *consts)
 {
-       asm volatile (
+       __asm__ volatile (
                "wldrd        wr0, [%0]\n"
                "tbcstw       wr4, %2\n"
                "wldrd        wr2, [%1]\n"
@@ -115,7 +115,7 @@ static inline void sbc_analyze_four_iwmmxt(const int16_t *in, int32_t *out,
 static inline void sbc_analyze_eight_iwmmxt(const int16_t *in, int32_t *out,
                                                        const FIXED_T *consts)
 {
-       asm volatile (
+       __asm__ volatile (
                "wldrd        wr0, [%0]\n"
                "tbcstw       wr15, %2\n"
                "wldrd        wr1, [%0, #8]\n"
index 7f2fbc3..27e9a56 100644 (file)
@@ -45,7 +45,7 @@ static inline void sbc_analyze_four_mmx(const int16_t *in, int32_t *out,
                1 << (SBC_PROTO_FIXED4_SCALE - 1),
                1 << (SBC_PROTO_FIXED4_SCALE - 1),
        };
-       asm volatile (
+       __asm__ volatile (
                "movq        (%0), %%mm0\n"
                "movq       8(%0), %%mm1\n"
                "pmaddwd     (%1), %%mm0\n"
@@ -111,7 +111,7 @@ static inline void sbc_analyze_eight_mmx(const int16_t *in, int32_t *out,
                1 << (SBC_PROTO_FIXED8_SCALE - 1),
                1 << (SBC_PROTO_FIXED8_SCALE - 1),
        };
-       asm volatile (
+       __asm__ volatile (
                "movq        (%0), %%mm0\n"
                "movq       8(%0), %%mm1\n"
                "movq      16(%0), %%mm2\n"
@@ -258,7 +258,7 @@ static inline void sbc_analyze_4b_4s_mmx(int16_t *x, int32_t *out,
        out += out_stride;
        sbc_analyze_four_mmx(x + 0, out, analysis_consts_fixed4_simd_even);
 
-       asm volatile ("emms\n");
+       __asm__ volatile ("emms\n");
 }
 
 static inline void sbc_analyze_4b_8s_mmx(int16_t *x, int32_t *out,
@@ -273,7 +273,7 @@ static inline void sbc_analyze_4b_8s_mmx(int16_t *x, int32_t *out,
        out += out_stride;
        sbc_analyze_eight_mmx(x + 0, out, analysis_consts_fixed8_simd_even);
 
-       asm volatile ("emms\n");
+       __asm__ volatile ("emms\n");
 }
 
 static void sbc_calc_scalefactors_mmx(
@@ -291,7 +291,7 @@ static void sbc_calc_scalefactors_mmx(
                for (sb = 0; sb < subbands; sb += 2) {
                        blk = (blocks - 1) * (((char *) &sb_sample_f[1][0][0] -
                                (char *) &sb_sample_f[0][0][0]));
-                       asm volatile (
+                       __asm__ volatile (
                                "movq         (%4), %%mm0\n"
                        "1:\n"
                                "movq     (%1, %0), %%mm1\n"
@@ -326,7 +326,7 @@ static void sbc_calc_scalefactors_mmx(
                        : "cc", "memory");
                }
        }
-       asm volatile ("emms\n");
+       __asm__ volatile ("emms\n");
 }
 
 static int check_mmx_support(void)
@@ -335,7 +335,7 @@ static int check_mmx_support(void)
        return 1; /* We assume that all 64-bit processors have MMX support */
 #else
        int cpuid_feature_information;
-       asm volatile (
+       __asm__ volatile (
                /* According to Intel manual, CPUID instruction is supported
                 * if the value of ID bit (bit 21) in EFLAGS can be modified */
                "pushf\n"
index 0572158..5d4d0e3 100644 (file)
@@ -44,7 +44,7 @@ static inline void _sbc_analyze_four_neon(const int16_t *in, int32_t *out,
        /* TODO: merge even and odd cases (or even merge all four calls to this
         * function) in order to have only aligned reads from 'in' array
         * and reduce number of load instructions */
-       asm volatile (
+       __asm__ volatile (
                "vld1.16    {d4, d5}, [%0, :64]!\n"
                "vld1.16    {d8, d9}, [%1, :128]!\n"
 
@@ -104,7 +104,7 @@ static inline void _sbc_analyze_eight_neon(const int16_t *in, int32_t *out,
        /* TODO: merge even and odd cases (or even merge all four calls to this
         * function) in order to have only aligned reads from 'in' array
         * and reduce number of load instructions */
-       asm volatile (
+       __asm__ volatile (
                "vld1.16    {d4, d5}, [%0, :64]!\n"
                "vld1.16    {d8, d9}, [%1, :128]!\n"
 
@@ -247,7 +247,7 @@ static void sbc_calc_scalefactors_neon(
                for (sb = 0; sb < subbands; sb += 4) {
                        int blk = blocks;
                        int32_t *in = &sb_sample_f[0][ch][sb];
-                       asm volatile (
+                       __asm__ volatile (
                                "vmov.s32  q0, #0\n"
                                "vmov.s32  q1, %[c1]\n"
                                "vmov.s32  q14, #1\n"
@@ -306,7 +306,7 @@ int sbc_calc_scalefactors_j_neon(
 
        i = subbands;
 
-       asm volatile (
+       __asm__ volatile (
                /*
                 * constants: q13 = (31 - SCALE_OUT_BITS), q14 = 1
                 * input:     q0  = ((1 << SCALE_OUT_BITS) + 1)
@@ -561,7 +561,7 @@ static SBC_ALWAYS_INLINE int sbc_enc_process_input_4s_neon_internal(
        if (position < nsamples) {
                int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 40];
                int16_t *src = &X[0][position];
-               asm volatile (
+               __asm__ volatile (
                        "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
                        "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
                        "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
@@ -575,7 +575,7 @@ static SBC_ALWAYS_INLINE int sbc_enc_process_input_4s_neon_internal(
                if (nchannels > 1) {
                        dst = &X[1][SBC_X_BUFFER_SIZE - 40];
                        src = &X[1][position];
-                       asm volatile (
+                       __asm__ volatile (
                                "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
                                "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
                                "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
@@ -594,7 +594,7 @@ static SBC_ALWAYS_INLINE int sbc_enc_process_input_4s_neon_internal(
                /* poor 'pcm' alignment */
                int16_t *x = &X[0][position];
                int16_t *y = &X[1][position];
-               asm volatile (
+               __asm__ volatile (
                        "vld1.8  {d0, d1}, [%[perm], :128]\n"
                "1:\n"
                        "sub     %[x], %[x], #16\n"
@@ -628,7 +628,7 @@ static SBC_ALWAYS_INLINE int sbc_enc_process_input_4s_neon_internal(
                /* proper 'pcm' alignment */
                int16_t *x = &X[0][position];
                int16_t *y = &X[1][position];
-               asm volatile (
+               __asm__ volatile (
                        "vld1.8  {d0, d1}, [%[perm], :128]\n"
                "1:\n"
                        "sub     %[x], %[x], #16\n"
@@ -658,7 +658,7 @@ static SBC_ALWAYS_INLINE int sbc_enc_process_input_4s_neon_internal(
                          "d20", "d21", "d22", "d23");
        } else {
                int16_t *x = &X[0][position];
-               asm volatile (
+               __asm__ volatile (
                        "vld1.8  {d0, d1}, [%[perm], :128]\n"
                "1:\n"
                        "sub     %[x], %[x], #16\n"
@@ -703,7 +703,7 @@ static SBC_ALWAYS_INLINE int sbc_enc_process_input_8s_neon_internal(
        if (position < nsamples) {
                int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 72];
                int16_t *src = &X[0][position];
-               asm volatile (
+               __asm__ volatile (
                        "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
                        "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
                        "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
@@ -721,7 +721,7 @@ static SBC_ALWAYS_INLINE int sbc_enc_process_input_8s_neon_internal(
                if (nchannels > 1) {
                        dst = &X[1][SBC_X_BUFFER_SIZE - 72];
                        src = &X[1][position];
-                       asm volatile (
+                       __asm__ volatile (
                                "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
                                "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
                                "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
@@ -744,7 +744,7 @@ static SBC_ALWAYS_INLINE int sbc_enc_process_input_8s_neon_internal(
                /* poor 'pcm' alignment */
                int16_t *x = &X[0][position];
                int16_t *y = &X[1][position];
-               asm volatile (
+               __asm__ volatile (
                        "vld1.8  {d0, d1, d2, d3}, [%[perm], :128]\n"
                "1:\n"
                        "sub     %[x], %[x], #32\n"
@@ -782,7 +782,7 @@ static SBC_ALWAYS_INLINE int sbc_enc_process_input_8s_neon_internal(
                /* proper 'pcm' alignment */
                int16_t *x = &X[0][position];
                int16_t *y = &X[1][position];
-               asm volatile (
+               __asm__ volatile (
                        "vld1.8  {d0, d1, d2, d3}, [%[perm], :128]\n"
                "1:\n"
                        "sub     %[x], %[x], #32\n"
@@ -816,7 +816,7 @@ static SBC_ALWAYS_INLINE int sbc_enc_process_input_8s_neon_internal(
                          "d20", "d21", "d22", "d23");
        } else {
                int16_t *x = &X[0][position];
-               asm volatile (
+               __asm__ volatile (
                        "vld1.8  {d0, d1, d2, d3}, [%[perm], :128]\n"
                "1:\n"
                        "sub     %[x], %[x], #32\n"
index 28c0d54..25e24e6 100644 (file)
@@ -40,11 +40,13 @@ static const int sbc_offset8[4][8] = {
        { -4, 0, 0, 0, 0, 0, 1, 2 }
 };
 
+/* extra bits of precision for the synthesis filter input data */
+#define SBCDEC_FIXED_EXTRA_BITS 2
 
 #define SS4(val) ASR(val, SCALE_SPROTO4_TBL)
 #define SS8(val) ASR(val, SCALE_SPROTO8_TBL)
-#define SN4(val) ASR(val, SCALE_NPROTO4_TBL)
-#define SN8(val) ASR(val, SCALE_NPROTO8_TBL)
+#define SN4(val) ASR(val, SCALE_NPROTO4_TBL + 1 + SBCDEC_FIXED_EXTRA_BITS)
+#define SN8(val) ASR(val, SCALE_NPROTO8_TBL + 1 + SBCDEC_FIXED_EXTRA_BITS)
 
 static const int32_t sbc_proto_4_40m0[] = {
        SS4(0x00000000), SS4(0xffa6982f), SS4(0xfba93848), SS4(0x0456c7b8),
index 6d92679..8cfb54a 100644 (file)
@@ -174,7 +174,7 @@ static int analyze_file(char *filename)
        unsigned char buf[64];
        double rate;
        int bitpool[SIZE], frame_len[SIZE];
-       int subbands, blocks, freq, mode, method;
+       int subbands, blocks, freq, method;
        int n, p1, p2, fd, size, num;
        ssize_t len;
        unsigned int count;
@@ -199,7 +199,6 @@ static int analyze_file(char *filename)
        subbands = (hdr.subbands + 1) * 4;
        blocks = (hdr.blocks + 1) * 4;
        freq = hdr.sampling_frequency;
-       mode = hdr.channel_mode;
        method = hdr.allocation_method;
 
        count = calc_frame_len(&hdr);
index b1e3608..c08c22a 100644 (file)
@@ -245,7 +245,7 @@ static int check_absolute_diff(SNDFILE * sndref, SF_INFO * infosref,
        return verdict;
 }
 
-static void usage()
+static void usage(void)
 {
        printf("SBC conformance test ver %s\n", VERSION);
        printf("Copyright (c) 2007-2010  Marcel Holtmann\n");
index 1b231d1..0687c8a 100644 (file)
@@ -1,36 +1,28 @@
-# Variety of Dell Bluetooth devices
-#
-# it looks like a bit of an odd rule, because it is matching
-# on a mouse device that is self powered, but that is where
-# a HID report needs to be sent to switch modes.
-#
-# Known supported devices:
-#   413c:8154
-#   413c:8158
-#   413c:8162
-ACTION=="add", ENV{ID_VENDOR}=="413c", ENV{ID_CLASS}=="mouse", ATTRS{bmAttributes}=="e0", KERNEL=="mouse*", RUN+="/usr/sbin/hid2hci --method dell -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
+# do not edit this file, it will be overwritten on update
+
+ACTION=="remove", GOTO="hid2hci_end"
+SUBSYSTEM!="usb", GOTO="hid2hci_end"
+
+# Variety of Dell Bluetooth devices - match on a mouse device that is
+# self powered and where a HID report needs to be sent to switch modes
+# Known supported devices: 413c:8154, 413c:8158, 413c:8162
+ATTR{bInterfaceClass}=="03", ATTR{bInterfaceSubClass}=="01", ATTR{bInterfaceProtocol}=="02", \
+  ATTRS{bDeviceClass}=="00", ATTRS{idVendor}=="413c", ATTRS{bmAttributes}=="e0", \
+  RUN+="hid2hci --method=dell --devpath=%p", ENV{HID2HCI_SWITCH}="1"
 
 # Logitech devices
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c703" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c704" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c705" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c70a" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c70b" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c70c" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c70e" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c713" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c714" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c71b" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c71c" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
+KERNEL=="hiddev*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c70[345abce]|c71[34bc]", \
+  RUN+="hid2hci --method=logitech-hid --devpath=%p"
+
+ENV{DEVTYPE}!="usb_device", GOTO="hid2hci_end"
+
+# When a Dell device recovers from S3, the mouse child needs to be repoked
+# Unfortunately the only event seen is the BT device disappearing, so the mouse
+# device needs to be chased down on the USB bus.
+ATTR{bDeviceClass}=="e0", ATTR{bDeviceSubClass}=="01", ATTR{bDeviceProtocol}=="01", ATTR{idVendor}=="413c", \
+  ENV{REMOVE_CMD}="/sbin/udevadm trigger --action=change --subsystem-match=usb --property-match=HID2HCI_SWITCH=1"
 
-# CSR devices (in HID mode)
-ACTION=="add", ENV{ID_VENDOR}=="0a12", ENV{ID_MODEL}=="1000" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="0458", ENV{ID_MODEL}=="1000" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="05ac", ENV{ID_MODEL}=="1000" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
+# CSR devices
+ATTR{idVendor}=="0a12|0458|05ac", ATTR{idProduct}=="1000", RUN+="hid2hci --method=csr --devpath=%p"
 
-# CSR devices (in HCI mode)
-#ACTION=="add", ENV{ID_VENDOR}=="0a12", ENV{ID_MODEL}=="0001" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hid"
-#ACTION=="add", ENV{ID_VENDOR}=="0458", ENV{ID_MODEL}=="003f" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hid"
-#ACTION=="add", ENV{ID_VENDOR}=="05ac", ENV{ID_MODEL}=="8203" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hid"
-#ACTION=="add", ENV{ID_VENDOR}=="05ac", ENV{ID_MODEL}=="8204" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hid"
-#ACTION=="add", ENV{ID_VENDOR}=="05ac", ENV{ID_MODEL}=="8207" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hid"
+LABEL="hid2hci_end"
index eba8a91..b609054 100644 (file)
@@ -54,7 +54,6 @@
 #include "device.h"
 
 #include "log.h"
-#include "textfile.h"
 
 #include "error.h"
 #include "port.h"
@@ -96,7 +95,7 @@ static int serial_probe(struct btd_device *device, const char *uuid)
        }
 
        adapter_get_address(adapter, &src);
-       device_get_address(device, &dst);
+       device_get_address(device, &dst, NULL);
 
        return port_register(connection, path, &src, &dst, uuid, ch);
 }
index 7d56faa..5b76d14 100644 (file)
@@ -48,7 +48,9 @@
 #include "../src/dbus-common.h"
 
 #include "log.h"
+#include "glib-compat.h"
 #include "glib-helper.h"
+#include "sdp-client.h"
 #include "btio.h"
 
 #include "error.h"
 #define MAX_OPEN_TRIES         5
 #define OPEN_WAIT              300     /* ms. udev node creation retry wait */
 
+#ifndef DBUS_TYPE_UNIX_FD
+#define DBUS_TYPE_UNIX_FD -1
+#endif
+
 struct serial_device {
        DBusConnection  *conn;          /* for name listener handling */
        bdaddr_t        src;            /* Source (local) address */
@@ -177,20 +183,21 @@ static int port_release(struct serial_port *port)
        req.flags = (1 << RFCOMM_HANGUP_NOW);
 
        if (ioctl(rfcomm_ctl, RFCOMMRELEASEDEV, &req) < 0) {
-               err = errno;
+               err = -errno;
                error("Can't release device %s: %s (%d)",
-                               port->dev, strerror(err), err);
+                               port->dev, strerror(-err), -err);
        }
 
        g_free(port->dev);
        port->dev = NULL;
        port->id = -1;
        close(rfcomm_ctl);
-       return -err;
+       return err;
 }
 
-static void serial_port_free(struct serial_port *port)
+static void serial_port_free(void *data)
 {
+       struct serial_port *port = data;
        struct serial_device *device = port->device;
 
        if (device && port->listener_id > 0)
@@ -202,8 +209,10 @@ static void serial_port_free(struct serial_port *port)
        g_free(port);
 }
 
-static void serial_device_free(struct serial_device *device)
+static void serial_device_free(void *data)
 {
+       struct serial_device *device = data;
+
        g_free(device->path);
        if (device->conn)
                dbus_connection_unref(device->conn);
@@ -232,8 +241,7 @@ static void path_unregister(void *data)
 
 void port_release_all(void)
 {
-       g_slist_foreach(devices, (GFunc) serial_device_free, NULL);
-       g_slist_free(devices);
+       g_slist_free_full(devices, serial_device_free);
 }
 
 static void open_notify(int fd, int err, struct serial_port *port)
@@ -316,6 +324,21 @@ static void rfcomm_connect_cb(GIOChannel *chan, GError *conn_err,
                goto fail;
        }
 
+       sk = g_io_channel_unix_get_fd(chan);
+
+       if (dbus_message_has_member(port->msg, "ConnectFD")) {
+               reply = g_dbus_create_reply(port->msg, DBUS_TYPE_UNIX_FD, &sk,
+                                                       DBUS_TYPE_INVALID);
+               g_dbus_send_message(device->conn, reply);
+
+               close(sk);
+
+               g_dbus_remove_watch(device->conn, port->listener_id);
+               port->listener_id = 0;
+
+               return;
+       }
+
        memset(&req, 0, sizeof(req));
        req.dev_id = -1;
        req.flags = (1 << RFCOMM_REUSE_DLC);
@@ -326,7 +349,6 @@ static void rfcomm_connect_cb(GIOChannel *chan, GError *conn_err,
        g_io_channel_unref(port->io);
        port->io = NULL;
 
-       sk = g_io_channel_unix_get_fd(chan);
        port->id = ioctl(sk, RFCOMMCREATEDEV, &req);
        if (port->id < 0) {
                int err = -errno;
@@ -366,10 +388,8 @@ static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
        DBusMessage *reply;
        GError *gerr = NULL;
 
-       if (!port->listener_id) {
-               reply = NULL;
-               goto failed;
-       }
+       if (!port->listener_id)
+               return;
 
        if (err < 0) {
                error("Unable to get service record: %s (%d)", strerror(-err),
@@ -443,10 +463,10 @@ connect:
                                BT_IO_OPT_DEST_BDADDR, &device->dst,
                                BT_IO_OPT_CHANNEL, port->channel,
                                BT_IO_OPT_INVALID);
-       if (port->io)
-               return 0;
+       if (port->io == NULL)
+               return -EIO;
 
-       return -errno;
+       return 0;
 }
 
 static struct serial_port *create_port(struct serial_device *device,
@@ -474,6 +494,9 @@ static DBusMessage *port_connect(DBusConnection *conn,
        const char *pattern;
        int err;
 
+       if (dbus_message_has_member(msg, "ConnectFD") && DBUS_TYPE_UNIX_FD < 0)
+               return btd_error_not_supported(msg);
+
        if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
                                                DBUS_TYPE_INVALID) == FALSE)
                return NULL;
@@ -497,6 +520,7 @@ static DBusMessage *port_connect(DBusConnection *conn,
                                                dbus_message_get_sender(msg),
                                                port_owner_exited, port,
                                                NULL);
+
        port->msg = dbus_message_ref(msg);
 
        err = connect_port(port);
@@ -544,6 +568,7 @@ static DBusMessage *port_disconnect(DBusConnection *conn,
 
 static GDBusMethodTable port_methods[] = {
        { "Connect",    "s", "s", port_connect, G_DBUS_METHOD_FLAG_ASYNC },
+       { "ConnectFD",    "s", "h", port_connect, G_DBUS_METHOD_FLAG_ASYNC },
        { "Disconnect", "s", "",  port_disconnect },
        { }
 };
@@ -613,8 +638,7 @@ int port_unregister(const char *path)
        if (!device)
                return -ENOENT;
 
-       g_slist_foreach(device->ports, (GFunc) serial_port_free, NULL);
-       g_slist_free(device->ports);
+       g_slist_free_full(device->ports, serial_port_free);
 
        g_dbus_unregister_interface(device->conn, path, SERIAL_PORT_INTERFACE);
 
index 46561d0..736f690 100644 (file)
@@ -53,7 +53,6 @@
 #include "../src/adapter.h"
 
 #include "log.h"
-#include "textfile.h"
 
 #include "error.h"
 #include "sdpd.h"
@@ -208,11 +207,10 @@ static int channel_write(GIOChannel *chan, char *buf, size_t size)
 
        fd = g_io_channel_unix_get_fd(chan);
 
-       wbytes = written = 0;
+       wbytes = 0;
        while (wbytes < size) {
                written = write(fd, buf + wbytes, size - wbytes);
-
-               if (written)
+               if (written < 0)
                        return -errno;
 
                wbytes += written;
@@ -291,19 +289,18 @@ static inline int unix_socket_connect(const char *address)
        /* Unix socket */
        sk = socket(AF_UNIX, SOCK_STREAM, 0);
        if (sk < 0) {
-               err = errno;
+               err = -errno;
                error("Unix socket(%s) create failed: %s(%d)",
-                               address, strerror(err), err);
-               return -err;
+                               address, strerror(-err), -err);
+               return err;
        }
 
        if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               err = errno;
+               err = -errno;
                error("Unix socket(%s) connect failed: %s(%d)",
-                               address, strerror(err), err);
+                               address, strerror(-err), -err);
                close(sk);
-               errno = err;
-               return -err;
+               return err;
        }
 
        return sk;
@@ -312,8 +309,7 @@ static inline int unix_socket_connect(const char *address)
 static int tcp_socket_connect(const char *address)
 {
        struct sockaddr_in addr;
-       int err, sk;
-       unsigned short int port;
+       int err, sk, port;
 
        memset(&addr, 0, sizeof(addr));
 
@@ -332,18 +328,17 @@ static int tcp_socket_connect(const char *address)
 
        sk = socket(PF_INET, SOCK_STREAM, 0);
        if (sk < 0) {
-               err = errno;
+               err = -errno;
                error("TCP socket(%s) create failed %s(%d)", address,
-                                                       strerror(err), err);
-               return -err;
+                                                       strerror(-err), -err);
+               return err;
        }
        if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               err = errno;
+               err = -errno;
                error("TCP socket(%s) connect failed: %s(%d)",
-                                               address, strerror(err), err);
+                                               address, strerror(-err), -err);
                close(sk);
-               errno = err;
-               return -err;
+               return err;
        }
        return sk;
 }
@@ -354,18 +349,17 @@ static inline int tty_open(const char *tty, struct termios *ti)
 
        sk = open(tty, O_RDWR | O_NOCTTY);
        if (sk < 0) {
-               err = errno;
-               error("Can't open TTY %s: %s(%d)", tty, strerror(err), err);
-               return -err;
+               err = -errno;
+               error("Can't open TTY %s: %s(%d)", tty, strerror(-err), -err);
+               return err;
        }
 
        if (ti && tcsetattr(sk, TCSANOW, ti) < 0) {
-               err = errno;
+               err = -errno;
                error("Can't change serial settings: %s(%d)",
-                               strerror(err), err);
+                               strerror(-err), -err);
                close(sk);
-               errno = err;
-               return -err;
+               return err;
        }
 
        return sk;
@@ -812,7 +806,7 @@ static int proxy_tty_register(struct serial_adapter *adapter,
 
        sk = open(address, O_RDONLY | O_NOCTTY);
        if (sk < 0) {
-               error("Cant open TTY: %s(%d)", strerror(errno), errno);
+               error("Can't open TTY: %s(%d)", strerror(errno), errno);
                return -EINVAL;
        }
 
@@ -1147,10 +1141,8 @@ static GDBusSignalTable manager_signals[] = {
 static struct serial_adapter *find_adapter(GSList *list,
                                        struct btd_adapter *btd_adapter)
 {
-       GSList *l;
-
-       for (l = list; l; l = l->next) {
-               struct serial_adapter *adapter = l->data;
+       for (; list; list = list->next) {
+               struct serial_adapter *adapter = list->data;
 
                if (adapter->btd_adapter == btd_adapter)
                        return adapter;
index 2e1df76..29eda3c 100644 (file)
 #include "manager.h"
 #include "device.h"
 #include "dbus-common.h"
-#include "event.h"
 #include "error.h"
+#include "glib-compat.h"
 #include "glib-helper.h"
 #include "agent.h"
 #include "storage.h"
-#include "attrib-server.h"
+#include "gattrib.h"
 #include "att.h"
+#include "attrib-server.h"
+#include "eir.h"
 
 /* Flags Descriptions */
 #define EIR_LIM_DISC                0x01 /* LE Limited Discoverable Mode */
 #define EIR_SIM_HOST                0x10 /* Simultaneous LE and BR/EDR to Same
                                            Device Capable (Host) */
 
-#define ADV_TYPE_IND           0x00
-#define ADV_TYPE_DIRECT_IND    0x01
-
 #define IO_CAPABILITY_DISPLAYONLY      0x00
 #define IO_CAPABILITY_DISPLAYYESNO     0x01
 #define IO_CAPABILITY_KEYBOARDONLY     0x02
 #define IO_CAPABILITY_NOINPUTNOOUTPUT  0x03
 #define IO_CAPABILITY_INVALID          0xFF
 
-/* Limited Discoverable bit mask in CoD */
-#define LIMITED_BIT                    0x002000
 #define check_address(address) bachk(address)
 
+#define OFF_TIMER 3
+
 static DBusConnection *connection = NULL;
 static GSList *adapter_drivers = NULL;
 
@@ -108,10 +107,12 @@ struct service_auth {
 
 struct btd_adapter {
        uint16_t dev_id;
-       int up;
+       gboolean up;
        char *path;                     /* adapter object path */
        bdaddr_t bdaddr;                /* adapter Bluetooth Address */
        uint32_t dev_class;             /* Class of Device */
+       char *name;                     /* adapter name */
+       gboolean allow_name_changes;    /* whether the adapter name can be changed */
        guint discov_timeout_id;        /* discoverable timeout id */
        guint stop_discov_id;           /* stop inquiry/scanning id */
        uint32_t discov_timeout;        /* discoverable time(sec) */
@@ -119,10 +120,6 @@ struct btd_adapter {
        uint32_t pairable_timeout;      /* pairable time(sec) */
        uint8_t scan_mode;              /* scan mode: SCAN_DISABLED, SCAN_PAGE,
                                         * SCAN_INQUIRY */
-#ifdef __TIZEN_PATCH__
-       // Adding Limited state for setting limited discoverable mode
-       gboolean limited;               /* limited discoverable state */
-#endif
        uint8_t mode;                   /* off, connectable, discoverable,
                                         * limited */
        uint8_t global_mode;            /* last valid global mode */
@@ -137,10 +134,12 @@ struct btd_adapter {
        GSList *devices;                /* Devices structure pointers */
        GSList *mode_sessions;          /* Request Mode sessions */
        GSList *disc_sessions;          /* Discovery sessions */
-       guint scheduler_id;             /* Scheduler handle */
+       guint discov_id;                /* Discovery timer */
+       gboolean discovering;           /* Discovery active */
+       gboolean discov_suspended;      /* Discovery suspended */
+       guint auto_timeout_id;          /* Automatic connections timeout */
        sdp_list_t *services;           /* Services associated to adapter */
 
-       struct hci_dev dev;             /* hci info */
        gboolean pairable;              /* pairable state */
        gboolean initialized;
 
@@ -148,172 +147,31 @@ struct btd_adapter {
 
        gint ref;
 
-       GSList *powered_callbacks;
+       guint off_timer;
 
-       gboolean name_stored;
+       GSList *powered_callbacks;
+       GSList *pin_callbacks;
 
        GSList *loaded_drivers;
 };
 
-static void adapter_set_pairable_timeout(struct btd_adapter *adapter,
-                                       guint interval);
-
-static int found_device_cmp(const struct remote_dev_info *d1,
-                       const struct remote_dev_info *d2)
+static void dev_info_free(void *data)
 {
-       int ret;
-
-       if (bacmp(&d2->bdaddr, BDADDR_ANY)) {
-               ret = bacmp(&d1->bdaddr, &d2->bdaddr);
-               if (ret)
-                       return ret;
-       }
-
-       if (d2->name_status != NAME_ANY) {
-               ret = (d1->name_status - d2->name_status);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
+       struct remote_dev_info *dev = data;
 
-static void dev_info_free(struct remote_dev_info *dev)
-{
        g_free(dev->name);
        g_free(dev->alias);
-       g_slist_foreach(dev->services, (GFunc) g_free, NULL);
-       g_slist_free(dev->services);
+       g_slist_free_full(dev->services, g_free);
        g_strfreev(dev->uuids);
        g_free(dev);
 }
 
-/*
- * Device name expansion
- *   %d - device id
- */
-static char *expand_name(char *dst, int size, char *str, int dev_id)
-{
-       register int sp, np, olen;
-       char *opt, buf[10];
-
-       if (!str || !dst)
-               return NULL;
-
-       sp = np = 0;
-       while (np < size - 1 && str[sp]) {
-               switch (str[sp]) {
-               case '%':
-                       opt = NULL;
-
-                       switch (str[sp+1]) {
-                       case 'd':
-                               sprintf(buf, "%d", dev_id);
-                               opt = buf;
-                               break;
-
-                       case 'h':
-                               opt = main_opts.host_name;
-                               break;
-
-                       case '%':
-                               dst[np++] = str[sp++];
-                               /* fall through */
-                       default:
-                               sp++;
-                               continue;
-                       }
-
-                       if (opt) {
-                               /* substitute */
-                               olen = strlen(opt);
-                               if (np + olen < size - 1)
-                                       memcpy(dst + np, opt, olen);
-                               np += olen;
-                       }
-                       sp += 2;
-                       continue;
-
-               case '\\':
-                       sp++;
-                       /* fall through */
-               default:
-                       dst[np++] = str[sp++];
-                       break;
-               }
-       }
-       dst[np] = '\0';
-       return dst;
-}
-
 int btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
                                                                uint8_t minor)
 {
        return adapter_ops->set_dev_class(adapter->dev_id, major, minor);
 }
 
-static int pending_remote_name_cancel(struct btd_adapter *adapter)
-{
-       struct remote_dev_info *dev, match;
-       int err;
-
-       /* find the pending remote name request */
-       memset(&match, 0, sizeof(struct remote_dev_info));
-       bacpy(&match.bdaddr, BDADDR_ANY);
-       match.name_status = NAME_REQUESTED;
-
-       dev = adapter_search_found_devices(adapter, &match);
-       if (!dev) /* no pending request */
-               return -ENODATA;
-
-       err = adapter_ops->cancel_resolve_name(adapter->dev_id, &dev->bdaddr);
-       if (err < 0)
-               error("Remote name cancel failed: %s(%d)",
-                                               strerror(errno), errno);
-       return err;
-}
-
-int adapter_resolve_names(struct btd_adapter *adapter)
-{
-       struct remote_dev_info *dev, match;
-       int err;
-
-       /* Do not attempt to resolve more names if on suspended state */
-       if (adapter->state & STATE_SUSPENDED)
-               return 0;
-
-       memset(&match, 0, sizeof(struct remote_dev_info));
-       bacpy(&match.bdaddr, BDADDR_ANY);
-       match.name_status = NAME_REQUIRED;
-
-       dev = adapter_search_found_devices(adapter, &match);
-       if (!dev)
-               return -ENODATA;
-
-       /* send at least one request or return failed if the list is empty */
-       do {
-               /* flag to indicate the current remote name requested */
-               dev->name_status = NAME_REQUESTED;
-
-               err = adapter_ops->resolve_name(adapter->dev_id, &dev->bdaddr);
-
-               if (!err)
-                       break;
-
-               error("Unable to send HCI remote name req: %s (%d)",
-                                               strerror(errno), errno);
-
-               /* if failed, request the next element */
-               /* remove the element from the list */
-               adapter_remove_found_device(adapter, &dev->bdaddr);
-
-               /* get the next element */
-               dev = adapter_search_found_devices(adapter, &match);
-       } while (dev);
-
-       return err;
-}
-
 static const char *mode2str(uint8_t mode)
 {
        switch(mode) {
@@ -463,10 +321,8 @@ static int adapter_set_mode(struct btd_adapter *adapter, uint8_t mode)
 
 static struct session_req *find_session_by_msg(GSList *list, const DBusMessage *msg)
 {
-       GSList *l;
-
-       for (l = list; l; l = l->next) {
-               struct session_req *req = l->data;
+       for (; list; list = list->next) {
+               struct session_req *req = list->data;
 
                if (req->msg == msg)
                        return req;
@@ -480,13 +336,10 @@ static int set_mode(struct btd_adapter *adapter, uint8_t new_mode,
 {
        int err;
        const char *modestr;
-       gboolean discoverable;
 
        if (adapter->pending_mode != NULL)
                return -EALREADY;
 
-       discoverable = new_mode == MODE_DISCOVERABLE;
-
        if (!adapter->up && new_mode != MODE_OFF) {
                err = adapter_ops->set_powered(adapter->dev_id, TRUE);
                if (err < 0)
@@ -564,19 +417,17 @@ static DBusMessage *set_powered(DBusConnection *conn, DBusMessage *msg,
        struct btd_adapter *adapter = data;
        uint8_t mode;
        int err;
-
-#ifdef __TIZEN_PATCH__
-       if (powered)
-       {
-               mode = adapter->mode ? adapter->mode : get_mode(&adapter->bdaddr, "on");
-
-       }
-       else
-               mode = MODE_OFF;
-#else
+#ifdef __SAMSUNG_PATCH__
        mode = powered ? get_mode(&adapter->bdaddr, "on") : MODE_OFF;
-#endif
+#else
+       if (powered) {
+               mode = get_mode(&adapter->bdaddr, "on");
+               return set_discoverable(conn, msg, mode == MODE_DISCOVERABLE,
+                                                                       data);
+       }
 
+       mode = MODE_OFF;
+#endif
        if (mode == adapter->mode) {
                adapter->global_mode = mode;
                return dbus_message_new_method_return(msg);
@@ -589,22 +440,6 @@ static DBusMessage *set_powered(DBusConnection *conn, DBusMessage *msg,
        return NULL;
 }
 
-void btd_adapter_pairable_changed(struct btd_adapter *adapter,
-                                                       gboolean pairable)
-{
-       adapter->pairable = pairable;
-
-       write_device_pairable(&adapter->bdaddr, pairable);
-
-       emit_property_changed(connection, adapter->path,
-                               ADAPTER_INTERFACE, "Pairable",
-                               DBUS_TYPE_BOOLEAN, &pairable);
-
-       if (pairable && adapter->pairable_timeout)
-               adapter_set_pairable_timeout(adapter,
-                                               adapter->pairable_timeout);
-}
-
 static DBusMessage *set_pairable(DBusConnection *conn, DBusMessage *msg,
                                gboolean pairable, void *data)
 {
@@ -620,11 +455,9 @@ static DBusMessage *set_pairable(DBusConnection *conn, DBusMessage *msg,
        if (!(adapter->scan_mode & SCAN_INQUIRY))
                goto store;
 
-#ifndef __TIZEN_PATCH__
        err = set_mode(adapter, MODE_DISCOVERABLE, NULL);
        if (err < 0 && msg)
                return btd_error_failed(msg, strerror(-err));
-#endif
 
 store:
        adapter_ops->set_pairable(adapter->dev_id, pairable);
@@ -656,12 +489,26 @@ static void adapter_set_pairable_timeout(struct btd_adapter *adapter,
                                                adapter);
 }
 
-static struct session_req *find_session(GSList *list, const char *sender)
+void btd_adapter_pairable_changed(struct btd_adapter *adapter,
+                                                       gboolean pairable)
 {
-       GSList *l;
+       adapter->pairable = pairable;
 
-       for (l = list; l; l = l->next) {
-               struct session_req *req = l->data;
+       write_device_pairable(&adapter->bdaddr, pairable);
+
+       emit_property_changed(connection, adapter->path,
+                               ADAPTER_INTERFACE, "Pairable",
+                               DBUS_TYPE_BOOLEAN, &pairable);
+
+       if (pairable && adapter->pairable_timeout)
+               adapter_set_pairable_timeout(adapter,
+                                               adapter->pairable_timeout);
+}
+
+static struct session_req *find_session(GSList *list, const char *sender)
+{
+       for (; list; list = list->next) {
+               struct session_req *req = list->data;
 
                if (g_str_equal(req->owner, sender))
                        return req;
@@ -693,7 +540,7 @@ static GSList *remove_bredr(GSList *all)
 
        for (l = all, le = NULL; l; l = l->next) {
                struct remote_dev_info *dev = l->data;
-               if (dev->le == FALSE) {
+               if (dev->type == ADDR_TYPE_BREDR) {
                        dev_info_free(dev);
                        continue;
                }
@@ -706,12 +553,10 @@ static GSList *remove_bredr(GSList *all)
        return le;
 }
 
-static void stop_discovery(struct btd_adapter *adapter, gboolean suspend)
+/* Called when a session gets removed or the adapter is stopped */
+static void stop_discovery(struct btd_adapter *adapter)
 {
-       pending_remote_name_cancel(adapter);
-
-       if (suspend == FALSE)
-               adapter->found_devices = remove_bredr(adapter->found_devices);
+       adapter->found_devices = remove_bredr(adapter->found_devices);
 
        if (adapter->oor_devices) {
                g_slist_free(adapter->oor_devices);
@@ -719,22 +564,19 @@ static void stop_discovery(struct btd_adapter *adapter, gboolean suspend)
        }
 
        /* Reset if suspended, otherwise remove timer (software scheduler)
-          or request inquiry to stop */
-       if (adapter->state & STATE_SUSPENDED) {
-               adapter->state &= ~STATE_SUSPENDED;
+        * or request inquiry to stop */
+       if (adapter->discov_suspended) {
+               adapter->discov_suspended = FALSE;
                return;
        }
 
-       if (adapter->scheduler_id) {
-               g_source_remove(adapter->scheduler_id);
-               adapter->scheduler_id = 0;
+       if (adapter->discov_id > 0) {
+               g_source_remove(adapter->discov_id);
+               adapter->discov_id = 0;
                return;
        }
 
-       if (adapter->state & STATE_LE_SCAN)
-               adapter_ops->stop_scanning(adapter->dev_id);
-       else
-               adapter_ops->stop_inquiry(adapter->dev_id);
+       adapter_ops->stop_discovery(adapter->dev_id);
 }
 
 static void session_remove(struct session_req *req)
@@ -771,17 +613,17 @@ static void session_remove(struct session_req *req)
 
                DBG("Stopping discovery");
 
-               stop_discovery(adapter, FALSE);
+               stop_discovery(adapter);
        }
 }
 
-static void session_free(struct session_req *req)
+static void session_free(void *data)
 {
+       struct session_req *req = data;
+
        if (req->id)
                g_dbus_remove_watch(req->conn, req->id);
 
-       session_remove(req);
-
        if (req->msg) {
                dbus_message_unref(req->msg);
                if (!req->got_reply && req->mode && req->adapter->agent)
@@ -800,6 +642,7 @@ static void session_owner_exit(DBusConnection *conn, void *user_data)
 
        req->id = 0;
 
+       session_remove(req);
        session_free(req);
 }
 
@@ -812,6 +655,7 @@ static void session_unref(struct session_req *req)
        if (req->refcount)
                return;
 
+       session_remove(req);
        session_free(req);
 }
 
@@ -924,7 +768,7 @@ void btd_adapter_class_changed(struct btd_adapter *adapter, uint32_t new_class)
        if (main_opts.attrib_server) {
                /* Removes service class */
                class[1] = class[1] & 0x1f;
-               attrib_gap_set(GATT_CHARAC_APPEARANCE, class, 2);
+               attrib_gap_set(adapter, GATT_CHARAC_APPEARANCE, class, 2);
        }
 
        emit_property_changed(connection, adapter->path,
@@ -932,63 +776,64 @@ void btd_adapter_class_changed(struct btd_adapter *adapter, uint32_t new_class)
                                DBUS_TYPE_UINT32, &new_class);
 }
 
-void adapter_update_local_name(struct btd_adapter *adapter, const char *name)
+void adapter_name_changed(struct btd_adapter *adapter, const char *name)
 {
-       struct hci_dev *dev = &adapter->dev;
-
-       if (strncmp(name, dev->name, MAX_NAME_LENGTH) == 0)
+       if (g_strcmp0(adapter->name, name) == 0)
                return;
 
-       strncpy(dev->name, name, MAX_NAME_LENGTH);
+       g_free(adapter->name);
+       adapter->name = g_strdup(name);
+
+       if (connection)
+               emit_property_changed(connection, adapter->path,
+                                       ADAPTER_INTERFACE, "Name",
+                                       DBUS_TYPE_STRING, &name);
 
        if (main_opts.attrib_server)
-               attrib_gap_set(GATT_CHARAC_DEVICE_NAME,
-                       (const uint8_t *) dev->name, strlen(dev->name));
+               attrib_gap_set(adapter, GATT_CHARAC_DEVICE_NAME,
+                               (const uint8_t *) name, strlen(name));
+}
+
+int adapter_set_name(struct btd_adapter *adapter, const char *name)
+{
+       char maxname[MAX_NAME_LENGTH + 1];
 
-       if (!adapter->name_stored) {
-               char *name_ptr = dev->name;
+       if (g_strcmp0(adapter->name, name) == 0)
+               return 0;
 
-               write_local_name(&adapter->bdaddr, dev->name);
+       memset(maxname, 0, sizeof(maxname));
+       strncpy(maxname, name, MAX_NAME_LENGTH);
+       if (!g_utf8_validate(maxname, -1, NULL)) {
+               error("Name change failed: supplied name isn't valid UTF-8");
+               return -EINVAL;
+       }
 
-               if (connection)
-                       emit_property_changed(connection, adapter->path,
-                                               ADAPTER_INTERFACE, "Name",
-                                               DBUS_TYPE_STRING, &name_ptr);
+       if (adapter->up) {
+               int err = adapter_ops->set_name(adapter->dev_id, maxname);
+               if (err < 0)
+                       return err;
        }
 
-       adapter->name_stored = FALSE;
+       write_local_name(&adapter->bdaddr, maxname);
+
+       return 0;
 }
 
 static DBusMessage *set_name(DBusConnection *conn, DBusMessage *msg,
                                        const char *name, void *data)
 {
        struct btd_adapter *adapter = data;
-       struct hci_dev *dev = &adapter->dev;
-       char *name_ptr = dev->name;
-
-       if (!g_utf8_validate(name, -1, NULL)) {
-               error("Name change failed: supplied name isn't valid UTF-8");
-               return btd_error_invalid_args(msg);
-       }
-
-       if (strncmp(name, dev->name, MAX_NAME_LENGTH) == 0)
-               goto done;
-
-       strncpy(dev->name, name, MAX_NAME_LENGTH);
-       write_local_name(&adapter->bdaddr, name);
-       emit_property_changed(connection, adapter->path,
-                                       ADAPTER_INTERFACE, "Name",
-                                       DBUS_TYPE_STRING, &name_ptr);
+       int ret;
 
-       if (adapter->up) {
-               int err = adapter_ops->set_name(adapter->dev_id, name);
-               if (err < 0)
-                       return btd_error_failed(msg, strerror(-err));
+       if (adapter->allow_name_changes == FALSE)
+               return btd_error_failed(msg, strerror(EPERM));
 
-               adapter->name_stored = TRUE;
-       }
+       ret = adapter_set_name(adapter, name);
+       if (ret == -EINVAL)
+               return btd_error_invalid_args(msg);
+       else if (ret < 0)
+               return btd_error_failed(msg, strerror(-ret));
 
-done:
        return dbus_message_new_method_return(msg);
 }
 
@@ -1036,6 +881,9 @@ static void adapter_emit_uuids_updated(struct btd_adapter *adapter)
        int i;
        sdp_list_t *list;
 
+       if (!adapter->initialized)
+               return;
+
        uuids = g_new0(char *, sdp_list_len(adapter->services) + 1);
 
        for (i = 0, list = adapter->services; list; list = list->next) {
@@ -1138,17 +986,11 @@ void adapter_service_remove(struct btd_adapter *adapter, void *r)
 
        adapter_emit_uuids_updated(adapter);
 }
-#ifdef __TIZEN_PATCH__
-sdp_list_t *adapter_get_services(struct btd_adapter *adapter)
-{
-       return adapter->services;
-}
 
-#endif
 static struct btd_device *adapter_create_device(DBusConnection *conn,
                                                struct btd_adapter *adapter,
                                                const char *address,
-                                               device_type_t type)
+                                               addr_type_t type)
 {
        struct btd_device *device;
        const char *path;
@@ -1215,52 +1057,21 @@ struct btd_device *adapter_get_device(DBusConnection *conn,
                return device;
 
        return adapter_create_device(conn, adapter, address,
-                                               DEVICE_TYPE_BREDR);
+                                               ADDR_TYPE_BREDR);
 }
 
-static gboolean stop_scanning(gpointer user_data)
+static gboolean discovery_cb(gpointer user_data)
 {
        struct btd_adapter *adapter = user_data;
+       int err;
 
-       adapter_ops->stop_scanning(adapter->dev_id);
-
-       return FALSE;
-}
-
-static int start_discovery(struct btd_adapter *adapter)
-{
-       int err, type;
-
-       /* Do not start if suspended */
-       if (adapter->state & STATE_SUSPENDED)
-               return 0;
-
-       /* Postpone discovery if still resolving names */
-       if (adapter->state & STATE_RESOLVNAME)
-               return 1;
-
-       pending_remote_name_cancel(adapter);
-
-       type = adapter_get_discover_type(adapter) & ~DISC_RESOLVNAME;
+       adapter->discov_id = 0;
 
-       switch (type) {
-       case DISC_STDINQ:
-       case DISC_INTERLEAVE:
-               err = adapter_ops->start_inquiry(adapter->dev_id,
-                                                       0x08, FALSE);
-               break;
-       case DISC_PINQ:
-               err = adapter_ops->start_inquiry(adapter->dev_id,
-                                                       0x08, TRUE);
-               break;
-       case DISC_LE:
-               err = adapter_ops->start_scanning(adapter->dev_id);
-               break;
-       default:
-               err = -EINVAL;
-       }
+       err = adapter_ops->start_discovery(adapter->dev_id);
+       if (err < 0)
+               error("start_discovery: %s (%d)", strerror(-err), -err);
 
-       return err;
+       return FALSE;
 }
 
 static DBusMessage *adapter_start_discovery(DBusConnection *conn,
@@ -1270,7 +1081,7 @@ static DBusMessage *adapter_start_discovery(DBusConnection *conn,
        struct btd_adapter *adapter = data;
        const char *sender = dbus_message_get_sender(msg);
        int err;
-       info("adapter_start_discovery");
+
        if (!adapter->up)
                return btd_error_not_ready(msg);
 
@@ -1283,14 +1094,16 @@ static DBusMessage *adapter_start_discovery(DBusConnection *conn,
        if (adapter->disc_sessions)
                goto done;
 
-       g_slist_foreach(adapter->found_devices, (GFunc) dev_info_free, NULL);
-       g_slist_free(adapter->found_devices);
+       g_slist_free_full(adapter->found_devices, dev_info_free);
        adapter->found_devices = NULL;
 
        g_slist_free(adapter->oor_devices);
        adapter->oor_devices = NULL;
 
-       err = start_discovery(adapter);
+       if (adapter->discov_suspended)
+               goto done;
+
+       err = adapter_ops->start_discovery(adapter->dev_id);
        if (err < 0)
                return btd_error_failed(msg, strerror(-err));
 
@@ -1322,11 +1135,6 @@ static DBusMessage *adapter_stop_discovery(DBusConnection *conn,
        return dbus_message_new_method_return(msg);
 }
 
-struct remote_device_list_t {
-       GSList *list;
-       time_t time;
-};
-
 static DBusMessage *get_properties(DBusConnection *conn,
                                        DBusMessage *msg, void *data)
 {
@@ -1335,13 +1143,13 @@ static DBusMessage *get_properties(DBusConnection *conn,
        DBusMessage *reply;
        DBusMessageIter iter;
        DBusMessageIter dict;
-       char str[MAX_NAME_LENGTH + 1], srcaddr[18];
+       char srcaddr[18];
        gboolean value;
        char **devices, **uuids;
        int i;
        GSList *l;
        sdp_list_t *list;
-               info("Get properties 1\n");
+
        ba2str(&adapter->bdaddr, srcaddr);
 
        if (check_address(srcaddr) < 0)
@@ -1363,9 +1171,7 @@ static DBusMessage *get_properties(DBusConnection *conn,
        dict_append_entry(&dict, "Address", DBUS_TYPE_STRING, &property);
 
        /* Name */
-       memset(str, 0, sizeof(str));
-       strncpy(str, (char *) adapter->dev.name, MAX_NAME_LENGTH);
-       property = str;
+       property = adapter->name ? : "";
 
        dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &property);
 
@@ -1380,12 +1186,6 @@ static DBusMessage *get_properties(DBusConnection *conn,
        /* Discoverable */
        value = adapter->scan_mode & SCAN_INQUIRY ? TRUE : FALSE;
        dict_append_entry(&dict, "Discoverable", DBUS_TYPE_BOOLEAN, &value);
-#ifdef __TIZEN_PATCH__
-       // Adding limited property for setting limited discoverable mode
-       /* Limited */
-       dict_append_entry(&dict, "Limited", DBUS_TYPE_BOOLEAN,
-                               &adapter->limited);
-#endif
 
        /* Pairable */
        dict_append_entry(&dict, "Pairable", DBUS_TYPE_BOOLEAN,
@@ -1400,13 +1200,9 @@ static DBusMessage *get_properties(DBusConnection *conn,
                                DBUS_TYPE_UINT32, &adapter->pairable_timeout);
 
 
-       if (adapter->state & (STATE_PINQ | STATE_STDINQ | STATE_LE_SCAN))
-               value = TRUE;
-       else
-               value = FALSE;
-
        /* Discovering */
-       dict_append_entry(&dict, "Discovering", DBUS_TYPE_BOOLEAN, &value);
+       dict_append_entry(&dict, "Discovering", DBUS_TYPE_BOOLEAN,
+                                                       &adapter->discovering);
 
        /* Devices */
        devices = g_new0(char *, g_slist_length(adapter->devices) + 1);
@@ -1442,7 +1238,6 @@ static DBusMessage *get_properties(DBusConnection *conn,
 static DBusMessage *set_property(DBusConnection *conn,
                                        DBusMessage *msg, void *data)
 {
-       info(" set_property 1 \n");
        struct btd_adapter *adapter = data;
        DBusMessageIter iter;
        DBusMessageIter sub;
@@ -1490,19 +1285,6 @@ static DBusMessage *set_property(DBusConnection *conn,
                dbus_message_iter_get_basic(&sub, &discoverable);
 
                return set_discoverable(conn, msg, discoverable, data);
-#ifdef __TIZEN_PATCH__
-       // Adding limited property for setting limited discoverable mode
-       } else if (g_str_equal("Limited", property)) {
-               gboolean limited;
-
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
-                       return btd_error_invalid_args(msg);
-
-               dbus_message_iter_get_basic(&sub, &limited);
-
-///            return set_limited(conn, msg, limited, data);
-       return btd_error_invalid_args(msg);
-#endif
        } else if (g_str_equal("DiscoverableTimeout", property)) {
                uint32_t timeout;
 
@@ -1661,61 +1443,22 @@ static DBusMessage *cancel_device_creation(DBusConnection *conn,
        return dbus_message_new_method_return(msg);
 }
 
-static device_type_t flags2type(uint8_t flags)
-{
-       /* Inferring the remote type based on the EIR Flags field */
-
-       /* For LE only and dual mode the following flags must be zero */
-       if (flags & (EIR_SIM_CONTROLLER | EIR_SIM_HOST))
-               return DEVICE_TYPE_UNKNOWN;
-
-       /* Limited or General discoverable mode bit must be enabled */
-       if (!(flags & (EIR_LIM_DISC | EIR_GEN_DISC)))
-               return DEVICE_TYPE_UNKNOWN;
-
-       if (flags & EIR_BREDR_UNSUP)
-               return DEVICE_TYPE_LE;
-       else
-               return DEVICE_TYPE_DUALMODE;
-}
-
-static gboolean event_is_connectable(uint8_t type)
-{
-       switch (type) {
-       case ADV_TYPE_IND:
-       case ADV_TYPE_DIRECT_IND:
-               return TRUE;
-       default:
-               return FALSE;
-       }
-}
-
 static struct btd_device *create_device_internal(DBusConnection *conn,
                                                struct btd_adapter *adapter,
-                                               const gchar *address,
-                                               gboolean force, int *err)
+                                               const char *address, int *err)
 {
-       struct remote_dev_info *dev, match;
+       struct remote_dev_info *dev;
        struct btd_device *device;
-       device_type_t type;
+       bdaddr_t addr;
+       addr_type_t type;
 
-       memset(&match, 0, sizeof(struct remote_dev_info));
-       str2ba(address, &match.bdaddr);
-       match.name_status = NAME_ANY;
+       str2ba(address, &addr);
 
-       dev = adapter_search_found_devices(adapter, &match);
-       if (dev && dev->flags)
-               type = flags2type(dev->flags);
+       dev = adapter_search_found_devices(adapter, &addr);
+       if (dev)
+               type = dev->type;
        else
-               type = DEVICE_TYPE_BREDR;
-
-       if (!force && type == DEVICE_TYPE_LE &&
-                                       !event_is_connectable(dev->evt_type)) {
-               if (err)
-                       *err = -ENOTCONN;
-
-               return NULL;
-       }
+               type = ADDR_TYPE_BREDR;
 
        device = adapter_create_device(conn, adapter, address, type);
        if (!device && err)
@@ -1748,11 +1491,11 @@ static DBusMessage *create_device(DBusConnection *conn,
 
        DBG("%s", address);
 
-       device = create_device_internal(conn, adapter, address, TRUE, &err);
+       device = create_device_internal(conn, adapter, address, &err);
        if (!device)
                goto failed;
 
-       if (device_get_type(device) != DEVICE_TYPE_LE)
+       if (device_is_bredr(device))
                err = device_browse_sdp(device, conn, msg, NULL, FALSE);
        else
                err = device_browse_primary(device, conn, msg, FALSE);
@@ -1794,233 +1537,63 @@ static uint8_t parse_io_capability(const char *capability)
                return IO_CAPABILITY_NOINPUTNOOUTPUT;
        return IO_CAPABILITY_INVALID;
 }
-#ifdef __TIZEN_PATCH__
-DBusMessage *adapter_encrypt_link(DBusConnection *conn,
-                                       DBusMessage *msg,
-                                       const char *address,
-                                       dbus_bool_t encrypt,
-                                       void* data)
 
+static DBusMessage *create_paired_device(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
 {
        struct btd_adapter *adapter = data;
        struct btd_device *device;
-       char filename[PATH_MAX + 1];
-       bdaddr_t bdaddr;
-       struct hci_conn_info_req *cr;
-       int opt, dd;
-       int dev_id = 0;
+       const gchar *address, *agent_path, *capability, *sender;
+       uint8_t cap;
+       int err;
 
-       DBG("handle_authenticate_link_request1");
-        device = adapter_get_device(conn, adapter, address);
+       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
+                                       DBUS_TYPE_OBJECT_PATH, &agent_path,
+                                       DBUS_TYPE_STRING, &capability,
+                                       DBUS_TYPE_INVALID) == FALSE)
+               return btd_error_invalid_args(msg);
 
-       str2ba(address, &bdaddr);
-       /* check if there is a pending discover: requested by D-Bus/non clients */
-       if (0)//todo
+       if (check_address(address) < 0)
+               return btd_error_invalid_args(msg);
 
-               return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", "Discover in progress");
+       if (!adapter->up)
+               return btd_error_not_ready(msg);
 
-       pending_remote_name_cancel(adapter);
+       sender = dbus_message_get_sender(msg);
+       if (adapter->agent &&
+                       agent_matches(adapter->agent, sender, agent_path)) {
+               error("Refusing adapter agent usage as device specific one");
+               return btd_error_invalid_args(msg);
+       }
 
-       if (device_get_bonding(device))
-               return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", "Bonding in progress");
+       cap = parse_io_capability(capability);
+       if (cap == IO_CAPABILITY_INVALID)
+               return btd_error_invalid_args(msg);
 
+       device = adapter_find_device(adapter, address);
+       if (!device) {
+               device = create_device_internal(conn, adapter, address, &err);
+               if (!device)
+                       return btd_error_failed(msg, strerror(-err));
+       }
 
-       /*if (adapter_find_auth_request(adapter, &bdaddr))
-               return in_progress(msg, "Bonding in progress");*/
+       if (device_is_bredr(device))
+               return device_create_bonding(device, conn, msg,
+                                                       agent_path, cap);
 
-       /* check if a link key already exists */
-       create_name(filename, PATH_MAX, STORAGEDIR,address,
-                       "linkkeys");
+       err = device_browse_primary(device, conn, msg, TRUE);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
 
-       dd = hci_open_dev(dev_id);
-       if (dd < 0) {
-               return g_dbus_create_error(msg,
-                               ERROR_INTERFACE ".Failed",
-                               "Device open failed");
-       }
+       return NULL;
+}
 
-       cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
-       if (!cr) {
-               return NULL;
-       }
+static gint device_path_cmp(struct btd_device *device, const gchar *path)
+{
+       const gchar *dev_path = device_get_path(device);
 
-       bacpy(&cr->bdaddr, &bdaddr);
-       cr->type = ACL_LINK;
-       if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
-               free(cr);
-               return g_dbus_create_error(msg,
-                               ERROR_INTERFACE ".Failed",
-                               "Getting connection info failed");
-       }
-
-#if 0
-       if (hci_authenticate_link(dd, htobs(cr->conn_info->handle), 25000) < 0) {
-               free(cr);
-               return g_dbus_create_error(msg,
-                               ERROR_INTERFACE ".Failed",
-                               "Authentication request failed");
-       }
-
-#endif
-       info("Encrypt value   %d",encrypt);
-       if (hci_encrypt_link(dd, htobs(cr->conn_info->handle), encrypt, 25000) < 0) {
-               free(cr);
-               return g_dbus_create_error(msg,
-                               ERROR_INTERFACE ".Failed",
-                               "Encryption request failed");
-       }
-
-       DBG("handle_authenticate_link_request2");
-       free(cr);
-
-       hci_close_dev(dd);
-
-       return dbus_message_new_method_return(msg);
-
-}
-#endif
-
-
-
-
-#ifdef __TIZEN_PATCH__
-static DBusMessage *authenticate_link(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       struct btd_adapter *adapter = data;
-       struct btd_device *device;
-       const gchar *address, *agent_path, *capability, *sender;
-       uint8_t cap;
-       info("authenticate_link 1\n");
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
-                                       DBUS_TYPE_OBJECT_PATH, &agent_path,
-                                       DBUS_TYPE_STRING, &capability,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               return btd_error_invalid_args(msg);
-      info("authenticate_link 2\n");
-       if (check_address(address) < 0)
-               return btd_error_invalid_args(msg);
-       info("authenticate_link 3\n");
-       sender = dbus_message_get_sender(msg);
-       if (adapter->agent &&
-                       agent_matches(adapter->agent, sender, agent_path)) {
-               error("Refusing adapter agent usage as device specific one");
-               return btd_error_invalid_args(msg);
-       }
-       info("authenticate_link 4\n");
-       cap = parse_io_capability(capability);
-       if (cap == IO_CAPABILITY_INVALID)
-               return btd_error_invalid_args(msg);
-       info("authenticate_link 5\n");
-       device = adapter_get_device(conn, adapter, address);
-       if (!device)
-               return g_dbus_create_error(msg,
-                               ERROR_INTERFACE ".Failed",
-                               "Unable to create a new device object");
-       info("authenticate_link 5\n");
-       return device_jsr82_authenticate_link(device, conn, msg, agent_path, cap);
-}
-#endif
-
-#ifdef __TIZEN_PATCH__
-static DBusMessage *encrypt_connection(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       struct btd_adapter *adapter = data;
-       gboolean encrypt = FALSE;
-       DBG("encrypt_link");
-       info("encrypt_connection value  1   %d",encrypt);
-       if (!adapter->up)
-               return btd_error_not_ready(msg);
-       DBusMessageIter iter;
-       DBusMessageIter sub;
-       const char *address;
-
-
-       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, &address);
-       dbus_message_iter_next(&iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
-               return btd_error_invalid_args(msg);
-       dbus_message_iter_recurse(&iter, &sub);
-
-       if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
-               return btd_error_invalid_args(msg);
-
-       dbus_message_iter_get_basic(&sub, &encrypt);
-/*     if (!dbus_message_get_args(msg, NULL,
-                               DBUS_TYPE_STRING, &address, DBUS_TYPE_BOOLEAN,&encrypt,
-                               DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);*/
-
-       info("encrypt_connection value  2   %d",encrypt);
-       return adapter_encrypt_link(conn, msg, address, encrypt, data);
-
-}
-#endif
-static DBusMessage *create_paired_device(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct btd_adapter *adapter = data;
-       struct btd_device *device;
-       const gchar *address, *agent_path, *capability, *sender;
-       uint8_t cap;
-       int err;
-
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
-                                       DBUS_TYPE_OBJECT_PATH, &agent_path,
-                                       DBUS_TYPE_STRING, &capability,
-                                       DBUS_TYPE_INVALID) == FALSE)
-               return btd_error_invalid_args(msg);
-
-       if (check_address(address) < 0)
-               return btd_error_invalid_args(msg);
-
-       if (!adapter->up)
-               return btd_error_not_ready(msg);
-
-       sender = dbus_message_get_sender(msg);
-       if (adapter->agent &&
-                       agent_matches(adapter->agent, sender, agent_path)) {
-               error("Refusing adapter agent usage as device specific one");
-               return btd_error_invalid_args(msg);
-       }
-
-       cap = parse_io_capability(capability);
-       if (cap == IO_CAPABILITY_INVALID)
-               return btd_error_invalid_args(msg);
-
-       device = adapter_find_device(adapter, address);
-       if (!device) {
-               device = create_device_internal(conn, adapter, address,
-                                                               FALSE, &err);
-               if (!device)
-                       return btd_error_failed(msg, strerror(-err));
-       }
-
-       if (device_get_type(device) != DEVICE_TYPE_LE)
-               return device_create_bonding(device, conn, msg,
-                                                       agent_path, cap);
-
-       err = device_browse_primary(device, conn, msg, TRUE);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
-
-       return NULL;
-}
-
-static gint device_path_cmp(struct btd_device *device, const gchar *path)
-{
-       const gchar *dev_path = device_get_path(device);
-
-       return strcasecmp(dev_path, path);
-}
+       return strcasecmp(dev_path, path);
+}
 
 static DBusMessage *remove_device(DBusConnection *conn, DBusMessage *msg,
                                                                void *data)
@@ -2179,11 +1752,6 @@ static GDBusMethodTable adapter_methods[] = {
        { "FindDevice",         "s",    "o",    find_device             },
        { "RegisterAgent",      "os",   "",     register_agent          },
        { "UnregisterAgent",    "o",    "",     unregister_agent        },
-
-       #ifdef __TIZEN_PATCH__
-       { "AuthenticateLink","sos",     "o",    authenticate_link, G_DBUS_METHOD_FLAG_ASYNC},
-       { "EncryptLink","sv",   "",     encrypt_connection, G_DBUS_METHOD_FLAG_ASYNC},
-       #endif
        { }
 };
 
@@ -2200,24 +1768,27 @@ static void create_stored_device_from_profiles(char *key, char *value,
                                                void *user_data)
 {
        struct btd_adapter *adapter = user_data;
-       GSList *uuids = bt_string2list(value);
+       GSList *list, *uuids = bt_string2list(value);
        struct btd_device *device;
 
        if (g_slist_find_custom(adapter->devices,
                                key, (GCompareFunc) device_address_cmp))
                return;
 
-       device = device_create(connection, adapter, key, DEVICE_TYPE_BREDR);
+       device = device_create(connection, adapter, key, ADDR_TYPE_BREDR);
        if (!device)
                return;
 
        device_set_temporary(device, FALSE);
        adapter->devices = g_slist_append(adapter->devices, device);
 
+       list = device_services_from_record(device, uuids);
+       if (list)
+               device_register_services(connection, device, list, ATT_PSM);
+
        device_probe_drivers(device, uuids);
 
-       g_slist_foreach(uuids, (GFunc) g_free, NULL);
-       g_slist_free(uuids);
+       g_slist_free_full(uuids, g_free);
 }
 
 struct adapter_keys {
@@ -2276,7 +1847,7 @@ static void create_stored_device_from_linkkeys(char *key, char *value,
                                        (GCompareFunc) device_address_cmp))
                return;
 
-       device = device_create(connection, adapter, key, DEVICE_TYPE_BREDR);
+       device = device_create(connection, adapter, key, ADDR_TYPE_BREDR);
        if (device) {
                device_set_temporary(device, FALSE);
                adapter->devices = g_slist_append(adapter->devices, device);
@@ -2293,32 +1864,7 @@ static void create_stored_device_from_blocked(char *key, char *value,
                                key, (GCompareFunc) device_address_cmp))
                return;
 
-       device = device_create(connection, adapter, key, DEVICE_TYPE_BREDR);
-       if (device) {
-               device_set_temporary(device, FALSE);
-               adapter->devices = g_slist_append(adapter->devices, device);
-       }
-}
-
-static void create_stored_device_from_types(char *key, char *value,
-                                                       void *user_data)
-{
-       GSList *l;
-       struct btd_adapter *adapter = user_data;
-       struct btd_device *device;
-       uint8_t type;
-
-       type = strtol(value, NULL, 16);
-
-       l = g_slist_find_custom(adapter->devices,
-                               key, (GCompareFunc) device_address_cmp);
-       if (l) {
-               device = l->data;
-               device_set_type(device, type);
-               return;
-       }
-
-       device = device_create(connection, adapter, key, type);
+       device = device_create(connection, adapter, key, ADDR_TYPE_BREDR);
        if (device) {
                device_set_temporary(device, FALSE);
                adapter->devices = g_slist_append(adapter->devices, device);
@@ -2367,18 +1913,17 @@ static void create_stored_device_from_primary(char *key, char *value,
        struct btd_device *device;
        GSList *services, *uuids, *l;
 
-       l = g_slist_find_custom(adapter->devices,
-                               key, (GCompareFunc) device_address_cmp);
-       if (l)
-               device = l->data;
-       else {
-               device = device_create(connection, adapter, key, DEVICE_TYPE_BREDR);
-               if (!device)
-                       return;
+       if (g_slist_find_custom(adapter->devices,
+                       key, (GCompareFunc) device_address_cmp))
+               return;
 
-               device_set_temporary(device, FALSE);
-               adapter->devices = g_slist_append(adapter->devices, device);
-       }
+       /* FIXME: Get the correct LE addr type (public/random) */
+       device = device_create(connection, adapter, key, ADDR_TYPE_LE_PUBLIC);
+       if (!device)
+               return;
+
+       device_set_temporary(device, FALSE);
+       adapter->devices = g_slist_append(adapter->devices, device);
 
        services = string_to_primary_list(value);
        if (services == NULL)
@@ -2387,13 +1932,12 @@ static void create_stored_device_from_primary(char *key, char *value,
        for (l = services, uuids = NULL; l; l = l->next) {
                struct att_primary *prim = l->data;
                uuids = g_slist_append(uuids, prim->uuid);
-
-               device_add_primary(device, prim);
        }
 
+       device_register_services(connection, device, services, -1);
+
        device_probe_drivers(device, uuids);
 
-       g_slist_free(services);
        g_slist_free(uuids);
 }
 
@@ -2422,15 +1966,11 @@ static void load_devices(struct btd_adapter *adapter)
        if (err < 0) {
                error("Unable to load keys to adapter_ops: %s (%d)",
                                                        strerror(-err), -err);
-               g_slist_foreach(keys.keys, (GFunc) g_free, NULL);
-               g_slist_free(keys.keys);
+               g_slist_free_full(keys.keys, g_free);
        }
 
        create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "blocked");
        textfile_foreach(filename, create_stored_device_from_blocked, adapter);
-
-       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "types");
-       textfile_foreach(filename, create_stored_device_from_types, adapter);
 }
 
 int btd_adapter_block_address(struct btd_adapter *adapter, bdaddr_t *bdaddr)
@@ -2507,8 +2047,7 @@ static void load_connections(struct btd_adapter *adapter)
                        adapter_add_connection(adapter, device);
        }
 
-       g_slist_foreach(conns, (GFunc) g_free, NULL);
-       g_slist_free(conns);
+       g_slist_free_full(conns, g_free);
 }
 
 static int get_discoverable_timeout(const char *src)
@@ -2560,49 +2099,6 @@ static void emit_device_disappeared(gpointer data, gpointer user_data)
        adapter->found_devices = g_slist_remove(adapter->found_devices, dev);
 }
 
-static void update_oor_devices(struct btd_adapter *adapter)
-{
-       g_slist_foreach(adapter->oor_devices, emit_device_disappeared, adapter);
-       g_slist_foreach(adapter->oor_devices, (GFunc) dev_info_free, NULL);
-       g_slist_free(adapter->oor_devices);
-       adapter->oor_devices =  g_slist_copy(adapter->found_devices);
-}
-
-static gboolean bredr_capable(struct btd_adapter *adapter)
-{
-       struct hci_dev *dev = &adapter->dev;
-
-       return (dev->features[4] & LMP_NO_BREDR) == 0 ? TRUE : FALSE;
-}
-
-static gboolean le_capable(struct btd_adapter *adapter)
-{
-       struct hci_dev *dev = &adapter->dev;
-
-       return (dev->features[4] & LMP_LE &&
-                       dev->extfeatures[0] & LMP_HOST_LE) ? TRUE : FALSE;
-}
-
-int adapter_get_discover_type(struct btd_adapter *adapter)
-{
-       gboolean le, bredr;
-       int type;
-
-       le = le_capable(adapter);
-       bredr = bredr_capable(adapter);
-
-       if (le)
-               type = bredr ? DISC_INTERLEAVE : DISC_LE;
-       else
-               type = main_opts.discov_interval ? DISC_STDINQ :
-                                                       DISC_PINQ;
-
-       if (main_opts.name_resolv)
-               type |= DISC_RESOLVNAME;
-
-       return type;
-}
-
 void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode,
                                        uint8_t *on_mode, gboolean *pairable)
 {
@@ -2613,26 +2109,15 @@ void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode,
        if (mode) {
                if (main_opts.remember_powered == FALSE)
                        *mode = main_opts.mode;
-               else if (read_device_mode(address, str, sizeof(str)) < 0)
-                       *mode = main_opts.mode;
-               else
+               else if (read_device_mode(address, str, sizeof(str)) == 0)
                        *mode = get_mode(&adapter->bdaddr, str);
-       }
-
-       if (on_mode) {
-               if (main_opts.remember_powered == FALSE) {
-                       if (adapter->initialized)
-                               *on_mode = get_mode(&adapter->bdaddr, "on");
-                       else {
-                               *on_mode = main_opts.mode;
-                               adapter->initialized = TRUE;
-                       }
-               } else if (read_on_mode(address, str, sizeof(str)) < 0)
-                       *on_mode = main_opts.mode;
                else
-                       *on_mode = get_mode(&adapter->bdaddr, str);
+                       *mode = main_opts.mode;
        }
 
+       if (on_mode)
+               *on_mode = get_mode(&adapter->bdaddr, "on");
+
        if (pairable)
                *pairable = adapter->pairable;
 }
@@ -2650,13 +2135,12 @@ void btd_adapter_start(struct btd_adapter *adapter)
        adapter->up = TRUE;
        adapter->discov_timeout = get_discoverable_timeout(address);
        adapter->pairable_timeout = get_pairable_timeout(address);
-       adapter->state = STATE_IDLE;
        adapter->mode = MODE_CONNECTABLE;
+       adapter->off_timer = 0;
 
-       if (main_opts.le)
-               adapter_ops->enable_le(adapter->dev_id);
-
-       adapter_ops->set_name(adapter->dev_id, adapter->dev.name);
+       /* Forcing: Name is lost when adapter is powered off */
+       if (adapter->name)
+               adapter_ops->set_name(adapter->dev_id, adapter->name);
 
        if (read_local_class(&adapter->bdaddr, cls) < 0) {
                uint32_t class = htobl(main_opts.class);
@@ -2718,6 +2202,11 @@ static void set_mode_complete(struct btd_adapter *adapter)
 
        DBG("");
 
+       if (adapter->mode == MODE_OFF) {
+               g_slist_free_full(adapter->mode_sessions, session_free);
+               adapter->mode_sessions = NULL;
+       }
+
        if (adapter->pending_mode == NULL)
                return;
 
@@ -2757,10 +2246,7 @@ static void set_mode_complete(struct btd_adapter *adapter)
 
 int btd_adapter_stop(struct btd_adapter *adapter)
 {
-       gboolean powered, discoverable, pairable;
-#ifdef __TIZEN_PATCH__
-       gboolean limited;
-#endif
+       gboolean prop_false = FALSE;
 
        /* cancel pending timeout */
        if (adapter->discov_timeout_id) {
@@ -2771,12 +2257,10 @@ int btd_adapter_stop(struct btd_adapter *adapter)
        /* check pending requests */
        reply_pending_requests(adapter);
 
-       stop_discovery(adapter, FALSE);
+       stop_discovery(adapter);
 
        if (adapter->disc_sessions) {
-               g_slist_foreach(adapter->disc_sessions, (GFunc) session_free,
-                               NULL);
-               g_slist_free(adapter->disc_sessions);
+               g_slist_free_full(adapter->disc_sessions, session_free);
                adapter->disc_sessions = NULL;
        }
 
@@ -2785,30 +2269,28 @@ int btd_adapter_stop(struct btd_adapter *adapter)
                adapter_remove_connection(adapter, device);
        }
 
-       if (adapter->scan_mode == (SCAN_PAGE | SCAN_INQUIRY)) {
-               discoverable = FALSE;
+       if (adapter->scan_mode == (SCAN_PAGE | SCAN_INQUIRY))
                emit_property_changed(connection, adapter->path,
                                        ADAPTER_INTERFACE, "Discoverable",
-                                       DBUS_TYPE_BOOLEAN, &discoverable);
-       }
+                                       DBUS_TYPE_BOOLEAN, &prop_false);
 
-       if ((adapter->scan_mode & SCAN_PAGE) && adapter->pairable == TRUE) {
-               pairable = FALSE;
+       if ((adapter->scan_mode & SCAN_PAGE) && adapter->pairable == TRUE)
                emit_property_changed(connection, adapter->path,
                                        ADAPTER_INTERFACE, "Pairable",
-                                       DBUS_TYPE_BOOLEAN, &pairable);
-       }
+                                       DBUS_TYPE_BOOLEAN, &prop_false);
+
+       if (adapter->discovering)
+               emit_property_changed(connection, adapter->path,
+                                       ADAPTER_INTERFACE, "Discovering",
+                                       DBUS_TYPE_BOOLEAN, &prop_false);
 
-       powered = FALSE;
        emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE,
-                               "Powered", DBUS_TYPE_BOOLEAN, &powered);
+                               "Powered", DBUS_TYPE_BOOLEAN, &prop_false);
 
-       adapter->up = 0;
+       adapter->up = FALSE;
        adapter->scan_mode = SCAN_DISABLED;
        adapter->mode = MODE_OFF;
-       adapter->state = STATE_IDLE;
        adapter->off_requested = FALSE;
-       adapter->name_stored = FALSE;
 
        call_adapter_powered_callbacks(adapter, FALSE);
 
@@ -2819,13 +2301,10 @@ int btd_adapter_stop(struct btd_adapter *adapter)
        return 0;
 }
 
-int adapter_update_ssp_mode(struct btd_adapter *adapter, uint8_t mode)
+static void off_timer_remove(struct btd_adapter *adapter)
 {
-       struct hci_dev *dev = &adapter->dev;
-
-       dev->ssp_mode = mode;
-
-       return 0;
+       g_source_remove(adapter->off_timer);
+       adapter->off_timer = 0;
 }
 
 static void adapter_free(gpointer user_data)
@@ -2840,14 +2319,17 @@ static void adapter_free(gpointer user_data)
        if (adapter->auth_idle_id)
                g_source_remove(adapter->auth_idle_id);
 
+       if (adapter->off_timer)
+               off_timer_remove(adapter);
+
        sdp_list_free(adapter->services, NULL);
 
-       g_slist_foreach(adapter->found_devices, (GFunc) dev_info_free, NULL);
-       g_slist_free(adapter->found_devices);
+       g_slist_free_full(adapter->found_devices, dev_info_free);
 
        g_slist_free(adapter->oor_devices);
 
        g_free(adapter->path);
+       g_free(adapter->name);
        g_free(adapter);
 }
 
@@ -2880,14 +2362,12 @@ void btd_adapter_unref(struct btd_adapter *adapter)
 
 gboolean adapter_init(struct btd_adapter *adapter)
 {
-       struct hci_version ver;
-       struct hci_dev *dev;
-       int err;
-
        /* adapter_ops makes sure that newly registered adapters always
         * start off as powered */
        adapter->up = TRUE;
 
+       adapter->allow_name_changes = TRUE;
+
        adapter_ops->read_bdaddr(adapter->dev_id, &adapter->bdaddr);
 
        if (bacmp(&adapter->bdaddr, BDADDR_ANY) == 0) {
@@ -2895,36 +2375,11 @@ gboolean adapter_init(struct btd_adapter *adapter)
                return FALSE;
        }
 
-       err = adapter_ops->read_local_version(adapter->dev_id, &ver);
-       if (err < 0) {
-               error("Can't read version info for hci%d: %s (%d)",
-                                       adapter->dev_id, strerror(-err), -err);
-               return FALSE;
-       }
-
-       dev = &adapter->dev;
-
-       dev->hci_rev = ver.hci_rev;
-       dev->lmp_ver = ver.lmp_ver;
-       dev->lmp_subver = ver.lmp_subver;
-       dev->manufacturer = ver.manufacturer;
-
-       err = adapter_ops->read_local_features(adapter->dev_id, dev->features);
-       if (err < 0) {
-               error("Can't read features for hci%d: %s (%d)",
-                                       adapter->dev_id, strerror(-err), -err);
-               return FALSE;
-       }
-
-       if (read_local_name(&adapter->bdaddr, adapter->dev.name) < 0)
-               expand_name(adapter->dev.name, MAX_NAME_LENGTH, main_opts.name,
-                                                       adapter->dev_id);
+       sdp_init_services_list(&adapter->bdaddr);
 
        if (main_opts.attrib_server)
-               attrib_gap_set(GATT_CHARAC_DEVICE_NAME,
-                       (const uint8_t *) dev->name, strlen(dev->name));
+               btd_adapter_gatt_server_start(adapter);
 
-       sdp_init_services_list(&adapter->bdaddr);
        load_drivers(adapter);
        clear_blocked(adapter);
        load_devices(adapter);
@@ -2937,6 +2392,8 @@ gboolean adapter_init(struct btd_adapter *adapter)
         * the are active connections before the daemon've started */
        load_connections(adapter);
 
+       adapter->initialized = TRUE;
+
        return TRUE;
 }
 
@@ -2982,11 +2439,13 @@ void adapter_remove(struct btd_adapter *adapter)
        g_slist_free(adapter->devices);
 
        unload_drivers(adapter);
+       if (main_opts.attrib_server)
+               btd_adapter_gatt_server_stop(adapter);
+
+       g_slist_free(adapter->pin_callbacks);
 
        /* Return adapter to down state if it was not up on init */
        adapter_ops->restore_powered(adapter->dev_id);
-
-       btd_adapter_unref(adapter);
 }
 
 uint16_t adapter_get_dev_id(struct btd_adapter *adapter)
@@ -3007,92 +2466,79 @@ void adapter_get_address(struct btd_adapter *adapter, bdaddr_t *bdaddr)
        bacpy(bdaddr, &adapter->bdaddr);
 }
 
-void adapter_set_state(struct btd_adapter *adapter, int state)
+void adapter_set_allow_name_changes(struct btd_adapter *adapter,
+                                               gboolean allow_name_changes)
+{
+       adapter->allow_name_changes = allow_name_changes;
+}
+
+void adapter_set_discovering(struct btd_adapter *adapter,
+                                               gboolean discovering)
 {
        const char *path = adapter->path;
-       gboolean discov_active;
-       int previous, type;
 
-       if (adapter->state == state)
+       adapter->discovering = discovering;
+
+       emit_property_changed(connection, path,
+                               ADAPTER_INTERFACE, "Discovering",
+                               DBUS_TYPE_BOOLEAN, &discovering);
+
+       if (discovering)
                return;
 
-       previous = adapter->state;
-       adapter->state = state;
+       g_slist_foreach(adapter->oor_devices, emit_device_disappeared, adapter);
+       g_slist_free_full(adapter->oor_devices, dev_info_free);
+       adapter->oor_devices = g_slist_copy(adapter->found_devices);
 
-       type = adapter_get_discover_type(adapter);
+       if (!adapter_has_discov_sessions(adapter) || adapter->discov_suspended)
+               return;
 
-       switch (state) {
-       case STATE_STDINQ:
-       case STATE_PINQ:
-               discov_active = TRUE;
+       DBG("hci%u enabling timer, disc_sessions %u", adapter->dev_id,
+                                       g_slist_length(adapter->disc_sessions));
 
-               /* Started a new session while resolving names ? */
-               if (previous & STATE_RESOLVNAME)
-                       return;
-               break;
-       case STATE_LE_SCAN:
-               /* Scanning enabled */
-               adapter->stop_discov_id = g_timeout_add(5120,
-                                               stop_scanning, adapter);
+       adapter->discov_id = g_timeout_add_seconds(main_opts.discov_interval,
+                                                       discovery_cb, adapter);
+}
 
-               /* For dual mode: don't send "Discovering = TRUE"  */
-               if (bredr_capable(adapter) == TRUE)
-                       return;
+static void suspend_discovery(struct btd_adapter *adapter)
+{
+       if (adapter->disc_sessions == NULL || adapter->discov_suspended)
+               return;
 
-               /* LE only */
-               discov_active = TRUE;
+       DBG("Suspending discovery");
 
-               break;
-       case STATE_IDLE:
-               /*
-                * Interleave: from inquiry to scanning. Interleave is not
-                * applicable to requests triggered by external applications.
-                */
-               if (adapter->disc_sessions && (type & DISC_INTERLEAVE) &&
-                                               (previous & STATE_STDINQ)) {
-                       adapter_ops->start_scanning(adapter->dev_id);
-                       return;
-               }
-               /* BR/EDR only: inquiry finished */
-               discov_active = FALSE;
-               break;
-       default:
-               discov_active = FALSE;
-               break;
+       if (adapter->oor_devices) {
+               g_slist_free(adapter->oor_devices);
+               adapter->oor_devices = NULL;
        }
 
-       if (discov_active == FALSE) {
-               if (type & DISC_RESOLVNAME) {
-                       if (adapter_resolve_names(adapter) == 0) {
-                               adapter->state |= STATE_RESOLVNAME;
-                               return;
-                       }
-               }
-
-               update_oor_devices(adapter);
-       } else if (adapter->disc_sessions && main_opts.discov_interval)
-                       adapter->scheduler_id = g_timeout_add_seconds(
-                                               main_opts.discov_interval,
-                                               (GSourceFunc) start_discovery,
-                                               adapter);
+       adapter->discov_suspended = TRUE;
 
-       emit_property_changed(connection, path,
-                               ADAPTER_INTERFACE, "Discovering",
-                               DBUS_TYPE_BOOLEAN, &discov_active);
+       if (adapter->discov_id > 0) {
+               g_source_remove(adapter->discov_id);
+               adapter->discov_id = 0;
+       } else
+               adapter_ops->stop_discovery(adapter->dev_id);
 }
 
-int adapter_get_state(struct btd_adapter *adapter)
+static int found_device_cmp(gconstpointer a, gconstpointer b)
 {
-       return adapter->state;
+       const struct remote_dev_info *d = a;
+       const bdaddr_t *bdaddr = b;
+
+       if (bacmp(bdaddr, BDADDR_ANY) == 0)
+               return 0;
+
+       return bacmp(&d->bdaddr, bdaddr);
 }
 
 struct remote_dev_info *adapter_search_found_devices(struct btd_adapter *adapter,
-                                               struct remote_dev_info *match)
+                                                       bdaddr_t *bdaddr)
 {
        GSList *l;
 
-       l = g_slist_find_custom(adapter->found_devices, match,
-                                       (GCompareFunc) found_device_cmp);
+       l = g_slist_find_custom(adapter->found_devices, bdaddr,
+                                                       found_device_cmp);
        if (l)
                return l->data;
 
@@ -3167,7 +2613,6 @@ static void emit_device_found(const char *path, const char *address,
 
 static char **strlist2array(GSList *list)
 {
-       GSList *l;
        unsigned int i, n;
        char **array;
 
@@ -3177,8 +2622,8 @@ static char **strlist2array(GSList *list)
        n = g_slist_length(list);
        array = g_new0(char *, n + 1);
 
-       for (l = list, i = 0; l; l = l->next, i++)
-               array[i] = g_strdup((const gchar *) l->data);
+       for (i = 0; list; list = list->next, i++)
+               array[i] = g_strdup((const gchar *) list->data);
 
        return array;
 }
@@ -3189,7 +2634,7 @@ void adapter_emit_device_found(struct btd_adapter *adapter,
        struct btd_device *device;
        char peer_addr[18], local_addr[18];
        const char *icon, *paddr = peer_addr;
-       dbus_bool_t paired = FALSE;
+       dbus_bool_t paired = FALSE, trusted = FALSE;
        dbus_int16_t rssi = dev->rssi;
        char *alias;
        size_t uuid_count;
@@ -3198,8 +2643,10 @@ void adapter_emit_device_found(struct btd_adapter *adapter,
        ba2str(&adapter->bdaddr, local_addr);
 
        device = adapter_find_device(adapter, paddr);
-       if (device)
+       if (device) {
                paired = device_is_paired(device);
+               trusted = device_is_trusted(device);
+       }
 
        /* The uuids string array is updated only if necessary */
        uuid_count = g_slist_length(dev->services);
@@ -3209,7 +2656,16 @@ void adapter_emit_device_found(struct btd_adapter *adapter,
                dev->uuid_count = uuid_count;
        }
 
-       if (dev->le) {
+       if (!dev->alias) {
+               if (!dev->name) {
+                       alias = g_strdup(peer_addr);
+                       g_strdelimit(alias, ":", '-');
+               } else
+                       alias = g_strdup(dev->name);
+       } else
+               alias = g_strdup(dev->alias);
+
+       if (dev->type != ADDR_TYPE_BREDR) {
                gboolean broadcaster;
 
                if (dev->flags & (EIR_LIM_DISC | EIR_GEN_DISC))
@@ -3217,66 +2673,54 @@ void adapter_emit_device_found(struct btd_adapter *adapter,
                else
                        broadcaster = TRUE;
 
+               dev->legacy = FALSE;
+
                emit_device_found(adapter->path, paddr,
                                "Address", DBUS_TYPE_STRING, &paddr,
                                "RSSI", DBUS_TYPE_INT16, &rssi,
                                "Name", DBUS_TYPE_STRING, &dev->name,
+                               "Alias", DBUS_TYPE_STRING, &alias,
+                               "LegacyPairing", DBUS_TYPE_BOOLEAN, &dev->legacy,
                                "Paired", DBUS_TYPE_BOOLEAN, &paired,
                                "Broadcaster", DBUS_TYPE_BOOLEAN, &broadcaster,
                                "UUIDs", DBUS_TYPE_ARRAY, &dev->uuids, uuid_count,
                                NULL);
-               return;
-       }
-
-       icon = class_to_icon(dev->class);
-
-       if (!dev->alias) {
-               if (!dev->name) {
-                       alias = g_strdup(peer_addr);
-                       g_strdelimit(alias, ":", '-');
-               } else
-                       alias = g_strdup(dev->name);
-       } else
-               alias = g_strdup(dev->alias);
+       } else {
+               icon = class_to_icon(dev->class);
 
-       emit_device_found(adapter->path, paddr,
-                       "Address", DBUS_TYPE_STRING, &paddr,
-                       "Class", DBUS_TYPE_UINT32, &dev->class,
-                       "Icon", DBUS_TYPE_STRING, &icon,
-                       "RSSI", DBUS_TYPE_INT16, &rssi,
-                       "Name", DBUS_TYPE_STRING, &dev->name,
-                       "Alias", DBUS_TYPE_STRING, &alias,
-                       "LegacyPairing", DBUS_TYPE_BOOLEAN, &dev->legacy,
-                       "Paired", DBUS_TYPE_BOOLEAN, &paired,
-                       "UUIDs", DBUS_TYPE_ARRAY, &dev->uuids, uuid_count,
-                       NULL);
+               emit_device_found(adapter->path, paddr,
+                               "Address", DBUS_TYPE_STRING, &paddr,
+                               "Class", DBUS_TYPE_UINT32, &dev->class,
+                               "Icon", DBUS_TYPE_STRING, &icon,
+                               "RSSI", DBUS_TYPE_INT16, &rssi,
+                               "Name", DBUS_TYPE_STRING, &dev->name,
+                               "Alias", DBUS_TYPE_STRING, &alias,
+                               "LegacyPairing", DBUS_TYPE_BOOLEAN, &dev->legacy,
+                               "Paired", DBUS_TYPE_BOOLEAN, &paired,
+                               "Trusted", DBUS_TYPE_BOOLEAN, &trusted,
+                               "UUIDs", DBUS_TYPE_ARRAY, &dev->uuids, uuid_count,
+                               NULL);
+       }
 
        g_free(alias);
 }
 
-static struct remote_dev_info *get_found_dev(struct btd_adapter *adapter,
-                                               const bdaddr_t *bdaddr,
-                                               gboolean *new_dev)
+static struct remote_dev_info *found_device_new(const bdaddr_t *bdaddr,
+                                       addr_type_t type, const char *name,
+                                       const char *alias, uint32_t class,
+                                       gboolean legacy, int flags)
 {
-       struct remote_dev_info *dev, match;
-
-       memset(&match, 0, sizeof(struct remote_dev_info));
-       bacpy(&match.bdaddr, bdaddr);
-       match.name_status = NAME_ANY;
+       struct remote_dev_info *dev;
 
-       dev = adapter_search_found_devices(adapter, &match);
-       if (dev) {
-               *new_dev = FALSE;
-               /* Out of range list update */
-               adapter->oor_devices = g_slist_remove(adapter->oor_devices,
-                                                       dev);
-       } else {
-               *new_dev = TRUE;
-               dev = g_new0(struct remote_dev_info, 1);
-               bacpy(&dev->bdaddr, bdaddr);
-               adapter->found_devices = g_slist_prepend(adapter->found_devices,
-                                                                       dev);
-       }
+       dev = g_new0(struct remote_dev_info, 1);
+       bacpy(&dev->bdaddr, bdaddr);
+       dev->type = type;
+       dev->name = g_strdup(name);
+       dev->alias = g_strdup(alias);
+       dev->class = class;
+       dev->legacy = legacy;
+       if (flags >= 0)
+               dev->flags = flags;
 
        return dev;
 }
@@ -3306,92 +2750,114 @@ static void dev_prepend_uuid(gpointer data, gpointer user_data)
        dev->services = g_slist_prepend(dev->services, g_strdup(new_uuid));
 }
 
-void adapter_update_device_from_info(struct btd_adapter *adapter,
-                                       bdaddr_t bdaddr, int8_t rssi,
-                                       uint8_t evt_type, const char *name,
-                                       GSList *services, int flags)
+static gboolean pairing_is_legacy(bdaddr_t *local, bdaddr_t *peer,
+                                       const uint8_t *eir, const char *name)
 {
-       struct remote_dev_info *dev;
-       gboolean new_dev;
+       unsigned char features[8];
 
-       dev = get_found_dev(adapter, &bdaddr, &new_dev);
+       if (eir)
+               return FALSE;
 
-       if (new_dev) {
-               dev->le = TRUE;
-               dev->evt_type = evt_type;
-       } else if (dev->rssi == rssi)
-               return;
+       if (name == NULL)
+               return TRUE;
 
-       dev->rssi = rssi;
+       if (read_remote_features(local, peer, NULL, features) < 0)
+               return TRUE;
 
-       adapter->found_devices = g_slist_sort(adapter->found_devices,
-                                               (GCompareFunc) dev_rssi_cmp);
+       if (features[0] & 0x01)
+               return FALSE;
+       else
+               return TRUE;
+}
 
-       g_slist_foreach(services, remove_same_uuid, dev);
-       g_slist_foreach(services, dev_prepend_uuid, dev);
+static char *read_stored_data(bdaddr_t *local, bdaddr_t *peer, const char *file)
+{
+       char local_addr[18], peer_addr[18], filename[PATH_MAX + 1];
 
-       if (flags >= 0)
-               dev->flags = flags;
+       ba2str(local, local_addr);
+       ba2str(peer, peer_addr);
 
-       if (name) {
-               g_free(dev->name);
-               dev->name = g_strdup(name);
-       }
+       create_name(filename, PATH_MAX, STORAGEDIR, local_addr, file);
 
-       /* FIXME: check if other information was changed before emitting the
-        * signal */
-       adapter_emit_device_found(adapter, dev);
+       return textfile_get(filename, peer_addr);
 }
 
-void adapter_update_found_devices(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                               int8_t rssi, uint32_t class, const char *name,
-                               const char *alias, gboolean legacy,
-                               GSList *services, name_status_t name_status)
+void adapter_update_found_devices(struct btd_adapter *adapter,
+                                       bdaddr_t *bdaddr, addr_type_t type,
+                                       uint32_t class, int8_t rssi,
+                                       uint8_t confirm_name,
+                                       uint8_t *data, uint8_t data_len)
 {
        struct remote_dev_info *dev;
-       gboolean new_dev;
+       struct eir_data eir_data;
+       char *alias, *name;
+       gboolean legacy, name_known;
+       int err;
+
+       memset(&eir_data, 0, sizeof(eir_data));
+       err = eir_parse(&eir_data, data, data_len);
+       if (err < 0) {
+               error("Error parsing EIR data: %s (%d)", strerror(-err), -err);
+               return;
+       }
 
-       dev = get_found_dev(adapter, bdaddr, &new_dev);
+       if (eir_data.name != NULL && eir_data.name_complete)
+               write_device_name(&adapter->bdaddr, bdaddr, eir_data.name);
 
-       if (new_dev) {
-               if (name)
-                       dev->name = g_strdup(name);
+       dev = adapter_search_found_devices(adapter, bdaddr);
+       if (dev) {
+               adapter->oor_devices = g_slist_remove(adapter->oor_devices,
+                                                       dev);
+               if (dev->rssi != rssi)
+                       goto done;
 
-               if (alias)
-                       dev->alias = g_strdup(alias);
+               eir_data_free(&eir_data);
 
-               dev->le = FALSE;
-               dev->class = class;
-               dev->legacy = legacy;
-               dev->name_status = name_status;
-       } else if (dev->rssi == rssi)
                return;
+       }
 
-       dev->rssi = rssi;
+       /* New device in the discovery session */
 
-       adapter->found_devices = g_slist_sort(adapter->found_devices,
-                                               (GCompareFunc) dev_rssi_cmp);
+       name = read_stored_data(&adapter->bdaddr, bdaddr, "names");
 
-       g_slist_foreach(services, remove_same_uuid, dev);
-       g_slist_foreach(services, dev_prepend_uuid, dev);
+       if (type == ADDR_TYPE_BREDR) {
+               legacy = pairing_is_legacy(&adapter->bdaddr, bdaddr, data,
+                                                                       name);
 
-       adapter_emit_device_found(adapter, dev);
-}
+               if (!name && main_opts.name_resolv &&
+                               adapter_has_discov_sessions(adapter))
+                       name_known = FALSE;
+               else
+                       name_known = TRUE;
+       } else {
+               legacy = FALSE;
+               name_known = TRUE;
+       }
 
-int adapter_remove_found_device(struct btd_adapter *adapter, bdaddr_t *bdaddr)
-{
-       struct remote_dev_info *dev, match;
+       if (confirm_name)
+               adapter_ops->confirm_name(adapter->dev_id, bdaddr, name_known);
 
-       memset(&match, 0, sizeof(struct remote_dev_info));
-       bacpy(&match.bdaddr, bdaddr);
+       alias = read_stored_data(&adapter->bdaddr, bdaddr, "aliases");
 
-       dev = adapter_search_found_devices(adapter, &match);
-       if (!dev)
-               return -1;
+       dev = found_device_new(bdaddr, type, name, alias, class, legacy,
+                                                       eir_data.flags);
+       free(name);
+       free(alias);
 
-       dev->name_status = NAME_NOT_REQUIRED;
+       adapter->found_devices = g_slist_prepend(adapter->found_devices, dev);
 
-       return 0;
+done:
+       dev->rssi = rssi;
+
+       adapter->found_devices = g_slist_sort(adapter->found_devices,
+                                               (GCompareFunc) dev_rssi_cmp);
+
+       g_slist_foreach(eir_data.services, remove_same_uuid, dev);
+       g_slist_foreach(eir_data.services, dev_prepend_uuid, dev);
+
+       adapter_emit_device_found(adapter, dev);
+
+       eir_data_free(&eir_data);
 }
 
 void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode)
@@ -3400,9 +2866,6 @@ void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode)
        gboolean discoverable, pairable;
 
        DBG("old 0x%02x new 0x%02x", adapter->scan_mode, scan_mode);
-#ifdef __TIZEN_PATCH__
-       gboolean limited;
-#endif
 
        if (adapter->scan_mode == scan_mode)
                return;
@@ -3414,17 +2877,11 @@ void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode)
                adapter->mode = MODE_OFF;
                discoverable = FALSE;
                pairable = FALSE;
-#ifdef __TIZEN_PATCH__
-               limited = FALSE;
-#endif
                break;
        case SCAN_PAGE:
                adapter->mode = MODE_CONNECTABLE;
                discoverable = FALSE;
                pairable = adapter->pairable;
-#ifdef __TIZEN_PATCH__
-               limited = FALSE;
-#endif
                break;
        case (SCAN_PAGE | SCAN_INQUIRY):
                adapter->mode = MODE_DISCOVERABLE;
@@ -3467,7 +2924,7 @@ void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode)
 
 struct agent *adapter_get_agent(struct btd_adapter *adapter)
 {
-       if (!adapter || !adapter->agent)
+       if (!adapter)
                return NULL;
 
        return adapter->agent;
@@ -3489,8 +2946,6 @@ void adapter_add_connection(struct btd_adapter *adapter,
 void adapter_remove_connection(struct btd_adapter *adapter,
                                                struct btd_device *device)
 {
-       bdaddr_t bdaddr;
-
        DBG("");
 
        if (!g_slist_find(adapter->connections, device)) {
@@ -3502,9 +2957,6 @@ void adapter_remove_connection(struct btd_adapter *adapter,
 
        adapter->connections = g_slist_remove(adapter->connections, device);
 
-       /* clean pending HCI cmds */
-       device_get_address(device, &bdaddr);
-
        if (device_is_authenticating(device))
                device_cancel_authentication(device, TRUE);
 
@@ -3524,29 +2976,6 @@ gboolean adapter_has_discov_sessions(struct btd_adapter *adapter)
        return TRUE;
 }
 
-void adapter_suspend_discovery(struct btd_adapter *adapter)
-{
-       if (adapter->disc_sessions == NULL ||
-                       adapter->state & STATE_SUSPENDED)
-               return;
-
-       DBG("Suspending discovery");
-
-       stop_discovery(adapter, TRUE);
-       adapter->state |= STATE_SUSPENDED;
-}
-
-void adapter_resume_discovery(struct btd_adapter *adapter)
-{
-       if (adapter->disc_sessions == NULL)
-               return;
-
-       DBG("Resuming discovery");
-
-       adapter->state &= ~STATE_SUSPENDED;
-       start_discovery(adapter);
-}
-
 int btd_register_adapter_driver(struct btd_adapter_driver *driver)
 {
        adapter_drivers = g_slist_append(adapter_drivers, driver);
@@ -3745,11 +3174,6 @@ void btd_adapter_any_release_path(void)
        adapter_any_path = NULL;
 }
 
-gboolean adapter_is_pairable(struct btd_adapter *adapter)
-{
-       return adapter->pairable;
-}
-
 gboolean adapter_powering_down(struct btd_adapter *adapter)
 {
        return adapter->off_requested;
@@ -3758,7 +3182,6 @@ gboolean adapter_powering_down(struct btd_adapter *adapter)
 int btd_adapter_restore_powered(struct btd_adapter *adapter)
 {
        char mode[14], address[18];
-       gboolean discoverable;
 
        if (!adapter_ops)
                return -EINVAL;
@@ -3774,18 +3197,29 @@ int btd_adapter_restore_powered(struct btd_adapter *adapter)
                                                g_str_equal(mode, "off"))
                return 0;
 
-       discoverable = get_mode(&adapter->bdaddr, mode) == MODE_DISCOVERABLE;
-
        return adapter_ops->set_powered(adapter->dev_id, TRUE);
 }
 
+static gboolean switch_off_timeout(gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       adapter_ops->set_powered(adapter->dev_id, FALSE);
+       adapter->off_timer = 0;
+
+       return FALSE;
+}
+
 int btd_adapter_switch_online(struct btd_adapter *adapter)
 {
        if (!adapter_ops)
                return -EINVAL;
 
        if (adapter->up)
-               return 0;
+               return -EALREADY;
+
+       if (adapter->off_timer)
+               off_timer_remove(adapter);
 
        return adapter_ops->set_powered(adapter->dev_id, TRUE);
 }
@@ -3796,9 +3230,95 @@ int btd_adapter_switch_offline(struct btd_adapter *adapter)
                return -EINVAL;
 
        if (!adapter->up)
+               return -EALREADY;
+
+       if (adapter->off_timer)
                return 0;
 
-       return adapter_ops->set_powered(adapter->dev_id, FALSE);
+       adapter->global_mode = MODE_OFF;
+
+       if (adapter->connections == NULL)
+               return adapter_ops->set_powered(adapter->dev_id, FALSE);
+
+       g_slist_foreach(adapter->connections,
+                               (GFunc) device_request_disconnect, NULL);
+
+       adapter->off_timer = g_timeout_add_seconds(OFF_TIMER,
+                                               switch_off_timeout, adapter);
+
+       return 0;
+}
+
+static gboolean disable_auto(gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       GSList *l;
+
+       for (l = adapter->devices; l; l = l->next) {
+               struct btd_device *device = l->data;
+
+               device_set_auto_connect(device, FALSE);
+       }
+
+       adapter->auto_timeout_id = 0;
+
+       return FALSE;
+}
+
+static void set_auto_connect(gpointer data, gpointer user_data)
+{
+       struct btd_device *device = data;
+
+       device_set_auto_connect(device, TRUE);
+}
+
+void btd_adapter_enable_auto_connect(struct btd_adapter *adapter)
+{
+       if (!adapter->up)
+               return;
+
+       DBG("Enabling automatic connections");
+
+       if (adapter->auto_timeout_id)
+               return;
+
+       g_slist_foreach(adapter->devices, set_auto_connect, NULL);
+
+       adapter->auto_timeout_id = g_timeout_add_seconds(main_opts.autoto,
+                                               disable_auto, adapter);
+}
+
+void btd_adapter_register_pin_cb(struct btd_adapter *adapter,
+                                                       btd_adapter_pin_cb_t cb)
+{
+       adapter->pin_callbacks = g_slist_prepend(adapter->pin_callbacks, cb);
+}
+
+void btd_adapter_unregister_pin_cb(struct btd_adapter *adapter,
+                                                       btd_adapter_pin_cb_t cb)
+{
+       adapter->pin_callbacks = g_slist_remove(adapter->pin_callbacks, cb);
+}
+
+ssize_t btd_adapter_get_pin(struct btd_adapter *adapter, struct btd_device *dev,
+                                                               char *pin_buf)
+{
+       GSList *l;
+       btd_adapter_pin_cb_t cb;
+       bdaddr_t sba, dba;
+       ssize_t ret;
+
+       for (l = adapter->pin_callbacks; l != NULL; l = g_slist_next(l)) {
+               cb = l->data;
+               ret = cb(adapter, dev, pin_buf);
+               if (ret > 0)
+                       return ret;
+       }
+
+       adapter_get_address(adapter, &sba);
+       device_get_address(dev, &dba, NULL);
+
+       return read_pin_code(&sba, &dba, pin_buf);
 }
 
 int btd_register_adapter_ops(struct btd_adapter_ops *ops, gboolean priority)
@@ -3896,9 +3416,10 @@ int btd_adapter_remove_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr)
 }
 
 int btd_adapter_pincode_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                                       const char *pin)
+                                       const char *pin, size_t pin_len)
 {
-       return adapter_ops->pincode_reply(adapter->dev_id, bdaddr, pin);
+       return adapter_ops->pincode_reply(adapter->dev_id, bdaddr, pin,
+                                                               pin_len);
 }
 
 int btd_adapter_confirm_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
@@ -3913,14 +3434,6 @@ int btd_adapter_passkey_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
        return adapter_ops->passkey_reply(adapter->dev_id, bdaddr, passkey);
 }
 
-void btd_adapter_update_local_ext_features(struct btd_adapter *adapter,
-                                               const uint8_t *features)
-{
-       struct hci_dev *dev = &adapter->dev;
-
-       memcpy(dev->extfeatures, features, 8);
-}
-
 int btd_adapter_encrypt_link(struct btd_adapter *adapter, bdaddr_t *bdaddr,
                                        bt_hci_result_t cb, gpointer user_data)
 {
@@ -3936,6 +3449,7 @@ int btd_adapter_set_did(struct btd_adapter *adapter, uint16_t vendor,
 int adapter_create_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr,
                                                                uint8_t io_cap)
 {
+       suspend_discovery(adapter);
        return adapter_ops->create_bonding(adapter->dev_id, bdaddr, io_cap);
 }
 
@@ -3943,3 +3457,42 @@ int adapter_cancel_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr)
 {
        return adapter_ops->cancel_bonding(adapter->dev_id, bdaddr);
 }
+
+void adapter_bonding_complete(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+                                                               uint8_t status)
+{
+       struct btd_device *device;
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       if (status == 0)
+               device = adapter_get_device(connection, adapter, addr);
+       else
+               device = adapter_find_device(adapter, addr);
+
+       if (device != NULL)
+               device_bonding_complete(device, status);
+
+       if (adapter->discov_suspended) {
+               adapter->discov_suspended = FALSE;
+               adapter_ops->start_discovery(adapter->dev_id);
+       }
+}
+
+int btd_adapter_read_local_oob_data(struct btd_adapter *adapter)
+{
+       return adapter_ops->read_local_oob_data(adapter->dev_id);
+}
+
+int btd_adapter_add_remote_oob_data(struct btd_adapter *adapter,
+                       bdaddr_t *bdaddr, uint8_t *hash, uint8_t *randomizer)
+{
+       return adapter_ops->add_remote_oob_data(adapter->dev_id, bdaddr, hash,
+                                                               randomizer);
+}
+
+int btd_adapter_remove_remote_oob_data(struct btd_adapter *adapter,
+                                                       bdaddr_t *bdaddr)
+{
+       return adapter_ops->remove_remote_oob_data(adapter->dev_id, bdaddr);
+}
index ba8c52a..fb1dcdf 100644 (file)
 #define MODE_DISCOVERABLE      0x02
 #define MODE_UNKNOWN           0xff
 
-/* Discover states */
-#define STATE_IDLE             0x00
-#define STATE_LE_SCAN          0x01
-#define STATE_STDINQ           0x02
-#define STATE_PINQ             0x04
-#define STATE_RESOLVNAME       0x08
-#define STATE_SUSPENDED                0x10
-
-/* Supported host/controller discover type */
-#define DISC_LE                        0x01
-#define DISC_STDINQ            0x02
-#define DISC_INTERLEAVE                0x04
-#define DISC_PINQ              0x08
-#define DISC_RESOLVNAME                0x10
-
 #define MAX_NAME_LENGTH                248
 
 /* Invalid SSP passkey value used to indicate negative replies */
 #define INVALID_PASSKEY                0xffffffff
 
 typedef enum {
-       NAME_ANY,
-       NAME_NOT_REQUIRED, /* used by get remote name without name resolving */
-       NAME_REQUIRED,      /* remote name needs be resolved       */
-       NAME_REQUESTED,    /* HCI remote name request was sent    */
-} name_status_t;
+       ADDR_TYPE_BREDR,
+       ADDR_TYPE_LE_PUBLIC,
+       ADDR_TYPE_LE_RANDOM,
+} addr_type_t;
 
 struct btd_adapter;
 
@@ -74,48 +58,19 @@ struct link_key_info {
 
 struct remote_dev_info {
        bdaddr_t bdaddr;
+       addr_type_t type;
        int8_t rssi;
        uint32_t class;
        char *name;
        char *alias;
        dbus_bool_t legacy;
-       name_status_t name_status;
-       gboolean le;
        char **uuids;
        size_t uuid_count;
        GSList *services;
-       uint8_t evt_type;
        uint8_t bdaddr_type;
        uint8_t flags;
 };
 
-struct hci_dev {
-       uint8_t  features[8];
-       uint8_t  extfeatures[8];
-       uint8_t  lmp_ver;
-       uint16_t lmp_subver;
-       uint16_t hci_rev;
-       uint16_t manufacturer;
-
-       uint8_t  ssp_mode;
-       char     name[MAX_NAME_LENGTH + 1];
-};
-
-#ifdef __TIZEN_PATCH__
-#ifndef MAX_REMOTE_SERVICES
-       #define MAX_REMOTE_SERVICES 0x14
-#endif
-typedef struct
-{
-       DBusMessage *msg;
-       DBusConnection* conn;
-#if 0 //Service search
-#else
-       DBusMessageIter* array_iter;
-#endif
-}service_dbus_ctxt_t;
-
-#endif
 void btd_adapter_start(struct btd_adapter *adapter);
 
 int btd_adapter_stop(struct btd_adapter *adapter);
@@ -123,8 +78,6 @@ int btd_adapter_stop(struct btd_adapter *adapter);
 void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode,
                                        uint8_t *on_mode, gboolean *pairable);
 
-int adapter_update_ssp_mode(struct btd_adapter *adapter, uint8_t mode);
-
 struct btd_device *adapter_get_device(DBusConnection *conn,
                                struct btd_adapter *adapter, const char *address);
 
@@ -134,32 +87,30 @@ void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,
                                                struct btd_device *device,
                                                gboolean remove_storage);
 
-int adapter_resolve_names(struct btd_adapter *adapter);
-
 struct btd_adapter *adapter_create(DBusConnection *conn, int id);
 gboolean adapter_init(struct btd_adapter *adapter);
 void adapter_remove(struct btd_adapter *adapter);
+void adapter_set_allow_name_changes(struct btd_adapter *adapter,
+                                               gboolean allow_name_changes);
+void adapter_set_discovering(struct btd_adapter *adapter,
+                                               gboolean discovering);
 uint16_t adapter_get_dev_id(struct btd_adapter *adapter);
 const gchar *adapter_get_path(struct btd_adapter *adapter);
 void adapter_get_address(struct btd_adapter *adapter, bdaddr_t *bdaddr);
 void adapter_set_state(struct btd_adapter *adapter, int state);
 int adapter_get_state(struct btd_adapter *adapter);
-int adapter_get_discover_type(struct btd_adapter *adapter);
 struct remote_dev_info *adapter_search_found_devices(struct btd_adapter *adapter,
-                                               struct remote_dev_info *match);
-void adapter_update_device_from_info(struct btd_adapter *adapter,
-                                       bdaddr_t bdaddr, int8_t rssi,
-                                       uint8_t evt_type, const char *name,
-                                       GSList *services, int flags);
-void adapter_update_found_devices(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                               int8_t rssi, uint32_t class, const char *name,
-                               const char *alias, gboolean legacy,
-                               GSList *services, name_status_t name_status);
-int adapter_remove_found_device(struct btd_adapter *adapter, bdaddr_t *bdaddr);
+                                                       bdaddr_t *bdaddr);
+void adapter_update_found_devices(struct btd_adapter *adapter,
+                                       bdaddr_t *bdaddr, addr_type_t type,
+                                       uint32_t class, int8_t rssi,
+                                       uint8_t confirm_name,
+                                       uint8_t *data, uint8_t data_len);
 void adapter_emit_device_found(struct btd_adapter *adapter,
                                                struct remote_dev_info *dev);
 void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode);
-void adapter_update_local_name(struct btd_adapter *adapter, const char *name);
+int adapter_set_name(struct btd_adapter *adapter, const char *name);
+void adapter_name_changed(struct btd_adapter *adapter, const char *name);
 void adapter_service_insert(struct btd_adapter *adapter, void *rec);
 void adapter_service_remove(struct btd_adapter *adapter, void *rec);
 void btd_adapter_class_changed(struct btd_adapter *adapter,
@@ -173,8 +124,6 @@ void adapter_add_connection(struct btd_adapter *adapter,
 void adapter_remove_connection(struct btd_adapter *adapter,
                                                struct btd_device *device);
 gboolean adapter_has_discov_sessions(struct btd_adapter *adapter);
-void adapter_suspend_discovery(struct btd_adapter *adapter);
-void adapter_resume_discovery(struct btd_adapter *adapter);
 
 struct btd_adapter *btd_adapter_ref(struct btd_adapter *adapter);
 void btd_adapter_unref(struct btd_adapter *adapter);
@@ -200,12 +149,21 @@ const char *adapter_any_get_path(void);
 
 const char *btd_adapter_any_request_path(void);
 void btd_adapter_any_release_path(void);
-gboolean adapter_is_pairable(struct btd_adapter *adapter);
 gboolean adapter_powering_down(struct btd_adapter *adapter);
 
 int btd_adapter_restore_powered(struct btd_adapter *adapter);
 int btd_adapter_switch_online(struct btd_adapter *adapter);
 int btd_adapter_switch_offline(struct btd_adapter *adapter);
+void btd_adapter_enable_auto_connect(struct btd_adapter *adapter);
+
+typedef ssize_t (*btd_adapter_pin_cb_t) (struct btd_adapter *adapter,
+                                       struct btd_device *dev, char *out);
+void btd_adapter_register_pin_cb(struct btd_adapter *adapter,
+                                               btd_adapter_pin_cb_t cb);
+void btd_adapter_unregister_pin_cb(struct btd_adapter *adapter,
+                                               btd_adapter_pin_cb_t cb);
+ssize_t btd_adapter_get_pin(struct btd_adapter *adapter, struct btd_device *dev,
+                                                               char *pin_buf);
 
 typedef void (*bt_hci_result_t) (uint8_t status, gpointer user_data);
 
@@ -216,13 +174,9 @@ struct btd_adapter_ops {
        int (*set_discoverable) (int index, gboolean discoverable);
        int (*set_pairable) (int index, gboolean pairable);
        int (*set_limited_discoverable) (int index, gboolean limited);
-       int (*start_inquiry) (int index, uint8_t length, gboolean periodic);
-       int (*stop_inquiry) (int index);
-       int (*start_scanning) (int index);
-       int (*stop_scanning) (int index);
+       int (*start_discovery) (int index);
+       int (*stop_discovery) (int index);
 
-       int (*resolve_name) (int index, bdaddr_t *bdaddr);
-       int (*cancel_resolve_name) (int index, bdaddr_t *bdaddr);
        int (*set_name) (int index, const char *name);
        int (*set_dev_class) (int index, uint8_t major, uint8_t minor);
        int (*set_fast_connectable) (int index, gboolean enable);
@@ -232,14 +186,12 @@ struct btd_adapter_ops {
        int (*block_device) (int index, bdaddr_t *bdaddr);
        int (*unblock_device) (int index, bdaddr_t *bdaddr);
        int (*get_conn_list) (int index, GSList **conns);
-       int (*read_local_version) (int index, struct hci_version *ver);
-       int (*read_local_features) (int index, uint8_t *features);
        int (*disconnect) (int index, bdaddr_t *bdaddr);
        int (*remove_bonding) (int index, bdaddr_t *bdaddr);
-       int (*pincode_reply) (int index, bdaddr_t *bdaddr, const char *pin);
+       int (*pincode_reply) (int index, bdaddr_t *bdaddr, const char *pin,
+                                                       size_t pin_len);
        int (*confirm_reply) (int index, bdaddr_t *bdaddr, gboolean success);
        int (*passkey_reply) (int index, bdaddr_t *bdaddr, uint32_t passkey);
-       int (*enable_le) (int index);
        int (*encrypt_link) (int index, bdaddr_t *bdaddr, bt_hci_result_t cb,
                                                        gpointer user_data);
        int (*set_did) (int index, uint16_t vendor, uint16_t product,
@@ -252,6 +204,11 @@ struct btd_adapter_ops {
        int (*set_io_capability) (int index, uint8_t io_capability);
        int (*create_bonding) (int index, bdaddr_t *bdaddr, uint8_t io_cap);
        int (*cancel_bonding) (int index, bdaddr_t *bdaddr);
+       int (*read_local_oob_data) (int index);
+       int (*add_remote_oob_data) (int index, bdaddr_t *bdaddr, uint8_t *hash,
+                                                       uint8_t *randomizer);
+       int (*remove_remote_oob_data) (int index, bdaddr_t *bdaddr);
+       int (*confirm_name) (int index, bdaddr_t *bdaddr, gboolean name_known);
 };
 
 int btd_register_adapter_ops(struct btd_adapter_ops *ops, gboolean priority);
@@ -284,15 +241,12 @@ int btd_adapter_disconnect_device(struct btd_adapter *adapter,
 int btd_adapter_remove_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr);
 
 int btd_adapter_pincode_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                                       const char *pin);
+                                       const char *pin, size_t pin_len);
 int btd_adapter_confirm_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
                                                        gboolean success);
 int btd_adapter_passkey_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
                                                        uint32_t passkey);
 
-void btd_adapter_update_local_ext_features(struct btd_adapter *adapter,
-                                               const uint8_t *features);
-
 int btd_adapter_encrypt_link(struct btd_adapter *adapter, bdaddr_t *bdaddr,
                                bt_hci_result_t cb, gpointer user_data);
 
@@ -304,6 +258,16 @@ int adapter_create_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr,
 
 int adapter_cancel_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr);
 
-#ifdef __TIZEN_PATCH__
-sdp_list_t *adapter_get_services(struct btd_adapter *adapter);
-#endif
+void adapter_bonding_complete(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+                                                       uint8_t status);
+
+int btd_adapter_read_local_oob_data(struct btd_adapter *adapter);
+
+int btd_adapter_add_remote_oob_data(struct btd_adapter *adapter,
+                       bdaddr_t *bdaddr, uint8_t *hash, uint8_t *randomizer);
+
+int btd_adapter_remove_remote_oob_data(struct btd_adapter *adapter,
+                                                       bdaddr_t *bdaddr);
+
+int btd_adapter_gatt_server_start(struct btd_adapter *adapter);
+void btd_adapter_gatt_server_stop(struct btd_adapter *adapter);
index 377abe7..cbd19a2 100644 (file)
@@ -41,7 +41,6 @@
 
 #include "log.h"
 
-#include "hcid.h"
 #include "adapter.h"
 #include "device.h"
 #include "agent.h"
@@ -80,9 +79,6 @@ struct agent_request {
 
 static DBusConnection *connection = NULL;
 
-static int request_fallback(struct agent_request *req,
-                               DBusPendingCallNotifyFunction function);
-
 static void agent_release(struct agent *agent)
 {
        DBusMessage *message;
@@ -259,17 +255,10 @@ static void simple_agent_reply(DBusPendingCall *call, void *user_data)
 
        dbus_error_init(&err);
        if (dbus_set_error_from_message(&err, message)) {
-               if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) ||
-                               g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) &&
-                               request_fallback(req, simple_agent_reply) == 0) {
-                       dbus_error_free(&err);
-                       return;
-               }
-
                error("Agent replied with an error: %s, %s",
                                err.name, err.message);
 
-#ifdef __TIZEN_PATCH__
+#ifdef __SAMSUNG_PATCH__
                if (strcmp(err.message, "CanceledbyUser") == 0)
                {
                        set_cancel_from_authentication_req(req->user_data);
@@ -342,7 +331,6 @@ int agent_authorize(struct agent *agent,
        struct agent_request *req;
        int err;
 
-       info("agent_authorize");
        if (agent->request)
                return -EBUSY;
 
@@ -382,17 +370,10 @@ static void pincode_reply(DBusPendingCall *call, void *user_data)
 
        dbus_error_init(&err);
        if (dbus_set_error_from_message(&err, message)) {
-               if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) ||
-                               g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) &&
-                               request_fallback(req, pincode_reply) == 0) {
-                       dbus_error_free(&err);
-                       return;
-               }
-
-               error("Agent replied with an error: %s, %s",
-                               err.name, err.message);
+               error("Agent %s replied with an error: %s, %s",
+                               agent->path, err.name, err.message);
 
-#ifdef __TIZEN_PATCH__
+#ifdef __SAMSUNG_PATCH__
                if (strcmp(err.message, "CanceledbyUser") == 0)
                {
                        set_cancel_from_authentication_req(req->user_data);
@@ -438,10 +419,13 @@ done:
 }
 
 static int pincode_request_new(struct agent_request *req, const char *device_path,
-                               dbus_bool_t numeric)
+                               dbus_bool_t secure)
 {
        struct agent *agent = req->agent;
 
+       /* TODO: Add a new method or a new param to Agent interface to request
+               secure pin. */
+
        req->msg = dbus_message_new_method_call(agent->name, agent->path,
                                        "org.bluez.Agent", "RequestPinCode");
        if (req->msg == NULL) {
@@ -463,8 +447,8 @@ static int pincode_request_new(struct agent_request *req, const char *device_pat
 }
 
 int agent_request_pincode(struct agent *agent, struct btd_device *device,
-                               agent_pincode_cb cb, void *user_data,
-                               GDestroyNotify destroy)
+                               agent_pincode_cb cb, gboolean secure,
+                               void *user_data, GDestroyNotify destroy)
 {
        struct agent_request *req;
        const gchar *dev_path = device_get_path(device);
@@ -476,7 +460,7 @@ int agent_request_pincode(struct agent *agent, struct btd_device *device,
        req = agent_request_new(agent, AGENT_REQUEST_PINCODE, cb,
                                                        user_data, destroy);
 
-       err = pincode_request_new(req, dev_path, FALSE);
+       err = pincode_request_new(req, dev_path, secure);
        if (err < 0)
                goto failed;
 
@@ -559,16 +543,9 @@ static void passkey_reply(DBusPendingCall *call, void *user_data)
 
        dbus_error_init(&err);
        if (dbus_set_error_from_message(&err, message)) {
-               if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) ||
-                               g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) &&
-                               request_fallback(req, passkey_reply) == 0) {
-                       dbus_error_free(&err);
-                       return;
-               }
-
                error("Agent replied with an error: %s, %s",
-                               err.name, err.message);
-#ifdef __TIZEN_PATCH__
+                                               err.name, err.message);
+#ifdef __SAMSUNG_PATCH__
                if (strcmp(err.message, "CanceledbyUser") == 0)
                {
                        set_cancel_from_authentication_req(req->user_data);
@@ -715,43 +692,6 @@ failed:
        return err;
 }
 
-static int request_fallback(struct agent_request *req,
-                               DBusPendingCallNotifyFunction function)
-{
-       struct btd_adapter *adapter = req->agent->adapter;
-       struct agent *adapter_agent = adapter_get_agent(adapter);
-       DBusMessage *msg;
-
-       if (req->agent == adapter_agent || adapter_agent == NULL)
-               return -EINVAL;
-
-       dbus_pending_call_cancel(req->call);
-       dbus_pending_call_unref(req->call);
-
-       msg = dbus_message_copy(req->msg);
-
-       dbus_message_set_destination(msg, adapter_agent->name);
-       dbus_message_set_path(msg, adapter_agent->path);
-
-       if (dbus_connection_send_with_reply(connection, msg,
-                                       &req->call, REQUEST_TIMEOUT) == FALSE) {
-               error("D-Bus send failed");
-               dbus_message_unref(msg);
-               return -EIO;
-       }
-
-       req->agent->request = NULL;
-       req->agent = adapter_agent;
-       req->agent->request = req;
-
-       dbus_message_unref(req->msg);
-       req->msg = msg;
-
-       dbus_pending_call_set_notify(req->call, function, req, NULL);
-
-       return 0;
-}
-
 int agent_display_passkey(struct agent *agent, struct btd_device *device,
                                uint32_t passkey)
 {
index e184250..f62bf3b 100644 (file)
@@ -46,8 +46,8 @@ int agent_authorize(struct agent *agent, const char *path,
                        GDestroyNotify destroy);
 
 int agent_request_pincode(struct agent *agent, struct btd_device *device,
-                               agent_pincode_cb cb, void *user_data,
-                               GDestroyNotify destroy);
+                               agent_pincode_cb cb, gboolean secure,
+                               void *user_data, GDestroyNotify destroy);
 
 int agent_confirm_mode_change(struct agent *agent, const char *new_mode,
                                agent_cb cb, void *user_data,
diff --git a/src/attio.h b/src/attio.h
new file mode 100644 (file)
index 0000000..16e2873
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+typedef void (*attio_connect_cb) (GAttrib *attrib, gpointer user_data);
+typedef void (*attio_disconnect_cb) (gpointer user_data);
+
+guint btd_device_add_attio_callback(struct btd_device *device,
+                                               attio_connect_cb cfunc,
+                                               attio_disconnect_cb dcfunc,
+                                               gpointer user_data);
+
+gboolean btd_device_remove_attio_callback(struct btd_device *device, guint id);
index 9e37aee..36a398f 100644 (file)
 #include <bluetooth/sdp_lib.h>
 
 #include "log.h"
-#include "glib-helper.h"
+#include "gdbus.h"
+#include "glib-compat.h"
 #include "btio.h"
 #include "sdpd.h"
 #include "hcid.h"
+#include "adapter.h"
+#include "device.h"
+#include "manager.h"
 #include "att.h"
 #include "gattrib.h"
+#include "storage.h"
 
 #include "attrib-server.h"
 
-#define GATT_PSM 0x1f
-#define GATT_CID 4
-
-static GSList *database = NULL;
+static GSList *servers = NULL;
+
+struct gatt_server {
+       struct btd_adapter *adapter;
+       GIOChannel *l2cap_io;
+       GIOChannel *le_io;
+       uint32_t gatt_sdp_handle;
+       uint32_t gap_sdp_handle;
+       GSList *database;
+       GSList *clients;
+       uint16_t name_handle;
+       uint16_t appearance_handle;
+};
 
 struct gatt_channel {
        bdaddr_t src;
        bdaddr_t dst;
-       GSList *configs;
-       GSList *notify;
-       GSList *indicate;
        GAttrib *attrib;
        guint mtu;
        gboolean le;
        guint id;
        gboolean encrypted;
+       struct gatt_server *server;
 };
 
 struct group_elem {
@@ -72,16 +84,6 @@ struct group_elem {
        uint16_t len;
 };
 
-static GIOChannel *l2cap_io = NULL;
-static GIOChannel *le_io = NULL;
-static GSList *clients = NULL;
-static uint32_t gatt_sdp_handle = 0;
-static uint32_t gap_sdp_handle = 0;
-
-/* GAP attribute handles */
-static uint16_t name_handle = 0x0000;
-static uint16_t appearance_handle = 0x0000;
-
 static bt_uuid_t prim_uuid = {
                        .type = BT_UUID16,
                        .value.u16 = GATT_PRIM_SVC_UUID
@@ -90,6 +92,91 @@ static bt_uuid_t snd_uuid = {
                        .type = BT_UUID16,
                        .value.u16 = GATT_SND_SVC_UUID
 };
+static bt_uuid_t ccc_uuid = {
+                       .type = BT_UUID16,
+                       .value.u16 = GATT_CLIENT_CHARAC_CFG_UUID
+};
+
+static void attrib_free(void *data)
+{
+       struct attribute *a = data;
+
+       g_free(a->data);
+       g_free(a);
+}
+
+static void channel_free(struct gatt_channel *channel)
+{
+       g_attrib_unref(channel->attrib);
+
+       g_free(channel);
+}
+
+static void gatt_server_free(struct gatt_server *server)
+{
+       g_slist_free_full(server->database, attrib_free);
+
+       if (server->l2cap_io != NULL) {
+               g_io_channel_unref(server->l2cap_io);
+               g_io_channel_shutdown(server->l2cap_io, FALSE, NULL);
+       }
+
+       if (server->le_io != NULL) {
+               g_io_channel_unref(server->le_io);
+               g_io_channel_shutdown(server->le_io, FALSE, NULL);
+       }
+
+       g_slist_free_full(server->clients, (GDestroyNotify) channel_free);
+
+       if (server->gatt_sdp_handle > 0)
+               remove_record_from_server(server->gatt_sdp_handle);
+
+       if (server->gap_sdp_handle > 0)
+               remove_record_from_server(server->gap_sdp_handle);
+
+       if (server->adapter != NULL)
+               btd_adapter_unref(server->adapter);
+
+       g_free(server);
+}
+
+static gint adapter_cmp_addr(gconstpointer a, gconstpointer b)
+{
+       const struct gatt_server *server = a;
+       const bdaddr_t *bdaddr = b;
+       bdaddr_t src;
+
+       adapter_get_address(server->adapter, &src);
+
+       return bacmp(&src, bdaddr);
+}
+
+static gint adapter_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct gatt_server *server = a;
+       const struct btd_adapter *adapter = b;
+
+       if (server->adapter == adapter)
+               return 0;
+
+       return -1;
+}
+
+static struct gatt_server *find_gatt_server(const bdaddr_t *bdaddr)
+{
+       GSList *l;
+
+       l = g_slist_find_custom(servers, bdaddr, adapter_cmp_addr);
+       if (l == NULL) {
+               char addr[18];
+
+               ba2str(bdaddr, addr);
+               error("Not GATT adapter found for address %s", addr);
+               return NULL;
+       }
+
+       return l->data;
+}
 
 static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t end)
 {
@@ -97,7 +184,7 @@ static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t en
        uuid_t root_uuid, proto_uuid, l2cap;
        sdp_record_t *record;
        sdp_data_t *psm, *sh, *eh;
-       uint16_t lp = GATT_PSM;
+       uint16_t lp = ATT_PSM;
 
        if (uuid == NULL)
                return NULL;
@@ -162,127 +249,143 @@ static int attribute_cmp(gconstpointer a1, gconstpointer a2)
        return attrib1->handle - attrib2->handle;
 }
 
-static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,
-                                                               int reqs)
+static struct attribute *find_primary_range(struct gatt_server *server,
+                                               uint16_t start, uint16_t *end)
 {
-       /* FIXME: currently, it is assumed an encrypted link is enough for
-        * authentication. This will allow to enable the SMP negotiation once
-        * it is on upstream kernel. */
-       if (!channel->encrypted)
-               channel->encrypted = g_attrib_is_encrypted(channel->attrib);
-       if (reqs == ATT_AUTHENTICATION && !channel->encrypted)
-               return ATT_ECODE_INSUFF_ENC;
+       struct attribute *attrib;
+       guint h = start;
+       GSList *l;
 
-       switch (opcode) {
-       case ATT_OP_READ_BY_GROUP_REQ:
-       case ATT_OP_READ_BY_TYPE_REQ:
-       case ATT_OP_READ_REQ:
-       case ATT_OP_READ_BLOB_REQ:
-       case ATT_OP_READ_MULTI_REQ:
-               if (reqs == ATT_NOT_PERMITTED)
-                       return ATT_ECODE_READ_NOT_PERM;
-               break;
-       case ATT_OP_PREP_WRITE_REQ:
-       case ATT_OP_WRITE_REQ:
-       case ATT_OP_WRITE_CMD:
-               if (reqs == ATT_NOT_PERMITTED)
-                       return ATT_ECODE_WRITE_NOT_PERM;
-               break;
-       }
+       if (end == NULL)
+               return NULL;
 
-       return 0;
-}
+       l = g_slist_find_custom(server->database, GUINT_TO_POINTER(h),
+                                                               handle_cmp);
+       if (!l)
+               return NULL;
 
-static uint8_t client_set_notifications(struct attribute *attr,
-                                                       gpointer user_data)
-{
-       struct gatt_channel *channel = user_data;
-       struct attribute *last_chr_val = NULL;
-       uint16_t cfg_val;
-       uint8_t props;
-       bt_uuid_t uuid;
-       GSList *l;
+       attrib = l->data;
 
-       cfg_val = att_get_u16(attr->data);
+       if (bt_uuid_cmp(&attrib->uuid, &prim_uuid) != 0)
+               return NULL;
 
-       bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
-       for (l = database, props = 0; l != NULL; l = l->next) {
+       *end = start;
+
+       for (l = l->next; l; l = l->next) {
                struct attribute *a = l->data;
-               static uint16_t handle = 0;
 
-               if (a->handle >= attr->handle)
+               if (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
+                               bt_uuid_cmp(&a->uuid, &snd_uuid) == 0)
                        break;
 
-               if (bt_uuid_cmp(&a->uuid, &uuid) == 0) {
-                       props = att_get_u8(&a->data[0]);
-                       handle = att_get_u16(&a->data[1]);
-                       continue;
-               }
-
-               if (handle && a->handle == handle)
-                       last_chr_val = a;
+               *end = a->handle;
        }
 
-       if (last_chr_val == NULL)
-               return 0;
+       return attrib;
+}
 
-       if ((cfg_val & 0x0001) && !(props & ATT_CHAR_PROPER_NOTIFY))
-               return ATT_ECODE_WRITE_NOT_PERM;
+static uint32_t attrib_create_sdp_new(struct gatt_server *server,
+                                       uint16_t handle, const char *name)
+{
+       sdp_record_t *record;
+       struct attribute *a;
+       uint16_t end = 0;
+       uuid_t svc, gap_uuid;
+       bdaddr_t addr;
 
-       if ((cfg_val & 0x0002) && !(props & ATT_CHAR_PROPER_INDICATE))
-               return ATT_ECODE_WRITE_NOT_PERM;
+       a = find_primary_range(server, handle, &end);
 
-       if (cfg_val & 0x0001)
-               channel->notify = g_slist_append(channel->notify, last_chr_val);
-       else
-               channel->notify = g_slist_remove(channel->notify, last_chr_val);
+       if (a == NULL)
+               return 0;
 
-       if (cfg_val & 0x0002)
-               channel->indicate = g_slist_append(channel->indicate,
-                                                               last_chr_val);
+       if (a->len == 2)
+               sdp_uuid16_create(&svc, att_get_u16(a->data));
+       else if (a->len == 16)
+               sdp_uuid128_create(&svc, a->data);
        else
-               channel->indicate = g_slist_remove(channel->indicate,
-                                                               last_chr_val);
+               return 0;
+
+       record = server_record_new(&svc, handle, end);
+       if (record == NULL)
+               return 0;
+
+       if (name != NULL)
+               sdp_set_info_attr(record, name, "BlueZ", NULL);
 
+       sdp_uuid16_create(&gap_uuid, GENERIC_ACCESS_PROFILE_ID);
+       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/");
+       }
+
+       adapter_get_address(server->adapter, &addr);
+       if (add_record_to_server(&addr, record) == 0)
+               return record->handle;
+
+       sdp_record_free(record);
        return 0;
 }
 
-static struct attribute *client_cfg_attribute(struct gatt_channel *channel,
-                                               struct attribute *orig_attr,
-                                               const uint8_t *value, int vlen)
+static struct attribute *attrib_db_add_new(struct gatt_server *server,
+                               uint16_t handle, bt_uuid_t *uuid, int read_reqs,
+                               int write_reqs, const uint8_t *value, int len)
 {
-       guint handle = orig_attr->handle;
-       bt_uuid_t uuid;
-       GSList *l;
+       struct attribute *a;
+       guint h = handle;
+
+       DBG("handle=0x%04x", handle);
 
-       bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
-       if (bt_uuid_cmp(&orig_attr->uuid, &uuid) != 0)
+       if (g_slist_find_custom(server->database, GUINT_TO_POINTER(h),
+                                                               handle_cmp))
                return NULL;
 
-       /* Value is unchanged, not need to create a private copy yet */
-       if (vlen == orig_attr->len && memcmp(orig_attr->data, value, vlen) == 0)
-               return orig_attr;
+       a = g_new0(struct attribute, 1);
+       a->len = len;
+       a->data = g_memdup(value, len);
+       a->handle = handle;
+       a->uuid = *uuid;
+       a->read_reqs = read_reqs;
+       a->write_reqs = write_reqs;
 
-       l = g_slist_find_custom(channel->configs, GUINT_TO_POINTER(handle),
-                                                               handle_cmp);
-       if (!l) {
-               struct attribute *a;
-
-               /* Create a private copy of the Client Characteristic
-                * Configuration attribute */
-               a = g_malloc0(sizeof(*a) + vlen);
-               memcpy(a, orig_attr, sizeof(*a));
-               memcpy(a->data, value, vlen);
-               a->write_cb = client_set_notifications;
-               a->cb_user_data = channel;
-
-               channel->configs = g_slist_insert_sorted(channel->configs, a,
+       server->database = g_slist_insert_sorted(server->database, a,
                                                                attribute_cmp);
 
-               return a;
+       return a;
+}
+
+static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,
+                                                               int reqs)
+{
+       /* FIXME: currently, it is assumed an encrypted link is enough for
+        * authentication. This will allow to enable the SMP negotiation once
+        * it is on upstream kernel. High security level should be mapped
+        * to authentication and medium to encryption permission. */
+       if (!channel->encrypted)
+               channel->encrypted = g_attrib_is_encrypted(channel->attrib);
+       if (reqs == ATT_AUTHENTICATION && !channel->encrypted)
+               return ATT_ECODE_AUTHENTICATION;
+       else if (reqs == ATT_AUTHORIZATION)
+               return ATT_ECODE_AUTHORIZATION;
+
+       switch (opcode) {
+       case ATT_OP_READ_BY_GROUP_REQ:
+       case ATT_OP_READ_BY_TYPE_REQ:
+       case ATT_OP_READ_REQ:
+       case ATT_OP_READ_BLOB_REQ:
+       case ATT_OP_READ_MULTI_REQ:
+               if (reqs == ATT_NOT_PERMITTED)
+                       return ATT_ECODE_READ_NOT_PERM;
+               break;
+       case ATT_OP_PREP_WRITE_REQ:
+       case ATT_OP_WRITE_REQ:
+       case ATT_OP_WRITE_CMD:
+               if (reqs == ATT_NOT_PERMITTED)
+                       return ATT_ECODE_WRITE_NOT_PERM;
+               break;
        }
 
-       return l->data;
+       return 0;
 }
 
 static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
@@ -292,7 +395,7 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
        struct att_data_list *adl;
        struct attribute *a;
        struct group_elem *cur, *old = NULL;
-       GSList *l, *groups;
+       GSList *l, *groups, *database;
        uint16_t length, last_handle, last_size = 0;
        uint8_t status;
        int i;
@@ -312,8 +415,8 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
                                        ATT_ECODE_UNSUPP_GRP_TYPE, pdu, len);
 
        last_handle = end;
-       for (l = database, groups = NULL; l; l = l->next) {
-               struct attribute *client_attr;
+       database = channel->server->database;
+       for (l = database, groups = NULL, cur = NULL; l; l = l->next) {
 
                a = l->data;
 
@@ -343,16 +446,11 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
                status = att_check_reqs(channel, ATT_OP_READ_BY_GROUP_REQ,
                                                                a->read_reqs);
 
-               client_attr = client_cfg_attribute(channel, a, a->data, a->len);
-               if (client_attr)
-                       a = client_attr;
-
                if (status == 0x00 && a->read_cb)
                        status = a->read_cb(a, a->cb_user_data);
 
                if (status) {
-                       g_slist_foreach(groups, (GFunc) g_free, NULL);
-                       g_slist_free(groups);
+                       g_slist_free_full(groups, g_free);
                        return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ,
                                                a->handle, status, pdu, len);
                }
@@ -399,8 +497,7 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
        length = enc_read_by_grp_resp(adl, pdu, len);
 
        att_data_list_free(adl);
-       g_slist_foreach(groups, (GFunc) g_free, NULL);
-       g_slist_free(groups);
+       g_slist_free_full(groups, g_free);
 
        return length;
 }
@@ -410,7 +507,7 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
                                                uint8_t *pdu, int len)
 {
        struct att_data_list *adl;
-       GSList *l, *types;
+       GSList *l, *types, *database;
        struct attribute *a;
        uint16_t num, length;
        uint8_t status;
@@ -420,15 +517,15 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
                return enc_error_resp(ATT_OP_READ_BY_TYPE_REQ, start,
                                        ATT_ECODE_INVALID_HANDLE, pdu, len);
 
+       database = channel->server->database;
        for (l = database, length = 0, types = NULL; l; l = l->next) {
-               struct attribute *client_attr;
 
                a = l->data;
 
                if (a->handle < start)
                        continue;
 
-               if (a->handle >= end)
+               if (a->handle > end)
                        break;
 
                if (bt_uuid_cmp(&a->uuid, uuid)  != 0)
@@ -437,10 +534,6 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
                status = att_check_reqs(channel, ATT_OP_READ_BY_TYPE_REQ,
                                                                a->read_reqs);
 
-               client_attr = client_cfg_attribute(channel, a, a->data, a->len);
-               if (client_attr)
-                       a = client_attr;
-
                if (status == 0x00 && a->read_cb)
                        status = a->read_cb(a, a->cb_user_data);
 
@@ -491,11 +584,12 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
        return length;
 }
 
-static int find_info(uint16_t start, uint16_t end, uint8_t *pdu, int len)
+static int find_info(struct gatt_channel *channel, uint16_t start, uint16_t end,
+                                                       uint8_t *pdu, int len)
 {
        struct attribute *a;
        struct att_data_list *adl;
-       GSList *l, *info;
+       GSList *l, *info, *database;
        uint8_t format, last_type = BT_UUID_UNSPEC;
        uint16_t length, num;
        int i;
@@ -504,6 +598,7 @@ static int find_info(uint16_t start, uint16_t end, uint8_t *pdu, int len)
                return enc_error_resp(ATT_OP_FIND_INFO_REQ, start,
                                        ATT_ECODE_INVALID_HANDLE, pdu, len);
 
+       database = channel->server->database;
        for (l = database, info = NULL, num = 0; l; l = l->next) {
                a = l->data;
 
@@ -535,6 +630,9 @@ static int find_info(uint16_t start, uint16_t end, uint8_t *pdu, int len)
        } else if (last_type == BT_UUID128) {
                length = 16;
                format = 0x02;
+       } else {
+               g_slist_free(info);
+               return 0;
        }
 
        adl = att_data_list_alloc(num, length + 2);
@@ -560,12 +658,13 @@ static int find_info(uint16_t start, uint16_t end, uint8_t *pdu, int len)
        return length;
 }
 
-static int find_by_type(uint16_t start, uint16_t end, bt_uuid_t *uuid,
-                       const uint8_t *value, int vlen, uint8_t *opdu, int mtu)
+static int find_by_type(struct gatt_channel *channel, uint16_t start,
+                       uint16_t end, bt_uuid_t *uuid, const uint8_t *value,
+                                       int vlen, uint8_t *opdu, int mtu)
 {
        struct attribute *a;
        struct att_range *range;
-       GSList *l, *matches;
+       GSList *l, *matches, *database;
        int len;
 
        if (start > end || start == 0x0000)
@@ -573,6 +672,7 @@ static int find_by_type(uint16_t start, uint16_t end, bt_uuid_t *uuid,
                                        ATT_ECODE_INVALID_HANDLE, opdu, mtu);
 
        /* Searching first requested handle number */
+       database = channel->server->database;
        for (l = database, matches = NULL, range = NULL; l; l = l->next) {
                a = l->data;
 
@@ -611,65 +711,38 @@ static int find_by_type(uint16_t start, uint16_t end, bt_uuid_t *uuid,
 
        len = enc_find_by_type_resp(matches, opdu, mtu);
 
-       g_slist_foreach(matches, (GFunc) g_free, NULL);
-       g_slist_free(matches);
+       g_slist_free_full(matches, g_free);
 
        return len;
 }
 
-static struct attribute *find_primary_range(uint16_t start, uint16_t *end)
-{
-       struct attribute *attrib;
-       guint h = start;
-       GSList *l;
-
-       if (end == NULL)
-               return NULL;
-
-       l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
-       if (!l)
-               return NULL;
-
-       attrib = l->data;
-
-       if (bt_uuid_cmp(&attrib->uuid, &prim_uuid) != 0)
-               return NULL;
-
-       *end = start;
-
-       for (l = l->next; l; l = l->next) {
-               struct attribute *a = l->data;
-
-               if (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
-                               bt_uuid_cmp(&a->uuid, &snd_uuid) == 0)
-                       break;
-
-               *end = a->handle;
-       }
-
-       return attrib;
-}
-
 static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
                                                        uint8_t *pdu, int len)
 {
-       struct attribute *a, *client_attr;
+       struct attribute *a;
        uint8_t status;
        GSList *l;
+       uint16_t cccval;
        guint h = handle;
 
-       l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
+       l = g_slist_find_custom(channel->server->database,
+                                       GUINT_TO_POINTER(h), handle_cmp);
        if (!l)
                return enc_error_resp(ATT_OP_READ_REQ, handle,
                                        ATT_ECODE_INVALID_HANDLE, pdu, len);
 
        a = l->data;
 
-       status = att_check_reqs(channel, ATT_OP_READ_REQ, a->read_reqs);
+       if (bt_uuid_cmp(&ccc_uuid, &a->uuid) == 0 &&
+               read_device_ccc(&channel->src, &channel->dst,
+                                       handle, &cccval) == 0) {
+               uint8_t config[2];
 
-       client_attr = client_cfg_attribute(channel, a, a->data, a->len);
-       if (client_attr)
-               a = client_attr;
+               att_put_u16(cccval, config);
+               return enc_read_resp(config, sizeof(config), pdu, len);
+       }
+
+       status = att_check_reqs(channel, ATT_OP_READ_REQ, a->read_reqs);
 
        if (status == 0x00 && a->read_cb)
                status = a->read_cb(a, a->cb_user_data);
@@ -684,12 +757,14 @@ static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
 static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle,
                                        uint16_t offset, uint8_t *pdu, int len)
 {
-       struct attribute *a, *client_attr;
+       struct attribute *a;
        uint8_t status;
        GSList *l;
+       uint16_t cccval;
        guint h = handle;
 
-       l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
+       l = g_slist_find_custom(channel->server->database,
+                                       GUINT_TO_POINTER(h), handle_cmp);
        if (!l)
                return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle,
                                        ATT_ECODE_INVALID_HANDLE, pdu, len);
@@ -700,11 +775,17 @@ static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle,
                return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle,
                                        ATT_ECODE_INVALID_OFFSET, pdu, len);
 
-       status = att_check_reqs(channel, ATT_OP_READ_BLOB_REQ, a->read_reqs);
+       if (bt_uuid_cmp(&ccc_uuid, &a->uuid) == 0 &&
+               read_device_ccc(&channel->src, &channel->dst,
+                                       handle, &cccval) == 0) {
+               uint8_t config[2];
+
+               att_put_u16(cccval, config);
+               return enc_read_blob_resp(config, sizeof(config), offset,
+                                                               pdu, len);
+       }
 
-       client_attr = client_cfg_attribute(channel, a, a->data, a->len);
-       if (client_attr)
-               a = client_attr;
+       status = att_check_reqs(channel, ATT_OP_READ_BLOB_REQ, a->read_reqs);
 
        if (status == 0x00 && a->read_cb)
                status = a->read_cb(a, a->cb_user_data);
@@ -720,12 +801,13 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
                                                const uint8_t *value, int vlen,
                                                uint8_t *pdu, int len)
 {
-       struct attribute *a, *client_attr;
+       struct attribute *a;
        uint8_t status;
        GSList *l;
        guint h = handle;
 
-       l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
+       l = g_slist_find_custom(channel->server->database,
+                                       GUINT_TO_POINTER(h), handle_cmp);
        if (!l)
                return enc_error_resp(ATT_OP_WRITE_REQ, handle,
                                ATT_ECODE_INVALID_HANDLE, pdu, len);
@@ -737,22 +819,21 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
                return enc_error_resp(ATT_OP_WRITE_REQ, handle, status, pdu,
                                                                        len);
 
-       client_attr = client_cfg_attribute(channel, a, value, vlen);
-       if (client_attr)
-               a = client_attr;
-       else
-               attrib_db_update(a->handle, &a->uuid, value, vlen);
+       if (bt_uuid_cmp(&ccc_uuid, &a->uuid) != 0) {
 
-       if (a->write_cb) {
-               status = a->write_cb(a, a->cb_user_data);
-               if (status)
-                       return enc_error_resp(ATT_OP_WRITE_REQ, handle, status,
-                                                               pdu, len);
-       }
+               attrib_db_update(channel->server->adapter, handle, NULL,
+                                                       value, vlen, NULL);
 
-       DBG("Notifications: %d, indications: %d",
-                                       g_slist_length(channel->notify),
-                                       g_slist_length(channel->indicate));
+               if (a->write_cb) {
+                       status = a->write_cb(a, a->cb_user_data);
+                       if (status)
+                               return enc_error_resp(ATT_OP_WRITE_REQ, handle,
+                                                       status, pdu, len);
+               }
+       } else {
+               uint16_t cccval = att_get_u16(value);
+               write_device_ccc(&channel->src, &channel->dst, handle, cccval);
+       }
 
        return enc_write_resp(pdu, len);
 }
@@ -767,7 +848,7 @@ static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
        else
                channel->mtu = MIN(mtu, channel->mtu);
 
-       bt_io_set(le_io, BT_IO_L2CAP, NULL,
+       bt_io_set(channel->server->le_io, BT_IO_L2CAP, NULL,
                        BT_IO_OPT_OMTU, channel->mtu,
                        BT_IO_OPT_INVALID);
 
@@ -778,15 +859,9 @@ static void channel_disconnect(void *user_data)
 {
        struct gatt_channel *channel = user_data;
 
-       g_attrib_unref(channel->attrib);
-       clients = g_slist_remove(clients, channel);
-
-       g_slist_free(channel->notify);
-       g_slist_free(channel->indicate);
-       g_slist_foreach(channel->configs, (GFunc) g_free, NULL);
-       g_slist_free(channel->configs);
-
-       g_free(channel);
+       channel->server->clients = g_slist_remove(channel->server->clients,
+                                                               channel);
+       channel_free(channel);
 }
 
 static void channel_handler(const uint8_t *ipdu, uint16_t len,
@@ -861,7 +936,7 @@ static void channel_handler(const uint8_t *ipdu, uint16_t len,
                        goto done;
                }
 
-               length = find_info(start, end, opdu, channel->mtu);
+               length = find_info(channel, start, end, opdu, channel->mtu);
                break;
        case ATT_OP_WRITE_REQ:
                length = dec_write_req(ipdu, len, &start, value, &vlen);
@@ -887,7 +962,7 @@ static void channel_handler(const uint8_t *ipdu, uint16_t len,
                        goto done;
                }
 
-               length = find_by_type(start, end, &uuid, value, vlen,
+               length = find_by_type(channel, start, end, &uuid, value, vlen,
                                                        opdu, channel->mtu);
                break;
        case ATT_OP_HANDLE_CNF:
@@ -913,16 +988,17 @@ done:
                                                        NULL, NULL, NULL);
 }
 
-static void connect_event(GIOChannel *io, GError *err, void *user_data)
+guint attrib_channel_attach(GAttrib *attrib, gboolean out)
 {
+       struct gatt_server *server;
+       struct btd_device *device;
        struct gatt_channel *channel;
-       uint16_t cid;
+       GIOChannel *io;
        GError *gerr = NULL;
+       char addr[18];
+       uint16_t cid;
 
-       if (err) {
-               error("%s", err->message);
-               return;
-       }
+       io = g_attrib_get_channel(attrib);
 
        channel = g_new0(struct gatt_channel, 1);
 
@@ -936,82 +1012,118 @@ static void connect_event(GIOChannel *io, GError *err, void *user_data)
                error("bt_io_get: %s", gerr->message);
                g_error_free(gerr);
                g_free(channel);
-               g_io_channel_shutdown(io, TRUE, NULL);
-               return;
+               return 0;
        }
 
+       server = find_gatt_server(&channel->src);
+       if (server == NULL)
+               return 0;
+
+       channel->server = server;
+
+       ba2str(&channel->dst, addr);
+       device = adapter_find_device(server->adapter, addr);
+
+       if (device_is_bonded(device) == FALSE)
+               delete_device_ccc(&channel->src, &channel->dst);
+
        if (channel->mtu > ATT_MAX_MTU)
                channel->mtu = ATT_MAX_MTU;
 
-       if (cid != GATT_CID)
+       if (cid != ATT_CID)
                channel->le = FALSE;
        else
                channel->le = TRUE;
 
-       channel->attrib = g_attrib_new(io);
-       g_io_channel_unref(io);
 
-       channel->id = g_attrib_register(channel->attrib, GATTRIB_ALL_EVENTS,
-                               channel_handler, channel, NULL);
+       channel->attrib = g_attrib_ref(attrib);
+       channel->id = g_attrib_register(channel->attrib, GATTRIB_ALL_REQS,
+                                       channel_handler, channel, NULL);
 
-       g_attrib_set_disconnect_function(channel->attrib, channel_disconnect,
-                                                               channel);
+       if (out == FALSE)
+               g_attrib_set_disconnect_function(channel->attrib,
+                                               channel_disconnect, channel);
+
+       server->clients = g_slist_append(server->clients, channel);
 
-       clients = g_slist_append(clients, channel);
+       return channel->id;
 }
 
-static void confirm_event(GIOChannel *io, void *user_data)
+static gint 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)
 {
+       struct gatt_server *server;
+       struct gatt_channel *channel;
        GError *gerr = NULL;
+       GIOChannel *io;
+       bdaddr_t src;
+       GSList *l;
 
-       if (bt_io_accept(io, connect_event, user_data, NULL, &gerr) == FALSE) {
-               error("bt_io_accept: %s", gerr->message);
+       io = g_attrib_get_channel(attrib);
+
+       bt_io_get(io, BT_IO_L2CAP, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src,
+                                                       BT_IO_OPT_INVALID);
+
+       if (gerr != NULL) {
+               error("bt_io_get: %s", gerr->message);
                g_error_free(gerr);
-               g_io_channel_unref(io);
+               return FALSE;
        }
 
-       return;
-}
+       server = find_gatt_server(&src);
+       if (server == NULL)
+               return FALSE;
 
-static void attrib_notify_clients(struct attribute *attr)
-{
-       guint handle = attr->handle;
-       GSList *l;
+       l = g_slist_find_custom(server->clients, GUINT_TO_POINTER(id),
+                                                               channel_id_cmp);
+       if (!l)
+               return FALSE;
 
-       for (l = clients; l; l = l->next) {
-               struct gatt_channel *channel = l->data;
+       channel = l->data;
 
-               /* Notification */
-               if (g_slist_find_custom(channel->notify,
-                                       GUINT_TO_POINTER(handle), handle_cmp)) {
-                       uint8_t pdu[ATT_MAX_MTU];
-                       uint16_t len;
+       g_attrib_unregister(channel->attrib, channel->id);
 
-                       len = enc_notification(attr, pdu, channel->mtu);
-                       if (len == 0)
-                               continue;
+       channel_disconnect(channel);
 
-                       g_attrib_send(channel->attrib, 0, pdu[0], pdu, len,
-                                                       NULL, NULL, NULL);
-               }
+       return TRUE;
+}
+
+static void connect_event(GIOChannel *io, GError *gerr, void *user_data)
+{
+       GAttrib *attrib;
 
-               /* Indication */
-               if (g_slist_find_custom(channel->indicate,
-                                       GUINT_TO_POINTER(handle), handle_cmp)) {
-                       uint8_t pdu[ATT_MAX_MTU];
-                       uint16_t len;
+       if (gerr) {
+               error("%s", gerr->message);
+               return;
+       }
 
-                       len = enc_indication(attr, pdu, channel->mtu);
-                       if (len == 0)
-                               return;
+       attrib = g_attrib_new(io);
+       attrib_channel_attach(attrib, FALSE);
+       g_io_channel_unref(io);
+       g_attrib_unref(attrib);
+}
 
-                       g_attrib_send(channel->attrib, 0, pdu[0], pdu, len,
-                                                       NULL, NULL, NULL);
-               }
+static void confirm_event(GIOChannel *io, void *user_data)
+{
+       GError *gerr = NULL;
+
+       if (bt_io_accept(io, connect_event, user_data, NULL, &gerr) == FALSE) {
+               error("bt_io_accept: %s", gerr->message);
+               g_error_free(gerr);
+               g_io_channel_unref(io);
        }
+
+       return;
 }
 
-static gboolean register_core_services(void)
+static gboolean register_core_services(struct gatt_server *server)
 {
        uint8_t atval[256];
        bt_uuid_t uuid;
@@ -1020,36 +1132,40 @@ static gboolean register_core_services(void)
        /* GAP service: primary service definition */
        bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
        att_put_u16(GENERIC_ACCESS_PROFILE_ID, &atval[0]);
-       attrib_db_add(0x0001, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
+       attrib_db_add_new(server, 0x0001, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 2);
 
        /* GAP service: device name characteristic */
-       name_handle = 0x0006;
+       server->name_handle = 0x0006;
        bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
        atval[0] = ATT_CHAR_PROPER_READ;
-       att_put_u16(name_handle, &atval[1]);
+       att_put_u16(server->name_handle, &atval[1]);
        att_put_u16(GATT_CHARAC_DEVICE_NAME, &atval[3]);
-       attrib_db_add(0x0004, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
+       attrib_db_add_new(server, 0x0004, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 5);
 
        /* GAP service: device name attribute */
        bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME);
-       attrib_db_add(name_handle, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
-                                                               NULL, 0);
+       attrib_db_add_new(server, server->name_handle, &uuid, ATT_NONE,
+                                               ATT_NOT_PERMITTED, NULL, 0);
 
        /* GAP service: device appearance characteristic */
-       appearance_handle = 0x0008;
+       server->appearance_handle = 0x0008;
        bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
        atval[0] = ATT_CHAR_PROPER_READ;
-       att_put_u16(appearance_handle, &atval[1]);
+       att_put_u16(server->appearance_handle, &atval[1]);
        att_put_u16(GATT_CHARAC_APPEARANCE, &atval[3]);
-       attrib_db_add(0x0007, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
+       attrib_db_add_new(server, 0x0007, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 5);
 
        /* GAP service: device appearance attribute */
        bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE);
        att_put_u16(appearance, &atval[0]);
-       attrib_db_add(appearance_handle, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
-                                                               atval, 2);
-       gap_sdp_handle = attrib_create_sdp(0x0001, "Generic Access Profile");
-       if (gap_sdp_handle == 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) {
                error("Failed to register GAP service record");
                return FALSE;
        }
@@ -1057,240 +1173,245 @@ static gboolean register_core_services(void)
        /* GATT service: primary service definition */
        bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
        att_put_u16(GENERIC_ATTRIB_PROFILE_ID, &atval[0]);
-       attrib_db_add(0x0010, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
+       attrib_db_add_new(server, 0x0010, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+                                                               atval, 2);
 
-       gatt_sdp_handle = attrib_create_sdp(0x0010,
+       server->gatt_sdp_handle = attrib_create_sdp_new(server, 0x0010,
                                                "Generic Attribute Profile");
-       if (gatt_sdp_handle == 0) {
+       if (server->gatt_sdp_handle == 0) {
                error("Failed to register GATT service record");
-               goto failed;
+               return FALSE;
        }
 
        return TRUE;
-
-failed:
-       remove_record_from_server(gap_sdp_handle);
-
-       return FALSE;
 }
 
-int attrib_server_init(void)
+int btd_adapter_gatt_server_start(struct btd_adapter *adapter)
 {
+       struct gatt_server *server;
        GError *gerr = NULL;
+       bdaddr_t addr;
+
+       DBG("Start GATT server in hci%d", adapter_get_dev_id(adapter));
+
+       server = g_new0(struct gatt_server, 1);
+       server->adapter = btd_adapter_ref(adapter);
+
+       adapter_get_address(server->adapter, &addr);
 
        /* BR/EDR socket */
-       l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
+       server->l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
                                        NULL, NULL, &gerr,
-                                       BT_IO_OPT_SOURCE_BDADDR, BDADDR_ANY,
-                                       BT_IO_OPT_PSM, GATT_PSM,
+                                       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 (l2cap_io == NULL) {
+
+       if (server->l2cap_io == NULL) {
                error("%s", gerr->message);
                g_error_free(gerr);
+               gatt_server_free(server);
                return -1;
        }
 
-       if (!register_core_services())
-               goto failed;
-
-       if (!main_opts.le)
-               return 0;
+       if (!register_core_services(server)) {
+               gatt_server_free(server);
+               return -1;
+       }
 
        /* LE socket */
-       le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
-                                       &le_io, NULL, &gerr,
-                                       BT_IO_OPT_SOURCE_BDADDR, BDADDR_ANY,
-                                       BT_IO_OPT_CID, GATT_CID,
+       server->le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
+                                       &server->le_io, NULL, &gerr,
+                                       BT_IO_OPT_SOURCE_BDADDR, &addr,
+                                       BT_IO_OPT_CID, ATT_CID,
                                        BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
                                        BT_IO_OPT_INVALID);
-       if (le_io == NULL) {
+
+       if (server->le_io == NULL) {
                error("%s", gerr->message);
                g_error_free(gerr);
                /* Doesn't have LE support, continue */
        }
 
+       servers = g_slist_prepend(servers, server);
        return 0;
-
-failed:
-       g_io_channel_unref(l2cap_io);
-       l2cap_io = NULL;
-
-       if (le_io) {
-               g_io_channel_unref(le_io);
-               le_io = NULL;
-       }
-
-       return -1;
 }
 
-void attrib_server_exit(void)
+void btd_adapter_gatt_server_stop(struct btd_adapter *adapter)
 {
+       struct gatt_server *server;
        GSList *l;
 
-       g_slist_foreach(database, (GFunc) g_free, NULL);
-       g_slist_free(database);
-
-       if (l2cap_io) {
-               g_io_channel_unref(l2cap_io);
-               g_io_channel_shutdown(l2cap_io, FALSE, NULL);
-       }
-
-       if (le_io) {
-               g_io_channel_unref(le_io);
-               g_io_channel_shutdown(le_io, FALSE, NULL);
-       }
+       l = g_slist_find_custom(servers, adapter, adapter_cmp);
+       if (l == NULL)
+               return;
 
-       for (l = clients; l; l = l->next) {
-               struct gatt_channel *channel = l->data;
+       DBG("Stop GATT server in hci%d", adapter_get_dev_id(adapter));
 
-               g_slist_free(channel->notify);
-               g_slist_free(channel->indicate);
-               g_slist_foreach(channel->configs, (GFunc) g_free, NULL);
-               g_slist_free(channel->configs);
+       server = l->data;
+       servers = g_slist_remove(servers, server);
+       gatt_server_free(server);
+}
 
-               g_attrib_unref(channel->attrib);
-               g_free(channel);
-       }
+uint32_t attrib_create_sdp(struct btd_adapter *adapter, uint16_t handle,
+                                                       const char *name)
+{
+       GSList *l;
 
-       g_slist_free(clients);
+       l = g_slist_find_custom(servers, adapter, adapter_cmp);
+       if (l == NULL)
+               return 0;
 
-       if (gatt_sdp_handle)
-               remove_record_from_server(gatt_sdp_handle);
+       return attrib_create_sdp_new(l->data, handle, name);
+}
 
-       if (gap_sdp_handle)
-               remove_record_from_server(gap_sdp_handle);
+void attrib_free_sdp(uint32_t sdp_handle)
+{
+       remove_record_from_server(sdp_handle);
 }
 
-uint32_t attrib_create_sdp(uint16_t handle, const char *name)
+uint16_t attrib_db_find_avail(struct btd_adapter *adapter, uint16_t nitems)
 {
-       sdp_record_t *record;
-       struct attribute *a;
-       uint16_t end = 0;
-       uuid_t svc, gap_uuid;
+       struct gatt_server *server;
+       uint16_t handle;
+       GSList *l;
 
-       a = find_primary_range(handle, &end);
+       g_assert(nitems > 0);
 
-       if (a == NULL)
+       l = g_slist_find_custom(servers, adapter, adapter_cmp);
+       if (l == NULL)
                return 0;
 
-       if (a->len == 2)
-               sdp_uuid16_create(&svc, att_get_u16(a->data));
-       else if (a->len == 16)
-               sdp_uuid128_create(&svc, a->data);
-       else
-               return 0;
+       server = l->data;
 
-       record = server_record_new(&svc, handle, end);
-       if (record == NULL)
-               return 0;
+       for (l = server->database, handle = 0; l; l = l->next) {
+               struct attribute *a = l->data;
 
-       if (name)
-               sdp_set_info_attr(record, name, "BlueZ", NULL);
+               if (handle && (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
+                               bt_uuid_cmp(&a->uuid, &snd_uuid) == 0) &&
+                               a->handle - handle >= nitems)
+                       /* Note: the range above excludes the current handle */
+                       return handle;
 
-       sdp_uuid16_create(&gap_uuid, GENERIC_ACCESS_PROFILE_ID);
-       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 (a->handle == 0xffff)
+                       return 0;
+
+               handle = a->handle + 1;
        }
 
-       if (add_record_to_server(BDADDR_ANY, record) < 0)
-               sdp_record_free(record);
-       else
-               return record->handle;
+       if (0xffff - handle + 1 >= nitems)
+               return handle;
 
        return 0;
 }
 
-void attrib_free_sdp(uint32_t sdp_handle)
+struct attribute *attrib_db_add(struct btd_adapter *adapter, uint16_t handle,
+                               bt_uuid_t *uuid, int read_reqs, int write_reqs,
+                                               const uint8_t *value, int len)
 {
-       remove_record_from_server(sdp_handle);
-}
-
-struct attribute *attrib_db_add(uint16_t handle, bt_uuid_t *uuid, int read_reqs,
-                               int write_reqs, const uint8_t *value, int len)
-{
-       struct attribute *a;
-
-       /* FIXME: handle conflicts */
-
-       a = g_malloc0(sizeof(struct attribute) + len);
-       a->handle = handle;
-       memcpy(&a->uuid, uuid, sizeof(bt_uuid_t));
-       a->read_reqs = read_reqs;
-       a->write_reqs = write_reqs;
-       a->len = len;
-       memcpy(a->data, value, len);
+       GSList *l;
 
-       database = g_slist_insert_sorted(database, a, attribute_cmp);
+       l = g_slist_find_custom(servers, adapter, adapter_cmp);
+       if (l == NULL)
+               return NULL;
 
-       return a;
+       return attrib_db_add_new(l->data, handle, uuid, read_reqs, write_reqs,
+                                                               value, len);
 }
 
-int attrib_db_update(uint16_t handle, bt_uuid_t *uuid, const uint8_t *value,
-                                                               int len)
+int attrib_db_update(struct btd_adapter *adapter, uint16_t handle,
+                                       bt_uuid_t *uuid, const uint8_t *value,
+                                       int len, struct attribute **attr)
 {
+       struct gatt_server *server;
        struct attribute *a;
        GSList *l;
        guint h = handle;
 
-       l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
+       l = g_slist_find_custom(servers, adapter, adapter_cmp);
+       if (l == NULL)
+               return -ENOENT;
+
+       server = l->data;
+
+       DBG("handle=0x%04x", handle);
+
+       l = g_slist_find_custom(server->database, GUINT_TO_POINTER(h),
+                                                               handle_cmp);
        if (!l)
                return -ENOENT;
 
-       a = g_try_realloc(l->data, sizeof(struct attribute) + len);
-       if (a == NULL)
+       a = l->data;
+
+       a->data = g_try_realloc(a->data, len);
+       if (a->data == NULL)
                return -ENOMEM;
 
-       l->data = a;
-       a->handle = handle;
-       if (uuid != &a->uuid)
-               memcpy(&a->uuid, uuid, sizeof(bt_uuid_t));
        a->len = len;
        memcpy(a->data, value, len);
 
-       attrib_notify_clients(a);
+       if (uuid != NULL)
+               a->uuid = *uuid;
+
+       if (attr)
+               *attr = a;
 
        return 0;
 }
 
-int attrib_db_del(uint16_t handle)
+int attrib_db_del(struct btd_adapter *adapter, uint16_t handle)
 {
+       struct gatt_server *server;
        struct attribute *a;
        GSList *l;
        guint h = handle;
 
-       l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
+       l = g_slist_find_custom(servers, adapter, adapter_cmp);
+       if (l == NULL)
+               return -ENOENT;
+
+       server = l->data;
+
+       DBG("handle=0x%04x", handle);
+
+       l = g_slist_find_custom(server->database, GUINT_TO_POINTER(h),
+                                                               handle_cmp);
        if (!l)
                return -ENOENT;
 
        a = l->data;
-       database = g_slist_remove(database, a);
+       server->database = g_slist_remove(server->database, a);
+       g_free(a->data);
        g_free(a);
 
        return 0;
 }
 
-int attrib_gap_set(uint16_t uuid, const uint8_t *value, int len)
+int attrib_gap_set(struct btd_adapter *adapter, uint16_t uuid,
+                                               const uint8_t *value, int len)
 {
-       bt_uuid_t u16;
+       struct gatt_server *server;
        uint16_t handle;
+       GSList *l;
 
-       /* FIXME: Missing Privacy and Reconnection Address */
+       l = g_slist_find_custom(servers, adapter, adapter_cmp);
+       if (l == NULL)
+               return -ENOENT;
+
+       server = l->data;
 
-       bt_uuid16_create(&u16, uuid);
+       /* FIXME: Missing Privacy and Reconnection Address */
 
        switch (uuid) {
        case GATT_CHARAC_DEVICE_NAME:
-               handle = name_handle;
+               handle = server->name_handle;
                break;
        case GATT_CHARAC_APPEARANCE:
-               handle = appearance_handle;
+               handle = server->appearance_handle;
                break;
        default:
                return -ENOSYS;
        }
 
-       return attrib_db_update(handle, &u16, value, len);
+       return attrib_db_update(adapter, handle, NULL, value, len, NULL);
 }
index c03d3c5..2c6f428 100644 (file)
  *
  */
 
-int attrib_server_init(void);
-void attrib_server_exit(void);
-
-struct attribute *attrib_db_add(uint16_t handle, bt_uuid_t *uuid, int read_reqs,
-                               int write_reqs, const uint8_t *value, int len);
-int attrib_db_update(uint16_t handle, bt_uuid_t *uuid, const uint8_t *value,
-                                                               int len);
-int attrib_db_del(uint16_t handle);
-int attrib_gap_set(uint16_t uuid, const uint8_t *value, int len);
-uint32_t attrib_create_sdp(uint16_t handle, const char *name);
+uint16_t attrib_db_find_avail(struct btd_adapter *adapter, uint16_t nitems);
+struct attribute *attrib_db_add(struct btd_adapter *adapter, uint16_t handle,
+                               bt_uuid_t *uuid, int read_reqs, int write_reqs,
+                               const uint8_t *value, int len);
+int attrib_db_update(struct btd_adapter *adapter, uint16_t handle,
+                                       bt_uuid_t *uuid, const uint8_t *value,
+                                       int len, struct attribute **attr);
+int attrib_db_del(struct btd_adapter *adapter, uint16_t handle);
+int attrib_gap_set(struct btd_adapter *adapter, uint16_t uuid,
+                                               const uint8_t *value, int len);
+uint32_t attrib_create_sdp(struct btd_adapter *adapter, uint16_t handle,
+                                                       const char *name);
 void attrib_free_sdp(uint32_t sdp_handle);
+guint attrib_channel_attach(GAttrib *attrib, gboolean out);
+gboolean attrib_channel_detach(GAttrib *attrib, guint id);
index 0aafe54..21e0e33 100644 (file)
@@ -1,4 +1,5 @@
 <?xml version="1.0"?><!--*-nxml-*-->
+
 <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
 
diff --git a/src/bluetooth.service.in b/src/bluetooth.service.in
new file mode 100644 (file)
index 0000000..02b6707
--- /dev/null
@@ -0,0 +1,12 @@
+[Unit]
+Description=Bluetooth service
+After=syslog.target
+
+[Service]
+Type=dbus
+BusName=org.bluez
+ExecStart=@prefix@/sbin/bluetoothd -n
+StandardOutput=syslog
+
+[Install]
+WantedBy=bluetooth.target
index 8436100..ef3b375 100644 (file)
 #endif
 
 #include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-
-#include <bluetooth/bluetooth.h>
+#include <stdint.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
@@ -42,9 +36,6 @@
 
 #include "log.h"
 
-#include "adapter.h"
-#include "manager.h"
-#include "event.h"
 #include "dbus-common.h"
 
 static DBusConnection *connection = NULL;
index c9c47c6..a9e6e1d 100644 (file)
 #include "att.h"
 #include "hcid.h"
 #include "adapter.h"
+#include "gattrib.h"
+#include "attio.h"
 #include "device.h"
 #include "dbus-common.h"
-#include "event.h"
 #include "error.h"
+#include "glib-compat.h"
 #include "glib-helper.h"
-#include "gattrib.h"
+#include "sdp-client.h"
 #include "gatt.h"
 #include "agent.h"
 #include "sdp-xml.h"
 #include "storage.h"
 #include "btio.h"
+#include "attrib-server.h"
+#include "attrib/client.h"
 
 #define DISCONNECT_TIMER       2
 #define DISCOVERY_TIMER                2
 
+#define AUTO_CONNECTION_INTERVAL       5 /* Next connection attempt */
+
 /* When all services should trust a remote device */
 #define GLOBAL_TRUST "[all]"
 
-struct btd_driver_data {
-       guint id;
-       struct btd_device_driver *driver;
-       void *priv;
-};
-
 struct btd_disconnect_data {
        guint id;
        disconnect_watch watch;
@@ -85,7 +85,7 @@ struct bonding_req {
        DBusMessage *msg;
        GIOChannel *io;
        guint listener_id;
-#ifdef __TIZEN_PATCH__
+#ifdef __SAMSUNG_PATCH__
        guint cancel_by_user;
 #endif
        struct btd_device *device;
@@ -96,13 +96,15 @@ struct authentication_req {
        void *cb;
        struct agent *agent;
        struct btd_device *device;
+       uint32_t passkey;
+       gboolean secure;
 };
 
 struct browse_req {
        DBusConnection *conn;
        DBusMessage *msg;
-       GAttrib *attrib;
        GIOChannel *io;
+       GAttrib *attrib;
        struct btd_device *device;
        GSList *match_uuids;
        GSList *profiles_added;
@@ -113,17 +115,27 @@ struct browse_req {
        guint listener_id;
 };
 
+struct attio_data {
+       guint id;
+       attio_connect_cb cfunc;
+       attio_disconnect_cb dcfunc;
+       gpointer user_data;
+};
+
 struct btd_device {
        bdaddr_t        bdaddr;
-       device_type_t   type;
+       addr_type_t     type;
        gchar           *path;
        char            name[MAX_NAME_LENGTH + 1];
        char            *alias;
+       uint16_t        vendor;
+       uint16_t        product;
+       uint16_t        version;
        struct btd_adapter      *adapter;
        GSList          *uuids;
        GSList          *services;              /* Primary services path */
        GSList          *primaries;             /* List of primary services */
-       GSList          *drivers;               /* List of driver_data */
+       GSList          *drivers;               /* List of device drivers */
        GSList          *watches;               /* List of disconnect_data */
        gboolean        temporary;
        struct agent    *agent;
@@ -133,17 +145,21 @@ struct btd_device {
        struct bonding_req *bonding;
        struct authentication_req *authr;       /* authentication request */
        GSList          *disconnects;           /* disconnects message */
+       GAttrib         *attrib;
+       GSList          *attios;
+       GSList          *attios_offline;
+       guint           attachid;               /* Attrib server attach */
+       guint           auto_id;                /* Auto connect source id */
 
        gboolean        connected;
 
-       /* Whether were creating a security mode 3 connection */
-       gboolean        secmode3;
-
        sdp_list_t      *tmp_records;
 
        gboolean        trusted;
        gboolean        paired;
        gboolean        blocked;
+       gboolean        bonded;
+       gboolean        auto_connect;
 
        gboolean        authorizing;
        gint            ref;
@@ -158,28 +174,28 @@ static uint16_t uuid_list[] = {
 
 static GSList *device_drivers = NULL;
 
-static void browse_request_free(struct browse_req *req)
+static void browse_request_free(struct browse_req *req, gboolean shutdown)
 {
        if (req->listener_id)
                g_dbus_remove_watch(req->conn, req->listener_id);
+       if (req->attrib)
+               g_attrib_unref(req->attrib);
+       if (req->io) {
+               if (shutdown)
+                       g_io_channel_shutdown(req->io, FALSE, NULL);
+               g_io_channel_unref(req->io);
+       }
        if (req->msg)
                dbus_message_unref(req->msg);
        if (req->conn)
                dbus_connection_unref(req->conn);
        if (req->device)
                btd_device_unref(req->device);
-       g_slist_foreach(req->profiles_added, (GFunc) g_free, NULL);
-       g_slist_free(req->profiles_added);
+       g_slist_free_full(req->profiles_added, g_free);
        g_slist_free(req->profiles_removed);
        if (req->records)
                sdp_list_free(req->records, (sdp_free_func_t) sdp_record_free);
 
-       if (req->io) {
-               g_attrib_unref(req->attrib);
-               g_io_channel_unref(req->io);
-               g_io_channel_shutdown(req->io, FALSE, NULL);
-       }
-
        g_free(req);
 }
 
@@ -197,7 +213,7 @@ static void browse_request_cancel(struct browse_req *req)
        bt_cancel_discovery(&src, &device->bdaddr);
 
        device->browse = NULL;
-       browse_request_free(req);
+       browse_request_free(req, TRUE);
 }
 
 static void device_free(gpointer user_data)
@@ -213,14 +229,13 @@ static void device_free(gpointer user_data)
                                agent_is_busy(agent, device->authr)))
                agent_cancel(agent);
 
-       g_slist_foreach(device->services, (GFunc) g_free, NULL);
-       g_slist_free(device->services);
-
-       g_slist_foreach(device->uuids, (GFunc) g_free, NULL);
-       g_slist_free(device->uuids);
+       g_slist_free_full(device->services, g_free);
+       g_slist_free_full(device->uuids, g_free);
+       g_slist_free_full(device->primaries, g_free);
+       g_slist_free_full(device->attios, g_free);
+       g_slist_free_full(device->attios_offline, g_free);
 
-       g_slist_foreach(device->primaries, (GFunc) g_free, NULL);
-       g_slist_free(device->primaries);
+       g_attrib_unref(device->attrib);
 
        if (device->tmp_records)
                sdp_list_free(device->tmp_records,
@@ -232,6 +247,9 @@ static void device_free(gpointer user_data)
        if (device->discov_timer)
                g_source_remove(device->discov_timer);
 
+       if (device->auto_id)
+               g_source_remove(device->auto_id);
+
        DBG("%p", device);
 
        g_free(device->authr);
@@ -240,100 +258,31 @@ static void device_free(gpointer user_data)
        g_free(device);
 }
 
-gboolean device_is_paired(struct btd_device *device)
+gboolean device_is_bredr(struct btd_device *device)
 {
-       return device->paired;
+       return (device->type == ADDR_TYPE_BREDR);
 }
 
-gboolean device_is_trusted(struct btd_device *device)
+gboolean device_is_le(struct btd_device *device)
 {
-       return device->trusted;
+       return (device->type != ADDR_TYPE_BREDR);
 }
 
-#ifdef __TIZEN_PATCH__
-#include "oui.h"
-uint32_t device_pin_length(struct btd_device *device)
+gboolean device_is_paired(struct btd_device *device)
 {
-       struct btd_adapter *adapter = device->adapter;
-       bdaddr_t src;
-       uint8_t length;
-       int len;
-
-       adapter_get_address(adapter, &src);
-
-       len = read_pin_length(&src, &device->bdaddr);
-       if (len < 0)
-               len = 0;
-
-       length = (uint32_t)len;
-
-       return length;
+       return device->paired;
 }
 
-int get_device_company(struct btd_device *device, char *company, size_t size)
+gboolean device_is_bonded(struct btd_device *device)
 {
-       char oui[9], *tmp;
-       int err;
-
-       ba2oui(&device->bdaddr, oui);
-       tmp = (char*)ouitocomp(oui);
-
-       err = snprintf(company, size, "%s", tmp);
-
-       free(tmp);
-
-       return err;
+       return device->bonded;
 }
 
-int get_device_version_info(struct btd_device *device,
-                                       char *manufacturer, size_t manufacturer_size,
-                                       char *revision, size_t revision_size,
-                                       char *version, size_t version_size)
+gboolean device_is_trusted(struct btd_device *device)
 {
-       struct btd_adapter *adapter = device->adapter;
-       int err;
-       bdaddr_t src;
-       char dstaddr[18], edr[7], *tmp;
-
-       uint16_t remote_manufacturer = 65534;
-       uint8_t remote_lmp_ver = 0;
-       uint16_t remote_lmp_subver = 0;
-       uint8_t features[8] = {0};
-
-       if (version_size < 14)
-               return -ENOBUFS;
-
-       adapter_get_address(adapter, &src);
-       ba2str(&device->bdaddr, dstaddr);
-
-       err = read_version_info(&src, dstaddr, &remote_manufacturer, &remote_lmp_ver, &remote_lmp_subver, features);
-       if (err < 0)
-               return err;
-
-       tmp = bt_compidtostr(remote_manufacturer);
-
-       err = snprintf(manufacturer, manufacturer_size, "%s", tmp);
-
-       snprintf(revision, revision_size, "HCI 0x%X", remote_lmp_subver);
-
-       if ((remote_lmp_ver == 0x03 || remote_lmp_ver == 0x04) &&
-                       (features[3] & (LMP_EDR_ACL_2M | LMP_EDR_ACL_3M)))
-               sprintf(edr, " + EDR");
-       else
-               edr[0] = '\0';
-
-       tmp = lmp_vertostr(remote_lmp_ver);
-
-       if (strlen(tmp) == 0)
-               err = snprintf(version, version_size, "not assigned");
-       else
-               err = snprintf(version, version_size, "Bluetooth %s%s", tmp, edr);
-
-       free(tmp);
-
-       return err;
+       return device->trusted;
 }
-#endif
+
 static DBusMessage *get_properties(DBusConnection *conn,
                                DBusMessage *msg, void *user_data)
 {
@@ -351,10 +300,6 @@ static DBusMessage *get_properties(DBusConnection *conn,
        int i;
        GSList *l;
 
-#ifdef __TIZEN_PATCH__
-       uint32_t pin_length;
-#endif
-
        ba2str(&device->bdaddr, dstaddr);
 
        reply = dbus_message_new_method_return(msg);
@@ -402,15 +347,25 @@ static DBusMessage *get_properties(DBusConnection *conn,
                                                DBUS_TYPE_STRING, &icon);
        }
 
+       /* Vendor */
+       if (device->vendor)
+               dict_append_entry(&dict, "Vendor", DBUS_TYPE_UINT16,
+                                                       &device->vendor);
+
+       /* Product */
+       if (device->product)
+               dict_append_entry(&dict, "Product", DBUS_TYPE_UINT16,
+                                                       &device->product);
+
+       /* Version */
+       if (device->product)
+               dict_append_entry(&dict, "Version", DBUS_TYPE_UINT16,
+                                                       &device->version);
+
        /* Paired */
        boolean = device_is_paired(device);
        dict_append_entry(&dict, "Paired", DBUS_TYPE_BOOLEAN, &boolean);
 
-#ifdef __TIZEN_PATCH__
-       /* PinLength */
-       pin_length = device_pin_length(device);
-       dict_append_entry(&dict, "PinLength", DBUS_TYPE_UINT32, &pin_length);
-#endif
        /* Trusted */
        boolean = device_is_trusted(device);
        dict_append_entry(&dict, "Trusted", DBUS_TYPE_BOOLEAN, &boolean);
@@ -445,89 +400,6 @@ static DBusMessage *get_properties(DBusConnection *conn,
 
        return reply;
 }
-#ifdef __TIZEN_PATCH__
-static DBusMessage *get_version_properties(DBusConnection *conn,
-                               DBusMessage *msg, void *user_data)
-{
-       struct btd_device *device = user_data;
-       struct btd_adapter *adapter = device->adapter;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       bdaddr_t src;
-       char name[MAX_NAME_LENGTH + 1], srcaddr[18], dstaddr[18];
-       const char *ptr;
-       uint32_t class;
-
-       char company[MAX_NAME_LENGTH + 1];
-       char manufacturer[MAX_NAME_LENGTH + 1];
-       char revision[MAX_NAME_LENGTH + 1];
-       char version[MAX_NAME_LENGTH + 1];
-
-       ba2str(&device->bdaddr, dstaddr);
-
-       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);
-
-       /* Address */
-       ptr = dstaddr;
-       dict_append_entry(&dict, "Address", DBUS_TYPE_STRING, &ptr);
-
-       /* Name */
-       ptr = NULL;
-       memset(name, 0, sizeof(name));
-       adapter_get_address(adapter, &src);
-       ba2str(&src, srcaddr);
-       if (g_str_equal("", device->name))
-       {
-               // use address itself instead name
-           ptr = dstaddr;
-       }
-       else
-       {
-               ptr = device->name;
-       }
-       dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &ptr);
-
-       /* Class */
-       if (read_remote_class(&src, &device->bdaddr, &class) == 0) {
-               dict_append_entry(&dict, "Class", DBUS_TYPE_UINT32, &class);
-       }
-
-       /* Company */
-       memset(company, 0, sizeof(company));
-       get_device_company(device, company, sizeof(company));
-       ptr = company;
-       dict_append_entry(&dict, "Company", DBUS_TYPE_STRING, &ptr);
-
-       /* Manufacturer */
-       memset(manufacturer, 0, sizeof(manufacturer));
-       memset(manufacturer, 0, sizeof(revision));
-       memset(manufacturer, 0, sizeof(version));
-       get_device_version_info(device, manufacturer, sizeof(manufacturer), revision, sizeof(revision), version, sizeof(version));
-
-       ptr = manufacturer;
-       dict_append_entry(&dict, "Manufacturer", DBUS_TYPE_STRING, &ptr);
-
-       ptr = revision;
-       dict_append_entry(&dict, "Revision", DBUS_TYPE_STRING, &ptr);
-
-       ptr = version;
-       dict_append_entry(&dict, "Version", DBUS_TYPE_STRING, &ptr);
-
-       dbus_message_iter_close_container(&iter, &dict);
-
-       return reply;
-}
-#endif
 
 static DBusMessage *set_alias(DBusConnection *conn, DBusMessage *msg,
                                        const char *alias, void *data)
@@ -592,15 +464,12 @@ static DBusMessage *set_trust(DBusConnection *conn, DBusMessage *msg,
        return dbus_message_new_method_return(msg);
 }
 
-static void driver_remove(struct btd_driver_data *driver_data,
+static void driver_remove(struct btd_device_driver *driver,
                                                struct btd_device *device)
 {
-       struct btd_device_driver *driver = driver_data->driver;
-
        driver->remove(device);
 
-       device->drivers = g_slist_remove(device->drivers, driver_data);
-       g_free(driver_data);
+       device->drivers = g_slist_remove(device->drivers, driver);
 }
 
 static gboolean do_disconnect(gpointer user_data)
@@ -614,9 +483,10 @@ static gboolean do_disconnect(gpointer user_data)
        return FALSE;
 }
 
-static int device_block(DBusConnection *conn, struct btd_device *device)
+int device_block(DBusConnection *conn, struct btd_device *device,
+                                               gboolean update_only)
 {
-       int err;
+       int err = 0;
        bdaddr_t src;
 
        if (device->blocked)
@@ -627,7 +497,9 @@ static int device_block(DBusConnection *conn, struct btd_device *device)
 
        g_slist_foreach(device->drivers, (GFunc) driver_remove, device);
 
-       err = btd_adapter_block_address(device->adapter, &device->bdaddr);
+       if (!update_only)
+               err = btd_adapter_block_address(device->adapter, &device->bdaddr);
+
        if (err < 0)
                return err;
 
@@ -647,16 +519,18 @@ static int device_block(DBusConnection *conn, struct btd_device *device)
        return 0;
 }
 
-static int device_unblock(DBusConnection *conn, struct btd_device *device,
-                                                       gboolean silent)
+int device_unblock(DBusConnection *conn, struct btd_device *device,
+                               gboolean silent, gboolean update_only)
 {
-       int err;
+       int err = 0;
        bdaddr_t src;
 
        if (!device->blocked)
                return 0;
 
-       err = btd_adapter_unblock_address(device->adapter, &device->bdaddr);
+       if (!update_only)
+               err = btd_adapter_unblock_address(device->adapter, &device->bdaddr);
+
        if (err < 0)
                return err;
 
@@ -685,9 +559,9 @@ static DBusMessage *set_blocked(DBusConnection *conn, DBusMessage *msg,
        int err;
 
        if (value)
-               err = device_block(conn, device);
+               err = device_block(conn, device, FALSE);
        else
-               err = device_unblock(conn, device, FALSE);
+               err = device_unblock(conn, device, FALSE, FALSE);
 
        switch (-err) {
        case 0:
@@ -965,9 +839,6 @@ static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg,
 
 static GDBusMethodTable device_methods[] = {
        { "GetProperties",      "",     "a{sv}",        get_properties  },
-#ifdef __TIZEN_PATCH__
-       { "GetVersionProperties",       "",     "a{sv}",        get_version_properties  },
-#endif
        { "SetProperty",        "sv",   "",             set_property    },
        { "DiscoverServices",   "s",    "a{us}",        discover_services,
                                                G_DBUS_METHOD_FLAG_ASYNC},
@@ -1027,6 +898,9 @@ void device_remove_connection(struct btd_device *device, DBusConnection *conn)
                device->disconnects = g_slist_remove(device->disconnects, msg);
        }
 
+       if (device_is_paired(device) && !device_is_bonded(device))
+               device_set_paired(device, FALSE);
+
        emit_property_changed(conn, device->path,
                                        DEVICE_INTERFACE, "Connected",
                                        DBUS_TYPE_BOOLEAN, &device->connected);
@@ -1068,15 +942,55 @@ void device_remove_disconnect_watch(struct btd_device *device, guint id)
        }
 }
 
+static void device_set_vendor(struct btd_device *device, uint16_t value)
+{
+       DBusConnection *conn = get_dbus_connection();
+
+       if (device->vendor == value)
+               return;
+
+       device->vendor = value;
+
+       emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Vendor",
+                               DBUS_TYPE_UINT16, &value);
+}
+
+static void device_set_product(struct btd_device *device, uint16_t value)
+{
+       DBusConnection *conn = get_dbus_connection();
+
+       if (device->product == value)
+               return;
+
+       device->product = value;
+
+       emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Product",
+                               DBUS_TYPE_UINT16, &value);
+}
+
+static void device_set_version(struct btd_device *device, uint16_t value)
+{
+       DBusConnection *conn = get_dbus_connection();
+
+       if (device->version == value)
+               return;
+
+       device->version = value;
+
+       emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Version",
+                               DBUS_TYPE_UINT16, &value);
+}
+
 struct btd_device *device_create(DBusConnection *conn,
                                struct btd_adapter *adapter,
-                               const gchar *address, device_type_t type)
+                               const gchar *address, addr_type_t type)
 {
        gchar *address_up;
        struct btd_device *device;
        const gchar *adapter_path = adapter_get_path(adapter);
        bdaddr_t src;
        char srcaddr[18], alias[MAX_NAME_LENGTH + 1];
+       uint16_t vendor, product, version;
 
        device = g_try_malloc0(sizeof(struct btd_device));
        if (device == NULL)
@@ -1107,10 +1021,19 @@ struct btd_device *device_create(DBusConnection *conn,
        device->trusted = read_trust(&src, address, GLOBAL_TRUST);
 
        if (read_blocked(&src, &device->bdaddr))
-               device_block(conn, device);
+               device_block(conn, device, FALSE);
+
+       if (read_link_key(&src, &device->bdaddr, NULL, NULL) == 0) {
+               device_set_paired(device, TRUE);
+               device_set_bonded(device, TRUE);
+       }
 
-       if (read_link_key(&src, &device->bdaddr, NULL, NULL) == 0)
-               device->paired = TRUE;
+       if (read_device_id(srcaddr, address, NULL, &vendor, &product, &version)
+                                                                       == 0) {
+               device_set_vendor(device, vendor);
+               device_set_product(device, product);
+               device_set_version(device, version);
+       }
 
        return btd_device_ref(device);
 }
@@ -1141,28 +1064,19 @@ void device_get_name(struct btd_device *device, char *name, size_t len)
        strncpy(name, device->name, len);
 }
 
-device_type_t device_get_type(struct btd_device *device)
+uint16_t btd_device_get_vendor(struct btd_device *device)
 {
-       return device->type;
+       return device->vendor;
 }
 
-void device_remove_bonding(struct btd_device *device)
+uint16_t btd_device_get_product(struct btd_device *device)
 {
-       char filename[PATH_MAX + 1];
-       char srcaddr[18], dstaddr[18];
-       bdaddr_t bdaddr;
-
-       adapter_get_address(device->adapter, &bdaddr);
-       ba2str(&bdaddr, srcaddr);
-       ba2str(&device->bdaddr, dstaddr);
-
-       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr,
-                       "linkkeys");
-
-       /* Delete the link key from storage */
-       textfile_casedel(filename, dstaddr);
+       return device->product;
+}
 
-       btd_adapter_remove_bonding(device->adapter, &device->bdaddr);
+uint16_t btd_device_get_version(struct btd_device *device)
+{
+       return device->version;
 }
 
 static void device_remove_stored(struct btd_device *device)
@@ -1174,17 +1088,20 @@ static void device_remove_stored(struct btd_device *device)
        adapter_get_address(device->adapter, &src);
        ba2str(&device->bdaddr, addr);
 
-       if (device->paired)
-               device_remove_bonding(device);
+       if (device_is_bonded(device)) {
+               delete_entry(&src, "linkkeys", addr);
+               delete_entry(&src, "aliases", addr);
+               device_set_bonded(device, FALSE);
+               device->paired = FALSE;
+               btd_adapter_remove_bonding(device->adapter, &device->bdaddr);
+       }
        delete_entry(&src, "profiles", addr);
        delete_entry(&src, "trusts", addr);
-       delete_entry(&src, "types", addr);
-       delete_entry(&src, "primary", addr);
        delete_all_records(&src, &device->bdaddr);
        delete_device_service(&src, &device->bdaddr);
 
        if (device->blocked)
-               device_unblock(conn, device, TRUE);
+               device_unblock(conn, device, TRUE, FALSE);
 }
 
 void device_remove(struct btd_device *device, gboolean remove_stored)
@@ -1221,6 +1138,8 @@ void device_remove(struct btd_device *device, gboolean remove_stored)
        g_slist_free(device->drivers);
        device->drivers = NULL;
 
+       attrib_client_unregister(device->services);
+
        btd_device_unref(device);
 }
 
@@ -1302,8 +1221,7 @@ static GSList *device_match_driver(struct btd_device *device,
 
                /* match pattern driver */
                match = device_match_pattern(device, *uuid, profiles);
-               for (; match; match = match->next)
-                       uuids = g_slist_append(uuids, match->data);
+               uuids = g_slist_concat(uuids, match);
        }
 
        return uuids;
@@ -1327,26 +1245,21 @@ void device_probe_drivers(struct btd_device *device, GSList *profiles)
        for (list = device_drivers; list; list = list->next) {
                struct btd_device_driver *driver = list->data;
                GSList *probe_uuids;
-               struct btd_driver_data *driver_data;
 
                probe_uuids = device_match_driver(device, driver, profiles);
 
                if (!probe_uuids)
                        continue;
 
-               driver_data = g_new0(struct btd_driver_data, 1);
-
                err = driver->probe(device, probe_uuids);
                if (err < 0) {
                        error("%s driver probe failed for device %s",
                                                        driver->name, addr);
-                       g_free(driver_data);
                        g_slist_free(probe_uuids);
                        continue;
                }
 
-               driver_data->driver = driver;
-               device->drivers = g_slist_append(device->drivers, driver_data);
+               device->drivers = g_slist_append(device->drivers, driver);
                g_slist_free(probe_uuids);
        }
 
@@ -1380,8 +1293,7 @@ static void device_remove_drivers(struct btd_device *device, GSList *uuids)
        DBG("Removing drivers for %s", dstaddr);
 
        for (list = device->drivers; list; list = next) {
-               struct btd_driver_data *driver_data = list->data;
-               struct btd_device_driver *driver = driver_data->driver;
+               struct btd_device_driver *driver = list->data;
                const char **uuid;
 
                next = list->next;
@@ -1396,9 +1308,7 @@ static void device_remove_drivers(struct btd_device *device, GSList *uuids)
 
                        driver->remove(device);
                        device->drivers = g_slist_remove(device->drivers,
-                                                               driver_data);
-                       g_free(driver_data);
-
+                                                               driver);
                        break;
                }
        }
@@ -1495,12 +1405,18 @@ static void update_services(struct browse_req *req, sdp_list_t *recs)
                        pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID);
                        vendor = pdlist ? pdlist->val.uint16 : 0x0000;
 
+                       device_set_vendor(device, vendor);
+
                        pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID);
                        product = pdlist ? pdlist->val.uint16 : 0x0000;
 
+                       device_set_product(device, product);
+
                        pdlist = sdp_data_get(rec, SDP_ATTR_VERSION);
                        version = pdlist ? pdlist->val.uint16 : 0x0000;
 
+                       device_set_version(device, version);
+
                        if (source || vendor || product || version)
                                store_device_id(srcaddr, dstaddr, source,
                                                vendor, product, version);
@@ -1520,15 +1436,15 @@ static void update_services(struct browse_req *req, sdp_list_t *recs)
                                                        sdp_copy_record(rec));
 
                l = g_slist_find_custom(device->uuids, profile_uuid,
-                               (GCompareFunc) strcmp);
+                                                       (GCompareFunc) strcmp);
                if (!l)
                        req->profiles_added =
-                               g_slist_append(req->profiles_added,
-                                               profile_uuid);
+                                       g_slist_append(req->profiles_added,
+                                                       profile_uuid);
                else {
                        req->profiles_removed =
-                               g_slist_remove(req->profiles_removed,
-                                               l->data);
+                                       g_slist_remove(req->profiles_removed,
+                                                       l->data);
                        g_free(profile_uuid);
                }
 
@@ -1568,6 +1484,45 @@ static void create_device_reply(struct btd_device *device, struct browse_req *re
        g_dbus_send_message(req->conn, reply);
 }
 
+GSList *device_services_from_record(struct btd_device *device, GSList *profiles)
+{
+       GSList *l, *prim_list = NULL;
+       char *att_uuid;
+       uuid_t proto_uuid;
+
+       sdp_uuid16_create(&proto_uuid, ATT_UUID);
+       att_uuid = bt_uuid2string(&proto_uuid);
+
+       for (l = profiles; l; l = l->next) {
+               const char *profile_uuid = l->data;
+               const sdp_record_t *rec;
+               struct att_primary *prim;
+               uint16_t start = 0, end = 0, psm = 0;
+               uuid_t prim_uuid;
+
+               rec = btd_device_get_record(device, profile_uuid);
+               if (!rec)
+                       continue;
+
+               if (!record_has_uuid(rec, att_uuid))
+                       continue;
+
+               if (!gatt_parse_record(rec, &prim_uuid, &psm, &start, &end))
+                       continue;
+
+               prim = g_new0(struct att_primary, 1);
+               prim->start = start;
+               prim->end = end;
+               sdp_uuid2strn(&prim_uuid, prim->uuid, sizeof(prim->uuid));
+
+               prim_list = g_slist_append(prim_list, prim);
+       }
+
+       g_free(att_uuid);
+
+       return prim_list;
+}
+
 static void search_cb(sdp_list_t *recs, int err, gpointer user_data)
 {
        struct browse_req *req = user_data;
@@ -1597,8 +1552,16 @@ static void search_cb(sdp_list_t *recs, int err, gpointer user_data)
        }
 
        /* Probe matching drivers for services added */
-       if (req->profiles_added)
+       if (req->profiles_added) {
+               GSList *list;
+
+               list = device_services_from_record(device, req->profiles_added);
+               if (list)
+                       device_register_services(req->conn, device, list,
+                                                               ATT_PSM);
+
                device_probe_drivers(device, req->profiles_added);
+       }
 
        /* Remove drivers for services removed */
        if (req->profiles_removed)
@@ -1635,14 +1598,13 @@ cleanup:
                bdaddr_t sba, dba;
 
                adapter_get_address(device->adapter, &sba);
-               device_get_address(device, &dba);
+               device_get_address(device, &dba, NULL);
 
                store_profiles(device);
-               write_device_type(&sba, &dba, device->type);
        }
 
        device->browse = NULL;
-       browse_request_free(req);
+       browse_request_free(req, FALSE);
 }
 
 static void browse_cb(sdp_list_t *recs, int err, gpointer user_data)
@@ -1717,71 +1679,214 @@ static char *primary_list_to_string(GSList *primary_list)
        return g_string_free(services, FALSE);
 }
 
+static void store_services(struct btd_device *device)
+{
+       struct btd_adapter *adapter = device->adapter;
+       bdaddr_t dba, sba;
+       char *str = primary_list_to_string(device->primaries);
+
+       adapter_get_address(adapter, &sba);
+       device_get_address(device, &dba, NULL);
+
+       write_device_services(&sba, &dba, str);
+
+       g_free(str);
+}
+
+static void attio_connected(gpointer data, gpointer user_data)
+{
+       struct attio_data *attio = data;
+       GAttrib *attrib = user_data;
+
+       if (attio->cfunc)
+               attio->cfunc(attrib, attio->user_data);
+}
+
+static void attio_disconnected(gpointer data, gpointer user_data)
+{
+       struct attio_data *attio = data;
+
+       if (attio->dcfunc)
+               attio->dcfunc(attio->user_data);
+}
+
+static void att_connect_dispatched(gpointer user_data)
+{
+       struct btd_device *device = user_data;
+
+       device->auto_id = 0;
+}
+
+static gboolean att_connect(gpointer user_data);
+
+static void attrib_disconnected(gpointer user_data)
+{
+       struct btd_device *device = user_data;
+       GIOChannel *io;
+       int sock, err = 0;
+       socklen_t len;
+
+       io = g_attrib_get_channel(device->attrib);
+       sock = g_io_channel_unix_get_fd(io);
+       len = sizeof(err);
+       getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len);
+
+       g_slist_foreach(device->attios, attio_disconnected, NULL);
+
+       attrib_channel_detach(device->attrib, device->attachid);
+       g_attrib_unref(device->attrib);
+       device->attrib = NULL;
+
+       if (device->auto_connect == FALSE)
+               return;
+
+       if (err != ETIMEDOUT)
+               return;
+
+       device->auto_id = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT_IDLE,
+                                               AUTO_CONNECTION_INTERVAL,
+                                               att_connect, device,
+                                               att_connect_dispatched);
+}
+
 static void primary_cb(GSList *services, guint8 status, gpointer user_data)
 {
        struct browse_req *req = user_data;
        struct btd_device *device = req->device;
-       struct btd_adapter *adapter = device->adapter;
        GSList *l, *uuids = NULL;
-       bdaddr_t dba, sba;
-       char *str;
+       gboolean shutdown;
 
        if (status) {
                DBusMessage *reply;
                reply = btd_error_failed(req->msg, att_ecode2str(status));
                g_dbus_send_message(req->conn, reply);
+               shutdown = TRUE;
                goto done;
        }
 
-       services_changed(device);
        device_set_temporary(device, FALSE);
 
        for (l = services; l; l = l->next) {
                struct att_primary *prim = l->data;
                uuids = g_slist_append(uuids, prim->uuid);
-               device_add_primary(device, prim);
        }
 
+       /*
+        * Profiles may register attio callbacks in the probing callback.
+        * GAttrib reference can be released if the registered callbacks
+        * list is emtpy.
+        */
+       device->attrib = g_attrib_ref(req->attrib);
+
+       device_register_services(req->conn, device, g_slist_copy(services), -1);
        device_probe_drivers(device, uuids);
+
+       if (device->attios == NULL && device->attios_offline == NULL) {
+               attrib_channel_detach(device->attrib, device->attachid);
+               g_attrib_unref(device->attrib);
+               device->attrib = NULL;
+       } else
+               g_attrib_set_disconnect_function(device->attrib,
+                                               attrib_disconnected, device);
+
        g_slist_free(uuids);
 
+       services_changed(device);
        create_device_reply(device, req);
 
-       str = primary_list_to_string(services);
-
-       adapter_get_address(adapter, &sba);
-       device_get_address(device, &dba);
-
-       write_device_type(&sba, &dba, device->type);
-       write_device_services(&sba, &dba, str);
-       g_free(str);
+       store_services(device);
+       shutdown = FALSE;
 
 done:
        device->browse = NULL;
-       browse_request_free(req);
+       browse_request_free(req, shutdown);
 }
 
-static void gatt_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
+static void att_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
 {
-       struct browse_req *req = user_data;
-       struct btd_device *device = req->device;
+       struct btd_device *device = user_data;
+       struct browse_req *req = device->browse;
+       GAttrib *attrib;
 
        if (gerr) {
                DBusMessage *reply;
 
                DBG("%s", gerr->message);
 
-               reply = btd_error_failed(req->msg, gerr->message);
-               g_dbus_send_message(req->conn, reply);
+               if (req) {
+                       reply = btd_error_failed(req->msg, gerr->message);
+                       g_dbus_send_message(req->conn, reply);
 
-               device->browse = NULL;
-               browse_request_free(req);
+                       device->browse = NULL;
+                       browse_request_free(req, TRUE);
+               } else if (device->auto_connect)
+                       device->auto_id = g_timeout_add_seconds_full(
+                                               G_PRIORITY_DEFAULT_IDLE,
+                                               AUTO_CONNECTION_INTERVAL,
+                                               att_connect, device,
+                                               att_connect_dispatched);
 
                return;
        }
 
-       req->attrib = g_attrib_new(io);
-       gatt_discover_primary(req->attrib, NULL, primary_cb, req);
+       attrib = g_attrib_new(io);
+       device->attachid = attrib_channel_attach(attrib, TRUE);
+       if (device->attachid == 0)
+               error("Attribute server attach failure!");
+
+       if (req) {
+               req->attrib = attrib;
+               gatt_discover_primary(req->attrib, NULL, primary_cb, req);
+       } else if (device->attios) {
+               device->attrib = attrib;
+               g_attrib_set_disconnect_function(device->attrib,
+                                               attrib_disconnected, device);
+               g_slist_foreach(device->attios, attio_connected,
+                                                       device->attrib);
+       }
+}
+
+static gboolean att_connect(gpointer user_data)
+{
+       struct btd_device *device = user_data;
+       struct btd_adapter *adapter = device->adapter;
+       GIOChannel *io;
+       GError *gerr = NULL;
+       char addr[18];
+       bdaddr_t sba;
+
+       adapter_get_address(adapter, &sba);
+       ba2str(&device->bdaddr, addr);
+
+       DBG("Connection attempt to: %s", addr);
+
+       if (device_is_bredr(device)) {
+               io = bt_io_connect(BT_IO_L2CAP, att_connect_cb,
+                                       device, NULL, &gerr,
+                                       BT_IO_OPT_SOURCE_BDADDR, &sba,
+                                       BT_IO_OPT_DEST_BDADDR, &device->bdaddr,
+                                       BT_IO_OPT_PSM, ATT_PSM,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+                                       BT_IO_OPT_INVALID);
+       } else {
+               io = bt_io_connect(BT_IO_L2CAP, att_connect_cb,
+                                       device, NULL, &gerr,
+                                       BT_IO_OPT_SOURCE_BDADDR, &sba,
+                                       BT_IO_OPT_DEST_BDADDR, &device->bdaddr,
+                                       BT_IO_OPT_CID, ATT_CID,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+                                       BT_IO_OPT_INVALID);
+       }
+
+       if (io == NULL) {
+               error("ATT bt_io_connect(%s): %s", addr, gerr->message);
+               g_error_free(gerr);
+               return FALSE;
+       }
+
+       g_io_channel_unref(io);
+
+       return FALSE;
 }
 
 int device_browse_primary(struct btd_device *device, DBusConnection *conn,
@@ -1802,21 +1907,19 @@ int device_browse_primary(struct btd_device *device, DBusConnection *conn,
 
        sec_level = secure ? BT_IO_SEC_HIGH : BT_IO_SEC_LOW;
 
-       req->io = bt_io_connect(BT_IO_L2CAP, gatt_connect_cb, req, NULL, NULL,
+       req->io = bt_io_connect(BT_IO_L2CAP, att_connect_cb,
+                               device, NULL, NULL,
                                BT_IO_OPT_SOURCE_BDADDR, &src,
                                BT_IO_OPT_DEST_BDADDR, &device->bdaddr,
-                               BT_IO_OPT_CID, GATT_CID,
+                               BT_IO_OPT_CID, ATT_CID,
                                BT_IO_OPT_SEC_LEVEL, sec_level,
                                BT_IO_OPT_INVALID);
 
-       if (req->io == NULL ) {
-               browse_request_free(req);
+       if (req->io == NULL) {
+               browse_request_free(req, FALSE);
                return -EIO;
        }
 
-       if (conn == NULL)
-               conn = get_dbus_connection();
-
        req->conn = dbus_connection_ref(conn);
        device->browse = req;
 
@@ -1863,7 +1966,7 @@ int device_browse_sdp(struct btd_device *device, DBusConnection *conn,
 
        err = bt_search_service(&src, &device->bdaddr, &uuid, cb, req, NULL);
        if (err < 0) {
-               browse_request_free(req);
+               browse_request_free(req, FALSE);
                return err;
        }
 
@@ -1887,15 +1990,7 @@ int device_browse_sdp(struct btd_device *device, DBusConnection *conn,
 
        return err;
 }
-#ifdef __TIZEN_PATCH__
-struct bonding_req *device_get_bonding(struct btd_device *device)
-{
-       if (!device)
-               return NULL;
 
-       return device->bonding;
-}
-#endif
 struct btd_adapter *device_get_adapter(struct btd_device *device)
 {
        if (!device)
@@ -1904,9 +1999,12 @@ struct btd_adapter *device_get_adapter(struct btd_device *device)
        return device->adapter;
 }
 
-void device_get_address(struct btd_device *device, bdaddr_t *bdaddr)
+void device_get_address(struct btd_device *device, bdaddr_t *bdaddr,
+                                                       addr_type_t *type)
 {
        bacpy(bdaddr, &device->bdaddr);
+       if (type != NULL)
+               *type = device->type;
 }
 
 const gchar *device_get_path(struct btd_device *device)
@@ -1948,12 +2046,51 @@ void device_set_temporary(struct btd_device *device, gboolean temporary)
        device->temporary = temporary;
 }
 
-void device_set_type(struct btd_device *device, device_type_t type)
+void device_set_bonded(struct btd_device *device, gboolean bonded)
 {
        if (!device)
                return;
 
-       device->type = type;
+       DBG("bonded %d", bonded);
+
+       device->bonded = bonded;
+}
+
+void device_set_auto_connect(struct btd_device *device, gboolean enable)
+{
+       char addr[18];
+
+       if (!device)
+               return;
+
+       ba2str(&device->bdaddr, addr);
+
+       DBG("%s auto connect: %d", addr, enable);
+
+       device->auto_connect = enable;
+
+       /* Disabling auto connect */
+       if (enable == FALSE) {
+               if (device->auto_id)
+                       g_source_remove(device->auto_id);
+               return;
+       }
+
+       /* Enabling auto connect */
+       if (device->auto_id != 0)
+               return;
+
+       if (device->attrib) {
+               DBG("Already connected");
+               return;
+       }
+
+       if (device->attios == NULL && device->attios_offline == NULL)
+               return;
+
+       device->auto_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
+                                               att_connect, device,
+                                               att_connect_dispatched);
 }
 
 static gboolean start_discovery(gpointer user_data)
@@ -2009,7 +2146,7 @@ static DBusMessage *new_authentication_return(DBusMessage *msg, int status)
                                        ERROR_INTERFACE ".AuthenticationCanceled",
                                        "Authentication Canceled");
 
-#ifdef __TIZEN_PATCH__
+#ifdef __SAMSUNG_PATCH__
        case 0x2a: /* Cancel by agent */
                return dbus_message_new_error(msg,
                                        ERROR_INTERFACE ".CanceledbyUser",
@@ -2055,8 +2192,6 @@ static void bonding_request_free(struct bonding_req *bonding)
 
        device->bonding = NULL;
 
-       adapter_resume_discovery(device->adapter);
-
        if (!device->agent)
                return;
 
@@ -2064,35 +2199,17 @@ static void bonding_request_free(struct bonding_req *bonding)
        agent_free(device->agent);
        device->agent = NULL;
 }
-#ifdef __TIZEN_PATCH__
-void device_send_reply(struct btd_device *device)
-{
-        info("device_send_reply 1\n");
-       DBusMessage *reply;
-
-       device_set_temporary(device, FALSE);
-
-       if(device->bonding !=NULL)
-       {
-               reply = dbus_message_new_method_return(device->bonding->msg);
-               dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &device->path, DBUS_TYPE_INVALID);
-               g_dbus_send_message(device->bonding->conn, reply);
-                info("device_send_reply 2\n");
-               bonding_request_free(device->bonding);
-
-       }
-        info("device_send_reply 3\n");
 
-}
-#endif
 void device_set_paired(struct btd_device *device, gboolean value)
 {
-       info("device_set_paired +\n");
        DBusConnection *conn = get_dbus_connection();
 
        if (device->paired == value)
                return;
 
+       if (!value)
+               btd_adapter_remove_bonding(device->adapter, &device->bdaddr);
+
        device->paired = value;
 
        emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Paired",
@@ -2104,7 +2221,7 @@ static void device_agent_removed(struct agent *agent, void *user_data)
        struct btd_device *device = user_data;
 
        device->agent = NULL;
-#ifdef __TIZEN_PATCH__
+#ifdef __SAMSUNG_PATCH__
        if (device->authr && (device->authr->agent == agent)) {
                DBG("device->agent is the same with authr->agent");
                device->authr->agent = NULL;
@@ -2152,96 +2269,9 @@ proceed:
        bonding->conn = dbus_connection_ref(conn);
        bonding->msg = dbus_message_ref(msg);
 
-       adapter_suspend_discovery(device->adapter);
-
        return bonding;
 }
 
-static int device_authentication_requested(struct btd_device *device,
-                                               int handle)
-{
-       struct hci_request rq;
-       auth_requested_cp cp;
-       evt_cmd_status rp;
-       int dd;
-
-       dd = hci_open_dev(adapter_get_dev_id(device->adapter));
-       if (dd < 0) {
-               int err = -errno;
-               error("Unable to open adapter: %s(%d)", strerror(-err), -err);
-               return err;
-       }
-
-       memset(&rp, 0, sizeof(rp));
-
-       memset(&cp, 0, sizeof(cp));
-       cp.handle = htobs(handle);
-
-       memset(&rq, 0, sizeof(rq));
-       rq.ogf    = OGF_LINK_CTL;
-       rq.ocf    = OCF_AUTH_REQUESTED;
-       rq.cparam = &cp;
-       rq.clen   = AUTH_REQUESTED_CP_SIZE;
-       rq.rparam = &rp;
-       rq.rlen   = EVT_CMD_STATUS_SIZE;
-       rq.event  = EVT_CMD_STATUS;
-
-       if (hci_send_req(dd, &rq, HCI_REQ_TIMEOUT) < 0) {
-               int err = -errno;
-               error("Unable to send HCI request: %s (%d)",
-                                       strerror(-err), -err);
-               hci_close_dev(dd);
-               return err;
-       }
-
-       if (rp.status) {
-               error("HCI_Authentication_Requested failed with status 0x%02x",
-                               rp.status);
-               hci_close_dev(dd);
-               return rp.status;
-       }
-
-       info("Authentication requested");
-
-       hci_close_dev(dd);
-       return 0;
-}
-
-static void bonding_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
-{
-       struct btd_device *device = user_data;
-       uint16_t handle;
-       int status;
-
-       if (!device->bonding) {
-               if (!err)
-                       g_io_channel_shutdown(io, TRUE, NULL);
-               return;
-       }
-
-       if (err)
-               /* Wait proper error to be propagated by bonding complete */
-               return;
-
-       if (!bt_io_get(io, BT_IO_L2RAW, &err,
-                       BT_IO_OPT_HANDLE, &handle,
-                       BT_IO_OPT_INVALID)) {
-               error("Unable to get connection handle: %s", err->message);
-               g_error_free(err);
-               status = -errno;
-               goto failed;
-       }
-
-       status = device_authentication_requested(device, handle);
-       if (status != 0)
-               goto failed;
-
-       return;
-
-failed:
-       g_io_channel_shutdown(io, TRUE, NULL);
-       device_cancel_bonding(device, status);
-}
 static void create_bond_req_exit(DBusConnection *conn, void *user_data)
 {
        struct btd_device *device = user_data;
@@ -2258,7 +2288,7 @@ static void create_bond_req_exit(DBusConnection *conn, void *user_data)
                device_request_disconnect(device, NULL);
        }
 }
-#ifdef __TIZEN_PATCH__
+#ifdef __SAMSUNG_PATCH__
 void set_cancel_from_authentication_req(void *user_data)
 {
        struct authentication_req *auth = (struct authentication_req *)user_data;
@@ -2269,79 +2299,6 @@ void set_cancel_from_authentication_req(void *user_data)
        }
 }
 #endif
-#ifdef __TIZEN_PATCH__
-DBusMessage *device_jsr82_authenticate_link(struct btd_device *device,
-                                       DBusConnection *conn,
-                                       DBusMessage *msg,
-                                       const char *agent_path,
-                                       uint8_t capability)
-
-{
-       char filename[PATH_MAX + 1];
-       char *str, srcaddr[18], dstaddr[18];
-       struct btd_adapter *adapter = device->adapter;
-       struct bonding_req *bonding;
-       bdaddr_t src;
-       GError *err = NULL;
-       GIOChannel *io;
-
-       adapter_get_address(adapter, &src);
-       ba2str(&src, srcaddr);
-       ba2str(&device->bdaddr, dstaddr);
-
-       if (device->bonding)
-               return btd_error_in_progress(msg);
-
-       /* check if a link key already exists */
-       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr,
-                       "linkkeys");
-
-       str = textfile_caseget(filename, dstaddr);
-/*     if (str) {
-               free(str);
-               return g_dbus_create_error(msg,
-                               ERROR_INTERFACE ".AlreadyExists",
-                               "Bonding already exists");
-       }*/
-
-
-       io = bt_io_connect(BT_IO_L2RAW, bonding_connect_cb, device,
-                               NULL, &err,
-                               BT_IO_OPT_SOURCE_BDADDR, &src,
-                               BT_IO_OPT_DEST_BDADDR, &device->bdaddr,
-                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH,
-                               BT_IO_OPT_INVALID);
-       if (io == NULL) {
-               DBusMessage *reply;
-               reply = g_dbus_create_error(msg,
-                               ERROR_INTERFACE ".ConnectionAttemptFailed",
-                               err->message);
-               error("bt_io_connect: %s", err->message);
-               g_error_free(err);
-               return reply;
-       }
-
-       bonding = bonding_request_new(conn, msg, device, agent_path,
-                                       capability);
-       if (!bonding) {
-               g_io_channel_shutdown(io, TRUE, NULL);
-               return NULL;
-       }
-
-       bonding->io = io;
-
-       bonding->listener_id = g_dbus_add_disconnect_watch(conn,
-                                               dbus_message_get_sender(msg),
-                                               create_bond_req_exit, device,
-                                               NULL);
-
-       device->bonding = bonding;
-       bonding->device = device;
-
-       return NULL;
-
-}
-#endif
 
 DBusMessage *device_create_bonding(struct btd_device *device,
                                        DBusConnection *conn,
@@ -2411,7 +2368,6 @@ static void device_auth_req_free(struct btd_device *device)
 
 void device_bonding_complete(struct btd_device *device, uint8_t status)
 {
-       info("device_bonding_complete() +");
        struct bonding_req *bonding = device->bonding;
        struct authentication_req *auth = device->authr;
 
@@ -2428,31 +2384,6 @@ void device_bonding_complete(struct btd_device *device, uint8_t status)
 
        device_auth_req_free(device);
 
-#ifdef __TIZEN_PATCH__
-       if (bonding) {
-               if (dbus_message_is_method_call(bonding->msg, ADAPTER_INTERFACE,
-                                                               "AuthenticateLink") ) {
-                       DBusMessage *reply;
-                       reply = dbus_message_new_method_return(bonding->msg);
-                       if (!reply) {
-                               bonding_request_free(bonding);
-                               return;
-                       }
-
-                       const char *path = device_get_path(device);
-
-                       dbus_message_append_args(reply,
-                                       DBUS_TYPE_OBJECT_PATH, &path,
-                                       DBUS_TYPE_INVALID);
-
-                       g_dbus_send_message(bonding->conn, reply);
-                       bonding_request_free(bonding);
-                       return;
-               }
-       }
-#endif
-
-
        /* If we're already paired nothing more is needed */
        if (device->paired)
                return;
@@ -2489,7 +2420,6 @@ void device_bonding_complete(struct btd_device *device, uint8_t status)
                                                        device);
                }
        }
-       info("device_bonding_complete() -");
 }
 
 gboolean device_is_creating(struct btd_device *device, const char *sender)
@@ -2543,7 +2473,7 @@ void device_cancel_bonding(struct btd_device *device, uint8_t status)
        if (device->authr)
                device_cancel_authentication(device, FALSE);
 
-#ifdef __TIZEN_PATCH__
+#ifdef __SAMSUNG_PATCH__
        if (bonding->cancel_by_user)
        {
                info("Bonding Cancel by user");
@@ -2563,7 +2493,24 @@ static void pincode_cb(struct agent *agent, DBusError *err,
 {
        struct authentication_req *auth = data;
        struct btd_device *device = auth->device;
+       struct btd_adapter *adapter = device_get_adapter(device);
+       struct agent *adapter_agent = adapter_get_agent(adapter);
+
+       if (err && (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) ||
+                               g_str_equal(DBUS_ERROR_NO_REPLY, err->name))) {
+
+               if (auth->agent == adapter_agent || adapter_agent == NULL)
+                       goto done;
+
+               if (agent_request_pincode(adapter_agent, device, pincode_cb,
+                                               auth->secure, auth, NULL) < 0)
+                       goto done;
 
+               auth->agent = adapter_agent;
+               return;
+       }
+
+done:
        /* No need to reply anything if the authentication already failed */
        if (auth->cb == NULL)
                return;
@@ -2578,23 +2525,31 @@ static void confirm_cb(struct agent *agent, DBusError *err, void *data)
 {
        struct authentication_req *auth = data;
        struct btd_device *device = auth->device;
+       struct btd_adapter *adapter = device_get_adapter(device);
+       struct agent *adapter_agent = adapter_get_agent(adapter);
 
-       /* No need to reply anything if the authentication already failed */
-       if (auth->cb == NULL)
+       if (err && (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) ||
+                               g_str_equal(DBUS_ERROR_NO_REPLY, err->name))) {
+
+               if (auth->agent == adapter_agent || adapter_agent == NULL)
+                       goto done;
+
+               if (agent_request_confirmation(adapter_agent, device,
+                                               auth->passkey, confirm_cb,
+                                               auth, NULL) < 0)
+                       goto done;
+
+               auth->agent = adapter_agent;
                return;
+       }
 
-#ifdef __TIZEN_PATCH__
-       if (!device)
+done:
+       /* No need to reply anything if the authentication already failed */
+       if (auth->cb == NULL)
                return;
-#endif
 
        ((agent_cb) auth->cb)(agent, err, device);
 
-#ifdef __TIZEN_PATCH__
-       if (!device->authr)
-               return;
-#endif
-
        device->authr->cb = NULL;
        device->authr->agent = NULL;
 }
@@ -2604,7 +2559,24 @@ static void passkey_cb(struct agent *agent, DBusError *err,
 {
        struct authentication_req *auth = data;
        struct btd_device *device = auth->device;
+       struct btd_adapter *adapter = device_get_adapter(device);
+       struct agent *adapter_agent = adapter_get_agent(adapter);
+
+       if (err && (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) ||
+                               g_str_equal(DBUS_ERROR_NO_REPLY, err->name))) {
+
+               if (auth->agent == adapter_agent || adapter_agent == NULL)
+                       goto done;
 
+               if (agent_request_passkey(adapter_agent, device, passkey_cb,
+                                                       auth, NULL) < 0)
+                       goto done;
+
+               auth->agent = adapter_agent;
+               return;
+       }
+
+done:
        /* No need to reply anything if the authentication already failed */
        if (auth->cb == NULL)
                return;
@@ -2616,7 +2588,7 @@ static void passkey_cb(struct agent *agent, DBusError *err,
 }
 
 int device_request_authentication(struct btd_device *device, auth_type_t type,
-                                               uint32_t passkey, void *cb)
+                               uint32_t passkey, gboolean secure, void *cb)
 {
        struct authentication_req *auth;
        struct agent *agent;
@@ -2642,11 +2614,13 @@ int device_request_authentication(struct btd_device *device, auth_type_t type,
        auth->device = device;
        auth->cb = cb;
        auth->type = type;
+       auth->passkey = passkey;
+       auth->secure = secure;
        device->authr = auth;
 
        switch (type) {
        case AUTH_TYPE_PINCODE:
-               err = agent_request_pincode(agent, device, pincode_cb,
+               err = agent_request_pincode(agent, device, pincode_cb, secure,
                                                                auth, NULL);
                break;
        case AUTH_TYPE_PASSKEY:
@@ -2741,17 +2715,12 @@ void device_set_authorizing(struct btd_device *device, gboolean auth)
        device->authorizing = auth;
 }
 
-void btd_device_add_service(struct btd_device *device, const char *path)
+void device_register_services(DBusConnection *conn, struct btd_device *device,
+                                               GSList *prim_list, int psm)
 {
-       if (g_slist_find_custom(device->services, path, (GCompareFunc) strcmp))
-               return;
-
-       device->services = g_slist_append(device->services, g_strdup(path));
-}
-
-void device_add_primary(struct btd_device *device, struct att_primary *prim)
-{
-       device->primaries = g_slist_append(device->primaries, prim);
+       device->primaries = g_slist_concat(device->primaries, prim_list);
+       device->services = attrib_client_register(conn, device, psm, NULL,
+                                                               prim_list);
 }
 
 GSList *btd_device_get_primaries(struct btd_device *device)
@@ -2841,3 +2810,103 @@ void btd_device_unref(struct btd_device *device)
 
        g_free(path);
 }
+
+void device_set_class(struct btd_device *device, uint32_t value)
+{
+       DBusConnection *conn = get_dbus_connection();
+
+       emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Class",
+                               DBUS_TYPE_UINT32, &value);
+}
+
+static gboolean notify_attios(gpointer user_data)
+{
+       struct btd_device *device = user_data;
+
+       if (device->attrib == NULL)
+               return FALSE;
+
+       g_slist_foreach(device->attios_offline, attio_connected, device->attrib);
+       device->attios = g_slist_concat(device->attios, device->attios_offline);
+       device->attios_offline = NULL;
+
+       return FALSE;
+}
+
+guint btd_device_add_attio_callback(struct btd_device *device,
+                                               attio_connect_cb cfunc,
+                                               attio_disconnect_cb dcfunc,
+                                               gpointer user_data)
+{
+       struct attio_data *attio;
+       static guint attio_id = 0;
+
+       DBG("%p registered ATT connection callback", device);
+
+       attio = g_new0(struct attio_data, 1);
+       attio->id = ++attio_id;
+       attio->cfunc = cfunc;
+       attio->dcfunc = dcfunc;
+       attio->user_data = user_data;
+
+       if (device->attrib && cfunc) {
+               device->attios_offline = g_slist_append(device->attios_offline,
+                                                                       attio);
+               g_idle_add(notify_attios, device);
+       } else {
+               device->auto_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
+                                               att_connect, device,
+                                               att_connect_dispatched);
+
+               device->attios = g_slist_append(device->attios, attio);
+       }
+
+       return attio->id;
+}
+
+static int attio_id_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct attio_data *attio = a;
+       guint id = GPOINTER_TO_UINT(b);
+
+       return attio->id - id;
+}
+
+gboolean btd_device_remove_attio_callback(struct btd_device *device, guint id)
+{
+       struct attio_data *attio;
+       GSList *l;
+
+       l = g_slist_find_custom(device->attios, GUINT_TO_POINTER(id),
+                                                               attio_id_cmp);
+       if (l) {
+               attio = l->data;
+               device->attios = g_slist_remove(device->attios, attio);
+       } else {
+               l = g_slist_find_custom(device->attios_offline,
+                                       GUINT_TO_POINTER(id), attio_id_cmp);
+               if (!l)
+                       return FALSE;
+
+               attio = l->data;
+               device->attios_offline = g_slist_remove(device->attios_offline,
+                                                                       attio);
+       }
+
+       g_free(attio);
+
+       if (device->attios != NULL || device->attios_offline != NULL)
+               return TRUE;
+
+       if (device->attachid) {
+               attrib_channel_detach(device->attrib, device->attachid);
+               device->attachid = 0;
+       }
+
+       if (device->attrib) {
+               g_attrib_unref(device->attrib);
+               device->attrib = NULL;
+       }
+
+       return TRUE;
+}
index 7b0b708..13005ae 100644 (file)
@@ -25,7 +25,6 @@
 #define DEVICE_INTERFACE       "org.bluez.Device"
 
 struct btd_device;
-struct att_primary;
 
 typedef enum {
        AUTH_TYPE_PINCODE,
@@ -34,19 +33,14 @@ typedef enum {
        AUTH_TYPE_NOTIFY,
 } auth_type_t;
 
-typedef enum {
-       DEVICE_TYPE_UNKNOWN,
-       DEVICE_TYPE_BREDR,
-       DEVICE_TYPE_LE,
-       DEVICE_TYPE_DUALMODE
-} device_type_t;
-
 struct btd_device *device_create(DBusConnection *conn,
-                               struct btd_adapter *adapter,
-                               const gchar *address, device_type_t type);
+                                       struct btd_adapter *adapter,
+                                       const char *address, addr_type_t type);
 void device_set_name(struct btd_device *device, const char *name);
 void device_get_name(struct btd_device *device, char *name, size_t len);
-device_type_t device_get_type(struct btd_device *device);
+uint16_t btd_device_get_vendor(struct btd_device *device);
+uint16_t btd_device_get_product(struct btd_device *device);
+uint16_t btd_device_get_version(struct btd_device *device);
 void device_remove(struct btd_device *device, gboolean remove_stored);
 gint device_address_cmp(struct btd_device *device, const gchar *address);
 int device_browse_primary(struct btd_device *device, DBusConnection *conn,
@@ -57,36 +51,38 @@ void device_probe_drivers(struct btd_device *device, GSList *profiles);
 const sdp_record_t *btd_device_get_record(struct btd_device *device,
                                                const char *uuid);
 GSList *btd_device_get_primaries(struct btd_device *device);
-void btd_device_add_service(struct btd_device *device, const char *path);
-void device_add_primary(struct btd_device *device, struct att_primary *prim);
+void device_register_services(DBusConnection *conn, struct btd_device *device,
+                                               GSList *prim_list, int psm);
+GSList *device_services_from_record(struct btd_device *device,
+                                                       GSList *profiles);
 void btd_device_add_uuid(struct btd_device *device, const char *uuid);
 struct btd_adapter *device_get_adapter(struct btd_device *device);
-void device_get_address(struct btd_device *device, bdaddr_t *bdaddr);
+void device_get_address(struct btd_device *device, bdaddr_t *bdaddr,
+                                                       addr_type_t *type);
 const gchar *device_get_path(struct btd_device *device);
 struct agent *device_get_agent(struct btd_device *device);
+gboolean device_is_bredr(struct btd_device *device);
+gboolean device_is_le(struct btd_device *device);
 gboolean device_is_busy(struct btd_device *device);
 gboolean device_is_temporary(struct btd_device *device);
 gboolean device_is_paired(struct btd_device *device);
+gboolean device_is_bonded(struct btd_device *device);
 gboolean device_is_trusted(struct btd_device *device);
 void device_set_paired(struct btd_device *device, gboolean paired);
 void device_set_temporary(struct btd_device *device, gboolean temporary);
-void device_set_cap(struct btd_device *device, uint8_t cap);
-void device_set_type(struct btd_device *device, device_type_t type);
-uint8_t device_get_cap(struct btd_device *device);
-void device_set_auth(struct btd_device *device, uint8_t auth);
-uint8_t device_get_auth(struct btd_device *device);
+void device_set_bonded(struct btd_device *device, gboolean bonded);
+void device_set_auto_connect(struct btd_device *device, gboolean enable);
 gboolean device_is_connected(struct btd_device *device);
 DBusMessage *device_create_bonding(struct btd_device *device,
                                DBusConnection *conn, DBusMessage *msg,
                                const char *agent_path, uint8_t capability);
-void device_remove_bonding(struct btd_device *device);
 void device_bonding_complete(struct btd_device *device, uint8_t status);
 void device_simple_pairing_complete(struct btd_device *device, uint8_t status);
 gboolean device_is_creating(struct btd_device *device, const char *sender);
 gboolean device_is_bonding(struct btd_device *device, const char *sender);
 void device_cancel_bonding(struct btd_device *device, uint8_t status);
 int device_request_authentication(struct btd_device *device, auth_type_t type,
-                               uint32_t passkey, void *cb);
+                               uint32_t passkey, gboolean secure, void *cb);
 void device_cancel_authentication(struct btd_device *device, gboolean aborted);
 gboolean device_is_authenticating(struct btd_device *device);
 gboolean device_is_authorizing(struct btd_device *device);
@@ -102,6 +98,7 @@ guint device_add_disconnect_watch(struct btd_device *device,
                                disconnect_watch watch, void *user_data,
                                GDestroyNotify destroy);
 void device_remove_disconnect_watch(struct btd_device *device, guint id);
+void device_set_class(struct btd_device *device, uint32_t value);
 
 #define BTD_UUIDS(args...) ((const char *[]) { args, NULL } )
 
@@ -118,10 +115,7 @@ void btd_unregister_device_driver(struct btd_device_driver *driver);
 struct btd_device *btd_device_ref(struct btd_device *device);
 void btd_device_unref(struct btd_device *device);
 
-#ifdef __TIZEN_PATCH__
-DBusMessage *device_jsr82_authenticate_link(struct btd_device *device,
-                                       DBusConnection *conn,
-                                       DBusMessage *msg,
-                                       const char *agent_path,
-                                       uint8_t capability);
-#endif
+int device_block(DBusConnection *conn, struct btd_device *device,
+                                               gboolean update_only);
+int device_unblock(DBusConnection *conn, struct btd_device *device,
+                                       gboolean silent, gboolean update_only);
diff --git a/src/eir.c b/src/eir.c
new file mode 100644 (file)
index 0000000..1b68949
--- /dev/null
+++ b/src/eir.c
@@ -0,0 +1,368 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <glib.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/sdp.h>
+
+#include "glib-compat.h"
+#include "glib-helper.h"
+#include "eir.h"
+
+#define EIR_FLAGS                   0x01  /* flags */
+#define EIR_UUID16_SOME             0x02  /* 16-bit UUID, more available */
+#define EIR_UUID16_ALL              0x03  /* 16-bit UUID, all listed */
+#define EIR_UUID32_SOME             0x04  /* 32-bit UUID, more available */
+#define EIR_UUID32_ALL              0x05  /* 32-bit UUID, all listed */
+#define EIR_UUID128_SOME            0x06  /* 128-bit UUID, more available */
+#define EIR_UUID128_ALL             0x07  /* 128-bit UUID, all listed */
+#define EIR_NAME_SHORT              0x08  /* shortened local name */
+#define EIR_NAME_COMPLETE           0x09  /* complete local name */
+#define EIR_TX_POWER                0x0A  /* transmit power level */
+#define EIR_DEVICE_ID               0x10  /* device ID */
+
+void eir_data_free(struct eir_data *eir)
+{
+       g_slist_free_full(eir->services, g_free);
+       eir->services = NULL;
+       g_free(eir->name);
+       eir->name = NULL;
+}
+
+static void eir_parse_uuid16(struct eir_data *eir, void *data, uint8_t len)
+{
+       uint16_t *uuid16 = data;
+       uuid_t service;
+       char *uuid_str;
+       unsigned int i;
+
+       service.type = SDP_UUID16;
+       for (i = 0; i < len / 2; i++, uuid16++) {
+               service.value.uuid16 = btohs(bt_get_unaligned(uuid16));
+               uuid_str = bt_uuid2string(&service);
+               eir->services = g_slist_append(eir->services, uuid_str);
+       }
+}
+
+static void eir_parse_uuid32(struct eir_data *eir, void *data, uint8_t len)
+{
+       uint32_t *uuid32 = data;
+       uuid_t service;
+       char *uuid_str;
+       unsigned int i;
+
+       service.type = SDP_UUID32;
+       for (i = 0; i < len / 4; i++, uuid32++) {
+               service.value.uuid32 = btohl(bt_get_unaligned(uuid32));
+               uuid_str = bt_uuid2string(&service);
+               eir->services = g_slist_append(eir->services, uuid_str);
+       }
+}
+
+static void eir_parse_uuid128(struct eir_data *eir, uint8_t *data, uint8_t len)
+{
+       uint8_t *uuid_ptr = data;
+       uuid_t service;
+       char *uuid_str;
+       unsigned int i;
+       int k;
+
+       service.type = SDP_UUID128;
+       for (i = 0; i < len / 16; i++) {
+               for (k = 0; k < 16; k++)
+                       service.value.uuid128.data[k] = uuid_ptr[16 - k - 1];
+               uuid_str = bt_uuid2string(&service);
+               eir->services = g_slist_append(eir->services, uuid_str);
+               uuid_ptr += 16;
+       }
+}
+
+int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len)
+{
+       uint16_t len = 0;
+
+       eir->flags = -1;
+
+       /* No EIR data to parse */
+       if (eir_data == NULL)
+               return 0;
+
+       while (len < eir_len - 1) {
+               uint8_t field_len = eir_data[0];
+               uint8_t name_len;
+
+               /* Check for the end of EIR */
+               if (field_len == 0)
+                       break;
+
+               len += field_len + 1;
+
+               /* Bail out if got incorrect length */
+               if (len > eir_len) {
+                       eir_data_free(eir);
+                       return -EINVAL;
+               }
+
+               switch (eir_data[1]) {
+               case EIR_UUID16_SOME:
+               case EIR_UUID16_ALL:
+                       eir_parse_uuid16(eir, &eir_data[2], field_len);
+                       break;
+
+               case EIR_UUID32_SOME:
+               case EIR_UUID32_ALL:
+                       eir_parse_uuid32(eir, &eir_data[2], field_len);
+                       break;
+
+               case EIR_UUID128_SOME:
+               case EIR_UUID128_ALL:
+                       eir_parse_uuid128(eir, &eir_data[2], field_len);
+                       break;
+
+               case EIR_FLAGS:
+                       eir->flags = eir_data[2];
+                       break;
+
+               case EIR_NAME_SHORT:
+               case EIR_NAME_COMPLETE:
+                       /* Some vendors put a NUL byte terminator into
+                        * the name */
+                       name_len = field_len - 1;
+
+                       while (name_len > 0 && eir_data[name_len - 1] == '\0')
+                               name_len--;
+
+                       if (!g_utf8_validate((char *) &eir_data[2],
+                                                               name_len, NULL))
+                               break;
+
+                       g_free(eir->name);
+
+                       eir->name = g_strndup((char *) &eir_data[2],
+                                                               field_len - 1);
+                       eir->name_complete = eir_data[1] == EIR_NAME_COMPLETE;
+                       break;
+               }
+
+               eir_data += field_len + 1;
+       }
+
+       return 0;
+}
+
+#define SIZEOF_UUID128 16
+
+static void eir_generate_uuid128(GSList *list, uint8_t *ptr, uint16_t *eir_len)
+{
+       int i, k, uuid_count = 0;
+       uint16_t len = *eir_len;
+       uint8_t *uuid128;
+       gboolean truncated = FALSE;
+
+       /* Store UUIDs in place, skip 2 bytes to write type and length later */
+       uuid128 = ptr + 2;
+
+       for (; list; list = list->next) {
+               struct uuid_info *uuid = list->data;
+               uint8_t *uuid128_data = uuid->uuid.value.uuid128.data;
+
+               if (uuid->uuid.type != SDP_UUID128)
+                       continue;
+
+               /* Stop if not enough space to put next UUID128 */
+               if ((len + 2 + SIZEOF_UUID128) > HCI_MAX_EIR_LENGTH) {
+                       truncated = TRUE;
+                       break;
+               }
+
+               /* Check for duplicates, EIR data is Little Endian */
+               for (i = 0; i < uuid_count; i++) {
+                       for (k = 0; k < SIZEOF_UUID128; k++) {
+                               if (uuid128[i * SIZEOF_UUID128 + k] !=
+                                       uuid128_data[SIZEOF_UUID128 - 1 - k])
+                                       break;
+                       }
+                       if (k == SIZEOF_UUID128)
+                               break;
+               }
+
+               if (i < uuid_count)
+                       continue;
+
+               /* EIR data is Little Endian */
+               for (k = 0; k < SIZEOF_UUID128; k++)
+                       uuid128[uuid_count * SIZEOF_UUID128 + k] =
+                               uuid128_data[SIZEOF_UUID128 - 1 - k];
+
+               len += SIZEOF_UUID128;
+               uuid_count++;
+       }
+
+       if (uuid_count > 0 || truncated) {
+               /* EIR Data length */
+               ptr[0] = (uuid_count * SIZEOF_UUID128) + 1;
+               /* EIR Data type */
+               ptr[1] = truncated ? EIR_UUID128_SOME : EIR_UUID128_ALL;
+               len += 2;
+               *eir_len = len;
+       }
+}
+
+void eir_create(const char *name, int8_t tx_power, uint16_t did_vendor,
+                       uint16_t did_product, uint16_t did_version,
+                       GSList *uuids, uint8_t *data)
+{
+       GSList *l;
+       uint8_t *ptr = data;
+       uint16_t eir_len = 0;
+       uint16_t uuid16[HCI_MAX_EIR_LENGTH / 2];
+       int i, uuid_count = 0;
+       gboolean truncated = FALSE;
+       size_t name_len;
+
+       name_len = strlen(name);
+
+       if (name_len > 0) {
+               /* EIR Data type */
+               if (name_len > 48) {
+                       name_len = 48;
+                       ptr[1] = EIR_NAME_SHORT;
+               } else
+                       ptr[1] = EIR_NAME_COMPLETE;
+
+               /* EIR Data length */
+               ptr[0] = name_len + 1;
+
+               memcpy(ptr + 2, name, name_len);
+
+               eir_len += (name_len + 2);
+               ptr += (name_len + 2);
+       }
+
+       if (tx_power != 0) {
+               *ptr++ = 2;
+               *ptr++ = EIR_TX_POWER;
+               *ptr++ = (uint8_t) tx_power;
+               eir_len += 3;
+       }
+
+       if (did_vendor != 0x0000) {
+               uint16_t source = 0x0002;
+               *ptr++ = 9;
+               *ptr++ = EIR_DEVICE_ID;
+               *ptr++ = (source & 0x00ff);
+               *ptr++ = (source & 0xff00) >> 8;
+               *ptr++ = (did_vendor & 0x00ff);
+               *ptr++ = (did_vendor & 0xff00) >> 8;
+               *ptr++ = (did_product & 0x00ff);
+               *ptr++ = (did_product & 0xff00) >> 8;
+               *ptr++ = (did_version & 0x00ff);
+               *ptr++ = (did_version & 0xff00) >> 8;
+               eir_len += 10;
+       }
+
+       /* Group all UUID16 types */
+       for (l = uuids; l != NULL; l = g_slist_next(l)) {
+               struct uuid_info *uuid = l->data;
+
+               if (uuid->uuid.type != SDP_UUID16)
+                       continue;
+
+               if (uuid->uuid.value.uuid16 < 0x1100)
+                       continue;
+
+               if (uuid->uuid.value.uuid16 == PNP_INFO_SVCLASS_ID)
+                       continue;
+
+               /* Stop if not enough space to put next UUID16 */
+               if ((eir_len + 2 + sizeof(uint16_t)) > HCI_MAX_EIR_LENGTH) {
+                       truncated = TRUE;
+                       break;
+               }
+
+               /* Check for duplicates */
+               for (i = 0; i < uuid_count; i++)
+                       if (uuid16[i] == uuid->uuid.value.uuid16)
+                               break;
+
+               if (i < uuid_count)
+                       continue;
+
+               uuid16[uuid_count++] = uuid->uuid.value.uuid16;
+               eir_len += sizeof(uint16_t);
+       }
+
+       if (uuid_count > 0) {
+               /* EIR Data length */
+               ptr[0] = (uuid_count * sizeof(uint16_t)) + 1;
+               /* EIR Data type */
+               ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
+
+               ptr += 2;
+               eir_len += 2;
+
+               for (i = 0; i < uuid_count; i++) {
+                       *ptr++ = (uuid16[i] & 0x00ff);
+                       *ptr++ = (uuid16[i] & 0xff00) >> 8;
+               }
+       }
+
+       /* Group all UUID128 types */
+       if (eir_len <= HCI_MAX_EIR_LENGTH - 2)
+               eir_generate_uuid128(uuids, ptr, &eir_len);
+}
+
+gboolean eir_has_complete_name(uint8_t *data, size_t len)
+{
+       uint8_t field_len;
+       size_t parsed;
+
+       for (parsed = 0; parsed < len - 1; parsed += field_len) {
+               field_len = data[0];
+
+               if (field_len == 0)
+                       break;
+
+               parsed += field_len + 1;
+
+               if (parsed > len)
+                       break;
+
+               if (data[1] == EIR_NAME_COMPLETE)
+                       return TRUE;
+
+               data += field_len + 1;
+       }
+
+       return FALSE;
+}
diff --git a/src/eir.h b/src/eir.h
new file mode 100644 (file)
index 0000000..47c2258
--- /dev/null
+++ b/src/eir.h
@@ -0,0 +1,43 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+struct uuid_info {
+       uuid_t uuid;
+       uint8_t svc_hint;
+};
+
+struct eir_data {
+       GSList *services;
+       int flags;
+       char *name;
+       gboolean name_complete;
+};
+
+void eir_data_free(struct eir_data *eir);
+int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len);
+void eir_create(const char *name, int8_t tx_power, uint16_t did_vendor,
+                       uint16_t did_product, uint16_t did_version,
+                       GSList *uuids, uint8_t *data);
+
+gboolean eir_has_complete_name(uint8_t *data, size_t len);
index 4ca1be5..6854990 100644 (file)
 
 #define _GNU_SOURCE
 #include <stdio.h>
+#include <ctype.h>
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
 
 #include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus.h>
 
 #include "log.h"
-#include "textfile.h"
 
-#include "hcid.h"
 #include "adapter.h"
 #include "manager.h"
 #include "device.h"
 #include "error.h"
-#include "glib-helper.h"
 #include "dbus-common.h"
 #include "agent.h"
 #include "storage.h"
 #include "event.h"
-#include "sdpd.h"
-
-struct eir_data {
-       GSList *services;
-       int flags;
-       char *name;
-       gboolean name_complete;
-};
 
 static gboolean get_adapter_and_device(bdaddr_t *src, bdaddr_t *dst,
                                        struct btd_adapter **adapter,
@@ -105,49 +90,48 @@ static void pincode_cb(struct agent *agent, DBusError *derr,
                                const char *pincode, struct btd_device *device)
 {
        struct btd_adapter *adapter = device_get_adapter(device);
-       bdaddr_t sba, dba;
+       bdaddr_t dba;
        int err;
 
-       device_get_address(device, &dba);
+       device_get_address(device, &dba, NULL);
 
        if (derr) {
-               err = btd_adapter_pincode_reply(adapter, &dba, NULL);
+               err = btd_adapter_pincode_reply(adapter, &dba, NULL, 0);
                if (err < 0)
                        goto fail;
                return;
        }
 
-       err = btd_adapter_pincode_reply(adapter, &dba, pincode);
+       err = btd_adapter_pincode_reply(adapter, &dba, pincode,
+                                               pincode ? strlen(pincode) : 0);
        if (err < 0)
                goto fail;
 
-       adapter_get_address(adapter, &sba);
-
        return;
 
 fail:
        error("Sending PIN code reply failed: %s (%d)", strerror(-err), -err);
 }
 
-int btd_event_request_pin(bdaddr_t *sba, bdaddr_t *dba)
+int btd_event_request_pin(bdaddr_t *sba, bdaddr_t *dba, gboolean secure)
 {
        struct btd_adapter *adapter;
        struct btd_device *device;
        char pin[17];
-       int pinlen;
+       ssize_t pinlen;
 
        if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE))
                return -ENODEV;
 
        memset(pin, 0, sizeof(pin));
-       pinlen = read_pin_code(sba, dba, pin);
-       if (pinlen > 0) {
-               btd_adapter_pincode_reply(adapter, dba, pin);
+       pinlen = btd_adapter_get_pin(adapter, device, pin);
+       if (pinlen > 0 && (!secure || pinlen == 16)) {
+               btd_adapter_pincode_reply(adapter, dba, pin, pinlen);
                return 0;
        }
 
        return device_request_authentication(device, AUTH_TYPE_PINCODE, 0,
-                                                               pincode_cb);
+                                                       secure, pincode_cb);
 }
 
 static int confirm_reply(struct btd_adapter *adapter,
@@ -155,7 +139,7 @@ static int confirm_reply(struct btd_adapter *adapter,
 {
        bdaddr_t bdaddr;
 
-       device_get_address(device, &bdaddr);
+       device_get_address(device, &bdaddr, NULL);
 
        return btd_adapter_confirm_reply(adapter, &bdaddr, success);
 }
@@ -176,7 +160,7 @@ static void passkey_cb(struct agent *agent, DBusError *err, uint32_t passkey,
        struct btd_adapter *adapter = device_get_adapter(device);
        bdaddr_t bdaddr;
 
-       device_get_address(device, &bdaddr);
+       device_get_address(device, &bdaddr, NULL);
 
        if (err)
                passkey = INVALID_PASSKEY;
@@ -193,7 +177,7 @@ int btd_event_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey)
                return -ENODEV;
 
        return device_request_authentication(device, AUTH_TYPE_CONFIRM,
-                                                       passkey, confirm_cb);
+                                               passkey, FALSE, confirm_cb);
 }
 
 int btd_event_user_passkey(bdaddr_t *sba, bdaddr_t *dba)
@@ -205,7 +189,7 @@ int btd_event_user_passkey(bdaddr_t *sba, bdaddr_t *dba)
                return -ENODEV;
 
        return device_request_authentication(device, AUTH_TYPE_PASSKEY, 0,
-                                                               passkey_cb);
+                                                       FALSE, passkey_cb);
 }
 
 int btd_event_user_notify(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey)
@@ -216,26 +200,8 @@ int btd_event_user_notify(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey)
        if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE))
                return -ENODEV;
 
-       return device_request_authentication(device, AUTH_TYPE_NOTIFY,
-                                                               passkey, NULL);
-}
-
-void btd_event_bonding_complete(bdaddr_t *local, bdaddr_t *peer,
-                                                       uint8_t status)
-{
-       struct btd_adapter *adapter;
-       struct btd_device *device;
-       gboolean create;
-
-       DBG("status 0x%02x", status);
-
-       create = status ? FALSE : TRUE;
-
-       if (!get_adapter_and_device(local, peer, &adapter, &device, create))
-               return;
-
-       if (device)
-               device_bonding_complete(device, status);
+       return device_request_authentication(device, AUTH_TYPE_NOTIFY, passkey,
+                                                               FALSE, NULL);
 }
 
 void btd_event_simple_pairing_complete(bdaddr_t *local, bdaddr_t *peer,
@@ -258,155 +224,6 @@ void btd_event_simple_pairing_complete(bdaddr_t *local, bdaddr_t *peer,
        device_simple_pairing_complete(device, status);
 }
 
-static int parse_eir_data(struct eir_data *eir, uint8_t *eir_data,
-                                                       size_t eir_length)
-{
-       uint16_t len = 0;
-       size_t total;
-       size_t uuid16_count = 0;
-       size_t uuid32_count = 0;
-       size_t uuid128_count = 0;
-       uint8_t *uuid16 = NULL;
-       uint8_t *uuid32 = NULL;
-       uint8_t *uuid128 = NULL;
-       uuid_t service;
-       char *uuid_str;
-       unsigned int i;
-
-       eir->flags = -1;
-
-       /* No EIR data to parse */
-       if (eir_data == NULL || eir_length == 0)
-               return 0;
-
-       while (len < eir_length - 1) {
-               uint8_t field_len = eir_data[0];
-
-               /* Check for the end of EIR */
-               if (field_len == 0)
-                       break;
-
-               switch (eir_data[1]) {
-               case EIR_UUID16_SOME:
-               case EIR_UUID16_ALL:
-                       uuid16_count = field_len / 2;
-                       uuid16 = &eir_data[2];
-                       break;
-               case EIR_UUID32_SOME:
-               case EIR_UUID32_ALL:
-                       uuid32_count = field_len / 4;
-                       uuid32 = &eir_data[2];
-                       break;
-               case EIR_UUID128_SOME:
-               case EIR_UUID128_ALL:
-                       uuid128_count = field_len / 16;
-                       uuid128 = &eir_data[2];
-                       break;
-               case EIR_FLAGS:
-                       eir->flags = eir_data[2];
-                       break;
-               case EIR_NAME_SHORT:
-               case EIR_NAME_COMPLETE:
-                       if (g_utf8_validate((char *) &eir_data[2],
-                                                       field_len - 1, NULL))
-                               eir->name = g_strndup((char *) &eir_data[2],
-                                                               field_len - 1);
-                       else
-                               eir->name = g_strdup("");
-                       eir->name_complete = eir_data[1] == EIR_NAME_COMPLETE;
-                       break;
-               }
-
-               len += field_len + 1;
-               eir_data += field_len + 1;
-       }
-
-       /* Bail out if got incorrect length */
-       if (len > eir_length)
-               return -EINVAL;
-
-       total = uuid16_count + uuid32_count + uuid128_count;
-
-       /* No UUIDs were parsed, so skip code below */
-       if (!total)
-               return 0;
-
-       /* Generate uuids in SDP format (EIR data is Little Endian) */
-       service.type = SDP_UUID16;
-       for (i = 0; i < uuid16_count; i++) {
-               uint16_t val16 = uuid16[1];
-
-               val16 = (val16 << 8) + uuid16[0];
-               service.value.uuid16 = val16;
-               uuid_str = bt_uuid2string(&service);
-               eir->services = g_slist_append(eir->services, uuid_str);
-               uuid16 += 2;
-       }
-
-       service.type = SDP_UUID32;
-       for (i = uuid16_count; i < uuid32_count + uuid16_count; i++) {
-               uint32_t val32 = uuid32[3];
-               int k;
-
-               for (k = 2; k >= 0; k--)
-                       val32 = (val32 << 8) + uuid32[k];
-
-               service.value.uuid32 = val32;
-               uuid_str = bt_uuid2string(&service);
-               eir->services = g_slist_append(eir->services, uuid_str);
-               uuid32 += 4;
-       }
-
-       service.type = SDP_UUID128;
-       for (i = uuid32_count + uuid16_count; i < total; i++) {
-               int k;
-
-               for (k = 0; k < 16; k++)
-                       service.value.uuid128.data[k] = uuid128[16 - k - 1];
-
-               uuid_str = bt_uuid2string(&service);
-               eir->services = g_slist_append(eir->services, uuid_str);
-               uuid128 += 16;
-       }
-
-       return 0;
-}
-
-static void free_eir_data(struct eir_data *eir)
-{
-       g_slist_foreach(eir->services, (GFunc) g_free, NULL);
-       g_slist_free(eir->services);
-       g_free(eir->name);
-}
-
-void btd_event_advertising_report(bdaddr_t *local, le_advertising_info *info)
-{
-       struct btd_adapter *adapter;
-       struct eir_data eir_data;
-       int8_t rssi;
-       int err;
-
-       adapter = manager_find_adapter(local);
-       if (adapter == NULL) {
-               error("No matching adapter found");
-               return;
-       }
-
-       memset(&eir_data, 0, sizeof(eir_data));
-       err = parse_eir_data(&eir_data, info->data, info->length);
-       if (err < 0)
-               error("Error parsing advertising data: %s (%d)",
-                                                       strerror(-err), -err);
-
-       rssi = *(info->data + info->length);
-
-       adapter_update_device_from_info(adapter, info->bdaddr, rssi,
-                                       info->evt_type, eir_data.name,
-                                       eir_data.services, eir_data.flags);
-
-       free_eir_data(&eir_data);
-}
-
 static void update_lastseen(bdaddr_t *sba, bdaddr_t *dba)
 {
        time_t t;
@@ -429,21 +246,12 @@ static void update_lastused(bdaddr_t *sba, bdaddr_t *dba)
        write_lastused_info(sba, dba, tm);
 }
 
-void btd_event_device_found(bdaddr_t *local, bdaddr_t *peer, uint32_t class,
-                               int8_t rssi, uint8_t *data)
+void btd_event_device_found(bdaddr_t *local, bdaddr_t *peer, addr_type_t type,
+                                       uint32_t class, int8_t rssi,
+                                       uint8_t confirm_name, uint8_t *data,
+                                       uint8_t data_len)
 {
-       char filename[PATH_MAX + 1];
        struct btd_adapter *adapter;
-       char local_addr[18], peer_addr[18], *alias, *name;
-       name_status_t name_status;
-       struct eir_data eir_data;
-       int state, err;
-       dbus_bool_t legacy;
-       unsigned char features[8];
-       const char *dev_name;
-
-       ba2str(local, local_addr);
-       ba2str(peer, peer_addr);
 
        adapter = manager_find_adapter(local);
        if (!adapter) {
@@ -457,73 +265,15 @@ void btd_event_device_found(bdaddr_t *local, bdaddr_t *peer, uint32_t class,
        if (data)
                write_remote_eir(local, peer, data);
 
-       /*
-        * Workaround to identify periodic inquiry: inquiry complete event is
-        * sent after each window, however there isn't an event to indicate the
-        * beginning of a new periodic inquiry window.
-        */
-       state = adapter_get_state(adapter);
-       if (!(state & (STATE_STDINQ | STATE_LE_SCAN | STATE_PINQ))) {
-               state |= STATE_PINQ;
-               adapter_set_state(adapter, state);
-       }
-
-       /* the inquiry result can be triggered by NON D-Bus client */
-       if (adapter_get_discover_type(adapter) & DISC_RESOLVNAME &&
-                               adapter_has_discov_sessions(adapter))
-               name_status = NAME_REQUIRED;
-       else
-               name_status = NAME_NOT_REQUIRED;
-
-       create_name(filename, PATH_MAX, STORAGEDIR, local_addr, "aliases");
-       alias = textfile_get(filename, peer_addr);
-
-       create_name(filename, PATH_MAX, STORAGEDIR, local_addr, "names");
-       name = textfile_get(filename, peer_addr);
-
-       if (data)
-               legacy = FALSE;
-       else if (name == NULL)
-               legacy = TRUE;
-       else if (read_remote_features(local, peer, NULL, features) == 0) {
-               if (features[0] & 0x01)
-                       legacy = FALSE;
-               else
-                       legacy = TRUE;
-       } else
-               legacy = TRUE;
-
-       memset(&eir_data, 0, sizeof(eir_data));
-       err = parse_eir_data(&eir_data, data, EIR_DATA_LENGTH);
-       if (err < 0)
-               error("Error parsing EIR data: %s (%d)", strerror(-err), -err);
-
-       /* Complete EIR names are always used. Shortened EIR names are only
-        * used if there is no name already in storage. */
-       dev_name = name;
-       if (eir_data.name != NULL) {
-               if (eir_data.name_complete) {
-                       write_device_name(local, peer, eir_data.name);
-                       name_status = NAME_NOT_REQUIRED;
-                       dev_name = eir_data.name;
-               } else if (name == NULL)
-                       dev_name = eir_data.name;
-       }
-
-       adapter_update_found_devices(adapter, peer, rssi, class, dev_name,
-                                       alias, legacy, eir_data.services,
-                                       name_status);
-
-       free_eir_data(&eir_data);
-       free(name);
-       free(alias);
+       adapter_update_found_devices(adapter, peer, type, class, rssi,
+                                               confirm_name, data, data_len);
 }
 
 void btd_event_set_legacy_pairing(bdaddr_t *local, bdaddr_t *peer,
                                                        gboolean legacy)
 {
        struct btd_adapter *adapter;
-       struct remote_dev_info *dev, match;
+       struct remote_dev_info *dev;
 
        adapter = manager_find_adapter(local);
        if (!adapter) {
@@ -531,22 +281,16 @@ void btd_event_set_legacy_pairing(bdaddr_t *local, bdaddr_t *peer,
                return;
        }
 
-       memset(&match, 0, sizeof(struct remote_dev_info));
-       bacpy(&match.bdaddr, peer);
-       match.name_status = NAME_ANY;
-
-       dev = adapter_search_found_devices(adapter, &match);
+       dev = adapter_search_found_devices(adapter, peer);
        if (dev)
                dev->legacy = legacy;
 }
 
 void btd_event_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class)
 {
-       uint32_t old_class = 0;
        struct btd_adapter *adapter;
        struct btd_device *device;
-       const gchar *dev_path;
-       DBusConnection *conn = get_dbus_connection();
+       uint32_t old_class = 0;
 
        read_remote_class(local, peer, &old_class);
 
@@ -561,45 +305,36 @@ void btd_event_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class)
        if (!device)
                return;
 
-       dev_path = device_get_path(device);
-
-       emit_property_changed(conn, dev_path, DEVICE_INTERFACE, "Class",
-                               DBUS_TYPE_UINT32, &class);
+       device_set_class(device, class);
 }
 
-void btd_event_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status,
-                               char *name)
+void btd_event_remote_name(bdaddr_t *local, bdaddr_t *peer, char *name)
 {
        struct btd_adapter *adapter;
-       char srcaddr[18], dstaddr[18];
-       int state;
+       char srcaddr[18];
        struct btd_device *device;
-       struct remote_dev_info match, *dev_info;
-
-       if (status == 0) {
-               char *end;
+       struct remote_dev_info *dev_info;
 
-               /* It's ok to cast end between const and non-const since
-                * we know it points to inside of name which is non-const */
-               if (!g_utf8_validate(name, -1, (const char **) &end))
-                       *end = '\0';
+       if (!g_utf8_validate(name, -1, NULL)) {
+               int i;
 
-               write_device_name(local, peer, name);
+               /* Assume ASCII, and replace all non-ASCII with spaces */
+               for (i = 0; name[i] != '\0'; i++) {
+                       if (!isascii(name[i]))
+                               name[i] = ' ';
+               }
+               /* Remove leading and trailing whitespace characters */
+               g_strstrip(name);
        }
 
+       write_device_name(local, peer, name);
+
        if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE))
                return;
 
        ba2str(local, srcaddr);
-       ba2str(peer, dstaddr);
-
-       if (status != 0)
-               goto proceed;
-
-       bacpy(&match.bdaddr, peer);
-       match.name_status = NAME_ANY;
 
-       dev_info = adapter_search_found_devices(adapter, &match);
+       dev_info = adapter_search_found_devices(adapter, peer);
        if (dev_info) {
                g_free(dev_info->name);
                dev_info->name = g_strdup(name);
@@ -608,18 +343,6 @@ void btd_event_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status,
 
        if (device)
                device_set_name(device, name);
-
-proceed:
-       /* remove from remote name request list */
-       adapter_remove_found_device(adapter, peer);
-
-       /* check if there is more devices to request names */
-       if (adapter_resolve_names(adapter) == 0)
-               return;
-
-       state = adapter_get_state(adapter);
-       state &= ~STATE_RESOLVNAME;
-       adapter_set_state(adapter, state);
 }
 
 int btd_event_link_key_notify(bdaddr_t *local, bdaddr_t *peer,
@@ -637,8 +360,12 @@ int btd_event_link_key_notify(bdaddr_t *local, bdaddr_t *peer,
 
        ret = write_link_key(local, peer, key, key_type, pin_length);
 
-       if (ret == 0 && device_is_temporary(device))
-               device_set_temporary(device, FALSE);
+       if (ret == 0) {
+               device_set_bonded(device, TRUE);
+
+               if (device_is_temporary(device))
+                       device_set_temporary(device, FALSE);
+       }
 
        return ret;
 }
@@ -670,6 +397,9 @@ void btd_event_conn_failed(bdaddr_t *local, bdaddr_t *peer, uint8_t status)
        if (!device)
                return;
 
+       if (device_is_bonding(device, NULL))
+               device_cancel_bonding(device, status);
+
        if (device_is_temporary(device))
                adapter_remove_device(conn, adapter, device, TRUE);
 }
@@ -690,35 +420,34 @@ void btd_event_disconn_complete(bdaddr_t *local, bdaddr_t *peer)
        adapter_remove_connection(adapter, device);
 }
 
-/* Section reserved to device HCI callbacks */
-
-void btd_event_le_set_scan_enable_complete(bdaddr_t *local, uint8_t status)
+void btd_event_device_blocked(bdaddr_t *local, bdaddr_t *peer)
 {
        struct btd_adapter *adapter;
-       int state;
+       struct btd_device *device;
 
-       adapter = manager_find_adapter(local);
-       if (!adapter) {
-               error("No matching adapter found");
-               return;
-       }
+       DBusConnection *conn = get_dbus_connection();
 
-       if (status) {
-               error("Can't enable/disable LE scan");
+       if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE))
                return;
-       }
 
-       state = adapter_get_state(adapter);
+       device_block(conn, device, TRUE);
+}
 
-       /* Enabling or disabling ? */
-       if (state & STATE_LE_SCAN)
-               state &= ~STATE_LE_SCAN;
-       else
-               state |= STATE_LE_SCAN;
+void btd_event_device_unblocked(bdaddr_t *local, bdaddr_t *peer)
+{
+       struct btd_adapter *adapter;
+       struct btd_device *device;
 
-       adapter_set_state(adapter, state);
+       DBusConnection *conn = get_dbus_connection();
+
+       if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE))
+               return;
+
+       device_unblock(conn, device, FALSE, TRUE);
 }
 
+/* Section reserved to device HCI callbacks */
+
 void btd_event_returned_link_key(bdaddr_t *local, bdaddr_t *peer)
 {
        struct btd_adapter *adapter;
index 765390a..708eeb9 100644 (file)
  *
  */
 
-int btd_event_request_pin(bdaddr_t *sba, bdaddr_t *dba);
-void btd_event_advertising_report(bdaddr_t *local, le_advertising_info *info);
-void btd_event_device_found(bdaddr_t *local, bdaddr_t *peer, uint32_t class,
-                                               int8_t rssi, uint8_t *data);
+int btd_event_request_pin(bdaddr_t *sba, bdaddr_t *dba, gboolean secure);
+void btd_event_device_found(bdaddr_t *local, bdaddr_t *peer, addr_type_t type,
+                               uint32_t cls, int8_t rssi, uint8_t confirm_name,
+                               uint8_t *data, uint8_t data_len);
 void btd_event_set_legacy_pairing(bdaddr_t *local, bdaddr_t *peer, gboolean legacy);
 void btd_event_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class);
-void btd_event_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status, char *name);
+void btd_event_remote_name(bdaddr_t *local, bdaddr_t *peer, char *name);
 void btd_event_conn_complete(bdaddr_t *local, bdaddr_t *peer);
 void btd_event_conn_failed(bdaddr_t *local, bdaddr_t *peer, uint8_t status);
 void btd_event_disconn_complete(bdaddr_t *local, bdaddr_t *peer);
-void btd_event_bonding_complete(bdaddr_t *local, bdaddr_t *peer,
-                                                       uint8_t status);
 void btd_event_simple_pairing_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t status);
-void btd_event_le_set_scan_enable_complete(bdaddr_t *local, uint8_t status);
 void btd_event_returned_link_key(bdaddr_t *local, bdaddr_t *peer);
 int btd_event_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey);
 int btd_event_user_passkey(bdaddr_t *sba, bdaddr_t *dba);
 int btd_event_user_notify(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey);
+void btd_event_device_blocked(bdaddr_t *local, bdaddr_t *peer);
+void btd_event_device_unblocked(bdaddr_t *local, bdaddr_t *peer);
 int btd_event_link_key_notify(bdaddr_t *local, bdaddr_t *peer, uint8_t *key,
                                        uint8_t key_type, uint8_t pin_length);
diff --git a/src/glib-compat.h b/src/glib-compat.h
new file mode 100644 (file)
index 0000000..d50d5e9
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef NEED_G_SLIST_FREE_FULL
+static inline void g_slist_free_full(GSList *list, GDestroyNotify free_func)
+{
+       g_slist_foreach(list, (GFunc) free_func, NULL);
+       g_slist_free(list);
+}
+#endif
index 22c14e7..8189a09 100644 (file)
@@ -27,9 +27,6 @@
 
 #include <stdlib.h>
 #include <errno.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
 #include <glib.h>
 
 #include "btio.h"
-#include "sdpd.h"
+#include "glib-compat.h"
 #include "glib-helper.h"
 
-/* Number of seconds to keep a sdp_session_t in the cache */
-#define CACHE_TIMEOUT 2
-
-struct cached_sdp_session {
-       bdaddr_t src;
-       bdaddr_t dst;
-       sdp_session_t *session;
-       guint timer;
-};
-
-static GSList *cached_sdp_sessions = NULL;
-
-static gboolean cached_session_expired(gpointer user_data)
-{
-       struct cached_sdp_session *cached = user_data;
-
-       cached_sdp_sessions = g_slist_remove(cached_sdp_sessions, cached);
-
-       sdp_close(cached->session);
-
-       g_free(cached);
-
-       return FALSE;
-}
-
-static sdp_session_t *get_sdp_session(const bdaddr_t *src, const bdaddr_t *dst)
-{
-       GSList *l;
-
-       for (l = cached_sdp_sessions; l != NULL; l = l->next) {
-               struct cached_sdp_session *c = l->data;
-               sdp_session_t *session;
-
-               if (bacmp(&c->src, src) || bacmp(&c->dst, dst))
-                       continue;
-
-               g_source_remove(c->timer);
-
-               session = c->session;
-
-               cached_sdp_sessions = g_slist_remove(cached_sdp_sessions, c);
-               g_free(c);
-
-               return session;
-       }
-
-       return sdp_connect(src, dst, SDP_NON_BLOCKING);
-}
-
-static void cache_sdp_session(bdaddr_t *src, bdaddr_t *dst,
-                                               sdp_session_t *session)
-{
-       struct cached_sdp_session *cached;
-
-       cached = g_new0(struct cached_sdp_session, 1);
-
-       bacpy(&cached->src, src);
-       bacpy(&cached->dst, dst);
-
-       cached->session = session;
-
-       cached_sdp_sessions = g_slist_append(cached_sdp_sessions, cached);
-
-       cached->timer = g_timeout_add_seconds(CACHE_TIMEOUT,
-                                               cached_session_expired,
-                                               cached);
-}
-
-struct search_context {
-       bdaddr_t                src;
-       bdaddr_t                dst;
-       sdp_session_t           *session;
-       bt_callback_t           cb;
-       bt_destroy_t            destroy;
-       gpointer                user_data;
-       uuid_t                  uuid;
-       guint                   io_id;
-};
-
-static GSList *context_list = NULL;
-
-static void search_context_cleanup(struct search_context *ctxt)
-{
-       context_list = g_slist_remove(context_list, ctxt);
-
-       if (ctxt->destroy)
-               ctxt->destroy(ctxt->user_data);
-
-       g_free(ctxt);
-}
-
-static void search_completed_cb(uint8_t type, uint16_t status,
-                       uint8_t *rsp, size_t size, void *user_data)
-{
-       struct search_context *ctxt = user_data;
-       sdp_list_t *recs = NULL;
-       int scanned, seqlen = 0, bytesleft = size;
-       uint8_t dataType;
-       int err = 0;
-
-       if (status || type != SDP_SVC_SEARCH_ATTR_RSP) {
-               err = -EPROTO;
-               goto done;
-       }
-
-       scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen);
-       if (!scanned || !seqlen)
-               goto done;
-
-       rsp += scanned;
-       bytesleft -= scanned;
-       do {
-               sdp_record_t *rec;
-               int recsize;
-
-               recsize = 0;
-               rec = sdp_extract_pdu(rsp, bytesleft, &recsize);
-               if (!rec)
-                       break;
-
-               if (!recsize) {
-                       sdp_record_free(rec);
-                       break;
-               }
-
-               scanned += recsize;
-               rsp += recsize;
-               bytesleft -= recsize;
-
-               recs = sdp_list_append(recs, rec);
-       } while (scanned < (ssize_t) size && bytesleft > 0);
-
-done:
-       cache_sdp_session(&ctxt->src, &ctxt->dst, ctxt->session);
-
-       if (ctxt->cb)
-               ctxt->cb(recs, err, ctxt->user_data);
-
-       if (recs)
-               sdp_list_free(recs, (sdp_free_func_t) sdp_record_free);
-
-       search_context_cleanup(ctxt);
-}
-
-static gboolean search_process_cb(GIOChannel *chan, GIOCondition cond,
-                                                       gpointer user_data)
-{
-       struct search_context *ctxt = user_data;
-       int err = 0;
-
-       if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
-               err = EIO;
-               goto failed;
-       }
-
-       if (sdp_process(ctxt->session) < 0)
-               goto failed;
-
-       return TRUE;
-
-failed:
-       if (err) {
-               sdp_close(ctxt->session);
-               ctxt->session = NULL;
-
-               if (ctxt->cb)
-                       ctxt->cb(NULL, err, ctxt->user_data);
-
-               search_context_cleanup(ctxt);
-       }
-
-       return FALSE;
-}
-
-static gboolean connect_watch(GIOChannel *chan, GIOCondition cond,
-                                                       gpointer user_data)
-{
-       struct search_context *ctxt = user_data;
-       sdp_list_t *search, *attrids;
-       uint32_t range = 0x0000ffff;
-       socklen_t len;
-       int sk, err = 0;
-
-       sk = g_io_channel_unix_get_fd(chan);
-       ctxt->io_id = 0;
-
-       len = sizeof(err);
-       if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
-               err = errno;
-               goto failed;
-       }
-
-       if (err != 0)
-               goto failed;
-
-       if (sdp_set_notify(ctxt->session, search_completed_cb, ctxt) < 0) {
-               err = EIO;
-               goto failed;
-       }
-
-       search = sdp_list_append(NULL, &ctxt->uuid);
-       attrids = sdp_list_append(NULL, &range);
-       if (sdp_service_search_attr_async(ctxt->session,
-                               search, SDP_ATTR_REQ_RANGE, attrids) < 0) {
-               sdp_list_free(attrids, NULL);
-               sdp_list_free(search, NULL);
-               err = EIO;
-               goto failed;
-       }
-
-       sdp_list_free(attrids, NULL);
-       sdp_list_free(search, NULL);
-
-       /* Set callback responsible for update the internal SDP transaction */
-       ctxt->io_id = g_io_add_watch(chan,
-                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                               search_process_cb, ctxt);
-       return FALSE;
-
-failed:
-       sdp_close(ctxt->session);
-       ctxt->session = NULL;
-
-       if (ctxt->cb)
-               ctxt->cb(NULL, -err, ctxt->user_data);
-
-       search_context_cleanup(ctxt);
-
-       return FALSE;
-}
-
-static int create_search_context(struct search_context **ctxt,
-                                       const bdaddr_t *src,
-                                       const bdaddr_t *dst,
-                                       uuid_t *uuid)
-{
-       sdp_session_t *s;
-       GIOChannel *chan;
-
-       if (!ctxt)
-               return -EINVAL;
-
-       s = get_sdp_session(src, dst);
-       if (!s)
-               return -errno;
-
-       *ctxt = g_try_malloc0(sizeof(struct search_context));
-       if (!*ctxt) {
-               sdp_close(s);
-               return -ENOMEM;
-       }
-
-       bacpy(&(*ctxt)->src, src);
-       bacpy(&(*ctxt)->dst, dst);
-       (*ctxt)->session = s;
-       (*ctxt)->uuid = *uuid;
-
-       chan = g_io_channel_unix_new(sdp_get_socket(s));
-       (*ctxt)->io_id = g_io_add_watch(chan,
-                               G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                               connect_watch, *ctxt);
-       g_io_channel_unref(chan);
-
-       return 0;
-}
-
-int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst,
-                       uuid_t *uuid, bt_callback_t cb, void *user_data,
-                       bt_destroy_t destroy)
-{
-       struct search_context *ctxt = NULL;
-       int err;
-
-       if (!cb)
-               return -EINVAL;
-
-       err = create_search_context(&ctxt, src, dst, uuid);
-       if (err < 0)
-               return err;
-
-       ctxt->cb        = cb;
-       ctxt->destroy   = destroy;
-       ctxt->user_data = user_data;
-
-       context_list = g_slist_append(context_list, ctxt);
-
-       return 0;
-}
-
-static gint find_by_bdaddr(gconstpointer data, gconstpointer user_data)
-{
-       const struct search_context *ctxt = data, *search = user_data;
-
-       return (bacmp(&ctxt->dst, &search->dst) &&
-                                       bacmp(&ctxt->src, &search->src));
-}
-
-int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst)
-{
-       struct search_context match, *ctxt;
-       GSList *l;
-
-       memset(&match, 0, sizeof(match));
-       bacpy(&match.src, src);
-       bacpy(&match.dst, dst);
-
-       /* Ongoing SDP Discovery */
-       l = g_slist_find_custom(context_list, &match, find_by_bdaddr);
-       if (l == NULL)
-               return -ENOENT;
-
-       ctxt = l->data;
-
-       if (!ctxt->session)
-               return -ENOTCONN;
-
-       if (ctxt->io_id)
-               g_source_remove(ctxt->io_id);
-
-       if (ctxt->session)
-               sdp_close(ctxt->session);
-
-       search_context_cleanup(ctxt);
-
-       return 0;
-}
-
 char *bt_uuid2string(uuid_t *uuid)
 {
        gchar *str;
index 510d61a..8836804 100644 (file)
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
-#include <bluetooth/bluetooth.h>
-typedef void (*bt_callback_t) (sdp_list_t *recs, int err, gpointer user_data);
-typedef void (*bt_destroy_t) (gpointer user_data);
-
-int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst,
-                       uuid_t *uuid, bt_callback_t cb, void *user_data,
-                       bt_destroy_t destroy);
-int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst);
 
 gchar *bt_uuid2string(uuid_t *uuid);
 char *bt_name2string(const char *string);
 int bt_string2uuid(uuid_t *uuid, const char *string);
 gchar *bt_list2string(GSList *list);
 GSList *bt_string2list(const gchar *str);
-
-#ifdef NEED_G_SLIST_FREE_FULL
-static inline void g_slist_free_full(GSList *list, GDestroyNotify free_func)
-{
-       g_slist_foreach(list, (GFunc) free_func, NULL);
-       g_slist_free(list);
-}
-#endif
index e3064d8..1987b7d 100644 (file)
  *
  */
 
-#define HCID_DEFAULT_DISCOVERABLE_TIMEOUT 180 /* 3 minutes */
-
-/* Timeout for hci_send_req (milliseconds) */
-#define HCI_REQ_TIMEOUT                5000
 struct main_opts {
        char            host_name[40];
        unsigned long   flags;
        char            *name;
        uint32_t        class;
        uint16_t        pageto;
+       uint16_t        autoto;
        uint32_t        discovto;
        uint32_t        pairto;
        uint16_t        link_mode;
@@ -42,9 +39,7 @@ struct main_opts {
        gboolean        name_resolv;
        gboolean        debug_keys;
        gboolean        attrib_server;
-       gboolean        le;
 
-       uint8_t         scan;
        uint8_t         mode;
        uint8_t         discov_interval;
        char            deviceid[15]; /* FIXME: */
index 4ec4633..4a50117 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -78,19 +78,29 @@ static gboolean is_enabled(struct btd_debug_desc *desc)
        if (enabled == NULL)
                return 0;
 
-       for (i = 0; enabled[i] != NULL; i++) {
-               if (desc->name != NULL && g_pattern_match_simple(enabled[i],
-                                                       desc->name) == TRUE)
-                       return 1;
+       for (i = 0; enabled[i] != NULL; i++)
                if (desc->file != NULL && g_pattern_match_simple(enabled[i],
                                                        desc->file) == TRUE)
                        return 1;
-       }
 
        return 0;
 }
 
-void __btd_toggle_debug()
+void __btd_enable_debug(struct btd_debug_desc *start,
+                                       struct btd_debug_desc *stop)
+{
+       struct btd_debug_desc *desc;
+
+       if (start == NULL || stop == NULL)
+               return;
+
+       for (desc = start; desc < stop; desc++) {
+               if (is_enabled(desc))
+                       desc->flags |= BTD_DEBUG_FLAG_PRINT;
+       }
+}
+
+void __btd_toggle_debug(void)
 {
        struct btd_debug_desc *desc;
 
@@ -101,31 +111,18 @@ void __btd_toggle_debug()
 void __btd_log_init(const char *debug, int detach)
 {
        int option = LOG_NDELAY | LOG_PID;
-       struct btd_debug_desc *desc;
-       const char *name = NULL, *file = NULL;
 
        if (debug != NULL)
                enabled = g_strsplit_set(debug, ":, ", 0);
 
-       for (desc = __start___debug; desc < __stop___debug; desc++) {
-               if (file != NULL || name != NULL) {
-                       if (g_strcmp0(desc->file, file) == 0) {
-                               if (desc->name == NULL)
-                                       desc->name = name;
-                       } else
-                               file = NULL;
-               }
-
-               if (is_enabled(desc))
-                       desc->flags |= BTD_DEBUG_FLAG_PRINT;
-       }
+       __btd_enable_debug(__start___debug, __stop___debug);
 
        if (!detach)
                option |= LOG_PERROR;
 
        openlog("bluetoothd", option, LOG_DAEMON);
 
-       syslog(LOG_INFO, "Bluetooth deamon %s", VERSION);
+       syslog(LOG_INFO, "Bluetooth daemon %s", VERSION);
 }
 
 void __btd_log_cleanup(void)
index cc45cbf..b43b2b7 100644 (file)
--- a/src/log.h
+++ b/src/log.h
@@ -28,16 +28,18 @@ void btd_debug(const char *format, ...) __attribute__((format(printf, 1, 2)));
 
 void __btd_log_init(const char *debug, int detach);
 void __btd_log_cleanup(void);
-void __btd_toggle_debug();
+void __btd_toggle_debug(void);
 
 struct btd_debug_desc {
-       const char *name;
        const char *file;
 #define BTD_DEBUG_FLAG_DEFAULT (0)
 #define BTD_DEBUG_FLAG_PRINT   (1 << 0)
        unsigned int flags;
 } __attribute__((aligned(8)));
 
+void __btd_enable_debug(struct btd_debug_desc *start,
+                                       struct btd_debug_desc *stop);
+
 /**
  * DBG:
  * @fmt: format string
index 9a890ad..86881eb 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <signal.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
+#include <sys/signalfd.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/uuid.h>
@@ -51,9 +50,7 @@
 
 #include "hcid.h"
 #include "sdpd.h"
-#include "attrib-server.h"
 #include "adapter.h"
-#include "event.h"
 #include "dbus-common.h"
 #include "agent.h"
 #include "manager.h"
 #ifdef HAVE_CAPNG
 #include <cap-ng.h>
 #endif
-#include <bluetooth/sdp_lib.h>
+
 #define BLUEZ_NAME "org.bluez"
 
 #define LAST_ADAPTER_EXIT_TIMEOUT 30
 
 #define DEFAULT_DISCOVERABLE_TIMEOUT 180 /* 3 minutes */
+#define DEFAULT_AUTO_CONNECT_TIMEOUT  60 /* 60 seconds */
 
 struct main_opts main_opts;
-sdp_session_t *g_cached_session = NULL;
 
 static GKeyFile *load_config(const char *file)
 {
@@ -133,6 +130,16 @@ static void parse_config(GKeyFile *config)
                main_opts.flags |= 1 << HCID_SET_PAGETO;
        }
 
+       val = g_key_file_get_integer(config, "General", "AutoConnectTimeout",
+                                                                       &err);
+       if (err) {
+               DBG("%s", err->message);
+               g_clear_error(&err);
+       } else {
+               DBG("auto_to=%d", val);
+               main_opts.autoto = val;
+       }
+
        str = g_key_file_get_string(config, "General", "Name", &err);
        if (err) {
                DBG("%s", err->message);
@@ -222,13 +229,6 @@ static void parse_config(GKeyFile *config)
        else
                main_opts.attrib_server = boolean;
 
-       boolean = g_key_file_get_boolean(config, "General",
-                                               "EnableLE", &err);
-       if (err)
-               g_clear_error(&err);
-       else
-               main_opts.le = boolean;
-
        main_opts.link_mode = HCI_LM_ACCEPT;
 
        main_opts.link_policy = HCI_LP_RSWITCH | HCI_LP_SNIFF |
@@ -239,14 +239,14 @@ static void init_defaults(void)
 {
        /* Default HCId settings */
        memset(&main_opts, 0, sizeof(main_opts));
-       main_opts.scan  = SCAN_PAGE;
-#ifdef __TIZEN_PATCH__
+#ifdef __SAMSUNG_PATCH__
        main_opts.mode  = MODE_DISCOVERABLE;
 #else
        main_opts.mode  = MODE_CONNECTABLE;
 #endif
        main_opts.name  = g_strdup("BlueZ");
        main_opts.discovto      = DEFAULT_DISCOVERABLE_TIMEOUT;
+       main_opts.autoto = DEFAULT_AUTO_CONNECT_TIMEOUT;
        main_opts.remember_powered = TRUE;
        main_opts.reverse_sdp = TRUE;
        main_opts.name_resolv = TRUE;
@@ -257,14 +257,82 @@ static void init_defaults(void)
 
 static GMainLoop *event_loop;
 
-static void sig_term(int sig)
+static unsigned int __terminated = 0;
+
+static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
+                                                       gpointer user_data)
 {
-       g_main_loop_quit(event_loop);
+       struct signalfd_siginfo si;
+       ssize_t result;
+       int fd;
+
+       if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
+               return FALSE;
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       result = read(fd, &si, sizeof(si));
+       if (result != sizeof(si))
+               return FALSE;
+
+       switch (si.ssi_signo) {
+       case SIGINT:
+       case SIGTERM:
+               if (__terminated == 0) {
+                       info("Terminating");
+                       g_main_loop_quit(event_loop);
+               }
+
+               __terminated = 1;
+               break;
+       case SIGUSR2:
+               __btd_toggle_debug();
+               break;
+       case SIGPIPE:
+               /* ignore */
+               break;
+       }
+
+       return TRUE;
 }
 
-static void sig_debug(int sig)
+static guint setup_signalfd(void)
 {
-       __btd_toggle_debug();
+       GIOChannel *channel;
+       guint source;
+       sigset_t mask;
+       int fd;
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+       sigaddset(&mask, SIGTERM);
+       sigaddset(&mask, SIGUSR2);
+       sigaddset(&mask, SIGPIPE);
+
+       if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+               perror("Failed to set signal mask");
+               return 0;
+       }
+
+       fd = signalfd(-1, &mask, 0);
+       if (fd < 0) {
+               perror("Failed to create signal descriptor");
+               return 0;
+       }
+
+       channel = g_io_channel_unix_new(fd);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               signal_handler, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
 }
 
 static gchar *option_debug = NULL;
@@ -328,6 +396,7 @@ static int connect_dbus(void)
        conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, BLUEZ_NAME, &err);
        if (!conn) {
                if (dbus_error_is_set(&err)) {
+                       g_printerr("D-Bus setup failed: %s\n", err.message);
                        dbus_error_free(&err);
                        return -EIO;
                }
@@ -375,10 +444,9 @@ int main(int argc, char *argv[])
 {
        GOptionContext *context;
        GError *err = NULL;
-       struct sigaction sa;
        uint16_t mtu = 0;
        GKeyFile *config;
-       info("(info)Bluetoothd main starting .......\n");
+       guint signal;
 
        init_defaults();
 
@@ -431,19 +499,11 @@ int main(int argc, char *argv[])
 
        umask(0077);
 
-       __btd_log_init(option_debug, option_detach);
-
-       memset(&sa, 0, sizeof(sa));
-       sa.sa_flags = SA_NOCLDSTOP;
-       sa.sa_handler = sig_term;
-       sigaction(SIGTERM, &sa, NULL);
-       sigaction(SIGINT,  &sa, NULL);
+       event_loop = g_main_loop_new(NULL, FALSE);
 
-       sa.sa_handler = sig_debug;
-       sigaction(SIGUSR2, &sa, NULL);
+       signal = setup_signalfd();
 
-       sa.sa_handler = SIG_IGN;
-       sigaction(SIGPIPE, &sa, NULL);
+       __btd_log_init(option_debug, option_detach);
 
        config = load_config(CONFIGDIR "/main.conf");
 
@@ -465,19 +525,12 @@ int main(int argc, char *argv[])
 
        start_sdp_server(mtu, main_opts.deviceid, SDP_SERVER_COMPAT);
 
-       if (main_opts.attrib_server) {
-               if (attrib_server_init() < 0)
-                       error("Can't initialize attribute server");
-       }
-
        /* 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
         * daemon needs to be re-worked. */
        plugin_init(config, option_plugin, option_noplugin);
 
-       event_loop = g_main_loop_new(NULL, FALSE);
-
        if (adapter_ops_setup() < 0) {
                error("adapter_ops_setup failed");
                exit(1);
@@ -489,15 +542,14 @@ int main(int argc, char *argv[])
 
        g_main_loop_run(event_loop);
 
+       g_source_remove(signal);
+
        disconnect_dbus();
 
        rfkill_exit();
 
        plugin_cleanup();
 
-       if (main_opts.attrib_server)
-               attrib_server_exit();
-
        stop_sdp_server();
 
        agent_exit();
index 9f472a0..00788c9 100644 (file)
@@ -10,8 +10,11 @@ Name = %h-%d
 
 # Default device class. Only the major and minor device class bits are
 # considered.
-#Class = 0x000100      # Computer
-Class = 0x5A020C       # Smart phone
+#ifdef __SAMSUNG_PATCH__
+Class = 0x00020C        # Smart phone
+#else
+#Class = 0x000100
+#endif
 
 # 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.
@@ -28,8 +31,14 @@ PairableTimeout = 0
 PageTimeout = 8192
 
 # Discover scheduler interval used in Adapter.DiscoverDevices
-# The value is in seconds. Defaults is 0 to use controller scheduler.
-DiscoverSchedulerInterval = 0
+# The value is in seconds. Defaults is 30.
+DiscoverSchedulerInterval = 30
+
+# 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.
+AutoConnectTimeout = 60
 
 # What value should be assumed for the adapter Powered property when
 # SetProperty(Powered, ...) hasn't been called yet. Defaults to true
@@ -57,11 +66,6 @@ NameResolving = true
 # that they were created for.
 DebugKeys = false
 
-# Enable Low Energy support if the dongle supports. Default is false.
-# Enable/Disable interleave discovery and attribute server over LE.
-EnableLE = false
-
 # Enable the GATT Attribute Server. Default is false, because it is only
-# useful for testing. Attribute server is not enabled over LE if EnableLE
-# is false.
+# useful for testing.
 AttributeServer = false
index e805e0c..1d44c66 100644 (file)
@@ -34,6 +34,8 @@
 #include <sys/socket.h>
 
 #include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
 
 #include <glib.h>
 
@@ -41,6 +43,7 @@
 
 #include <gdbus.h>
 
+#include "glib-helper.h"
 #include "hcid.h"
 #include "dbus-common.h"
 #include "log.h"
@@ -262,6 +265,11 @@ static void manager_set_default_adapter(int id)
                        DBUS_TYPE_INVALID);
 }
 
+struct btd_adapter *manager_get_default_adapter(void)
+{
+       return manager_find_adapter_by_id(default_adapter_id);
+}
+
 static void manager_remove_adapter(struct btd_adapter *adapter)
 {
        uint16_t dev_id = adapter_get_dev_id(adapter);
@@ -283,6 +291,7 @@ static void manager_remove_adapter(struct btd_adapter *adapter)
                        DBUS_TYPE_INVALID);
 
        adapter_remove(adapter);
+       btd_adapter_unref(adapter);
 
        if (adapters == NULL)
                btd_start_exit_timer();
@@ -290,8 +299,15 @@ static void manager_remove_adapter(struct btd_adapter *adapter)
 
 void manager_cleanup(DBusConnection *conn, const char *path)
 {
-       g_slist_foreach(adapters, (GFunc) manager_remove_adapter, NULL);
-       g_slist_free(adapters);
+       while (adapters) {
+               struct btd_adapter *adapter = adapters->data;
+
+               adapters = g_slist_remove(adapters, adapter);
+               adapter_remove(adapter);
+               btd_adapter_unref(adapter);
+       }
+
+       btd_start_exit_timer();
 
        g_dbus_unregister_interface(conn, "/", MANAGER_INTERFACE);
 }
@@ -379,6 +395,7 @@ struct btd_adapter *btd_manager_register_adapter(int id)
        adapters = g_slist_append(adapters, adapter);
 
        if (!adapter_init(adapter)) {
+               adapters = g_slist_remove(adapters, adapter);
                btd_adapter_unref(adapter);
                return NULL;
        }
index 05c38b3..4f92d2f 100644 (file)
@@ -35,6 +35,7 @@ void manager_cleanup(DBusConnection *conn, const char *path);
 const char *manager_get_base_path(void);
 struct btd_adapter *manager_find_adapter(const bdaddr_t *sba);
 struct btd_adapter *manager_find_adapter_by_id(int id);
+struct btd_adapter *manager_get_default_adapter(void);
 void manager_foreach_adapter(adapter_cb func, gpointer user_data);
 GSList *manager_get_adapters(void);
 struct btd_adapter *btd_manager_register_adapter(int id);
diff --git a/src/oob.c b/src/oob.c
new file mode 100644 (file)
index 0000000..75798fb
--- /dev/null
+++ b/src/oob.c
@@ -0,0 +1,41 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  ST-Ericsson SA
+ *
+ *  Author: Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include "adapter.h"
+#include "oob.h"
+
+static oob_read_cb_t local_oob_read_cb = NULL;
+
+void oob_register_cb(oob_read_cb_t cb)
+{
+       local_oob_read_cb = cb;
+}
+
+void oob_read_local_data_complete(struct btd_adapter *adapter, uint8_t *hash,
+                                                       uint8_t *randomizer)
+{
+       if (local_oob_read_cb)
+               local_oob_read_cb(adapter, hash, randomizer);
+}
diff --git a/src/oob.h b/src/oob.h
new file mode 100644 (file)
index 0000000..5805082
--- /dev/null
+++ b/src/oob.h
@@ -0,0 +1,32 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  ST-Ericsson SA
+ *
+ *  Author: Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson
+ *
+ *
+ *  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
+ *
+ */
+
+typedef void (*oob_read_cb_t) (struct btd_adapter *adapter, uint8_t *hash,
+                                                       uint8_t *randomizer);
+
+void oob_register_cb(oob_read_cb_t cb);
+
+void oob_read_local_data_complete(struct btd_adapter *adapter, uint8_t *hash,
+                                                       uint8_t *randomizer);
index 3506553..2a86e68 100644 (file)
@@ -77,6 +77,8 @@ static gboolean add_plugin(void *handle, struct bluetooth_plugin_desc *desc)
        plugin->active = FALSE;
        plugin->desc = desc;
 
+       __btd_enable_debug(desc->debug_start, desc->debug_stop);
+
        plugins = g_slist_insert_sorted(plugins, plugin, compare_priority);
 
        return TRUE;
index 30bd415..89c7b85 100644 (file)
@@ -30,6 +30,8 @@ struct bluetooth_plugin_desc {
        int priority;
        int (*init) (void);
        void (*exit) (void);
+       void *debug_start;
+       void *debug_stop;
 };
 
 #ifdef BLUETOOTH_PLUGIN_BUILTIN
@@ -39,9 +41,14 @@ struct bluetooth_plugin_desc {
                };
 #else
 #define BLUETOOTH_PLUGIN_DEFINE(name, version, priority, init, exit) \
+               extern struct btd_debug_desc __start___debug[] \
+                               __attribute__ ((weak, visibility("hidden"))); \
+               extern struct btd_debug_desc __stop___debug[] \
+                               __attribute__ ((weak, visibility("hidden"))); \
                extern struct bluetooth_plugin_desc bluetooth_plugin_desc \
                                __attribute__ ((visibility("default"))); \
                struct bluetooth_plugin_desc bluetooth_plugin_desc = { \
-                       #name, version, priority, init, exit \
+                       #name, version, priority, init, exit, \
+                       __start___debug, __stop___debug \
                };
 #endif
diff --git a/src/sdp-client.c b/src/sdp-client.c
new file mode 100644 (file)
index 0000000..f119313
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+
+#include "btio.h"
+#include "sdp-client.h"
+
+/* Number of seconds to keep a sdp_session_t in the cache */
+#define CACHE_TIMEOUT 2
+
+struct cached_sdp_session {
+       bdaddr_t src;
+       bdaddr_t dst;
+       sdp_session_t *session;
+       guint timer;
+};
+
+static GSList *cached_sdp_sessions = NULL;
+
+static gboolean cached_session_expired(gpointer user_data)
+{
+       struct cached_sdp_session *cached = user_data;
+
+       cached_sdp_sessions = g_slist_remove(cached_sdp_sessions, cached);
+
+       sdp_close(cached->session);
+
+       g_free(cached);
+
+       return FALSE;
+}
+
+static sdp_session_t *get_sdp_session(const bdaddr_t *src, const bdaddr_t *dst)
+{
+       GSList *l;
+
+       for (l = cached_sdp_sessions; l != NULL; l = l->next) {
+               struct cached_sdp_session *c = l->data;
+               sdp_session_t *session;
+
+               if (bacmp(&c->src, src) || bacmp(&c->dst, dst))
+                       continue;
+
+               g_source_remove(c->timer);
+
+               session = c->session;
+
+               cached_sdp_sessions = g_slist_remove(cached_sdp_sessions, c);
+               g_free(c);
+
+               return session;
+       }
+
+       return sdp_connect(src, dst, SDP_NON_BLOCKING);
+}
+
+static void cache_sdp_session(bdaddr_t *src, bdaddr_t *dst,
+                                               sdp_session_t *session)
+{
+       struct cached_sdp_session *cached;
+
+       cached = g_new0(struct cached_sdp_session, 1);
+
+       bacpy(&cached->src, src);
+       bacpy(&cached->dst, dst);
+
+       cached->session = session;
+
+       cached_sdp_sessions = g_slist_append(cached_sdp_sessions, cached);
+
+       cached->timer = g_timeout_add_seconds(CACHE_TIMEOUT,
+                                               cached_session_expired,
+                                               cached);
+}
+
+struct search_context {
+       bdaddr_t                src;
+       bdaddr_t                dst;
+       sdp_session_t           *session;
+       bt_callback_t           cb;
+       bt_destroy_t            destroy;
+       gpointer                user_data;
+       uuid_t                  uuid;
+       guint                   io_id;
+};
+
+static GSList *context_list = NULL;
+
+static void search_context_cleanup(struct search_context *ctxt)
+{
+       context_list = g_slist_remove(context_list, ctxt);
+
+       if (ctxt->destroy)
+               ctxt->destroy(ctxt->user_data);
+
+       g_free(ctxt);
+}
+
+static void search_completed_cb(uint8_t type, uint16_t status,
+                       uint8_t *rsp, size_t size, void *user_data)
+{
+       struct search_context *ctxt = user_data;
+       sdp_list_t *recs = NULL;
+       int scanned, seqlen = 0, bytesleft = size;
+       uint8_t dataType;
+       int err = 0;
+
+       if (status || type != SDP_SVC_SEARCH_ATTR_RSP) {
+               err = -EPROTO;
+               goto done;
+       }
+
+       scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen);
+       if (!scanned || !seqlen)
+               goto done;
+
+       rsp += scanned;
+       bytesleft -= scanned;
+       do {
+               sdp_record_t *rec;
+               int recsize;
+
+               recsize = 0;
+               rec = sdp_extract_pdu(rsp, bytesleft, &recsize);
+               if (!rec)
+                       break;
+
+               if (!recsize) {
+                       sdp_record_free(rec);
+                       break;
+               }
+
+               scanned += recsize;
+               rsp += recsize;
+               bytesleft -= recsize;
+
+               recs = sdp_list_append(recs, rec);
+       } while (scanned < (ssize_t) size && bytesleft > 0);
+
+done:
+       cache_sdp_session(&ctxt->src, &ctxt->dst, ctxt->session);
+
+       if (ctxt->cb)
+               ctxt->cb(recs, err, ctxt->user_data);
+
+       if (recs)
+               sdp_list_free(recs, (sdp_free_func_t) sdp_record_free);
+
+       search_context_cleanup(ctxt);
+}
+
+static gboolean search_process_cb(GIOChannel *chan, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct search_context *ctxt = user_data;
+       int err = 0;
+
+       if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
+               err = EIO;
+               goto failed;
+       }
+
+       if (sdp_process(ctxt->session) < 0)
+               goto failed;
+
+       return TRUE;
+
+failed:
+       if (err) {
+               sdp_close(ctxt->session);
+               ctxt->session = NULL;
+
+               if (ctxt->cb)
+                       ctxt->cb(NULL, err, ctxt->user_data);
+
+               search_context_cleanup(ctxt);
+       }
+
+       return FALSE;
+}
+
+static gboolean connect_watch(GIOChannel *chan, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct search_context *ctxt = user_data;
+       sdp_list_t *search, *attrids;
+       uint32_t range = 0x0000ffff;
+       socklen_t len;
+       int sk, err, sk_err = 0;
+
+       sk = g_io_channel_unix_get_fd(chan);
+       ctxt->io_id = 0;
+
+       len = sizeof(sk_err);
+       if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+               err = -errno;
+       else
+               err = -sk_err;
+
+       if (err != 0)
+               goto failed;
+
+       if (sdp_set_notify(ctxt->session, search_completed_cb, ctxt) < 0) {
+               err = -EIO;
+               goto failed;
+       }
+
+       search = sdp_list_append(NULL, &ctxt->uuid);
+       attrids = sdp_list_append(NULL, &range);
+       if (sdp_service_search_attr_async(ctxt->session,
+                               search, SDP_ATTR_REQ_RANGE, attrids) < 0) {
+               sdp_list_free(attrids, NULL);
+               sdp_list_free(search, NULL);
+               err = -EIO;
+               goto failed;
+       }
+
+       sdp_list_free(attrids, NULL);
+       sdp_list_free(search, NULL);
+
+       /* Set callback responsible for update the internal SDP transaction */
+       ctxt->io_id = g_io_add_watch(chan,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               search_process_cb, ctxt);
+       return FALSE;
+
+failed:
+       sdp_close(ctxt->session);
+       ctxt->session = NULL;
+
+       if (ctxt->cb)
+               ctxt->cb(NULL, err, ctxt->user_data);
+
+       search_context_cleanup(ctxt);
+
+       return FALSE;
+}
+
+static int create_search_context(struct search_context **ctxt,
+                                       const bdaddr_t *src,
+                                       const bdaddr_t *dst,
+                                       uuid_t *uuid)
+{
+       sdp_session_t *s;
+       GIOChannel *chan;
+
+       if (!ctxt)
+               return -EINVAL;
+
+       s = get_sdp_session(src, dst);
+       if (!s)
+               return -errno;
+
+       *ctxt = g_try_malloc0(sizeof(struct search_context));
+       if (!*ctxt) {
+               sdp_close(s);
+               return -ENOMEM;
+       }
+
+       bacpy(&(*ctxt)->src, src);
+       bacpy(&(*ctxt)->dst, dst);
+       (*ctxt)->session = s;
+       (*ctxt)->uuid = *uuid;
+
+       chan = g_io_channel_unix_new(sdp_get_socket(s));
+       (*ctxt)->io_id = g_io_add_watch(chan,
+                               G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               connect_watch, *ctxt);
+       g_io_channel_unref(chan);
+
+       return 0;
+}
+
+int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst,
+                       uuid_t *uuid, bt_callback_t cb, void *user_data,
+                       bt_destroy_t destroy)
+{
+       struct search_context *ctxt = NULL;
+       int err;
+
+       if (!cb)
+               return -EINVAL;
+
+       err = create_search_context(&ctxt, src, dst, uuid);
+       if (err < 0)
+               return err;
+
+       ctxt->cb        = cb;
+       ctxt->destroy   = destroy;
+       ctxt->user_data = user_data;
+
+       context_list = g_slist_append(context_list, ctxt);
+
+       return 0;
+}
+
+static gint find_by_bdaddr(gconstpointer data, gconstpointer user_data)
+{
+       const struct search_context *ctxt = data, *search = user_data;
+       int ret;
+
+       ret = bacmp(&ctxt->src, &search->src);
+       if (ret != 0)
+               return ret;
+
+       return bacmp(&ctxt->dst, &search->dst);
+}
+
+int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst)
+{
+       struct search_context match, *ctxt;
+       GSList *l;
+
+       memset(&match, 0, sizeof(match));
+       bacpy(&match.src, src);
+       bacpy(&match.dst, dst);
+
+       /* Ongoing SDP Discovery */
+       l = g_slist_find_custom(context_list, &match, find_by_bdaddr);
+       if (l == NULL)
+               return -ENOENT;
+
+       ctxt = l->data;
+
+       if (!ctxt->session)
+               return -ENOTCONN;
+
+       if (ctxt->io_id)
+               g_source_remove(ctxt->io_id);
+
+       if (ctxt->session)
+               sdp_close(ctxt->session);
+
+       search_context_cleanup(ctxt);
+
+       return 0;
+}
+
diff --git a/src/sdp-client.h b/src/sdp-client.h
new file mode 100644 (file)
index 0000000..13d9121
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *
+ *  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
+ *
+ */
+
+typedef void (*bt_callback_t) (sdp_list_t *recs, int err, gpointer user_data);
+typedef void (*bt_destroy_t) (gpointer user_data);
+
+int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst,
+                       uuid_t *uuid, bt_callback_t cb, void *user_data,
+                       bt_destroy_t destroy);
+int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst);
index 3aa9df0..d7b2aef 100644 (file)
@@ -47,7 +47,6 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
        int i, hex;
        char buf[STRBUFSIZE];
        char indent[MAXINDENT];
-       char next_indent[MAXINDENT];
 
        if (!value)
                return;
@@ -55,15 +54,10 @@ static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
        if (indent_level >= MAXINDENT)
                indent_level = MAXINDENT - 2;
 
-       for (i = 0; i < indent_level; i++) {
+       for (i = 0; i < indent_level; i++)
                indent[i] = '\t';
-               next_indent[i] = '\t';
-       }
 
        indent[i] = '\0';
-       next_indent[i] = '\t';
-       next_indent[i + 1] = '\0';
-
        buf[STRBUFSIZE - 1] = '\0';
 
        switch (value->dtd) {
@@ -704,7 +698,7 @@ sdp_data_t *sdp_xml_parse_nil(const char *data)
 
 #define DEFAULT_XML_DATA_SIZE 1024
 
-struct sdp_xml_data *sdp_xml_data_alloc()
+struct sdp_xml_data *sdp_xml_data_alloc(void)
 {
        struct sdp_xml_data *elem;
 
index 7031276..db7db30 100644 (file)
@@ -49,7 +49,7 @@ struct sdp_xml_data {
        /* TODO: What is it used for? */
 };
 
-struct sdp_xml_data *sdp_xml_data_alloc();
+struct sdp_xml_data *sdp_xml_data_alloc(void);
 void sdp_xml_data_free(struct sdp_xml_data *elem);
 struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem);
 
index 08f542f..dd492bf 100644 (file)
@@ -90,7 +90,7 @@ static void access_free(void *p)
 /*
  * Reset the service repository by deleting its contents
  */
-void sdp_svcdb_reset()
+void sdp_svcdb_reset(void)
 {
        sdp_list_free(service_db, (sdp_free_func_t) sdp_record_free);
        sdp_list_free(access_db, access_free);
index 1722f78..ff00df7 100644 (file)
@@ -67,7 +67,7 @@ struct _sdp_cstate_list {
 
 static sdp_cstate_list_t *cstates;
 
-// FIXME: should probably remove it when it's found
+/* FIXME: should probably remove it when it's found */
 static sdp_buf_t *sdp_get_cached_rsp(sdp_cont_state_t *cstate)
 {
        sdp_cstate_list_t *p;
@@ -256,15 +256,14 @@ static int sdp_set_cstate_pdu(sdp_buf_t *buf, sdp_cont_state_t *cstate)
 
        if (cstate) {
                SDPDBG("Non null sdp_cstate_t id : 0x%x", cstate->timestamp);
-               *(uint8_t *)pdata = sizeof(sdp_cont_state_t);
+               *pdata = sizeof(sdp_cont_state_t);
                pdata += sizeof(uint8_t);
                length += sizeof(uint8_t);
                memcpy(pdata, cstate, sizeof(sdp_cont_state_t));
                length += sizeof(sdp_cont_state_t);
        } else {
-               // set "null" continuation state
-               *(uint8_t *)pdata = 0;
-               pdata += sizeof(uint8_t);
+               /* set "null" continuation state */
+               *pdata = 0;
                length += sizeof(uint8_t);
        }
        buf->data_size += length;
@@ -335,7 +334,7 @@ static int sdp_match_uuid(sdp_list_t *search, sdp_list_t *pattern)
                if (data == NULL)
                        return -1;
 
-               // create 128-bit form of the search UUID
+               /* create 128-bit form of the search UUID */
                uuid128 = sdp_uuid_to_uuid128((uuid_t *)data);
                list = sdp_list_find(pattern, uuid128, sdp_uuid128_cmp);
                bt_free(uuid128);
@@ -375,7 +374,7 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
 
        plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
        mlen = scanned + sizeof(uint16_t) + 1;
-       // ensure we don't read past buffer
+       /* ensure we don't read past buffer */
        if (plen < mlen || plen != mlen + *(uint8_t *)(pdata+sizeof(uint16_t))) {
                status = SDP_INVALID_SYNTAX;
                goto done;
@@ -671,7 +670,7 @@ static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf)
 
        plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
        mlen = scanned + sizeof(uint32_t) + sizeof(uint16_t) + 1;
-       // ensure we don't read past buffer
+       /* ensure we don't read past buffer */
        if (plen < mlen || plen != mlen + *(uint8_t *)pdata) {
                status = SDP_INVALID_PDU_SIZE;
                goto done;
@@ -699,7 +698,7 @@ static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf)
        }
 
        /*
-        * Calculate Attribute size acording to MTU
+        * Calculate Attribute size according to MTU
         * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
         */
        max_rsp_size = MIN(max_rsp_size, req->mtu - sizeof(sdp_pdu_hdr_t) -
@@ -754,7 +753,7 @@ static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf)
                }
        }
 
-       // push header
+       /* push header */
        buf->data -= sizeof(uint16_t);
        buf->buf_size += sizeof(uint16_t);
 
@@ -785,7 +784,7 @@ static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
        short cstate_size = 0;
        uint8_t dtd = 0;
        sdp_buf_t tmpbuf;
-       size_t data_left = req->len;
+       size_t data_left;
 
        tmpbuf.data = NULL;
        pdata = req->buf + sizeof(sdp_pdu_hdr_t);
@@ -854,7 +853,7 @@ static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
        memset(tmpbuf.data, 0, USHRT_MAX);
 
        /*
-        * Calculate Attribute size acording to MTU
+        * Calculate Attribute size according to MTU
         * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
         */
        max = MIN(max, req->mtu - sizeof(sdp_pdu_hdr_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));
@@ -880,7 +879,7 @@ static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
                                        break;
                                }
                                if (buf->data_size + tmpbuf.data_size < buf->buf_size) {
-                                       // to be sure no relocations
+                                       /* to be sure no relocations */
                                        sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);
                                        tmpbuf.data_size = 0;
                                        memset(tmpbuf.data, 0, USHRT_MAX);
@@ -925,13 +924,13 @@ static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
        }
 
        if (!rsp_count && !cstate) {
-               // found nothing
+               /* found nothing */
                buf->data_size = 0;
                sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);
                sdp_set_cstate_pdu(buf, NULL);
        }
 
-       // push header
+       /* push header */
        buf->data -= sizeof(uint16_t);
        buf->buf_size += sizeof(uint16_t);
 
@@ -962,7 +961,6 @@ static void process_request(sdp_req_t *req)
        sdp_pdu_hdr_t *rsphdr;
        sdp_buf_t rsp;
        uint8_t *buf = malloc(USHRT_MAX);
-       int sent = 0;
        int status = SDP_INVALID_SYNTAX;
 
        memset(buf, 0, USHRT_MAX);
@@ -1036,7 +1034,8 @@ send_rsp:
        rsp.data = buf;
 
        /* stream the rsp PDU */
-       sent = send(req->sock, rsp.data, rsp.data_size, 0);
+       if (send(req->sock, rsp.data, rsp.data_size, 0) < 0)
+               error("send: %s (%d)", strerror(errno), errno);
 
        SDPDBG("Bytes Sent : %d", sent);
 
index c52ee63..de11562 100644 (file)
@@ -65,7 +65,7 @@ static const int sdpServerVnumEntries = 1;
  * seconds. Used for updating the service db state
  * attribute of the service record of the SDP server
  */
-uint32_t sdp_get_time()
+uint32_t sdp_get_time(void)
 {
        /*
         * To handle failure in gettimeofday, so an old
@@ -86,90 +86,13 @@ uint32_t sdp_get_time()
  * Set the SDP server DB. Simply a timestamp which is the marker
  * when the DB was modified.
  */
-void update_db_timestamp(void)
+static void update_db_timestamp(void)
 {
        uint32_t dbts = sdp_get_time();
        sdp_data_t *d = sdp_data_alloc(SDP_UINT32, &dbts);
        sdp_attr_replace(server, SDP_ATTR_SVCDB_STATE, d);
 }
 
-#ifdef __TIZEN_PATCH__
-static void update_adapter_svclass_list(struct btd_adapter *adapter)
-{
-       sdp_list_t *list = adapter_get_services(adapter);
-       uint8_t val = 0;
-
-       for (; list; list = list->next) {
-               sdp_record_t *rec = (sdp_record_t *) list->data;
-
-               if (rec->svclass.type != SDP_UUID16)
-                       continue;
-
-               switch (rec->svclass.value.uuid16) {
-               case DIALUP_NET_SVCLASS_ID:
-               case CIP_SVCLASS_ID:
-                       val |= 0x42;    /* Telephony & Networking */
-                       break;
-               case IRMC_SYNC_SVCLASS_ID:
-               case OBEX_OBJPUSH_SVCLASS_ID:
-               case OBEX_FILETRANS_SVCLASS_ID:
-               case IRMC_SYNC_CMD_SVCLASS_ID:
-               case PBAP_PSE_SVCLASS_ID:
-                       val |= 0x10;    /* Object Transfer */
-                       break;
-               case HEADSET_SVCLASS_ID:
-               case HANDSFREE_SVCLASS_ID:
-                       val |= 0x20;    /* Audio */
-                       break;
-               case CORDLESS_TELEPHONY_SVCLASS_ID:
-               case INTERCOM_SVCLASS_ID:
-               case FAX_SVCLASS_ID:
-               case SAP_SVCLASS_ID:
-               /*
-                * Setting the telephony bit for the handsfree audio gateway
-                * role is not required by the HFP specification, but the
-                * Nokia 616 carkit is just plain broken! It will refuse
-                * pairing without this bit set.
-                */
-               case HANDSFREE_AGW_SVCLASS_ID:
-                       val |= 0x40;    /* Telephony */
-                       break;
-               case AUDIO_SOURCE_SVCLASS_ID:
-               case VIDEO_SOURCE_SVCLASS_ID:
-                       val |= 0x08;    /* Capturing */
-                       break;
-               case AUDIO_SINK_SVCLASS_ID:
-               case VIDEO_SINK_SVCLASS_ID:
-                       val |= 0x04;    /* Rendering */
-                       break;
-               case PANU_SVCLASS_ID:
-               case NAP_SVCLASS_ID:
-               case GN_SVCLASS_ID:
-                       val |= 0x02;    /* Networking */
-                       break;
-               }
-       }
-
-       SDPDBG("Service classes 0x%02x", val);
-
-//     manager_update_svc(adapter, val);
-}
-void update_svclass_list(const bdaddr_t *src)
-{
-       GSList *adapters = manager_get_adapters();
-
-       for (; adapters; adapters = adapters->next) {
-               struct btd_adapter *adapter = adapters->data;
-               bdaddr_t bdaddr;
-
-               adapter_get_address(adapter, &bdaddr);
-
-               if (bacmp(src, BDADDR_ANY) == 0 || bacmp(src, &bdaddr) == 0)
-                       update_adapter_svclass_list(adapter);
-       }
-
-}
-#endif
 void register_public_browse_group(void)
 {
        sdp_list_t *browselist;
@@ -488,7 +411,7 @@ int service_register_req(sdp_req_t *req, sdp_buf_t *rsp)
                bufsize -= sizeof(bdaddr_t);
        }
 
-       // save image of PDU: we need it when clients request this attribute
+       /* save image of PDU: we need it when clients request this attribute */
        rec = extract_pdu_server(&req->device, p, bufsize, 0xffffffff, &scanned);
        if (!rec)
                goto invalid;
@@ -592,7 +515,6 @@ int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp)
        int status = 0;
 
        /* extract service record handle */
-       p += sizeof(uint32_t);
 
        rec = sdp_record_find(handle);
        if (rec) {
index 48efab6..9f5415f 100644 (file)
 #define SDPDBG(fmt...)
 #endif
 
-#define EIR_DATA_LENGTH  240
-
-#define EIR_FLAGS                   0x01  /* flags */
-#define EIR_UUID16_SOME             0x02  /* 16-bit UUID, more available */
-#define EIR_UUID16_ALL              0x03  /* 16-bit UUID, all listed */
-#define EIR_UUID32_SOME             0x04  /* 32-bit UUID, more available */
-#define EIR_UUID32_ALL              0x05  /* 32-bit UUID, all listed */
-#define EIR_UUID128_SOME            0x06  /* 128-bit UUID, more available */
-#define EIR_UUID128_ALL             0x07  /* 128-bit UUID, all listed */
-#define EIR_NAME_SHORT              0x08  /* shortened local name */
-#define EIR_NAME_COMPLETE           0x09  /* complete local name */
-#define EIR_TX_POWER                0x0A  /* transmit power level */
-#define EIR_DEVICE_ID               0x10  /* device ID */
-
 typedef struct request {
        bdaddr_t device;
        bdaddr_t bdaddr;
@@ -83,7 +69,7 @@ sdp_list_t *sdp_get_access_list(void);
 int sdp_check_access(uint32_t handle, bdaddr_t *device);
 uint32_t sdp_next_handle(void);
 
-uint32_t sdp_get_time();
+uint32_t sdp_get_time(void);
 
 #define SDP_SERVER_COMPAT (1 << 0)
 #define SDP_SERVER_MASTER (1 << 1)
@@ -95,7 +81,3 @@ int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec);
 int remove_record_from_server(uint32_t handle);
 
 void sdp_init_services_list(bdaddr_t *device);
-#ifdef __TIZEN_PATCH__
-sdp_record_t *sdp_extract_pdu_safe(const uint8_t *buf, int bufsize, int *scanned);
-#endif
-
index d7862e2..a47720a 100644 (file)
@@ -35,8 +35,6 @@
 #include <time.h>
 #include <sys/file.h>
 #include <sys/stat.h>
-#include <sys/param.h>
-#include <sys/socket.h>
 
 #include <glib.h>
 
@@ -45,8 +43,7 @@
 #include <bluetooth/sdp_lib.h>
 
 #include "textfile.h"
-#include "adapter.h"
-#include "device.h"
+#include "glib-compat.h"
 #include "glib-helper.h"
 #include "storage.h"
 
@@ -241,8 +238,8 @@ int read_local_name(bdaddr_t *bdaddr, char *name)
                return -ENOENT;
 
        len = strlen(str);
-       if (len > 248)
-               str[248] = '\0';
+       if (len > HCI_MAX_NAME_LENGTH)
+               str[HCI_MAX_NAME_LENGTH] = '\0';
        strcpy(name, str);
 
        free(str);
@@ -323,11 +320,11 @@ int read_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t *class)
 
 int write_device_name(bdaddr_t *local, bdaddr_t *peer, char *name)
 {
-       char filename[PATH_MAX + 1], addr[18], str[249];
+       char filename[PATH_MAX + 1], addr[18], str[HCI_MAX_NAME_LENGTH + 1];
        int i;
 
        memset(str, 0, sizeof(str));
-       for (i = 0; i < 248 && name[i]; i++)
+       for (i = 0; i < HCI_MAX_NAME_LENGTH && name[i]; i++)
                if ((unsigned char) name[i] < 32 || name[i] == 127)
                        str[i] = '.';
                else
@@ -353,8 +350,8 @@ int read_device_name(const char *src, const char *dst, char *name)
                return -ENOENT;
 
        len = strlen(str);
-       if (len > 248)
-               str[248] = '\0';
+       if (len > HCI_MAX_NAME_LENGTH)
+               str[HCI_MAX_NAME_LENGTH] = '\0';
        strcpy(name, str);
 
        free(str);
@@ -368,7 +365,7 @@ int write_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data)
        int i;
 
        memset(str, 0, sizeof(str));
-       for (i = 0; i < 240; i++)
+       for (i = 0; i < HCI_MAX_EIR_LENGTH; i++)
                sprintf(str + (i * 2), "%2.2X", data[i]);
 
        create_filename(filename, PATH_MAX, local, "eir");
@@ -402,7 +399,7 @@ int read_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data)
                return -EIO;
        }
 
-       for (i = 0; i < 240; i++)
+       for (i = 0; i < HCI_MAX_EIR_LENGTH; i++)
                sscanf(str + (i * 2), "%02hhX", &data[i]);
 
        free(str);
@@ -593,35 +590,11 @@ int read_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t *
 
        return 0;
 }
-#ifdef __TIZEN_PATCH__
-int read_pin_length(bdaddr_t *local, bdaddr_t *peer)
-{
-       char filename[PATH_MAX + 1], addr[18], *str;
-       int len;
 
-       create_filename(filename, PATH_MAX, local, "linkkeys");
-
-       ba2str(peer, addr);
-       str = textfile_get(filename, addr);
-       if (!str)
-               return -ENOENT;
-
-       if (strlen(str) < 36) {
-               free(str);
-               return -ENOENT;
-       }
-
-       len = atoi(str + 35);
-
-       free(str);
-
-       return len;
-}
-#endif
-int read_pin_code(bdaddr_t *local, bdaddr_t *peer, char *pin)
+ssize_t read_pin_code(bdaddr_t *local, bdaddr_t *peer, char *pin)
 {
        char filename[PATH_MAX + 1], addr[18], *str;
-       int len;
+       ssize_t len;
 
        create_filename(filename, PATH_MAX, local, "pincodes");
 
@@ -756,35 +729,6 @@ gboolean read_trust(const bdaddr_t *local, const char *addr, const char *service
        return ret;
 }
 
-struct trust_list {
-       GSList *trusts;
-       const char *service;
-};
-
-static void append_trust(char *key, char *value, void *data)
-{
-       struct trust_list *list = data;
-
-       if (strstr(value, list->service))
-               list->trusts = g_slist_append(list->trusts, g_strdup(key));
-}
-
-GSList *list_trusts(bdaddr_t *local, const char *service)
-{
-       char filename[PATH_MAX + 1];
-       struct trust_list list;
-
-       create_filename(filename, PATH_MAX, local, "trusts");
-
-       list.trusts = NULL;
-       list.service = service;
-
-       if (textfile_foreach(filename, append_trust, &list) < 0)
-               return NULL;
-
-       return list.trusts;
-}
-
 int write_device_profiles(bdaddr_t *src, bdaddr_t *dst, const char *profiles)
 {
        char filename[PATH_MAX + 1], addr[18];
@@ -1134,8 +1078,6 @@ int read_device_pairable(bdaddr_t *bdaddr, gboolean *mode)
 
        create_filename(filename, PATH_MAX, bdaddr, "config");
 
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
        str = textfile_get(filename, "pairable");
        if (!str)
                return -ENOENT;
@@ -1146,134 +1088,7 @@ int read_device_pairable(bdaddr_t *bdaddr, gboolean *mode)
 
        return 0;
 }
-#ifdef __TIZEN_PATCH__
-// Storing limited property
-int write_device_limited(bdaddr_t *bdaddr, gboolean mode)
-{
-       char filename[PATH_MAX + 1];
-
-       create_filename(filename, PATH_MAX, bdaddr, "config");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       return textfile_put(filename, "limited", mode ? "yes" : "no");
-}
 
-int read_device_limited(bdaddr_t *bdaddr, gboolean *mode)
-{
-       char filename[PATH_MAX + 1], *str;
-
-       create_filename(filename, PATH_MAX, bdaddr, "config");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       str = textfile_get(filename, "limited");
-       if (!str)
-               return -ENOENT;
-
-       *mode = strcmp(str, "yes") == 0 ? TRUE : FALSE;
-
-       free(str);
-
-       return 0;
-}
-
-int read_version_info(const bdaddr_t *local, const char *addr,
-                                       uint16_t *manufacturer, uint8_t *lmp_ver, uint16_t *lmp_subver,
-                                       uint8_t *features)
-{
-       char filename[PATH_MAX + 1], *str, feature_value[5];
-       int i;
-
-       create_filename(filename, PATH_MAX, local, "manufacturers");
-
-       str = textfile_caseget(filename, addr);
-
-       if (!str)
-               return -ENOENT;
-
-       if (sscanf(str, "%d %d %d", manufacturer, lmp_ver, lmp_subver) != 3) {
-               free(str);
-               return -ENOENT;
-       }
-
-       free(str);
-
-       create_filename(filename, PATH_MAX, local, "features");
-
-       str = textfile_caseget(filename, addr);
-
-       if (!str)
-               return -ENOENT;
-
-       if (strlen(str) != 16)
-       {
-               free(str);
-               return -ENOENT;
-       }
-
-       memset(feature_value, 0x00, sizeof(feature_value));
-
-       for (i = 0; i < 8; i++)
-       {
-               strncpy(feature_value, str + (i * 2), 4);
-               if (sscanf(feature_value, "%x", &features[i]) != 1) {
-                       free(str);
-                       return -ENOENT;
-               }
-       }
-
-       free(str);
-
-       return 0;
-}
-int read_aptx_preference(bdaddr_t *bdaddr, gboolean *aptx_preference)
-{
-       char filename[PATH_MAX + 1], *str;
-       int len;
-
-       create_filename(filename, PATH_MAX, bdaddr, "config");
-
-       str = textfile_get(filename, "Codec_preference");
-       if (!str)
-               return -ENOENT;
-
-       len = strlen(str);
-       if (len > 248)
-               str[248] = '\0';
-
-       if(!aptx_preference)
-               return -EINVAL;
-
-       if(!strncmp(str,"aptx",4))
-               *aptx_preference=TRUE;
-       else
-               *aptx_preference=FALSE;
-
-       free(str);
-
-       return 0;
-}
-
-int write_aptx_preference(bdaddr_t *bdaddr, gboolean aptx_preference)
-{
-       char filename[PATH_MAX + 1], str[249];
-       int i;
-
-       memset(str, 0, sizeof(str));
-       if(aptx_preference)
-               memcpy(str,"aptx",5);
-       else
-               memcpy(str,"sbc",4);
-
-       create_filename(filename, PATH_MAX, bdaddr, "config");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       return textfile_put(filename, "Codec_preference", str);
-}
-
-#endif
 gboolean read_blocked(const bdaddr_t *local, const bdaddr_t *remote)
 {
        char filename[PATH_MAX + 1], *str, addr[18];
@@ -1325,64 +1140,54 @@ int write_device_services(const bdaddr_t *sba, const bdaddr_t *dba,
 static void filter_keys(char *key, char *value, void *data)
 {
        struct match *match = data;
-       const char *address = match->pattern;
 
-       /* Each key contains: MAC#handle*/
-       if (strncasecmp(key, address, 17) == 0)
+       if (strncasecmp(key, match->pattern, strlen(match->pattern)) == 0)
                match->keys = g_slist_append(match->keys, g_strdup(key));
 }
 
-int delete_device_service(const bdaddr_t *sba, const bdaddr_t *dba)
+static void delete_by_pattern(const char *filename, char *pattern)
 {
-       GSList *l;
        struct match match;
-       char filename[PATH_MAX + 1], address[18];
+       GSList *l;
        int err;
 
-       create_filename(filename, PATH_MAX, sba, "primary");
-
-       memset(address, 0, sizeof(address));
-       ba2str(dba, address);
-
-       err = textfile_del(filename, address);
-       if (err < 0)
-               return err;
-
-       /* Deleting all characteristics of a given address */
        memset(&match, 0, sizeof(match));
-       match.pattern = address;
+       match.pattern = pattern;
 
-       create_filename(filename, PATH_MAX, sba, "characteristic");
        err = textfile_foreach(filename, filter_keys, &match);
        if (err < 0)
-               return err;
+               goto done;
 
        for (l = match.keys; l; l = l->next) {
                const char *key = l->data;
                textfile_del(filename, key);
        }
 
-       g_slist_foreach(match.keys, (GFunc) g_free, NULL);
-       g_slist_free(match.keys);
+done:
+       g_slist_free_full(match.keys, g_free);
+}
 
-       /* Deleting all attributes values of a given address */
-       memset(&match, 0, sizeof(match));
-       match.pattern = address;
+int delete_device_service(const bdaddr_t *sba, const bdaddr_t *dba)
+{
+       char filename[PATH_MAX + 1], address[18];
 
-       create_filename(filename, PATH_MAX, sba, "attributes");
-       err = textfile_foreach(filename, filter_keys, &match);
-       if (err < 0)
-               return err;
+       memset(address, 0, sizeof(address));
+       ba2str(dba, address);
 
-       for (l = match.keys; l; l = l->next) {
-               const char *key = l->data;
-               textfile_del(filename, key);
-       }
+       /* Deleting all characteristics of a given address */
+       create_filename(filename, PATH_MAX, sba, "characteristic");
+       delete_by_pattern(filename, address);
 
-       g_slist_foreach(match.keys, (GFunc) g_free, NULL);
-       g_slist_free(match.keys);
+       /* Deleting all attributes values of a given address */
+       create_filename(filename, PATH_MAX, sba, "attributes");
+       delete_by_pattern(filename, address);
 
-       return 0;
+       /* Deleting all CCC values of a given address */
+       create_filename(filename, PATH_MAX, sba, "ccc");
+       delete_by_pattern(filename, address);
+
+       create_filename(filename, PATH_MAX, sba, "primary");
+       return textfile_del(filename, address);
 }
 
 char *read_device_services(const bdaddr_t *sba, const bdaddr_t *dba)
@@ -1391,8 +1196,6 @@ char *read_device_services(const bdaddr_t *sba, const bdaddr_t *dba)
 
        create_filename(filename, PATH_MAX, sba, "primary");
 
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
        ba2str(dba, addr);
 
        return textfile_caseget(filename, addr);
@@ -1421,8 +1224,6 @@ char *read_device_characteristics(const bdaddr_t *sba, const bdaddr_t *dba,
 
        create_filename(filename, PATH_MAX, sba, "characteristic");
 
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
        ba2str(dba, addr);
 
        snprintf(key, sizeof(key), "%17s#%04X", addr, handle);
@@ -1452,45 +1253,60 @@ int read_device_attributes(const bdaddr_t *sba, textfile_cb func, void *data)
 
        create_filename(filename, PATH_MAX, sba, "attributes");
 
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
        return textfile_foreach(filename, func, data);
 }
 
-int write_device_type(const bdaddr_t *sba, const bdaddr_t *dba,
-                                               device_type_t type)
+int read_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint16_t handle,
+                                                       uint16_t *value)
 {
-       char filename[PATH_MAX + 1], addr[18], chars[3];
+       char filename[PATH_MAX + 1], addr[18], key[23];
+       char *str;
+       unsigned int config;
+       int err = 0;
 
-       create_filename(filename, PATH_MAX, sba, "types");
+       create_filename(filename, PATH_MAX, local, "ccc");
 
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+       ba2str(peer, addr);
+       snprintf(key, sizeof(key), "%17s#%04X", addr, handle);
 
-       ba2str(dba, addr);
+       str = textfile_caseget(filename, key);
+       if (str == NULL)
+               return -ENOENT;
 
-       snprintf(chars, sizeof(chars), "%2.2X", type);
+       if (sscanf(str, "%04X", &config) != 1)
+               err = -ENOENT;
+       else
+               *value = config;
+
+       free(str);
 
-       return textfile_put(filename, addr, chars);
+       return err;
 }
 
-device_type_t read_device_type(const bdaddr_t *sba, const bdaddr_t *dba)
+int write_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint16_t handle,
+                                                       uint16_t value)
 {
-       char filename[PATH_MAX + 1], addr[18], *chars;
-       device_type_t type;
+       char filename[PATH_MAX + 1], addr[18], key[23], config[5];
 
-       create_filename(filename, PATH_MAX, sba, "types");
+       create_filename(filename, PATH_MAX, local, "ccc");
 
        create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 
-       ba2str(dba, addr);
+       ba2str(peer, addr);
 
-       chars = textfile_caseget(filename, addr);
-       if (chars == NULL)
-               return DEVICE_TYPE_UNKNOWN;
+       snprintf(key, sizeof(key), "%17s#%04X", addr, handle);
+       snprintf(config, sizeof(config), "%04X", value);
+
+       return textfile_put(filename, key, config);
+}
 
-       type = strtol(chars, NULL, 16);
+void delete_device_ccc(bdaddr_t *local, bdaddr_t *peer)
+{
+       char filename[PATH_MAX + 1], addr[18];
 
-       free(chars);
+       ba2str(peer, addr);
 
-       return type;
+       /* Deleting all CCC values of a given address */
+       create_filename(filename, PATH_MAX, local, "ccc");
+       delete_by_pattern(filename, addr);
 }
index 1cb0af2..51259f6 100644 (file)
@@ -49,10 +49,9 @@ int write_lastseen_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm);
 int write_lastused_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm);
 int write_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t type, int length);
 int read_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t *type);
-int read_pin_code(bdaddr_t *local, bdaddr_t *peer, char *pin);
+ssize_t read_pin_code(bdaddr_t *local, bdaddr_t *peer, char *pin);
 gboolean read_trust(const bdaddr_t *local, const char *addr, const char *service);
 int write_trust(const char *src, const char *addr, const char *service, gboolean trust);
-GSList *list_trusts(bdaddr_t *local, const char *service);
 int write_device_profiles(bdaddr_t *src, bdaddr_t *dst, const char *profiles);
 int delete_entry(bdaddr_t *src, const char *storage, const char *key);
 int store_record(const gchar *src, const gchar *dst, sdp_record_t *rec);
@@ -84,17 +83,11 @@ char *read_device_characteristics(const bdaddr_t *sba, const bdaddr_t *dba,
 int write_device_attribute(const bdaddr_t *sba, const bdaddr_t *dba,
                                         uint16_t handle, const char *chars);
 int read_device_attributes(const bdaddr_t *sba, textfile_cb func, void *data);
-int write_device_type(const bdaddr_t *sba, const bdaddr_t *dba,
-                                               device_type_t type);
-device_type_t read_device_type(const bdaddr_t *sba, const bdaddr_t *dba);
+int read_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint16_t handle,
+                                                       uint16_t *value);
+int write_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint16_t handle,
+                                                       uint16_t value);
+void delete_device_ccc(bdaddr_t *local, bdaddr_t *peer);
 
 #define PNP_UUID               "00001200-0000-1000-8000-00805f9b34fb"
 
-#ifdef __TIZEN_PATCH__
-// Storing limited property
-int write_device_limited(bdaddr_t *local, gboolean mode);
-int read_device_limited(bdaddr_t *local, gboolean *mode);
-int read_version_info(const bdaddr_t *local, const char *addr,
-                                       uint16_t *manufacturer, uint8_t *lmp_ver, uint16_t *lmp_subver,
-                                       uint8_t *features);
-#endif
index d115ff6..2712cd8 100644 (file)
@@ -149,7 +149,7 @@ static inline int write_key_value(int fd, const char *key, const char *value)
        sprintf(str, "%s %s\n", key, value);
 
        if (write(fd, str, size) < 0)
-               err = errno;
+               err = -errno;
 
        free(str);
 
@@ -182,7 +182,8 @@ static int write_key(const char *pathname, const char *key, const char *value, i
 {
        struct stat st;
        char *map, *off, *end, *str;
-       off_t size, pos; size_t base;
+       off_t size;
+       size_t base;
        int fd, len, err = 0;
 
        fd = open(pathname, O_RDWR);
@@ -190,12 +191,12 @@ static int write_key(const char *pathname, const char *key, const char *value, i
                return -errno;
 
        if (flock(fd, LOCK_EX) < 0) {
-               err = errno;
+               err = -errno;
                goto close;
        }
 
        if (fstat(fd, &st) < 0) {
-               err = errno;
+               err = -errno;
                goto unlock;
        }
 
@@ -203,7 +204,7 @@ static int write_key(const char *pathname, const char *key, const char *value, i
 
        if (!size) {
                if (value) {
-                       pos = lseek(fd, size, SEEK_SET);
+                       lseek(fd, size, SEEK_SET);
                        err = write_key_value(fd, key, value);
                }
                goto unlock;
@@ -212,7 +213,7 @@ static int write_key(const char *pathname, const char *key, const char *value, i
        map = mmap(NULL, size, PROT_READ | PROT_WRITE,
                                        MAP_PRIVATE | MAP_LOCKED, fd, 0);
        if (!map || map == MAP_FAILED) {
-               err = errno;
+               err = -errno;
                goto unlock;
        }
 
@@ -221,7 +222,7 @@ static int write_key(const char *pathname, const char *key, const char *value, i
        if (!off) {
                if (value) {
                        munmap(map, size);
-                       pos = lseek(fd, size, SEEK_SET);
+                       lseek(fd, size, SEEK_SET);
                        err = write_key_value(fd, key, value);
                }
                goto unlock;
@@ -231,7 +232,7 @@ static int write_key(const char *pathname, const char *key, const char *value, i
 
        end = strnpbrk(off, size, "\r\n");
        if (!end) {
-               err = EILSEQ;
+               err = -EILSEQ;
                goto unmap;
        }
 
@@ -246,10 +247,10 @@ static int write_key(const char *pathname, const char *key, const char *value, i
        if (!len) {
                munmap(map, size);
                if (ftruncate(fd, base) < 0) {
-                       err = errno;
+                       err = -errno;
                        goto unlock;
                }
-               pos = lseek(fd, base, SEEK_SET);
+               lseek(fd, base, SEEK_SET);
                if (value)
                        err = write_key_value(fd, key, value);
 
@@ -257,13 +258,13 @@ static int write_key(const char *pathname, const char *key, const char *value, i
        }
 
        if (len < 0 || len > size) {
-               err = EILSEQ;
+               err = -EILSEQ;
                goto unmap;
        }
 
        str = malloc(len);
        if (!str) {
-               err = errno;
+               err = -errno;
                goto unmap;
        }
 
@@ -271,16 +272,16 @@ static int write_key(const char *pathname, const char *key, const char *value, i
 
        munmap(map, size);
        if (ftruncate(fd, base) < 0) {
-               err = errno;
+               err = -errno;
                free(str);
                goto unlock;
        }
-       pos = lseek(fd, base, SEEK_SET);
+       lseek(fd, base, SEEK_SET);
        if (value)
                err = write_key_value(fd, key, value);
 
        if (write(fd, str, len) < 0)
-               err = errno;
+               err = -errno;
 
        free(str);
 
@@ -296,9 +297,9 @@ close:
        fdatasync(fd);
 
        close(fd);
-       errno = err;
+       errno = -err;
 
-       return -err;
+       return err;
 }
 
 static char *read_key(const char *pathname, const char *key, int icase)
@@ -313,12 +314,12 @@ static char *read_key(const char *pathname, const char *key, int icase)
                return NULL;
 
        if (flock(fd, LOCK_SH) < 0) {
-               err = errno;
+               err = -errno;
                goto close;
        }
 
        if (fstat(fd, &st) < 0) {
-               err = errno;
+               err = -errno;
                goto unlock;
        }
 
@@ -326,26 +327,26 @@ static char *read_key(const char *pathname, const char *key, int icase)
 
        map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
        if (!map || map == MAP_FAILED) {
-               err = errno;
+               err = -errno;
                goto unlock;
        }
 
        len = strlen(key);
        off = find_key(map, size, key, len, icase);
        if (!off) {
-               err = EILSEQ;
+               err = -EILSEQ;
                goto unmap;
        }
 
        end = strnpbrk(off, size - (map - off), "\r\n");
        if (!end) {
-               err = EILSEQ;
+               err = -EILSEQ;
                goto unmap;
        }
 
        str = malloc(end - off - len);
        if (!str) {
-               err = EILSEQ;
+               err = -EILSEQ;
                goto unmap;
        }
 
@@ -360,7 +361,7 @@ unlock:
 
 close:
        close(fd);
-       errno = err;
+       errno = -err;
 
        return str;
 }
@@ -407,12 +408,12 @@ int textfile_foreach(const char *pathname, textfile_cb func, void *data)
                return -errno;
 
        if (flock(fd, LOCK_SH) < 0) {
-               err = errno;
+               err = -errno;
                goto close;
        }
 
        if (fstat(fd, &st) < 0) {
-               err = errno;
+               err = -errno;
                goto unlock;
        }
 
@@ -420,7 +421,7 @@ int textfile_foreach(const char *pathname, textfile_cb func, void *data)
 
        map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
        if (!map || map == MAP_FAILED) {
-               err = errno;
+               err = -errno;
                goto unlock;
        }
 
@@ -429,7 +430,7 @@ int textfile_foreach(const char *pathname, textfile_cb func, void *data)
        while (size - (off - map) > 0) {
                end = strnpbrk(off, size - (off - map), " ");
                if (!end) {
-                       err = EILSEQ;
+                       err = -EILSEQ;
                        break;
                }
 
@@ -437,7 +438,7 @@ int textfile_foreach(const char *pathname, textfile_cb func, void *data)
 
                key = malloc(len + 1);
                if (!key) {
-                       err = errno;
+                       err = -errno;
                        break;
                }
 
@@ -447,14 +448,14 @@ int textfile_foreach(const char *pathname, textfile_cb func, void *data)
                off = end + 1;
 
                if (size - (off - map) < 0) {
-                       err = EILSEQ;
+                       err = -EILSEQ;
                        free(key);
                        break;
                }
 
                end = strnpbrk(off, size - (off - map), "\r\n");
                if (!end) {
-                       err = EILSEQ;
+                       err = -EILSEQ;
                        free(key);
                        break;
                }
@@ -463,7 +464,7 @@ int textfile_foreach(const char *pathname, textfile_cb func, void *data)
 
                value = malloc(len + 1);
                if (!value) {
-                       err = errno;
+                       err = -errno;
                        free(key);
                        break;
                }
@@ -486,7 +487,7 @@ unlock:
 
 close:
        close(fd);
-       errno = err;
+       errno = -err;
 
        return 0;
 }
index fed3266..5cdeeb4 100644 (file)
@@ -41,6 +41,7 @@ static int do_reject = 0;
 
 static volatile sig_atomic_t __io_canceled = 0;
 static volatile sig_atomic_t __io_terminated = 0;
+static volatile sig_atomic_t exit_on_release = 1;
 
 static void sig_term(int sig)
 {
@@ -286,7 +287,8 @@ static DBusHandlerResult release_message(DBusConnection *conn,
        if (!__io_canceled)
                fprintf(stderr, "Agent has been released\n");
 
-       __io_terminated = 1;
+       if (exit_on_release)
+               __io_terminated = 1;
 
        reply = dbus_message_new_method_return(msg);
        if (!reply) {
@@ -414,6 +416,13 @@ static int unregister_agent(DBusConnection *conn, const char *adapter_path,
        return 0;
 }
 
+static void create_paired_device_reply(DBusPendingCall *pending,
+                                                       void *user_data)
+{
+       __io_terminated = 1;
+       return;
+}
+
 static int create_paired_device(DBusConnection *conn, const char *adapter_path,
                                                const char *agent_path,
                                                const char *capabilities,
@@ -421,6 +430,7 @@ static int create_paired_device(DBusConnection *conn, const char *adapter_path,
 {
        dbus_bool_t success;
        DBusMessage *msg;
+       DBusPendingCall *pending;
 
        msg = dbus_message_new_method_call("org.bluez", adapter_path,
                                                "org.bluez.Adapter",
@@ -435,7 +445,12 @@ static int create_paired_device(DBusConnection *conn, const char *adapter_path,
                                        DBUS_TYPE_STRING, &capabilities,
                                        DBUS_TYPE_INVALID);
 
-       success = dbus_connection_send(conn, msg, NULL);
+       exit_on_release = 0;
+       success = dbus_connection_send_with_reply(conn, msg, &pending, -1);
+       if (pending)
+               dbus_pending_call_set_notify(pending,
+                                               create_paired_device_reply,
+                                               NULL, NULL);
 
        dbus_message_unref(msg);
 
index b1c3f10..f1d51f1 100755 (executable)
@@ -403,7 +403,7 @@ class Tester:
                    print 'Usage: %s -i <dev> ListRecentRemoteDevices date' % self.name
            else:
                 # FIXME: remove at future version
-                print 'Script Error: Method %s not found. Maybe a mispelled word.' % (self.cmd_args)
+                print 'Script Error: Method %s not found. Maybe a misspelled word.' % (self.cmd_args)
        except dbus.DBusException, e:
            print '%s failed: %s' % (self.cmd, e)
            sys.exit(1)
index 168326f..541b3cd 100644 (file)
@@ -714,7 +714,7 @@ static void do_avctp_send(int sk, int invalid)
                dump_avctp_header(hdr);
 }
 
-static void usage()
+static void usage(void)
 {
        printf("avtest - Audio/Video testing ver %s\n", VERSION);
        printf("Usage:\n"
index 683b3b9..f87fa38 100644 (file)
@@ -437,7 +437,7 @@ int main(int argc, char *argv[])
                                        printf("Reset device manually\n");
                                } else {
                                        ioctl(dd, HCIDEVRESET, dev);
-                                       printf("Device reset successully\n");
+                                       printf("Device reset successfully\n");
                                }
                        } else {
                                printf("Reset device now\n");
index c02a25a..91fc1d5 100644 (file)
@@ -225,7 +225,8 @@ static void confirm_cb(GIOChannel *io, gpointer user_data)
 }
 
 static void l2cap_connect(const char *src, const char *dst, uint16_t psm,
-                                               gint disconn, gint sec)
+                                               gint disconn, gint sec,
+                                               gint prio)
 {
        struct io_data *data;
        GError *err = NULL;
@@ -242,6 +243,7 @@ static void l2cap_connect(const char *src, const char *dst, uint16_t psm,
                                                BT_IO_OPT_DEST, dst,
                                                BT_IO_OPT_PSM, psm,
                                                BT_IO_OPT_SEC_LEVEL, sec,
+                                               BT_IO_OPT_PRIORITY, prio,
                                                BT_IO_OPT_INVALID);
        else
                data->io = bt_io_connect(BT_IO_L2CAP, connect_cb, data,
@@ -250,6 +252,7 @@ static void l2cap_connect(const char *src, const char *dst, uint16_t psm,
                                                BT_IO_OPT_DEST, dst,
                                                BT_IO_OPT_PSM, psm,
                                                BT_IO_OPT_SEC_LEVEL, sec,
+                                               BT_IO_OPT_PRIORITY, prio,
                                                BT_IO_OPT_INVALID);
 
        if (!data->io) {
@@ -466,6 +469,7 @@ static gint opt_disconn = -1;
 static gint opt_accept = DEFAULT_ACCEPT_TIMEOUT;
 static gint opt_sec = 0;
 static gboolean opt_master = FALSE;
+static gint opt_priority = 0;
 
 static GMainLoop *main_loop;
 
@@ -490,6 +494,10 @@ static GOptionEntry options[] = {
                                "Accept connection after N seconds" },
        { "master", 'm', 0, G_OPTION_ARG_NONE, &opt_master,
                                "Master role switch (incoming connections)" },
+       { "priority", 'P', 0, G_OPTION_ARG_INT, &opt_priority,
+                               "Transmission priority: Setting a priority "
+                               "outside the range 0 to 6 requires the"
+                               "CAP_NET_ADMIN capability." },
        { NULL },
 };
 
@@ -510,13 +518,15 @@ int main(int argc, char *argv[])
 
        g_option_context_free(context);
 
-       printf("accept=%d, reject=%d, discon=%d, defer=%d, sec=%d\n",
-               opt_accept, opt_reject, opt_disconn, opt_defer, opt_sec);
+       printf("accept=%d, reject=%d, discon=%d, defer=%d, sec=%d, prio=%d\n",
+               opt_accept, opt_reject, opt_disconn, opt_defer, opt_sec,
+               opt_priority);
 
        if (opt_psm) {
                if (argc > 1)
                        l2cap_connect(opt_dev, argv[1], opt_psm,
-                                                       opt_disconn, opt_sec);
+                                                       opt_disconn, opt_sec,
+                                                       opt_priority);
                else
                        l2cap_listen(opt_dev, opt_psm, opt_defer, opt_reject,
                                        opt_disconn, opt_accept, opt_sec,
index 9950372..7eb8814 100644 (file)
@@ -28,7 +28,6 @@
 
 #include <stdio.h>
 #include <errno.h>
-#include <ctype.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <getopt.h>
 #include <syslog.h>
 #include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/poll.h>
-#include <sys/ioctl.h>
+#include <sys/epoll.h>
 #include <sys/socket.h>
 #include <sys/resource.h>
+#include <sys/stat.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
 #include <bluetooth/hci_lib.h>
-
-#include <netdb.h>
-
-#include <glib.h>
-
-#define GHCI_DEV               "/dev/ghci"
+#include <bluetooth/l2cap.h>
 
 #define VHCI_DEV               "/dev/vhci"
-#define VHCI_UDEV              "/dev/hci_vhci"
 
 #define VHCI_MAX_CONN          12
 
@@ -68,18 +60,18 @@ struct vhci_device {
        uint8_t         dev_class[3];
        uint8_t         inq_mode;
        uint8_t         eir_fec;
-       uint8_t         eir_data[240];
+       uint8_t         eir_data[HCI_MAX_EIR_LENGTH];
        uint16_t        acl_cnt;
        bdaddr_t        bdaddr;
-       int             fd;
+       int             dev_fd;
+       int             scan_fd;
        int             dd;
-       GIOChannel      *scan;
 };
 
 struct vhci_conn {
        bdaddr_t        dest;
        uint16_t        handle;
-       GIOChannel      *chan;
+       int             fd;
 };
 
 struct vhci_link_info {
@@ -111,30 +103,17 @@ struct btsnoop_pkt {
 
 static uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 };
 
-static GMainLoop *event_loop;
+#define MAX_EPOLL_EVENTS 10
 
-static volatile sig_atomic_t __io_canceled;
+static int epoll_fd;
 
-static inline void io_init(void)
-{
-       __io_canceled = 0;
-}
-
-static inline void io_cancel(void)
-{
-       __io_canceled = 1;
-}
+static volatile sig_atomic_t __io_canceled = 0;
 
 static void sig_term(int sig)
 {
-       io_cancel();
-       g_main_loop_quit(event_loop);
+       __io_canceled = 1;
 }
 
-static gboolean io_acl_data(GIOChannel *chan, GIOCondition cond, gpointer data);
-static gboolean io_conn_ind(GIOChannel *chan, GIOCondition cond, gpointer data);
-static gboolean io_hci_data(GIOChannel *chan, GIOCondition cond, gpointer data);
-
 static inline int read_n(int fd, void *buf, int len)
 {
        register int w, t = 0;
@@ -197,13 +176,13 @@ static int create_snoop(char *file)
        return fd;
 }
 
-static int write_snoop(int fd, int type, int incoming, unsigned char *buf, int len)
+static int write_snoop(int fd, int type, int incoming,
+                               unsigned char *buf, int len)
 {
        struct btsnoop_pkt pkt;
        struct timeval tv;
        uint32_t size = len;
        uint64_t ts;
-       int err;
 
        if (fd < 0)
                return -1;
@@ -221,8 +200,11 @@ static int write_snoop(int fd, int type, int incoming, unsigned char *buf, int l
        if (type == HCI_COMMAND_PKT || type == HCI_EVENT_PKT)
                pkt.flags |= ntohl(0x02);
 
-       err = write(fd, &pkt, BTSNOOP_PKT_SIZE);
-       err = write(fd, buf, size);
+       if (write(fd, &pkt, BTSNOOP_PKT_SIZE) < 0)
+               return -errno;
+
+       if (write(fd, buf, size) < 0)
+               return -errno;
 
        return 0;
 }
@@ -261,7 +243,7 @@ static void command_status(uint16_t ogf, uint16_t ocf, uint8_t status)
 
        write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
 
-       if (write(vdev.fd, buf, ptr - buf) < 0)
+       if (write(vdev.dev_fd, buf, ptr - buf) < 0)
                syslog(LOG_ERR, "Can't send event: %s(%d)",
                                                strerror(errno), errno);
 }
@@ -293,7 +275,7 @@ static void command_complete(uint16_t ogf, uint16_t ocf, int plen, void *data)
 
        write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
 
-       if (write(vdev.fd, buf, ptr - buf) < 0)
+       if (write(vdev.dev_fd, buf, ptr - buf) < 0)
                syslog(LOG_ERR, "Can't send event: %s(%d)",
                                                strerror(errno), errno);
 }
@@ -321,7 +303,7 @@ static void connect_request(struct vhci_conn *conn)
 
        write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
 
-       if (write(vdev.fd, buf, ptr - buf) < 0)
+       if (write(vdev.dev_fd, buf, ptr - buf) < 0)
                syslog(LOG_ERR, "Can't send event: %s (%d)",
                                                strerror(errno), errno);
 }
@@ -351,9 +333,11 @@ static void connect_complete(struct vhci_conn *conn)
 
        write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
 
-       if (write(vdev.fd, buf, ptr - buf) < 0)
+       if (write(vdev.dev_fd, buf, ptr - buf) < 0)
                syslog(LOG_ERR, "Can't send event: %s (%d)",
                                                strerror(errno), errno);
+
+       /* TODO: Add io_acl_data() handling */
 }
 
 static void disconn_complete(struct vhci_conn *conn)
@@ -379,7 +363,7 @@ static void disconn_complete(struct vhci_conn *conn)
 
        write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
 
-       if (write(vdev.fd, buf, ptr - buf) < 0)
+       if (write(vdev.dev_fd, buf, ptr - buf) < 0)
                syslog(LOG_ERR, "Can't send event: %s (%d)",
                                                strerror(errno), errno);
 
@@ -409,27 +393,27 @@ static void num_completed_pkts(struct vhci_conn *conn)
 
        write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
 
-       if (write(vdev.fd, buf, ptr - buf) < 0)
+       if (write(vdev.dev_fd, buf, ptr - buf) < 0)
                syslog(LOG_ERR, "Can't send event: %s (%d)",
                                                strerror(errno), errno);
 }
 
 static int scan_enable(uint8_t *data)
 {
+       struct epoll_event scan_event;
        struct sockaddr_in sa;
-       GIOChannel *sk_io;
        bdaddr_t ba;
        int sk, opt;
 
        if (!(*data & SCAN_PAGE)) {
-               if (vdev.scan) {
-                       g_io_channel_shutdown(vdev.scan, TRUE, NULL);
-                       vdev.scan = NULL;
+               if (vdev.scan_fd >= 0) {
+                       close(vdev.scan_fd);
+                       vdev.scan_fd = -1;
                }
                return 0;
        }
 
-       if (vdev.scan)
+       if (vdev.scan_fd >= 0)
                return 0;
 
        if ((sk = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
@@ -444,7 +428,7 @@ static int scan_enable(uint8_t *data)
        baswap(&ba, &vdev.bdaddr);
        sa.sin_family = AF_INET;
        memcpy(&sa.sin_addr.s_addr, &ba, sizeof(sa.sin_addr.s_addr));
-       sa.sin_port = *(uint16_t *) &ba.b[4];
+       memcpy(&sa.sin_port, &ba.b[4], sizeof(sa.sin_port));
        if (bind(sk, (struct sockaddr *) &sa, sizeof(sa))) {
                syslog(LOG_ERR, "Can't bind socket: %s (%d)",
                                                strerror(errno), errno);
@@ -457,9 +441,16 @@ static int scan_enable(uint8_t *data)
                goto failed;
        }
 
-       sk_io = g_io_channel_unix_new(sk);
-       g_io_add_watch(sk_io, G_IO_IN | G_IO_NVAL, io_conn_ind, NULL);
-       vdev.scan = sk_io;
+       memset(&scan_event, 0, sizeof(scan_event));
+       scan_event.events = EPOLLIN;
+       scan_event.data.fd = sk;
+
+       if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sk, &scan_event) < 0) {
+               syslog(LOG_ERR, "Failed to setup scan event watch");
+               goto failed;
+       }
+
+       vdev.scan_fd = sk;
        return 0;
 
 failed:
@@ -476,9 +467,6 @@ static void accept_connection(uint8_t *data)
                return;
 
        connect_complete(conn);
-
-       g_io_add_watch(conn->chan, G_IO_IN | G_IO_NVAL | G_IO_HUP,
-                       io_acl_data, (gpointer) conn);
 }
 
 static void close_connection(struct vhci_conn *conn)
@@ -489,8 +477,7 @@ static void close_connection(struct vhci_conn *conn)
        syslog(LOG_INFO, "Closing connection %s handle %d",
                                        addr, conn->handle);
 
-       g_io_channel_shutdown(conn->chan, TRUE, NULL);
-       g_io_channel_unref(conn->chan);
+       close(conn->fd);
 
        vconn[conn->handle - 1] = NULL;
        disconn_complete(conn);
@@ -554,7 +541,7 @@ do_connect:
        baswap(&ba, &cp->bdaddr);
        sa.sin_family = AF_INET;
        memcpy(&sa.sin_addr.s_addr, &ba, sizeof(sa.sin_addr.s_addr));
-       sa.sin_port = *(uint16_t *) &ba.b[4];
+       memcpy(&sa.sin_port, &ba.b[4], sizeof(sa.sin_port));
        if (connect(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
                syslog(LOG_ERR, "Can't connect: %s (%d)",
                                                strerror(errno), errno);
@@ -582,12 +569,9 @@ do_connect:
 
        vconn[h] = conn;
        conn->handle = h + 1;
-       conn->chan = g_io_channel_unix_new(sk);
+       conn->fd = sk;
 
        connect_complete(conn);
-       g_io_add_watch(conn->chan, G_IO_IN | G_IO_NVAL | G_IO_HUP,
-                               io_acl_data, (gpointer) conn);
-       return;
 }
 
 static void hci_link_control(uint16_t ocf, int plen, uint8_t *data)
@@ -714,14 +698,14 @@ static void hci_host_control(uint16_t ocf, int plen, uint8_t *data)
        case OCF_READ_EXT_INQUIRY_RESPONSE:
                ir.status = 0x00;
                ir.fec = vdev.eir_fec;
-               memcpy(ir.data, vdev.eir_data, 240);
+               memcpy(ir.data, vdev.eir_data, HCI_MAX_EIR_LENGTH);
                command_complete(ogf, ocf, sizeof(ir), &ir);
                break;
 
        case OCF_WRITE_EXT_INQUIRY_RESPONSE:
                status = 0x00;
                vdev.eir_fec = data[0];
-               memcpy(vdev.eir_data, data + 1, 240);
+               memcpy(vdev.eir_data, data + 1, HCI_MAX_EIR_LENGTH);
                command_complete(ogf, ocf, 1, &status);
                break;
 
@@ -796,6 +780,36 @@ static void hci_info_param(uint16_t ocf, int plen, uint8_t *data)
        }
 }
 
+static void hci_status_param(uint16_t ocf, int plen, uint8_t *data)
+{
+       read_local_amp_info_rp ai;
+       uint8_t status;
+
+       const uint16_t ogf = OGF_STATUS_PARAM;
+
+       switch (ocf) {
+       case OCF_READ_LOCAL_AMP_INFO:
+               memset(&ai, 0, sizeof(ai));
+
+               /* BT only */
+               ai.amp_status = 0x01;
+               ai.max_pdu_size = htobl(L2CAP_DEFAULT_MTU);
+               ai.controller_type = HCI_AMP;
+               ai.max_amp_assoc_length = htobl(HCI_MAX_ACL_SIZE);
+               /* No flushing at all */
+               ai.max_flush_timeout = 0xFFFFFFFF;
+               ai.best_effort_flush_timeout = 0xFFFFFFFF;
+
+               command_complete(ogf, ocf, sizeof(ai), &ai);
+               break;
+
+       default:
+               status = 0x01;
+               command_complete(ogf, ocf, 1, &status);
+               break;
+       }
+}
+
 static void hci_command(uint8_t *data)
 {
        hci_command_hdr *ch;
@@ -825,6 +839,10 @@ static void hci_command(uint8_t *data)
        case OGF_INFO_PARAM:
                hci_info_param(ocf, ch->plen, ptr);
                break;
+
+       case OGF_STATUS_PARAM:
+               hci_status_param(ocf, ch->plen, ptr);
+               break;
        }
 }
 
@@ -833,7 +851,6 @@ static void hci_acl_data(uint8_t *data)
        hci_acl_hdr *ah = (void *) data;
        struct vhci_conn *conn;
        uint16_t handle;
-       int fd;
 
        handle = acl_handle(btohs(ah->handle));
 
@@ -842,8 +859,7 @@ static void hci_acl_data(uint8_t *data)
                return;
        }
 
-       fd = g_io_channel_unix_get_fd(conn->chan);
-       if (write_n(fd, data, btohs(ah->dlen) + HCI_ACL_HDR_SIZE) < 0) {
+       if (write_n(conn->fd, data, btohs(ah->dlen) + HCI_ACL_HDR_SIZE) < 0) {
                close_connection(conn);
                return;
        }
@@ -855,39 +871,28 @@ static void hci_acl_data(uint8_t *data)
        }
 }
 
-static gboolean io_acl_data(GIOChannel *chan, GIOCondition cond, gpointer data)
+#if 0
+static void io_acl_data(void *data)
 {
-       struct vhci_conn *conn = (struct vhci_conn *) data;
+       struct vhci_conn *conn = data;
        unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;
        hci_acl_hdr *ah;
        uint16_t flags;
-       int fd, err, len;
-
-       if (cond & G_IO_NVAL) {
-               g_io_channel_unref(chan);
-               return FALSE;
-       }
-
-       if (cond & G_IO_HUP) {
-               close_connection(conn);
-               return FALSE;
-       }
-
-       fd = g_io_channel_unix_get_fd(chan);
+       int len;
 
        ptr = buf + 1;
-       if (read_n(fd, ptr, HCI_ACL_HDR_SIZE) <= 0) {
+       if (read_n(conn->fd, ptr, HCI_ACL_HDR_SIZE) <= 0) {
                close_connection(conn);
-               return FALSE;
+               return;
        }
 
        ah = (void *) ptr;
        ptr += HCI_ACL_HDR_SIZE;
 
        len = btohs(ah->dlen);
-       if (read_n(fd, ptr, len) <= 0) {
+       if (read_n(conn->fd, ptr, len) <= 0) {
                close_connection(conn);
-               return FALSE;
+               return;
        }
 
        buf[0] = HCI_ACLDATA_PKT;
@@ -898,37 +903,32 @@ static gboolean io_acl_data(GIOChannel *chan, GIOCondition cond, gpointer data)
 
        write_snoop(vdev.dd, HCI_ACLDATA_PKT, 1, buf, len);
 
-       err = write(vdev.fd, buf, len);
-
-       return TRUE;
+       if (write(vdev.dev_fd, buf, len) < 0)
+               syslog(LOG_ERR, "ACL data write error");
 }
+#endif
 
-static gboolean io_conn_ind(GIOChannel *chan, GIOCondition cond, gpointer data)
+static void io_conn_ind(void)
 {
        struct vhci_link_info info;
        struct vhci_conn *conn;
        struct sockaddr_in sa;
        socklen_t len;
-       int sk, nsk, h;
-
-       if (cond & G_IO_NVAL)
-               return FALSE;
-
-       sk = g_io_channel_unix_get_fd(chan);
+       int nsk, h;
 
        len = sizeof(sa);
-       if ((nsk = accept(sk, (struct sockaddr *) &sa, &len)) < 0)
-               return TRUE;
+       if ((nsk = accept(vdev.scan_fd, (struct sockaddr *) &sa, &len)) < 0)
+               return;
 
        if (read_n(nsk, &info, sizeof(info)) < 0) {
                syslog(LOG_ERR, "Can't read link info");
-               return TRUE;
+               return;
        }
 
        if (!(conn = malloc(sizeof(*conn)))) {
                syslog(LOG_ERR, "Can't alloc new connection");
                close(nsk);
-               return TRUE;
+               return;
        }
 
        bacpy(&conn->dest, &info.bdaddr);
@@ -940,37 +940,31 @@ static gboolean io_conn_ind(GIOChannel *chan, GIOCondition cond, gpointer data)
        syslog(LOG_ERR, "Too many connections");
        free(conn);
        close(nsk);
-       return TRUE;
+       return;
 
 accepted:
        vconn[h] = conn;
        conn->handle = h + 1;
-       conn->chan = g_io_channel_unix_new(nsk);
+       conn->fd = nsk;
        connect_request(conn);
-
-       return TRUE;
 }
 
-static gboolean io_hci_data(GIOChannel *chan, GIOCondition cond, gpointer data)
+static void io_hci_data(void)
 {
        unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;
        int type;
        ssize_t len;
-       int fd;
 
        ptr = buf;
 
-       fd = g_io_channel_unix_get_fd(chan);
-
-       len = read(fd, buf, sizeof(buf));
+       len = read(vdev.dev_fd, buf, sizeof(buf));
        if (len < 0) {
                if (errno == EAGAIN)
-                       return TRUE;
+                       return;
 
                syslog(LOG_ERR, "Read failed: %s (%d)", strerror(errno), errno);
-               g_io_channel_unref(chan);
-               g_main_loop_quit(event_loop);
-               return FALSE;
+               __io_canceled = 1;
+               return;
        }
 
        type = *ptr++;
@@ -990,8 +984,6 @@ static gboolean io_hci_data(GIOChannel *chan, GIOCondition cond, gpointer data)
                syslog(LOG_ERR, "Unknown packet type 0x%2.2x", type);
                break;
        }
-
-       return TRUE;
 }
 
 static int getbdaddrbyname(char *str, bdaddr_t *ba)
@@ -1011,22 +1003,13 @@ static int getbdaddrbyname(char *str, bdaddr_t *ba)
                return 0;
        }
 
-       if (n == 1) {
-               /* IP address + port */
-               struct hostent *hent;
+       if (n == 0) {
+               /* loopback port */
+               in_addr_t addr = INADDR_LOOPBACK;
                bdaddr_t b;
-               char *ptr;
 
-               ptr = strchr(str, ':');
-               *ptr++ = 0;
-
-               if (!(hent = gethostbyname(str))) {
-                       fprintf(stderr, "Can't resolve %s\n", str);
-                       return -2;
-               }
-
-               memcpy(&b, hent->h_addr, 4);
-               *(uint16_t *) (&b.b[4]) = htons(atoi(ptr));
+               memcpy(&b, &addr, 4);
+               *(uint16_t *) (&b.b[4]) = htons(atoi(str));
                baswap(ba, &b);
 
                return 0;
@@ -1037,181 +1020,53 @@ static int getbdaddrbyname(char *str, bdaddr_t *ba)
        return -1;
 }
 
-static void rewrite_bdaddr(unsigned char *buf, int len, bdaddr_t *bdaddr)
-{
-       hci_event_hdr *eh;
-       unsigned char *ptr = buf;
-       int type;
-
-       if (!bdaddr)
-               return;
-
-       if (!bacmp(bdaddr, BDADDR_ANY))
-               return;
-
-       type = *ptr++;
-
-       switch (type) {
-       case HCI_EVENT_PKT:
-               eh = (hci_event_hdr *) ptr;
-               ptr += HCI_EVENT_HDR_SIZE;
-
-               if (eh->evt == EVT_CMD_COMPLETE) {
-                       evt_cmd_complete *cc = (void *) ptr;
-
-                       ptr += EVT_CMD_COMPLETE_SIZE;
-
-                       if (cc->opcode == htobs(cmd_opcode_pack(OGF_INFO_PARAM,
-                                               OCF_READ_BD_ADDR))) {
-                               bacpy((bdaddr_t *) (ptr + 1), bdaddr);
-                       }
-               }
-               break;
-       }
-}
-
-static int run_proxy(int fd, int dev, bdaddr_t *bdaddr)
-{
-       unsigned char buf[HCI_MAX_FRAME_SIZE + 1];
-       struct hci_dev_info di;
-       struct hci_filter flt;
-       struct pollfd p[2];
-       int dd, err, len, need_raw;
-
-       dd = hci_open_dev(dev);
-       if (dd < 0) {
-               syslog(LOG_ERR, "Can't open device hci%d: %s (%d)",
-                                               dev, strerror(errno), errno);
-               return 1;
-       }
-
-       if (hci_devinfo(dev, &di) < 0) {
-               syslog(LOG_ERR, "Can't get device info for hci%d: %s (%d)",
-                                               dev, strerror(errno), errno);
-               hci_close_dev(dd);
-               return 1;
-       }
-
-       need_raw = !hci_test_bit(HCI_RAW, &di.flags);
-
-       hci_filter_clear(&flt);
-       hci_filter_all_ptypes(&flt);
-       hci_filter_all_events(&flt);
-
-       if (setsockopt(dd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
-               syslog(LOG_ERR, "Can't set filter for hci%d: %s (%d)",
-                                               dev, strerror(errno), errno);
-               hci_close_dev(dd);
-               return 1;
-       }
-
-       if (need_raw) {
-               if (ioctl(dd, HCISETRAW, 1) < 0) {
-                       syslog(LOG_ERR, "Can't set raw mode on hci%d: %s (%d)",
-                                               dev, strerror(errno), errno);
-                       hci_close_dev(dd);
-                       return 1;
-               }
-       }
-
-       p[0].fd = fd;
-       p[0].events = POLLIN;
-       p[1].fd = dd;
-       p[1].events = POLLIN;
-
-       while (!__io_canceled) {
-               p[0].revents = 0;
-               p[1].revents = 0;
-               err = poll(p, 2, 500);
-               if (err < 0)
-                       break;
-               if (!err)
-                       continue;
-
-               if (p[0].revents & POLLIN) {
-                       len = read(fd, buf, sizeof(buf));
-                       if (len > 0) {
-                               rewrite_bdaddr(buf, len, bdaddr);
-                               err = write(dd, buf, len);
-                       }
-               }
-
-               if (p[1].revents & POLLIN) {
-                       len = read(dd, buf, sizeof(buf));
-                       if (len > 0) {
-                               rewrite_bdaddr(buf, len, bdaddr);
-                               err = write(fd, buf, len);
-                       }
-               }
-       }
-
-       if (need_raw) {
-               if (ioctl(dd, HCISETRAW, 0) < 0)
-                       syslog(LOG_ERR, "Can't clear raw mode on hci%d: %s (%d)",
-                                               dev, strerror(errno), errno);
-       }
-
-       hci_close_dev(dd);
-
-       syslog(LOG_INFO, "Exit");
-
-       return 0;
-}
-
 static void usage(void)
 {
        printf("hciemu - HCI emulator ver %s\n", VERSION);
        printf("Usage: \n");
-       printf("\thciemu [options] local_address\n"
+       printf("\thciemu [options] port_number\n"
                "Options:\n"
-               "\t[-d device] use specified device\n"
-               "\t[-b bdaddr] emulate specified address\n"
+               "\t[-d device] use specified device node\n"
                "\t[-s file] create snoop file\n"
                "\t[-n] do not detach\n"
                "\t[-h] help, you are looking at it\n");
 }
 
-static struct option main_options[] = {
+static const struct option options[] = {
        { "device",     1, 0, 'd' },
        { "bdaddr",     1, 0, 'b' },
        { "snoop",      1, 0, 's' },
        { "nodetach",   0, 0, 'n' },
        { "help",       0, 0, 'h' },
-       { }
+       { }
 };
 
 int main(int argc, char *argv[])
 {
+       int exitcode = EXIT_FAILURE;
        struct sigaction sa;
-       GIOChannel *dev_io;
        char *device = NULL, *snoop = NULL;
-       bdaddr_t bdaddr;
-       int fd, dd, opt, detach = 1, dev = -1;
-
-       bacpy(&bdaddr, BDADDR_ANY);
+       int device_fd;
+       struct epoll_event device_event;
+       int dd, opt, detach = 1;
 
-       while ((opt=getopt_long(argc, argv, "d:b:s:nh", main_options, NULL)) != EOF) {
+       while ((opt=getopt_long(argc, argv, "d:s:nh", options, NULL)) != EOF) {
                switch(opt) {
                case 'd':
                        device = strdup(optarg);
                        break;
-
-               case 'b':
-                       str2ba(optarg, &bdaddr);
-                       break;
-
                case 's':
                        snoop = strdup(optarg);
                        break;
-
                case 'n':
                        detach = 0;
                        break;
-
                case 'h':
-               default:
                        usage();
                        exit(0);
+               default:
+                       usage();
+                       exit(1);
                }
        }
 
@@ -1224,16 +1079,8 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
-       if (strlen(argv[0]) > 3 && !strncasecmp(argv[0], "hci", 3)) {
-               dev = hci_devid(argv[0]);
-               if (dev < 0) {
-                       perror("Invalid device");
-                       exit(1);
-               }
-       } else {
-               if (getbdaddrbyname(argv[0], &vdev.bdaddr) < 0)
-                       exit(1);
-       }
+       if (getbdaddrbyname(argv[0], &vdev.bdaddr) < 0)
+               exit(1);
 
        if (detach) {
                if (daemon(0, 0)) {
@@ -1256,33 +1103,20 @@ int main(int argc, char *argv[])
        sigaction(SIGTERM, &sa, NULL);
        sigaction(SIGINT,  &sa, NULL);
 
-       io_init();
-
-       if (!device && dev >= 0)
-               device = strdup(GHCI_DEV);
+       if (!device)
+               device = strdup(VHCI_DEV);
 
        /* Open and create virtual HCI device */
-       if (device) {
-               fd = open(device, O_RDWR);
-               if (fd < 0) {
-                       syslog(LOG_ERR, "Can't open device %s: %s (%d)",
-                                               device, strerror(errno), errno);
-                       free(device);
-                       exit(1);
-               }
+       device_fd = open(device, O_RDWR);
+       if (device_fd < 0) {
+               syslog(LOG_ERR, "Can't open device %s: %s (%d)",
+                                       device, strerror(errno), errno);
                free(device);
-       } else {
-               fd = open(VHCI_DEV, O_RDWR);
-               if (fd < 0) {
-                       fd = open(VHCI_UDEV, O_RDWR);
-                       if (fd < 0) {
-                               syslog(LOG_ERR, "Can't open device %s: %s (%d)",
-                                               VHCI_DEV, strerror(errno), errno);
-                               exit(1);
-                       }
-               }
+               return exitcode;
        }
 
+       free(device);
+
        /* Create snoop file */
        if (snoop) {
                dd = create_snoop(snoop);
@@ -1294,10 +1128,11 @@ int main(int argc, char *argv[])
                dd = -1;
 
        /* Create event loop */
-       event_loop = g_main_loop_new(NULL, FALSE);
-
-       if (dev >= 0)
-               return run_proxy(fd, dev, &bdaddr);
+       epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+       if (epoll_fd < 0) {
+               perror("Failed to create epoll descriptor");
+               goto close_device;
+       }
 
        /* Device settings */
        vdev.features[0] = 0xff;
@@ -1321,23 +1156,53 @@ int main(int argc, char *argv[])
        vdev.eir_fec = 0x00;
        memset(vdev.eir_data, 0, sizeof(vdev.eir_data));
 
-       vdev.fd = fd;
+       vdev.dev_fd = device_fd;
        vdev.dd = dd;
 
-       dev_io = g_io_channel_unix_new(fd);
-       g_io_add_watch(dev_io, G_IO_IN, io_hci_data, NULL);
+       memset(&device_event, 0, sizeof(device_event));
+       device_event.events = EPOLLIN;
+       device_event.data.fd = device_fd;
+
+       if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, device_fd, &device_event) < 0) {
+               perror("Failed to setup device event watch");
+               goto close_device;
+       }
 
        setpriority(PRIO_PROCESS, 0, -19);
 
        /* Start event processor */
-       g_main_loop_run(event_loop);
+       for (;;) {
+               struct epoll_event events[MAX_EPOLL_EVENTS];
+               int n, nfds;
+
+               if (__io_canceled)
+                       break;
 
-       close(fd);
+               nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, -1);
+               if (nfds < 0)
+                       continue;
+
+               for (n = 0; n < nfds; n++) {
+                       if (events[n].data.fd == vdev.dev_fd)
+                               io_hci_data();
+                       else if (events[n].data.fd == vdev.scan_fd)
+                               io_conn_ind();
+               }
+       }
+
+       exitcode = EXIT_SUCCESS;
+
+       epoll_ctl(epoll_fd, EPOLL_CTL_DEL, device_fd, NULL);
+
+close_device:
+       close(device_fd);
 
        if (dd >= 0)
                close(dd);
 
+       close(epoll_fd);
+
        syslog(LOG_INFO, "Exit");
 
-       return 0;
+       return exitcode;
 }
index 08f2257..ac68059 100644 (file)
@@ -159,7 +159,7 @@ int main(int argc, char *argv[])
 
        char *filename;
        mode_t filemode;
-       int err, mode = 0;
+       int mode = 0;
        int dd, rd, sd, fd;
        uint16_t sco_handle, sco_mtu, vs;
 
@@ -244,8 +244,10 @@ int main(int argc, char *argv[])
 
        fprintf(stderr, "SCO audio channel connected (handle %d, mtu %d)\n", sco_handle, sco_mtu);
 
-       if (mode == RECORD)
-               err = write(rd, "RING\r\n", 6);
+       if (mode == RECORD) {
+               if (write(rd, "RING\r\n", 6) < 0)
+                       return -errno;
+       }
 
        maxfd = (rd > sd) ? rd : sd;
 
diff --git a/test/ipctest-a2dp-easy.test b/test/ipctest-a2dp-easy.test
new file mode 100644 (file)
index 0000000..ba62d93
--- /dev/null
@@ -0,0 +1,8 @@
+profile a2dp
+init_bt
+init_profile
+start_stream
+sleep 2
+stop_stream
+quit
+
diff --git a/test/ipctest-a2dp-resume-fast.test b/test/ipctest-a2dp-resume-fast.test
new file mode 100644 (file)
index 0000000..bbc99e2
--- /dev/null
@@ -0,0 +1,82 @@
+#!./ipctest
+
+profile a2dp
+init_bt
+
+init_profile
+
+start_stream
+sleep 1
+stop_stream
+
+stop_stream
+start_stream
+
+stop_stream
+start_stream
+
+stop_stream
+start_stream
+
+stop_stream
+start_stream
+
+stop_stream
+start_stream
+
+stop_stream
+stop_stream
+stop_stream
+
+start_stream
+start_stream
+start_stream
+
+stop_stream
+
+sleep 1
+
+start_stream
+start_stream
+start_stream
+stop_stream
+stop_stream
+
+start_stream
+sleep 1
+stop_stream
+
+start_stream
+stop_stream
+
+start_stream
+stop_stream
+
+shutdown_bt
+
+init_bt
+
+init_profile
+
+start_stream
+stop_stream
+stop_stream
+start_stream
+stop_stream
+start_stream
+stop_stream
+start_stream
+stop_stream
+start_stream
+stop_stream
+start_stream
+stop_stream
+stop_stream
+stop_stream
+
+start_stream
+start_stream
+start_stream
+stop_stream
+
+quit
diff --git a/test/ipctest-hsp-a2dp-switch.test b/test/ipctest-hsp-a2dp-switch.test
new file mode 100644 (file)
index 0000000..e99878f
--- /dev/null
@@ -0,0 +1,50 @@
+init_bt
+
+profile a2dp
+init_profile
+start_stream
+sleep 2
+stop_stream
+start_stream
+sleep 2
+stop_stream
+
+shutdown_bt
+init_bt
+
+profile hsp
+init_profile
+start_stream
+sleep 2
+stop_stream
+start_stream
+sleep 2
+stop_stream
+
+shutdown_bt
+init_bt
+
+profile a2dp
+init_profile
+start_stream
+sleep 2
+stop_stream
+start_stream
+sleep 2
+stop_stream
+
+shutdown_bt
+init_bt
+
+profile hsp
+init_profile
+start_stream
+sleep 2
+stop_stream
+start_stream
+sleep 2
+stop_stream
+
+shutdown_bt
+
+quit
diff --git a/test/ipctest-hsp-easy.test b/test/ipctest-hsp-easy.test
new file mode 100644 (file)
index 0000000..0756a78
--- /dev/null
@@ -0,0 +1,7 @@
+profile hsp
+init_bt
+init_profile
+start_stream
+sleep 2
+stop_stream
+quit
diff --git a/test/ipctest-init-shutdown.test b/test/ipctest-init-shutdown.test
new file mode 100644 (file)
index 0000000..578883a
--- /dev/null
@@ -0,0 +1,59 @@
+#!./ipctest
+
+init_bt
+shutdown_bt
+
+init_bt
+shutdown_bt
+
+init_bt
+shutdown_bt
+
+init_bt
+shutdown_bt
+
+init_bt
+shutdown_bt
+
+init_bt
+shutdown_bt
+
+init_bt
+shutdown_bt
+
+init_bt
+shutdown_bt
+
+init_bt
+shutdown_bt
+
+init_bt
+shutdown_bt
+
+init_bt
+shutdown_bt
+
+
+init_bt
+sleep 1
+shutdown_bt
+
+init_bt
+sleep 1
+shutdown_bt
+
+init_bt
+sleep 1
+shutdown_bt
+
+init_bt
+shutdown_bt
+
+init_bt
+shutdown_bt
+
+init_bt
+shutdown_bt
+
+quit
+
index 9fdfac4..cbfd78d 100644 (file)
@@ -139,7 +139,7 @@ static int service_send(struct userdata *u, const bt_audio_msg_header_t *msg)
        else {
                err = -errno;
                ERR("Error sending data to audio service: %s(%d)",
-                       strerror(errno), errno);
+                       strerror(-err), -err);
        }
 
        return err;
@@ -171,7 +171,7 @@ static int service_recv(struct userdata *u, bt_audio_msg_header_t *rsp)
        } else {
                err = -errno;
                ERR("Error receiving data from audio service: %s(%d)",
-                       strerror(errno), errno);
+                       strerror(-err), -err);
        }
 
        return err;
@@ -214,9 +214,13 @@ static int init_bt(struct userdata *u)
        DBG("bt_audio_service_open");
 
        u->service_fd = bt_audio_service_open();
-       if (u->service_fd <= 0) {
-               perror(strerror(errno));
-               return errno;
+       if (u->service_fd < 0) {
+               int err = -errno;
+
+               ERR("bt_audio_service_open() failed: %s (%d)", strerror(-err),
+                                                                       -err);
+
+               return err;
        }
 
        return 0;
index 3ac332f..c5bc3d3 100644 (file)
@@ -97,7 +97,10 @@ static int num_frames = -1;
 static int count = 1;
 
 /* Default delay after sending count number of frames */
-static unsigned long delay = 0;
+static unsigned long send_delay = 0;
+
+/* Default delay before receiving */
+static unsigned long recv_delay = 0;
 
 static char *filename = NULL;
 
@@ -111,6 +114,32 @@ static int linger = 0;
 static int reliable = 0;
 static int timestamp = 0;
 static int defer_setup = 0;
+static int priority = -1;
+static int rcvbuf = 0;
+
+static struct {
+       char    *name;
+       int     flag;
+} l2cap_modes[] = {
+       { "basic",      L2CAP_MODE_BASIC        },
+       /* Not implemented
+       { "flowctl",    L2CAP_MODE_FLOWCTL      },
+       { "retrans",    L2CAP_MODE_RETRANS      },
+       */
+       { "ertm",       L2CAP_MODE_ERTM         },
+       { "streaming",  L2CAP_MODE_STREAMING    },
+       { 0 }
+};
+
+static void list_l2cap_modes(void)
+{
+       int i;
+
+       printf("l2test - L2CAP testing\n"
+               "List L2CAP modes:\n");
+       for (i=0; l2cap_modes[i].name; i++)
+               printf("\t%s\n", l2cap_modes[i].name);
+}
 
 static float tv2fl(struct timeval tv)
 {
@@ -284,6 +313,21 @@ static int do_connect(char *svr)
                goto error;
        }
 
+       /* Set receive buffer size */
+       if (rcvbuf && setsockopt(sk, SOL_SOCKET, SO_RCVBUF,
+                                               &rcvbuf, sizeof(rcvbuf)) < 0) {
+               syslog(LOG_ERR, "Can't set socket rcv buf size: %s (%d)",
+                                                       strerror(errno), errno);
+               goto error;
+       }
+
+       optlen = sizeof(rcvbuf);
+       if (getsockopt(sk, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &optlen) < 0) {
+               syslog(LOG_ERR, "Can't get socket rcv buf size: %s (%d)",
+                                                       strerror(errno), errno);
+               goto error;
+       }
+
        /* Connect to remote device */
        memset(&addr, 0, sizeof(addr));
        addr.l2_family = AF_BLUETOOTH;
@@ -321,10 +365,24 @@ static int do_connect(char *svr)
                goto error;
        }
 
+       if (priority > 0 && setsockopt(sk, SOL_SOCKET, SO_PRIORITY, &priority,
+                                               sizeof(priority)) < 0) {
+               syslog(LOG_ERR, "Can't set socket priority: %s (%d)",
+                                                       strerror(errno), errno);
+               goto error;
+       }
+
+       if (getsockopt(sk, SOL_SOCKET, SO_PRIORITY, &opt, &optlen) < 0) {
+               syslog(LOG_ERR, "Can't get socket priority: %s (%d)",
+                                                       strerror(errno), errno);
+               goto error;
+       }
+
        syslog(LOG_INFO, "Connected [imtu %d, omtu %d, flush_to %d, "
-                               "mode %d, handle %d, class 0x%02x%02x%02x]",
+               "mode %d, handle %d, class 0x%02x%02x%02x, priority %d, rcvbuf %d]",
                opts.imtu, opts.omtu, opts.flush_to, opts.mode, conn.hci_handle,
-               conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
+               conn.dev_class[2], conn.dev_class[1], conn.dev_class[0], opt,
+               rcvbuf);
 
        omtu = (opts.omtu > buffer_size) ? buffer_size : opts.omtu;
        imtu = (opts.imtu > buffer_size) ? buffer_size : opts.imtu;
@@ -430,6 +488,7 @@ static void do_listen(void (*handler)(int sk))
                goto error;
        }
 
+
        /* Listen for connections */
        if (listen(sk, 10)) {
                syslog(LOG_ERR, "Can not listen on the socket: %s (%d)",
@@ -470,6 +529,22 @@ static void do_listen(void (*handler)(int sk))
                /* Child */
                close(sk);
 
+               /* Set receive buffer size */
+               if (rcvbuf && setsockopt(nsk, SOL_SOCKET, SO_RCVBUF, &rcvbuf,
+                                                       sizeof(rcvbuf)) < 0) {
+                       syslog(LOG_ERR, "Can't set rcv buf size: %s (%d)",
+                                                       strerror(errno), errno);
+                       goto error;
+               }
+
+               optlen = sizeof(rcvbuf);
+               if (getsockopt(nsk, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &optlen)
+                                                                       < 0) {
+                       syslog(LOG_ERR, "Can't get rcv buf size: %s (%d)",
+                                                       strerror(errno), errno);
+                       goto error;
+               }
+
                /* Get current options */
                memset(&opts, 0, sizeof(opts));
                optlen = sizeof(opts);
@@ -496,11 +571,29 @@ static void do_listen(void (*handler)(int sk))
                        }
                }
 
+               if (priority > 0 && setsockopt(sk, SOL_SOCKET, SO_PRIORITY,
+                                       &priority, sizeof(priority)) < 0) {
+                       syslog(LOG_ERR, "Can't set socket priority: %s (%d)",
+                                               strerror(errno), errno);
+                       close(nsk);
+                       goto error;
+               }
+
+               optlen = sizeof(priority);
+               if (getsockopt(nsk, SOL_SOCKET, SO_PRIORITY, &opt, &optlen) < 0) {
+                       syslog(LOG_ERR, "Can't get socket priority: %s (%d)",
+                                                       strerror(errno), errno);
+                       goto error;
+               }
+
                ba2str(&addr.l2_bdaddr, ba);
-               syslog(LOG_INFO, "Connect from %s [imtu %d, omtu %d, flush_to %d, "
-                                       "mode %d, handle %d, class 0x%02x%02x%02x]",
-                       ba, opts.imtu, opts.omtu, opts.flush_to, opts.mode, conn.hci_handle,
-                       conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
+               syslog(LOG_INFO, "Connect from %s [imtu %d, omtu %d, "
+                               "flush_to %d, mode %d, handle %d, "
+                               "class 0x%02x%02x%02x, priority %d, rcvbuf %d]",
+                               ba, opts.imtu, opts.omtu, opts.flush_to,
+                               opts.mode, conn.hci_handle, conn.dev_class[2],
+                               conn.dev_class[1], conn.dev_class[0], opt,
+                               rcvbuf);
 
                omtu = (opts.omtu > buffer_size) ? buffer_size : opts.omtu;
                imtu = (opts.imtu > buffer_size) ? buffer_size : opts.imtu;
@@ -632,6 +725,9 @@ static void recv_mode(int sk)
                        syslog(LOG_INFO, "Initial bytes %d", len);
        }
 
+       if (recv_delay)
+               usleep(recv_delay);
+
        syslog(LOG_INFO, "Receiving ...");
 
        memset(ts, 0, sizeof(ts));
@@ -775,8 +871,8 @@ static void do_send(int sk)
                        size -= len;
                }
 
-               if (num_frames && delay && count && !(seq % count))
-                       usleep(delay);
+               if (num_frames && send_delay && count && !(seq % count))
+                       usleep(send_delay);
        }
 }
 
@@ -948,25 +1044,25 @@ static void info_request(char *svr)
        case 0x0000:
                memcpy(&mask, rsp->data, sizeof(mask));
                printf("Extended feature mask is 0x%04x\n", btohl(mask));
-               if (mask & 0x01)
+               if (mask & L2CAP_FEAT_FLOWCTL)
                        printf("  Flow control mode\n");
-               if (mask & 0x02)
+               if (mask & L2CAP_FEAT_RETRANS)
                        printf("  Retransmission mode\n");
-               if (mask & 0x04)
+               if (mask & L2CAP_FEAT_BIDIR_QOS)
                        printf("  Bi-directional QoS\n");
-               if (mask & 0x08)
+               if (mask & L2CAP_FEAT_ERTM)
                        printf("  Enhanced Retransmission mode\n");
-               if (mask & 0x10)
+               if (mask & L2CAP_FEAT_STREAMING)
                        printf("  Streaming mode\n");
-               if (mask & 0x20)
+               if (mask & L2CAP_FEAT_FCS)
                        printf("  FCS Option\n");
-               if (mask & 0x40)
+               if (mask & L2CAP_FEAT_EXT_FLOW)
                        printf("  Extended Flow Specification\n");
-               if (mask & 0x80)
+               if (mask & L2CAP_FEAT_FIXED_CHAN)
                        printf("  Fixed Channels\n");
-               if (mask & 0x0100)
+               if (mask & L2CAP_FEAT_EXT_WINDOW)
                        printf("  Extended Window Size\n");
-               if (mask & 0x0200)
+               if (mask & L2CAP_FEAT_UCD)
                        printf("  Unicast Connectionless Data Reception\n");
                break;
        case 0x0001:
@@ -1083,10 +1179,13 @@ static void usage(void)
                "\t[-N num] send num frames (default = infinite)\n"
                "\t[-C num] send num frames before delay (default = 1)\n"
                "\t[-D milliseconds] delay after sending num frames (default = 0)\n"
-               "\t[-X mode] select retransmission/flow-control mode\n"
+               "\t[-K milliseconds] delay before receiving (default = 0)\n"
+               "\t[-X mode] l2cap mode (help for list, default = basic)\n"
                "\t[-F fcs] use CRC16 check (default = 1)\n"
                "\t[-Q num] Max Transmit value (default = 3)\n"
                "\t[-Z size] Transmission Window size (default = 63)\n"
+               "\t[-Y priority] socket priority\n"
+               "\t[-H size] Maximum receive buffer size\n"
                "\t[-R] reliable mode\n"
                "\t[-G] use connectionless channel (datagram)\n"
                "\t[-U] use sock stream\n"
@@ -1100,11 +1199,11 @@ static void usage(void)
 int main(int argc, char *argv[])
 {
        struct sigaction sa;
-       int opt, sk, mode = RECV, need_addr = 0;
+       int opt, sk, i, mode = RECV, need_addr = 0;
 
        bacpy(&bdaddr, BDADDR_ANY);
 
-       while ((opt=getopt(argc,argv,"rdscuwmntqxyzpb:i:P:I:O:J:B:N:L:W:C:D:X:F:Q:Z:RUGAESMT")) != EOF) {
+       while ((opt=getopt(argc,argv,"rdscuwmntqxyzpb:i:P:I:O:J:B:N:L:W:C:D:X:F:Q:Z:Y:H:K:RUGAESMT")) != EOF) {
                switch(opt) {
                case 'r':
                        mode = RECV;
@@ -1214,14 +1313,29 @@ int main(int argc, char *argv[])
                        break;
 
                case 'D':
-                       delay = atoi(optarg) * 1000;
+                       send_delay = atoi(optarg) * 1000;
+                       break;
+
+               case 'K':
+                       recv_delay = atoi(optarg) * 1000;
                        break;
 
                case 'X':
-                       if (strcasecmp(optarg, "ertm") == 0)
-                               rfcmode = L2CAP_MODE_ERTM;
-                       else
-                               rfcmode = atoi(optarg);
+                       rfcmode = -1;
+
+                       for (i = 0; l2cap_modes[i].name; i++)
+                               if (!strcasecmp(l2cap_modes[i].name, optarg))
+                                       rfcmode = l2cap_modes[i].flag;
+
+                       if (!strcasecmp(optarg, "help") || rfcmode == -1) {
+                               list_l2cap_modes();
+                               exit(1);
+                       }
+
+                       break;
+
+               case 'Y':
+                       priority = atoi(optarg);
                        break;
 
                case 'F':
@@ -1272,6 +1386,10 @@ int main(int argc, char *argv[])
                        cid = atoi(optarg);
                        break;
 
+               case 'H':
+                       rcvbuf = atoi(optarg);
+                       break;
+
                default:
                        usage();
                        exit(1);
index 9120714..cb564be 100755 (executable)
@@ -67,6 +67,12 @@ for i in adapter_list:
                                print "        %s = %s" % (key, list)
                        elif (key == "Class"):
                                print "        %s = 0x%06x" % (key, value)
+                       elif (key == "Vendor"):
+                               print "        %s = 0x%04x" % (key, value)
+                       elif (key == "Product"):
+                               print "        %s = 0x%04x" % (key, value)
+                       elif (key == "Version"):
+                               print "        %s = 0x%04x" % (key, value)
                        else:
                                print "        %s = %s" % (key, value)
 
diff --git a/test/mpris-player.c b/test/mpris-player.c
new file mode 100644 (file)
index 0000000..a2c4cc6
--- /dev/null
@@ -0,0 +1,993 @@
+/*
+ *
+ *  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 <dbus/dbus.h>
+#include <glib.h>
+
+static volatile sig_atomic_t __io_canceled = 0;
+static volatile sig_atomic_t __io_terminated = 0;
+static char *adapter = NULL;
+static DBusConnection *sys = NULL;
+static DBusConnection *session = NULL;
+
+static void sig_term(int sig)
+{
+       __io_canceled = 1;
+}
+
+static DBusMessage *get_all(DBusConnection *conn, const char *name)
+{
+       DBusMessage *msg, *reply;
+       DBusError err;
+       const char *iface = "org.mpris.MediaPlayer2.Player";
+
+       msg = dbus_message_new_method_call(name, "/org/mpris/MediaPlayer2",
+                                       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) {
+               fprintf(stderr, "Can't get default adapter\n");
+               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 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);
+
+       append_variant(&entry, type, val);
+
+       dbus_message_iter_close_container(dict, &entry);
+}
+
+static dbus_bool_t emit_property_changed(DBusConnection *conn,
+                                       const char *path,
+                                       const char *interface,
+                                       const char *name,
+                                       int type, void *value)
+{
+       DBusMessage *signal;
+       DBusMessageIter iter;
+       dbus_bool_t result;
+
+       signal = dbus_message_new_signal(path, interface, "PropertyChanged");
+
+       if (!signal) {
+               fprintf(stderr, "Unable to allocate new %s.PropertyChanged"
+                                                       " signal", interface);
+               return FALSE;
+       }
+
+       dbus_message_iter_init_append(signal, &iter);
+
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
+
+       append_variant(&iter, type, value);
+
+       result = dbus_connection_send(conn, signal, NULL);
+       dbus_message_unref(signal);
+
+       return result;
+}
+
+static int parse_property(DBusConnection *conn, const char *path,
+                                               const char *key,
+                                               DBusMessageIter *entry,
+                                               DBusMessageIter *properties)
+{
+       DBusMessageIter var;
+
+       printf("property %s found\n", key);
+
+       if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
+               return -EINVAL;
+
+       dbus_message_iter_recurse(entry, &var);
+
+       if (strcasecmp(key, "PlaybackStatus") == 0) {
+               const char *value;
+
+               if (dbus_message_iter_get_arg_type(&var) !=
+                                                       DBUS_TYPE_STRING)
+                       return -EINVAL;
+
+               dbus_message_iter_get_basic(&var, &value);
+
+               if (properties)
+                       dict_append_entry(properties, "Status",
+                                               DBUS_TYPE_STRING, &value);
+               else
+                       emit_property_changed(sys, path,
+                                       "org.bluez.MediaPlayer", "Status",
+                                       DBUS_TYPE_STRING, &value);
+       } else if (strcasecmp(key, "Position") == 0) {
+               int64_t usec, msec;
+
+               if (dbus_message_iter_get_arg_type(&var) !=
+                                                       DBUS_TYPE_INT64)
+                       return -EINVAL;
+
+               dbus_message_iter_get_basic(&var, &usec);
+               msec = usec / 1000;
+
+               if (properties)
+                       dict_append_entry(properties, "Position",
+                                               DBUS_TYPE_UINT32, &msec);
+               else
+                       emit_property_changed(sys, path,
+                                       "org.bluez.MediaPlayer", "Position",
+                                       DBUS_TYPE_UINT32, &msec);
+       } else if (strcasecmp(key, "Shuffle") == 0) {
+               dbus_bool_t value;
+               const char *str;
+
+               if (dbus_message_iter_get_arg_type(&var) !=
+                                                       DBUS_TYPE_BOOLEAN)
+                       return -EINVAL;
+
+               dbus_message_iter_get_basic(&var, &value);
+
+               str = value ? "on" : "off";
+               if (properties)
+                       dict_append_entry(properties, "Shuffle",
+                                               DBUS_TYPE_STRING, &str);
+               else
+                       emit_property_changed(sys, path,
+                                       "org.bluez.MediaPlayer", "Shuffle",
+                                       DBUS_TYPE_UINT32, &str);
+       }
+
+       return 0;
+}
+
+static int parse_properties(DBusConnection *conn, const char *path,
+                                               DBusMessageIter *args,
+                                               DBusMessageIter *properties)
+{
+       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 (parse_property(conn, path, key, &entry, properties) < 0)
+                       return -EINVAL;
+
+               dbus_message_iter_next(&dict);
+       }
+
+       return 0;
+}
+
+static int parse_metadata_entry(DBusMessageIter *entry, const char *key,
+                                               DBusMessageIter *metadata)
+{
+       DBusMessageIter var;
+
+       printf("metadata %s found\n", key);
+
+       if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
+               return -EINVAL;
+
+       dbus_message_iter_recurse(entry, &var);
+
+       if (strcasecmp(key, "xesam:title") == 0) {
+               const char *value;
+
+               if (dbus_message_iter_get_arg_type(&var) !=
+                                                       DBUS_TYPE_STRING)
+                       return -EINVAL;
+
+               dbus_message_iter_get_basic(&var, &value);
+               dict_append_entry(metadata, "Title", DBUS_TYPE_STRING,
+                                                               &value);
+       } else if (strcasecmp(key, "xesam:artist") == 0) {
+               const char *value;
+               DBusMessageIter array;
+
+               if (dbus_message_iter_get_arg_type(&var) !=
+                                                       DBUS_TYPE_ARRAY)
+                       return -EINVAL;
+
+               dbus_message_iter_recurse(&var, &array);
+
+               if (dbus_message_iter_get_arg_type(&array) !=
+                                                       DBUS_TYPE_STRING)
+                       return -EINVAL;
+
+               dbus_message_iter_get_basic(&array, &value);
+               dict_append_entry(metadata, "Artist", DBUS_TYPE_STRING,
+                                                               &value);
+       } else if (strcasecmp(key, "xesam:album") == 0) {
+               const char *value;
+
+               if (dbus_message_iter_get_arg_type(&var) !=
+                                                       DBUS_TYPE_STRING)
+                       return -EINVAL;
+
+               dbus_message_iter_get_basic(&var, &value);
+               dict_append_entry(metadata, "Album", DBUS_TYPE_STRING,
+                                                               &value);
+       } else if (strcasecmp(key, "xesam:genre") == 0) {
+               const char *value;
+               DBusMessageIter array;
+
+               if (dbus_message_iter_get_arg_type(&var) !=
+                                                       DBUS_TYPE_ARRAY)
+                       return -EINVAL;
+
+               dbus_message_iter_recurse(&var, &array);
+
+               if (dbus_message_iter_get_arg_type(&array) !=
+                                                       DBUS_TYPE_STRING)
+                       return -EINVAL;
+
+               dbus_message_iter_get_basic(&array, &value);
+               dict_append_entry(metadata, "Genre", DBUS_TYPE_STRING,
+                                                               &value);
+       } else if (strcasecmp(key, "mpris:length") == 0) {
+               int64_t usec, msec;
+
+               if (dbus_message_iter_get_arg_type(&var) !=
+                                                       DBUS_TYPE_INT64)
+                       return -EINVAL;
+
+               dbus_message_iter_get_basic(&var, &usec);
+               msec = usec / 1000;
+
+               dict_append_entry(metadata, "Duration", DBUS_TYPE_UINT32,
+                                                               &msec);
+       } else if (strcasecmp(key, "xesam:trackNumber") == 0) {
+               int32_t value;
+
+               if (dbus_message_iter_get_arg_type(&var) !=
+                                                       DBUS_TYPE_INT32)
+                       return -EINVAL;
+
+               dbus_message_iter_get_basic(&var, &value);
+
+               dict_append_entry(metadata, "Number", DBUS_TYPE_UINT32,
+                                                               &value);
+       }
+
+       return 0;
+}
+
+static int parse_track(DBusMessageIter *args, DBusMessageIter *metadata)
+{
+       DBusMessageIter var, dict;
+       int ctype;
+
+       ctype = dbus_message_iter_get_arg_type(args);
+       if (ctype != DBUS_TYPE_VARIANT)
+               return -EINVAL;
+
+       dbus_message_iter_recurse(args, &var);
+
+       ctype = dbus_message_iter_get_arg_type(&var);
+       if (ctype != DBUS_TYPE_ARRAY)
+               return -EINVAL;
+
+       dbus_message_iter_recurse(&var, &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 (parse_metadata_entry(&entry, key, metadata) < 0)
+                       return -EINVAL;
+
+               dbus_message_iter_next(&dict);
+       }
+
+       return 0;
+}
+
+static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata)
+{
+       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 (strcasecmp(key, "Metadata") == 0)
+                       return parse_track(&entry, metadata);
+
+               dbus_message_iter_next(&dict);
+       }
+
+       return -EINVAL;
+}
+
+static char *sender2path(const char *sender)
+{
+       char *path;
+
+       path = g_strconcat("/", sender, NULL);
+       return g_strdelimit(path, ":.", '_');
+}
+
+static DBusHandlerResult player_message(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       if (dbus_message_is_method_call(msg, "org.bluez.MediaPlayer",
+                                                               "Release")) {
+               printf("Release\n");
+               exit(1);
+       }
+
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static const DBusObjectPathVTable player_table = {
+       .message_function = player_message,
+};
+
+static void add_player(DBusConnection *conn, const char *name,
+                                                       const char *sender)
+{
+       DBusMessage *reply = get_all(conn, name);
+       DBusMessage *msg;
+       DBusMessageIter iter, args, properties, metadata;
+       DBusError err;
+       char *path;
+
+       if (!reply)
+               return;
+
+       msg = dbus_message_new_method_call("org.bluez", adapter,
+                                       "org.bluez.Media",
+                                       "RegisterPlayer");
+       if (!msg) {
+               fprintf(stderr, "Can't allocate new method call\n");
+               return;
+       }
+
+       dbus_message_iter_init_append(msg, &iter);
+
+       path = sender2path(sender);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+       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, &properties);
+
+       dbus_message_iter_init(reply, &args);
+
+       if (parse_properties(conn, path, &args, &properties) < 0)
+               goto done;
+
+       dbus_message_iter_close_container(&iter, &properties);
+
+       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);
+
+       dbus_message_iter_init(reply, &args);
+
+       if (parse_metadata(&args, &metadata) < 0)
+               goto done;
+
+       dbus_message_iter_close_container(&iter, &metadata);
+
+       dbus_message_unref(reply);
+
+       dbus_error_init(&err);
+
+       reply = dbus_connection_send_with_reply_and_block(sys, msg, -1, &err);
+       if (!reply) {
+               fprintf(stderr, "Can't register player\n");
+               if (dbus_error_is_set(&err)) {
+                       fprintf(stderr, "%s\n", err.message);
+                       dbus_error_free(&err);
+               }
+               goto done;
+       }
+
+       if (!dbus_connection_register_object_path(sys, path, &player_table,
+                                                               NULL))
+               fprintf(stderr, "Can't register object path for agent\n");
+
+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;
+
+       msg = dbus_message_new_method_call("org.bluez", adapter,
+                                       "org.bluez.Media",
+                                       "UnregisterPlayer");
+       if (!msg) {
+               fprintf(stderr, "Can't allocate new method call\n");
+               return;
+       }
+
+       path = sender2path(sender);
+       dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &path,
+                                       DBUS_TYPE_INVALID);
+
+       dbus_connection_send(sys, msg, NULL);
+
+       dbus_message_unref(msg);
+       g_free(path);
+}
+
+static DBusHandlerResult properties_changed(DBusConnection *conn,
+                                                       DBusMessage *msg)
+{
+       DBusMessage *signal;
+       DBusMessageIter iter, entry, metadata;
+       const char *iface;
+       char *path;
+
+       dbus_message_iter_init(msg, &iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+       dbus_message_iter_get_basic(&iter, &iface);
+
+       printf("PropertiesChanged interface %s\n", iface);
+
+       dbus_message_iter_next(&iter);
+
+       path = sender2path(dbus_message_get_sender(msg));
+       parse_properties(conn, path, &iter, NULL);
+
+       signal = dbus_message_new_signal(path, "org.bluez.MediaPlayer",
+                                                       "TrackChanged");
+       if (!signal) {
+               fprintf(stderr, "Unable to allocate new PropertyChanged"
+                                                       " signal\n");
+               goto err;
+       }
+
+       dbus_message_iter_init_append(signal, &entry);
+
+       dbus_message_iter_open_container(&entry, 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);
+
+       dbus_message_iter_init(msg, &iter);
+       dbus_message_iter_next(&iter);
+
+       if (parse_metadata(&iter, &metadata) < 0)
+               goto err;
+
+       dbus_message_iter_close_container(&entry, &metadata);
+
+       dbus_connection_send(sys, signal, NULL);
+       dbus_message_unref(signal);
+       g_free(path);
+
+       return DBUS_HANDLER_RESULT_HANDLED;
+
+err:
+       if (signal)
+               dbus_message_unref(signal);
+       g_free(path);
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult session_filter(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       const char *name, *old, *new;
+
+       if (dbus_message_is_signal(msg, DBUS_INTERFACE_PROPERTIES,
+                                               "PropertiesChanged"))
+               return properties_changed(conn, msg);
+
+       if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS,
+                                               "NameOwnerChanged"))
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+       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 {
+               printf("player %s at %s found\n", name, new);
+               add_player(conn, name, new);
+       }
+
+       return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult system_filter(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       const char *name, *old, *new;
+
+       if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS,
+                                               "NameOwnerChanged"))
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+       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 (!strcmp(name, "org.bluez") && *new == '\0') {
+               fprintf(stderr, "bluetoothd disconnected\n");
+               __io_terminated = 1;
+       }
+
+       return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static char *get_default_adapter(DBusConnection *conn)
+{
+       DBusMessage *msg, *reply;
+       DBusError err;
+       const char *reply_path;
+       char *path;
+
+       msg = dbus_message_new_method_call("org.bluez", "/",
+                                       "org.bluez.Manager", "DefaultAdapter");
+
+       if (!msg) {
+               fprintf(stderr, "Can't allocate new method call\n");
+               return NULL;
+       }
+
+       dbus_error_init(&err);
+
+       reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
+
+       dbus_message_unref(msg);
+
+       if (!reply) {
+               fprintf(stderr, "Can't get default adapter\n");
+               if (dbus_error_is_set(&err)) {
+                       fprintf(stderr, "%s\n", err.message);
+                       dbus_error_free(&err);
+               }
+               return NULL;
+       }
+
+       if (!dbus_message_get_args(reply, &err,
+                                       DBUS_TYPE_OBJECT_PATH, &reply_path,
+                                       DBUS_TYPE_INVALID)) {
+               fprintf(stderr, "Can't get reply arguments\n");
+               if (dbus_error_is_set(&err)) {
+                       fprintf(stderr, "%s\n", err.message);
+                       dbus_error_free(&err);
+               }
+               dbus_message_unref(reply);
+               return NULL;
+       }
+
+       path = strdup(reply_path);
+
+       dbus_message_unref(reply);
+
+       dbus_connection_flush(conn);
+
+       return path;
+}
+
+static char *get_adapter(DBusConnection *conn, const char *adapter)
+{
+       DBusMessage *msg, *reply;
+       DBusError err;
+       const char *reply_path;
+       char *path;
+
+       if (!adapter)
+               return get_default_adapter(conn);
+
+       msg = dbus_message_new_method_call("org.bluez", "/",
+                                       "org.bluez.Manager", "FindAdapter");
+
+       if (!msg) {
+               fprintf(stderr, "Can't allocate new method call\n");
+               return NULL;
+       }
+
+       dbus_message_append_args(msg, DBUS_TYPE_STRING, &adapter,
+                                       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) {
+               fprintf(stderr, "Can't find adapter %s\n", adapter);
+               if (dbus_error_is_set(&err)) {
+                       fprintf(stderr, "%s\n", err.message);
+                       dbus_error_free(&err);
+               }
+               return NULL;
+       }
+
+       if (!dbus_message_get_args(reply, &err,
+                                       DBUS_TYPE_OBJECT_PATH, &reply_path,
+                                       DBUS_TYPE_INVALID)) {
+               fprintf(stderr, "Can't get reply arguments\n");
+               if (dbus_error_is_set(&err)) {
+                       fprintf(stderr, "%s\n", err.message);
+                       dbus_error_free(&err);
+               }
+               dbus_message_unref(reply);
+               return NULL;
+       }
+
+       path = strdup(reply_path);
+
+       dbus_message_unref(reply);
+
+       dbus_connection_flush(conn);
+
+       return path;
+}
+
+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) {
+               fprintf(stderr, "Can't find adapter %s\n", adapter);
+               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;
+
+               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) {
+               fprintf(stderr, "Can't find adapter %s\n", adapter);
+               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 player ver %s\n\n", VERSION);
+
+       printf("Usage:\n"
+               "\tplayer [--adapter adapter id]\n"
+               "\n");
+}
+
+static struct option main_options[] = {
+       { "adapter",    1, 0, 'a' },
+       { 0, 0, 0, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+       struct sigaction sa;
+       char *adapter_id = NULL;
+       char match[128];
+       int opt;
+
+       while ((opt = getopt_long(argc, argv, "+a,h", main_options, NULL)) != EOF) {
+               switch(opt) {
+               case '1':
+                       adapter_id = optarg;
+                       break;
+               case 'h':
+                       usage();
+                       exit(0);
+               default:
+                       exit(1);
+               }
+       }
+
+       sys = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+       if (!sys) {
+               fprintf(stderr, "Can't get on system bus");
+               exit(1);
+       }
+
+       adapter = get_adapter(sys, adapter_id);
+       if (!adapter)
+               exit(1);
+
+       if (!dbus_connection_add_filter(sys, system_filter, NULL, NULL)) {
+               fprintf(stderr, "Can't add signal filter");
+               exit(1);
+       }
+
+       snprintf(match, sizeof(match),
+                       "interface=%s,member=NameOwnerChanged,arg0=%s",
+                       DBUS_INTERFACE_DBUS, "org.bluez");
+
+       dbus_bus_add_match(sys, match, NULL);
+
+       session = dbus_bus_get(DBUS_BUS_SESSION, NULL);
+       if (!session) {
+               fprintf(stderr, "Can't get on session bus");
+               exit(1);
+       }
+
+       if (!dbus_connection_add_filter(session, session_filter, NULL, NULL)) {
+               fprintf(stderr, "Can't add signal filter");
+               exit(1);
+       }
+
+       snprintf(match, sizeof(match),
+                       "interface=%s,member=NameOwnerChanged",
+                       DBUS_INTERFACE_DBUS);
+
+       dbus_bus_add_match(session, match, NULL);
+
+       snprintf(match, sizeof(match),
+                       "interface=%s,member=PropertiesChanged,arg0=%s",
+                       DBUS_INTERFACE_PROPERTIES,
+                       "org.mpris.MediaPlayer2.Player");
+
+       list_names(session);
+
+       dbus_bus_add_match(session, match, NULL);
+
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_flags   = SA_NOCLDSTOP;
+       sa.sa_handler = sig_term;
+       sigaction(SIGTERM, &sa, NULL);
+       sigaction(SIGINT,  &sa, NULL);
+
+       while (!__io_canceled && !__io_terminated) {
+               if (dbus_connection_read_write_dispatch(sys, 500) != TRUE)
+                       break;
+               if (dbus_connection_read_write_dispatch(session, 500) != TRUE)
+                       break;
+       }
+
+       dbus_connection_unref(sys);
+
+       return 0;
+}
index b3804f5..4d7c90a 100644 (file)
@@ -85,6 +85,7 @@ static int socktype = SOCK_STREAM;
 static int linger = 0;
 static int timestamp = 0;
 static int defer_setup = 0;
+static int priority = -1;
 
 static float tv2fl(struct timeval tv)
 {
@@ -232,9 +233,22 @@ static int do_connect(const char *svr)
                //goto error;
        }
 
-       syslog(LOG_INFO, "Connected [handle %d, class 0x%02x%02x%02x]",
-               conn.hci_handle,
-               conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
+       if (priority > 0 && setsockopt(sk, SOL_SOCKET, SO_PRIORITY, &priority,
+                                               sizeof(priority)) < 0) {
+               syslog(LOG_ERR, "Can't set socket priority: %s (%d)",
+                                                       strerror(errno), errno);
+               goto error;
+       }
+
+       if (getsockopt(sk, SOL_SOCKET, SO_PRIORITY, &opt, &optlen) < 0) {
+               syslog(LOG_ERR, "Can't get socket priority: %s (%d)",
+                                                       strerror(errno), errno);
+               goto error;
+       }
+
+       syslog(LOG_INFO, "Connected [handle %d, class 0x%02x%02x%02x, "
+                       "priority %d]", conn.hci_handle, conn.dev_class[2],
+                       conn.dev_class[1], conn.dev_class[0], opt);
 
        return sk;
 
@@ -348,10 +362,26 @@ static void do_listen(void (*handler)(int sk))
                        //goto error;
                }
 
+               if (priority > 0 && setsockopt(sk, SOL_SOCKET, SO_PRIORITY,
+                                       &priority, sizeof(priority)) < 0) {
+                       syslog(LOG_ERR, "Can't set socket priority: %s (%d)",
+                                               strerror(errno), errno);
+                       close(nsk);
+                       goto error;
+               }
+
+               optlen = sizeof(priority);
+               if (getsockopt(nsk, SOL_SOCKET, SO_PRIORITY, &opt, &optlen) < 0) {
+                       syslog(LOG_ERR, "Can't get socket priority: %s (%d)",
+                                                       strerror(errno), errno);
+                       goto error;
+               }
+
                ba2str(&addr.rc_bdaddr, ba);
-               syslog(LOG_INFO, "Connect from %s [handle %d, class 0x%02x%02x%02x]",
-                       ba, conn.hci_handle,
-                       conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
+               syslog(LOG_INFO, "Connect from %s [handle %d, "
+                               "class 0x%02x%02x%02x, priority %d]",
+                               ba, conn.hci_handle, conn.dev_class[2],
+                               conn.dev_class[1], conn.dev_class[0], opt);
 
 #if 0
                /* Enable SO_TIMESTAMP */
@@ -417,13 +447,11 @@ static void recv_mode(int sk)
        struct timeval tv_beg, tv_end, tv_diff;
        char ts[30];
        long total;
-       uint32_t seq;
 
        syslog(LOG_INFO, "Receiving ...");
 
        memset(ts, 0, sizeof(ts));
 
-       seq = 0;
        while (1) {
                gettimeofday(&tv_beg,NULL);
                total = 0;
@@ -586,6 +614,7 @@ static void usage(void)
                "\t[-N num] number of frames to send\n"
                "\t[-C num] send num frames before delay (default = 1)\n"
                "\t[-D milliseconds] delay after sending num frames (default = 0)\n"
+               "\t[-Y priority] socket priority\n"
                "\t[-A] request authentication\n"
                "\t[-E] request encryption\n"
                "\t[-S] secure connection\n"
@@ -600,7 +629,7 @@ int main(int argc, char *argv[])
 
        bacpy(&bdaddr, BDADDR_ANY);
 
-       while ((opt=getopt(argc,argv,"rdscuwmnb:i:P:U:B:N:MAESL:W:C:D:T")) != EOF) {
+       while ((opt=getopt(argc,argv,"rdscuwmnb:i:P:U:B:N:MAESL:W:C:D:Y:T")) != EOF) {
                switch (opt) {
                case 'r':
                        mode = RECV;
@@ -703,6 +732,10 @@ int main(int argc, char *argv[])
                        delay = atoi(optarg) * 1000;
                        break;
 
+               case 'Y':
+                       priority = atoi(optarg);
+                       break;
+
                case 'T':
                        timestamp = 1;
                        break;
diff --git a/test/sap-client b/test/sap-client
new file mode 100644 (file)
index 0000000..413424c
--- /dev/null
@@ -0,0 +1,943 @@
+""" Copyright (C) 2010-2011 ST-Ericsson SA """
+
+""" Author: Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson. """
+
+""" 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 """
+
+from array import array
+from bluetooth import *
+import time
+import re
+
+class SAPParam:
+    """ SAP Parameter Class """
+
+    MaxMsgSize = 0x00
+    ConnectionStatus = 0x01
+    ResultCode = 0x02
+    DisconnectionType = 0x03
+    CommandAPDU = 0x04
+    ResponseAPDU = 0x05
+    ATR = 0x06
+    CardReaderStatus = 0x07
+    StatusChange = 0x08
+    TransportProtocol = 0x09
+    CommandAPDU7816 = 0x10
+
+    def __init__(self, name, id, value = None):
+        self.name = name
+        self.id = id
+        self.value = value
+
+    def _padding(self,  buf):
+        pad = array('B')
+        while ( (len(buf) + len(pad)) % 4 ) != 0:
+            pad.append(0)
+        return pad
+
+    def _basicCheck(self,  buf):
+        if len(buf) < 4 or (len(buf) % 4) != 0 or buf[1] != 0:
+                return (-1,  -1)
+        if buf[0] != self.id:
+            return (-1,  -1)
+        plen = buf[2] * 256 + buf[3] + 4
+        if plen > len(buf):
+            return (-1,  -1)
+        pad = plen
+        while (pad % 4) != 0:
+            if buf[pad] != 0:
+                return (-1,  -1)
+            pad+=1
+        return (plen,  pad)
+
+    def getID(self):
+        return self.id
+
+    def getValue(self):
+        return self.value
+
+    def getContent(self):
+        return "%s(id=0x%.2X), value=%s \n" %  (self.name,  self.id, self.value)
+
+    def serialize(self):
+        a = array('B', '\00\00\00\00')
+        a[0] = self.id
+        a[1] = 0       # reserved
+        a[2] = 0       # length
+        a[3] = 1       # length
+        a.append(self.value)
+        a.extend(self._padding(a))
+        return a
+
+    def deserialize(self,  buf):
+        p = self._basicCheck(buf)
+        if p[0] == -1:
+            return -1
+        self.id = buf[0]
+        self.value = buf[4]
+        return p[1]
+
+
+class SAPParam_MaxMsgSize(SAPParam):
+    """MaxMsgSize Param """
+
+    def __init__(self,  value = None):
+        SAPParam.__init__(self,"MaxMsgSize",  SAPParam.MaxMsgSize, value)
+        self.__validate()
+
+    def __validate(self):
+        if self.value > 0xFFFF:
+             self.value = 0xFFFF
+
+    def serialize(self):
+        a = array('B', '\00\00\00\00')
+        a[0] = self.id
+        a[3] = 2
+        a.append(self.value / 256)
+        a.append(self.value % 256)
+        a.extend(self._padding(a))
+        return a
+
+    def deserialize(self,  buf):
+        p = self._basicCheck(buf)
+        if p[0] == -1 :
+            return -1
+        self.value = buf[4] * 256 + buf[5]
+        return p[1]
+
+class SAPParam_CommandAPDU(SAPParam):
+    def __init__(self,  value = None):
+        if value is None:
+            SAPParam.__init__(self, "CommandAPDU",  SAPParam.CommandAPDU, array('B'))
+        else:
+            SAPParam.__init__(self, "CommandAPDU",  SAPParam.CommandAPDU, array('B', value))
+
+    def serialize(self):
+        a = array('B', '\00\00\00\00')
+        a[0] = self.id
+        plen = len(self.value)
+        a[2] = plen / 256
+        a[3] = plen % 256
+        a.extend(self.value)
+        a.extend(self._padding(a))
+        return a
+
+    def deserialize(self,  buf):
+        p = self._basicCheck(buf)
+        if p[0] == -1:
+            return -1
+        self.value = buf[4:p[0]]
+        return p[1]
+
+class SAPParam_ResponseAPDU(SAPParam_CommandAPDU):
+    """ResponseAPDU Param """
+
+    def __init__(self,  value = None):
+        if value is None:
+            SAPParam.__init__(self, "ResponseAPDU",  SAPParam.ResponseAPDU, array('B'))
+        else:
+            SAPParam.__init__(self, "ResponseAPDU",  SAPParam.ResponseAPDU, array('B', value))
+
+class SAPParam_ATR(SAPParam_CommandAPDU):
+    """ATR Param """
+
+    def __init__(self,  value = None):
+        if value is None:
+            SAPParam.__init__(self, "ATR",  SAPParam.ATR, array('B'))
+        else:
+            SAPParam.__init__(self, "ATR",  SAPParam.ATR, array('B', value))
+
+class SAPParam_CommandAPDU7816(SAPParam_CommandAPDU):
+    """Command APDU7816 Param."""
+
+    def __init__(self,  value = None):
+        if value is None:
+            SAPParam.__init__(self, "CommandAPDU7816",  SAPParam.CommandAPDU7816, array('B'))
+        else:
+            SAPParam.__init__(self, "CommandAPDU7816",  SAPParam.CommandAPDU7816, array('B', value))
+
+
+class SAPParam_ConnectionStatus(SAPParam):
+    """Connection status Param."""
+
+    def __init__(self,  value = None):
+        SAPParam.__init__(self,"ConnectionStatus",  SAPParam.ConnectionStatus, value)
+        self.__validate()
+
+    def __validate(self):
+        if self.value is not None and self.value not in (0x00,  0x01,  0x02,  0x03,  0x04):
+            print "Warning. ConnectionStatus value in reserved range (0x%x)" % self.value
+
+    def deserialize(self,  buf):
+        ret = SAPParam.deserialize(self, buf)
+        if ret == -1:
+            return -1
+        self.__validate()
+        return ret
+
+class SAPParam_ResultCode(SAPParam):
+    """ Result Code Param """
+
+    def __init__(self,  value = None):
+        SAPParam.__init__(self,"ResultCode",  SAPParam.ResultCode, value)
+        self.__validate()
+
+    def __validate(self):
+        if self.value is not None and self.value not in (0x00,  0x01,  0x02,  0x03,  0x04,  0x05,  0x06,  0x07):
+            print "Warning. ResultCode value in reserved range (0x%x)" % self.value
+
+    def deserialize(self,  buf):
+        ret = SAPParam.deserialize(self, buf)
+        if ret == -1:
+            return -1
+        self.__validate()
+        return ret
+
+class SAPParam_DisconnectionType(SAPParam):
+    """Disconnection Type Param."""
+
+    def __init__(self,  value = None):
+        SAPParam.__init__(self,"DisconnectionType",  SAPParam.DisconnectionType, value)
+        self.__validate()
+
+    def __validate(self):
+        if self.value is not None and self.value not in (0x00,  0x01):
+            print "Warning. DisconnectionType value in reserved range (0x%x)" % self.value
+
+    def deserialize(self,  buf):
+        ret = SAPParam.deserialize(self, buf)
+        if ret == -1:
+            return -1
+        self.__validate()
+        return ret
+
+class SAPParam_CardReaderStatus(SAPParam_CommandAPDU):
+    """Card reader Status Param."""
+
+    def __init__(self,  value = None):
+        if value is None:
+            SAPParam.__init__(self, "CardReaderStatus",  SAPParam.CardReaderStatus, array('B'))
+        else:
+            SAPParam.__init__(self, "CardReaderStatus",  SAPParam.CardReaderStatus, array('B', value))
+
+class SAPParam_StatusChange(SAPParam):
+    """Status Change Param """
+
+    def __init__(self,  value = None):
+        SAPParam.__init__(self,"StatusChange",  SAPParam.StatusChange, value)
+
+    def __validate(self):
+        if self.value is not None and self.value not in (0x00,  0x01,  0x02,  0x03,  0x04,  0x05):
+            print "Warning. StatusChange value in reserved range (0x%x)" % self.value
+
+    def deserialize(self,  buf):
+        ret = SAPParam.deserialize(self, buf)
+        if ret == -1:
+            return -1
+        self.__validate()
+        return ret
+
+class SAPParam_TransportProtocol(SAPParam):
+    """Transport Protocol Param """
+
+    def __init__(self,  value = None):
+        SAPParam.__init__(self,"TransportProtocol",  SAPParam.TransportProtocol, value)
+        self.__validate()
+
+    def __validate(self):
+        if self.value is not None and self.value not in (0x00,  0x01):
+            print "Warning. TransportProtoco value in reserved range (0x%x)" % self.value
+
+    def deserialize(self,  buf):
+        ret = SAPParam.deserialize(self, buf)
+        if ret == -1:
+            return -1
+        self.__validate()
+        return ret
+
+class SAPMessage:
+
+    CONNECT_REQ = 0x00
+    CONNECT_RESP = 0x01
+    DISCONNECT_REQ = 0x02
+    DISCONNECT_RESP =0x03
+    DISCONNECT_IND = 0x04
+    TRANSFER_APDU_REQ = 0x05
+    TRANSFER_APDU_RESP = 0x06
+    TRANSFER_ATR_REQ = 0x07
+    TRANSFER_ATR_RESP = 0x08
+    POWER_SIM_OFF_REQ = 0x09
+    POWER_SIM_OFF_RESP = 0x0A
+    POWER_SIM_ON_REQ = 0x0B
+    POWER_SIM_ON_RESP = 0x0C
+    RESET_SIM_REQ = 0x0D
+    RESET_SIM_RESP = 0x0E
+    TRANSFER_CARD_READER_STATUS_REQ = 0x0F
+    TRANSFER_CARD_READER_STATUS_RESP = 0x10
+    STATUS_IND = 0x11
+    ERROR_RESP = 0x12
+    SET_TRANSPORT_PROTOCOL_REQ = 0x13
+    SET_TRANSPORT_PROTOCOL_RESP = 0x14
+
+    def __init__(self,  name,  id):
+        self.name = name
+        self.id = id
+        self.params = []
+        self.buf = array('B')
+
+    def _basicCheck(self,  buf):
+        if len(buf) < 4 or (len(buf) % 4) != 0 :
+            return False
+
+        if buf[0] != self.id:
+            return False
+
+        return True
+
+    def getID(self):
+        return self.id
+
+    def getContent(self):
+        s = "%s(id=0x%.2X) " % (self.name,  self.id)
+        if len( self.buf): s = s + "[%s]" % re.sub("(.{2})", "0x\\1 " , self.buf.tostring().encode("hex").upper(), re.DOTALL)
+        s = s + "\n\t"
+        for p in self.params:
+            s = s + "\t" + p.getContent()
+        return s
+
+    def getParams(self):
+        return self.params
+
+    def addParam(self,  param):
+        self.params.append(param)
+
+    def serialize(self):
+        ret = array('B', '\00\00\00\00')
+        ret[0] = self.id
+        ret[1] = len(self.params)
+        ret[2] = 0     # reserved
+        ret[3] = 0     # reserved
+        for p in self.params:
+            ret.extend(p.serialize())
+
+        self.buf = ret
+        return ret
+
+    def deserialize(self,  buf):
+        self.buf = buf
+        return len(buf) == 4 and buf[1] == 0 and self._basicCheck(buf)
+
+
+class SAPMessage_CONNECT_REQ(SAPMessage):
+    def __init__(self,  MaxMsgSize = None):
+        SAPMessage.__init__(self,"CONNECT_REQ",  SAPMessage.CONNECT_REQ)
+        if MaxMsgSize is not None:
+            self.addParam(SAPParam_MaxMsgSize(MaxMsgSize))
+
+    def _validate(self):
+        if len(self.params) == 1:
+            if self.params[0].getID() == SAPParam.MaxMsgSize:
+                return True
+        return False
+
+    def deserialize(self,  buf):
+        self.buf = buf
+        self.params[:] = []
+        if SAPMessage._basicCheck(self,  buf):
+            p = SAPParam_MaxMsgSize()
+            if p.deserialize(buf[4:]) == len(buf[4:]):
+                self.addParam(p)
+                return self._validate()
+
+        return False
+
+class SAPMessage_CONNECT_RESP(SAPMessage):
+    def __init__(self,  ConnectionStatus = None,  MaxMsgSize = None):
+        SAPMessage.__init__(self,"CONNECT_RESP",  SAPMessage.CONNECT_RESP)
+        if ConnectionStatus is not None:
+            self.addParam(SAPParam_ConnectionStatus(ConnectionStatus))
+            if MaxMsgSize is not None:
+                self.addParam(SAPParam_MaxMsgSize(MaxMsgSize))
+
+    def _validate(self):
+        if len(self.params) > 0:
+            if self.params[0] .getID() == SAPParam.ConnectionStatus:
+                if self.params[0].getValue() ==  0x02:
+                    if len(self.params) == 2:
+                        return True
+                else:
+                    if len(self.params) == 1:
+                        return True
+        return False
+
+    def deserialize(self,  buf):
+        self.buf = buf
+        self.params[:] = []
+
+        if SAPMessage._basicCheck(self,  buf):
+            p = SAPParam_ConnectionStatus()
+            r = p.deserialize(buf[4:])
+            if  r != -1:
+                self.addParam(p)
+                if buf[1] == 2:
+                    p = SAPParam_MaxMsgSize()
+                    r = p.deserialize(buf[4+r:])
+                    if r != -1:
+                        self.addParam(p)
+
+                return self._validate()
+
+        return False
+
+class SAPMessage_DISCONNECT_REQ(SAPMessage):
+    def __init__(self):
+        SAPMessage.__init__(self,"DISCONNECT_REQ",  SAPMessage.DISCONNECT_REQ)
+
+class SAPMessage_DISCONNECT_RESP(SAPMessage):
+    def __init__(self):
+        SAPMessage.__init__(self,"DISCONNECT_RESP",  SAPMessage.DISCONNECT_RESP)
+
+class SAPMessage_DISCONNECT_IND(SAPMessage):
+    def __init__(self,  Type = None):
+        SAPMessage.__init__(self,"DISCONNECT_IND",  SAPMessage.DISCONNECT_IND)
+        if Type is not None:
+            self.addParam(SAPParam_DisconnectionType(Type))
+
+    def _validate(self):
+        if len(self.params) == 1:
+            if self.params[0].getID() == SAPParam.DisconnectionType:
+                return True
+        return False
+
+    def deserialize(self,  buf):
+        self.buf = buf
+        self.params[:] = []
+        if SAPMessage._basicCheck(self,  buf):
+            p = SAPParam_DisconnectionType()
+            if p.deserialize(buf[4:]) == len(buf[4:]):
+                self.addParam(p)
+                return self._validate()
+
+        return False
+
+
+class SAPMessage_TRANSFER_APDU_REQ(SAPMessage):
+    def __init__(self,  APDU = None,  T = False):
+        SAPMessage.__init__(self,"TRANSFER_APDU_REQ",  SAPMessage.TRANSFER_APDU_REQ)
+        if APDU is not None:
+            if T :
+                self.addParam(SAPParam_CommandAPDU(APDU))
+            else:
+                self.addParam(SAPParam_CommandAPDU7816(APDU))
+
+    def _validate(self):
+        if len(self.params) == 1:
+            if self.params[0].getID() == SAPParam.CommandAPDU or self.params[0].getID() == SAPParam.CommandAPDU7816:
+                return True
+        return False
+
+    def deserialize(self,  buf):
+        self.buf = buf
+        self.params[:] = []
+        if SAPMessage._basicCheck(self,  buf):
+
+            p = SAPParam_CommandAPDU()
+            p2 = SAPParam_CommandAPDU7816()
+            if p.deserialize(buf[4:]) == len(buf[4:]):
+                self.addParam(p)
+                return self._validate()
+            elif p2.deserialize(buf[4:]) == len(buf[4:]):
+                self.addParam(p2)
+                return self._validate()
+
+        return False
+
+class SAPMessage_TRANSFER_APDU_RESP(SAPMessage):
+    def __init__(self,  ResultCode = None,  Response = None):
+        SAPMessage.__init__(self,"TRANSFER_APDU_RESP",  SAPMessage.TRANSFER_APDU_RESP)
+        if ResultCode is not None:
+            self.addParam(SAPParam_ResultCode(ResultCode))
+            if Response is not None:
+                self.addParam(SAPParam_ResponseAPDU(Response))
+
+    def _validate(self):
+        if len(self.params) > 0:
+            if self.params[0] .getID() == SAPParam.ResultCode:
+                if self.params[0].getValue() == 0x00:
+                    if len(self.params) == 2:
+                        return True
+                else:
+                    if len(self.params) == 1:
+                        return True
+        return False
+
+    def deserialize(self,  buf):
+        self.buf = buf
+        self.params[:] = []
+
+        if SAPMessage._basicCheck(self,  buf):
+            p = SAPParam_ResultCode()
+            r = p.deserialize(buf[4:])
+            if  r != -1:
+                self.addParam(p)
+                if buf[1] == 2:
+                    p = SAPParam_ResponseAPDU()
+                    r = p.deserialize(buf[4+r:])
+                    if r != -1:
+                        self.addParam(p)
+
+                return self._validate()
+
+        return False
+
+class SAPMessage_TRANSFER_ATR_REQ(SAPMessage):
+    def __init__(self):
+        SAPMessage.__init__(self,"TRANSFER_ATR_REQ",  SAPMessage.TRANSFER_ATR_REQ)
+
+class SAPMessage_TRANSFER_ATR_RESP(SAPMessage):
+    def __init__(self,  ResultCode = None,  ATR = None):
+        SAPMessage.__init__(self,"TRANSFER_ATR_RESP",  SAPMessage.TRANSFER_ATR_RESP)
+        if ResultCode is not None:
+            self.addParam(SAPParam_ResultCode(ResultCode))
+            if ATR is not None:
+                self.addParam(SAPParam_ATR(ATR))
+
+    def _validate(self):
+        if len(self.params) > 0:
+            if self.params[0] .getID() == SAPParam.ResultCode:
+                if self.params[0].getValue() == 0x00:
+                    if len(self.params) == 2:
+                        return True
+                else:
+                    if len(self.params) == 1:
+                        return True
+        return False
+
+    def deserialize(self,  buf):
+        self.buf = buf
+        self.params[:] = []
+
+        if SAPMessage._basicCheck(self,  buf):
+
+            p = SAPParam_ResultCode()
+            r = p.deserialize(buf[4:])
+
+            if  r != -1:
+
+                self.addParam(p)
+                if buf[1] == 2:
+
+                    p = SAPParam_ATR()
+                    r = p.deserialize(buf[4+r:])
+                    if r != -1:
+                        self.addParam(p)
+
+                return self._validate()
+
+        return False
+
+class SAPMessage_POWER_SIM_OFF_REQ(SAPMessage):
+    def __init__(self):
+        SAPMessage.__init__(self,"POWER_SIM_OFF_REQ",  SAPMessage.POWER_SIM_OFF_REQ)
+
+class SAPMessage_POWER_SIM_OFF_RESP(SAPMessage):
+    def __init__(self,  ResultCode = None):
+        SAPMessage.__init__(self,"POWER_SIM_OFF_RESP",  SAPMessage.POWER_SIM_OFF_RESP)
+        if ResultCode is not None:
+            self.addParam(SAPParam_ResultCode(ResultCode))
+
+    def _validate(self):
+        if len(self.params) == 1:
+            if self.params[0].getID() == SAPParam.ResultCode:
+                return True
+        return False
+
+    def deserialize(self,  buf):
+        self.buf = buf
+        self.params[:] = []
+        if SAPMessage._basicCheck(self,  buf):
+            p = SAPParam_ResultCode()
+            if p.deserialize(buf[4:]) == len(buf[4:]):
+                self.addParam(p)
+                return self._validate()
+
+        return False
+
+class SAPMessage_POWER_SIM_ON_REQ(SAPMessage):
+    def __init__(self):
+        SAPMessage.__init__(self,"POWER_SIM_ON_REQ",  SAPMessage.POWER_SIM_ON_REQ)
+
+class SAPMessage_POWER_SIM_ON_RESP(SAPMessage_POWER_SIM_OFF_RESP):
+    def __init__(self,  ResultCode = None):
+        SAPMessage.__init__(self,"POWER_SIM_ON_RESP",  SAPMessage.POWER_SIM_ON_RESP)
+        if ResultCode is not None:
+            self.addParam(SAPParam_ResultCode(ResultCode))
+
+class SAPMessage_RESET_SIM_REQ(SAPMessage):
+    def __init__(self):
+        SAPMessage.__init__(self,"RESET_SIM_REQ",  SAPMessage.RESET_SIM_REQ)
+
+class SAPMessage_RESET_SIM_RESP(SAPMessage_POWER_SIM_OFF_RESP):
+    def __init__(self,  ResultCode = None):
+        SAPMessage.__init__(self,"RESET_SIM_RESP",  SAPMessage.RESET_SIM_RESP)
+        if ResultCode is not None:
+            self.addParam(SAPParam_ResultCode(ResultCode))
+
+class SAPMessage_STATUS_IND(SAPMessage):
+    def __init__(self,  StatusChange = None):
+        SAPMessage.__init__(self,"STATUS_IND",  SAPMessage.STATUS_IND)
+        if StatusChange is not None:
+            self.addParam(SAPParam_StatusChange(StatusChange))
+
+    def _validate(self):
+        if len(self.params) == 1:
+            if self.params[0].getID() == SAPParam.StatusChange:
+                return True
+        return False
+
+    def deserialize(self,  buf):
+        self.buf = buf
+        self.params[:] = []
+        if SAPMessage._basicCheck(self,  buf):
+            p = SAPParam_StatusChange()
+            if p.deserialize(buf[4:]) == len(buf[4:]):
+                self.addParam(p)
+                return self._validate()
+
+        return False
+
+class SAPMessage_TRANSFER_CARD_READER_STATUS_REQ(SAPMessage):
+    def __init__(self):
+        SAPMessage.__init__(self,"TRANSFER_CARD_READER_STATUS_REQ",  SAPMessage.TRANSFER_CARD_READER_STATUS_REQ)
+
+class SAPMessage_TRANSFER_CARD_READER_STATUS_RESP(SAPMessage):
+    def __init__(self,  ResultCode = None,  Status = None):
+        SAPMessage.__init__(self,"TRANSFER_CARD_READER_STATUS_RESP",  SAPMessage.TRANSFER_CARD_READER_STATUS_RESP)
+        if ResultCode is not None:
+            self.addParam(SAPParam_ResultCode(ResultCode))
+            if Status is not None:
+                self.addParam(SAPParam_CardReaderStatus(Status))
+
+    def _validate(self):
+        if len(self.params) > 0:
+            if self.params[0] .getID() == SAPParam.ResultCode:
+                if self.params[0].getValue() == 0x00:
+                    if len(self.params) == 2:
+                        return True
+                else:
+                    if len(self.params) == 1:
+                        return True
+        return False
+
+    def deserialize(self,  buf):
+        self.buf = buf
+        self.params[:] = []
+
+        if SAPMessage._basicCheck(self,  buf):
+            p = SAPParam_ResultCode()
+            r = p.deserialize(buf[4:])
+            if  r != -1:
+                self.addParam(p)
+                if buf[1] == 2:
+                    p = SAPParam_CardReaderStatus()
+                    r = p.deserialize(buf[4+r:])
+                    if r != -1:
+                        self.addParam(p)
+
+                return self._validate()
+
+        return False
+
+class SAPMessage_ERROR_RESP(SAPMessage):
+    def __init__(self):
+        SAPMessage.__init__(self,"ERROR_RESP",  SAPMessage.ERROR_RESP)
+
+
+class SAPMessage_SET_TRANSPORT_PROTOCOL_REQ(SAPMessage):
+    def __init__(self,  protocol = None):
+        SAPMessage.__init__(self,"SET_TRANSPORT_PROTOCOL_REQ",  SAPMessage.SET_TRANSPORT_PROTOCOL_REQ)
+        if protocol is not None:
+            self.addParam(SAPParam_TransportProtocol(protocol))
+
+    def _validate(self):
+        if len(self.params) == 1:
+            if self.params[0].getID() == SAPParam.TransportProtocol:
+                return True
+        return False
+
+    def deserialize(self,  buf):
+        self.buf = buf
+        self.params[:] = []
+        if SAPMessage._basicCheck(self,  buf):
+            p = SAPParam_TransportProtocol()
+            if p.deserialize(buf[4:]) == len(buf[4:]):
+                self.addParam(p)
+                return self._validate()
+
+        return False
+
+class SAPMessage_SET_TRANSPORT_PROTOCOL_RESP(SAPMessage_POWER_SIM_OFF_RESP):
+    def __init__(self,  ResultCode = None):
+        SAPMessage.__init__(self,"SET_TRANSPORT_PROTOCOL_RESP",  SAPMessage.SET_TRANSPORT_PROTOCOL_RESP)
+        if ResultCode is not None:
+            self.addParam(SAPParam_ResultCode(ResultCode))
+
+
+class SAPClient:
+
+    CONNECTED = 1
+    DISCONNECTED = 0
+
+    uuid = "0000112D-0000-1000-8000-00805F9B34FB"
+    bufsize = 1024
+    timeout = 20
+    state = DISCONNECTED
+
+    def __init__(self,  host = None,  port = None):
+        self.sock = None
+
+        if host is None or is_valid_address(host):
+            self.host = host
+        else:
+            raise BluetoothError ("%s is not a valid BT address." % host)
+            self.host = None
+            return
+
+        if port is None:
+            self.__discover()
+        else:
+            self.port = port
+
+        self.__connectRFCOMM()
+
+    def __del__(self):
+        self.__disconnectRFCOMM()
+
+    def __disconnectRFCOMM(self):
+        if self.sock is not None:
+            self.sock.close()
+            self.state = self.DISCONNECTED
+
+    def __discover(self):
+        service_matches = find_service(self.uuid, self.host)
+
+        if len(service_matches) == 0:
+            raise BluetoothError ("No SAP service found")
+            return
+
+        first_match = service_matches[0]
+        self.port = first_match["port"]
+        self.host = first_match["host"]
+
+        print "SAP Service found on %s(%s)" % first_match["name"] % self.host
+
+    def __connectRFCOMM(self):
+        self.sock=BluetoothSocket( RFCOMM )
+        self.sock.connect((self.host, self.port))
+        self.sock.settimeout(self.timeout)
+        self.state = self.CONNECTED
+
+    def __sendMsg(self, msg):
+        if isinstance(msg,  SAPMessage):
+            s = msg.serialize()
+            print "\tTX: " + msg.getContent()
+            return self.sock.send(s.tostring())
+
+    def __rcvMsg(self,  msg):
+        if isinstance(msg,  SAPMessage):
+            print "\tRX Wait: %s(id = 0x%.2x)" % (msg.name, msg.id)
+            data = self.sock.recv(self.bufsize)
+            if data:
+                if msg.deserialize(array('B',data)):
+                    print "\tRX: len(%d) %s" % (len(data), msg.getContent())
+                    return msg
+                else:
+                    print "msg: %s" % array('B',data)
+                    raise BluetoothError ("Message deserialization failed.")
+            else:
+                raise BluetoothError ("Timeout. No data received.")
+
+    def connect(self):
+        self.__connectRFCOMM()
+
+    def disconnect(self):
+        self.__disconnectRFCOMM()
+
+    def isConnected(self):
+        return self.state
+
+    def proc_connect(self):
+        try:
+            self.__sendMsg(SAPMessage_CONNECT_REQ(self.bufsize))
+            params = self.__rcvMsg(SAPMessage_CONNECT_RESP()).getParams()
+
+            if params[0].getValue() in (0x00,  0x04):
+                pass
+            elif params[0].getValue() == 0x02:
+                self.bufsize = params[1].getValue()
+
+                self.__sendMsg(SAPMessage_CONNECT_REQ(self.bufsize))
+                params = self.__rcvMsg(SAPMessage_CONNECT_RESP()).getParams()
+
+                if params[0].getValue() not in (0x00,  0x04):
+                    return False
+            else:
+                return False
+
+            params = self.__rcvMsg(SAPMessage_STATUS_IND()).getParams()
+            if params[0].getValue() == 0x00:
+                return False
+            elif params[0].getValue() == 0x01:
+                """OK, Card reset"""
+                return self.proc_transferATR()
+            elif params[0].getValue() == 0x02:
+                """T0 not supported"""
+                if self.proc_transferATR():
+                    return self.proc_setTransportProtocol(1)
+                else:
+                    return False
+            else:
+                return False
+        except BluetoothError , e:
+            print "Error. " +str(e)
+            return False
+
+    def proc_disconnectByClient(self, timeout=0):
+        try:
+            self.__sendMsg(SAPMessage_DISCONNECT_REQ())
+            self.__rcvMsg(SAPMessage_DISCONNECT_RESP())
+            time.sleep(timeout) # let srv to close rfcomm
+            self.__disconnectRFCOMM()
+            return True
+        except BluetoothError , e:
+            print "Error. " +str(e)
+            return False
+
+    def proc_disconnectByServer(self, timeout=0):
+        try:
+            params = self.__rcvMsg(SAPMessage_DISCONNECT_IND()).getParams()
+
+            """graceful"""
+            if params[0].getValue() == 0x00:
+                if not self.proc_transferAPDU():
+                    return False
+
+            return self.proc_disconnectByClient(timeout)
+
+        except BluetoothError , e:
+            print "Error. " +str(e)
+            return False
+
+    def proc_transferAPDU(self,  apdu = "Sample APDU command"):
+        try:
+            self.__sendMsg(SAPMessage_TRANSFER_APDU_REQ(apdu))
+            params = self.__rcvMsg(SAPMessage_TRANSFER_APDU_RESP()).getParams()
+            return True
+        except BluetoothError , e:
+            print "Error. " +str(e)
+            return False
+
+    def proc_transferATR(self):
+        try:
+            self.__sendMsg(SAPMessage_TRANSFER_ATR_REQ())
+            params = self.__rcvMsg(SAPMessage_TRANSFER_ATR_RESP()).getParams()
+            return True
+        except BluetoothError , e:
+            print "Error. " +str(e)
+            return False
+
+    def proc_powerSimOff(self):
+        try:
+            self.__sendMsg(SAPMessage_POWER_SIM_OFF_REQ())
+            params = self.__rcvMsg(SAPMessage_POWER_SIM_OFF_RESP()).getParams()
+            return True
+        except BluetoothError , e:
+            print "Error. " +str(e)
+            return False
+
+    def proc_powerSimOn(self):
+        try:
+            self.__sendMsg(SAPMessage_POWER_SIM_ON_REQ())
+            params = self.__rcvMsg(SAPMessage_POWER_SIM_ON_RESP()).getParams()
+            if params[0].getValue() == 0x00:
+                return self.proc_transferATR()
+
+            return True
+        except BluetoothError , e:
+            print "Error. " +str(e)
+            return False
+
+    def proc_resetSim(self):
+        try:
+            self.__sendMsg(SAPMessage_RESET_SIM_REQ())
+            params = self.__rcvMsg(SAPMessage_RESET_SIM_RESP()).getParams()
+            if params[0].getValue() == 0x00:
+                return self.proc_transferATR()
+
+            return True
+        except BluetoothError , e:
+            print "Error. " +str(e)
+            return False
+
+    def proc_reportStatus(self):
+        try:
+            params = self.__rcvMsg(SAPMessage_STATUS_IND()).getParams()
+        except BluetoothError , e:
+            print "Error. " +str(e)
+            return False
+
+    def proc_transferCardReaderStatus(self):
+        try:
+            self.__sendMsg(SAPMessage_TRANSFER_CARD_READER_STATUS_REQ())
+            params = self.__rcvMsg(SAPMessage_TRANSFER_CARD_READER_STATUS_RESP()).getParams()
+        except BluetoothError , e:
+            print "Error. " +str(e)
+            return False
+
+    def proc_errorResponse(self):
+        try:
+            """ send malformed message, no mandatory maxmsgsize parameter"""
+            self.__sendMsg(SAPMessage_CONNECT_REQ())
+
+            params = self.__rcvMsg(SAPMessage_ERROR_RESP()).getParams()
+        except BluetoothError , e:
+            print "Error. " +str(e)
+            return False
+
+    def proc_setTransportProtocol(self,  protocol = 0):
+        try:
+            self.__sendMsg(SAPMessage_SET_TRANSPORT_PROTOCOL_REQ(protocol))
+            params = self.__rcvMsg(SAPMessage_SET_TRANSPORT_PROTOCOL_RESP()).getParams()
+
+            if params[0].getValue() == 0x00:
+                params = self.__rcvMsg(SAPMessage_STATUS_IND()).getParams()
+                if params[0].getValue() in (0x01,  0x02):
+                    return self.proc_transferATR()
+                else:
+                    return True
+                    """return False ???"""
+            elif params[0].getValue == 0x07:
+                """not supported"""
+                return True
+                """return False ???"""
+            else:
+                return False
+
+        except BluetoothError , e:
+            print "Error. " +str(e)
+            return False
+
+if __name__ == "__main__":
+    pass
index 50b622a..17bd8a6 100644 (file)
@@ -216,11 +216,9 @@ static void recv_mode(int sk)
 {
        struct timeval tv_beg,tv_end,tv_diff;
        long total;
-       uint32_t seq;
 
        syslog(LOG_INFO, "Receiving ...");
 
-       seq = 0;
        while (1) {
                gettimeofday(&tv_beg, NULL);
                total = 0;
index f2cc3dd..8d65860 100755 (executable)
@@ -6,6 +6,7 @@ import sys
 import dbus
 import dbus.service
 import dbus.mainloop.glib
+from optparse import OptionParser
 
 class Rejected(dbus.DBusException):
        _dbus_error_name = "org.bluez.Error.Rejected"
@@ -88,8 +89,17 @@ if __name__ == '__main__':
        manager = dbus.Interface(bus.get_object("org.bluez", "/"),
                                                        "org.bluez.Manager")
 
-       if len(sys.argv) > 1:
-               path = manager.FindAdapter(sys.argv[1])
+       capability = "DisplayYesNo"
+
+       parser = OptionParser()
+       parser.add_option("-c", "--capability", action="store",
+                                       type="string", dest="capability")
+       (options, args) = parser.parse_args()
+       if options.capability:
+               capability  = options.capability
+
+       if len(args) > 0:
+               path = manager.FindAdapter(args[0])
        else:
                path = manager.DefaultAdapter()
 
@@ -101,17 +111,17 @@ if __name__ == '__main__':
 
        mainloop = gobject.MainLoop()
 
-       if len(sys.argv) > 2:
-               if len(sys.argv) > 3:
-                       device = adapter.FindDevice(sys.argv[2])
+       if len(args) > 1:
+               if len(args) > 2:
+                       device = adapter.FindDevice(args[1])
                        adapter.RemoveDevice(device)
 
                agent.set_exit_on_release(False)
-               adapter.CreatePairedDevice(sys.argv[2], path, "DisplayYesNo",
+               adapter.CreatePairedDevice(args[1], path, capability,
                                        reply_handler=create_device_reply,
                                        error_handler=create_device_error)
        else:
-               adapter.RegisterAgent(path, "DisplayYesNo")
+               adapter.RegisterAgent(path, capability)
                print "Agent registered"
 
        mainloop.run()
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/test/simple-player b/test/simple-player
new file mode 100755 (executable)
index 0000000..70701da
--- /dev/null
@@ -0,0 +1,125 @@
+#!/usr/bin/python
+
+from __future__ import print_function
+import os
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+import gobject
+
+class Player(dbus.service.Object):
+       @dbus.service.method("org.bluez.MediaPlayer",
+                                       in_signature="", out_signature="")
+       def Release(self):
+               print("Release")
+               mainloop.quit()
+
+       @dbus.service.method("org.bluez.MediaPlayer",
+                                       in_signature="sv", out_signature="")
+       def SetProperty(self, key, value):
+               print("SetProperty (%s, %s)" % (key, value), file=sys.stderr)
+               return
+
+       @dbus.service.signal("org.bluez.MediaPlayer", signature="sv")
+       def PropertyChanged(self, setting, value):
+               """PropertyChanged(setting, value)
+
+               Send a PropertyChanged signal. 'setting' and 'value' are
+               string parameters as specified in doc/media-api.txt.
+               """
+               pass
+
+       @dbus.service.signal("org.bluez.MediaPlayer", signature="a{sv}")
+       def TrackChanged(self, metadata):
+               """TrackChanged(metadata)
+
+               Send a TrackChanged signal. 'metadata' parameter is a dictionary,
+               with values as defined in doc/media-api.txt.
+               """
+               pass
+
+       def help(self, func):
+               help(self.__class__.__dict__[func])
+
+class InputHandler:
+       commands = { 'TrackChanged': '(metadata)',
+                                       'PropertyChanged': '(key, value)',
+                                       'help': '(cmd)' }
+       def __init__(self, player):
+               self.player = player
+               print('\n\nAvailable commands:')
+               for cmd in self.commands:
+                       print('\t', cmd, self.commands[cmd], sep='')
+
+               print("\nUse python syntax to pass arguments to available methods.\n" \
+                "E.g.: TrackChanged({'Title': 'My title', 'Album': 'my album' })")
+               self.prompt()
+
+       def prompt(self):
+               print('\n>>> ', end='')
+               sys.stdout.flush()
+
+       def handle(self, fd, condition):
+               s = os.read(fd.fileno(), 1024).strip()
+               try:
+                       cmd = s[:s.find('(')]
+                       if not cmd in self.commands:
+                               print("Unknown command ", cmd)
+               except ValueError:
+                       print("Malformed command")
+                       return True
+
+               try:
+                       exec "self.player.%s" % s
+               except Exception as e:
+                       print(e)
+                       pass
+               self.prompt()
+               return True
+
+
+
+if __name__ == '__main__':
+       dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+       bus = dbus.SystemBus()
+       manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+                                               "org.bluez.Manager")
+
+       if len(sys.argv) > 1:
+               path = manager.FindAdapter(sys.argv[1])
+       else:
+               path = manager.DefaultAdapter()
+
+       media = dbus.Interface(bus.get_object("org.bluez", path),
+                                               "org.bluez.Media")
+
+       path = "/test/player"
+       player = Player(bus, path)
+       mainloop = gobject.MainLoop()
+
+       properties = dbus.Dictionary({ "Equalizer" : "off",
+                                       "Repeat" : "off",
+                                       "Shuffle" : "off",
+                                       "Scan" : "off",
+                                       "Status" : "playing",
+                                       "Position" : dbus.UInt32(0) }, signature="sv")
+
+       metadata = dbus.Dictionary({ "Title" : "Title",
+                                       "Artist" : "Artist",
+                                       "Album" : "Album",
+                                       "Genre" : "Genre",
+                                       "NumberOfTracks" : dbus.UInt32(10),
+                                       "Number" : dbus.UInt32(1),
+                                       "Duration" : dbus.UInt32(10000) }, signature="sv")
+
+       print('Register media player with:\n\tProperties: %s\n\tMetadata: %s' \
+                                               % (properties, metadata))
+
+       handler = InputHandler(player)
+       gobject.io_add_watch(sys.stdin, gobject.IO_IN, handler.handle)
+
+       media.RegisterPlayer(dbus.ObjectPath(path), properties, metadata)
+
+       mainloop.run()
index 00ef6f5..762ef98 100755 (executable)
@@ -29,6 +29,7 @@ if (len(args) < 1):
        print "Usage: %s <command>" % (sys.argv[0])
        print ""
        print "  address"
+       print "  list"
        print "  name [name]"
        print "  powered [on/off]"
        print "  pairable [on/off]"
@@ -51,6 +52,22 @@ if (args[0] == "name"):
                adapter.SetProperty("Name", args[1])
        sys.exit(0)
 
+if (args[0] == "list"):
+       if (len(args) < 2):
+               properties = manager.GetProperties()
+               for adapter_path in properties["Adapters"]:
+                       adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+                                                               "org.bluez.Adapter")
+                       prop = adapter.GetProperties()
+                       print " [ %s ]" % (adapter_path)
+                       for (key, value) in prop.iteritems():
+                               if (key == "Class"):
+                                       print "    %s = 0x%06x" % (key, value)
+                               else:
+                                       print "    %s = %s" % (key, value)
+                       print
+       sys.exit(0)
+
 if (args[0] == "powered"):
        if (len(args) < 2):
                properties = adapter.GetProperties()
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/test/test-health b/test/test-health
new file mode 100755 (executable)
index 0000000..16a5a2b
--- /dev/null
@@ -0,0 +1,217 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import dbus
+import dbus.service
+import gobject
+from dbus.mainloop.glib import DBusGMainLoop
+import sys
+
+DBusGMainLoop(set_as_default=True)
+loop = gobject.MainLoop()
+
+bus = dbus.SystemBus()
+
+def sig_received(*args, **kwargs):
+       if "member" not in kwargs:
+               return
+       if "path" not in kwargs:
+               return;
+       sig_name = kwargs["member"]
+       path = kwargs["path"]
+       print sig_name
+       print path
+       if sig_name == "PropertyChanged":
+               k, v = args
+               print k
+               print v
+       else:
+               ob = args[0]
+               print ob
+
+
+def enter_mainloop():
+       bus.add_signal_receiver(sig_received, bus_name="org.bluez",
+                               dbus_interface = "org.bluez.HealthDevice",
+                               path_keyword="path",
+                               member_keyword="member",
+                               interface_keyword="interface")
+
+       try:
+               print "Entering main lopp, push Ctrl+C for finish"
+
+               mainloop = gobject.MainLoop()
+               mainloop.run()
+       except KeyboardInterrupt:
+               pass
+       finally:
+               print "Exiting, bye"
+
+hdp_manager = dbus.Interface(bus.get_object("org.bluez", "/org/bluez"),
+                                               "org.bluez.HealthManager")
+
+role = None
+while role == None:
+       print "Select 1. source or 2. sink: ",
+       try:
+               sel = int(sys.stdin.readline())
+               if sel == 1:
+                       role = "Source"
+               elif sel == 2:
+                       role = "Sink"
+               else:
+                       raise ValueError
+       except (TypeError, ValueError):
+               print "Wrong selection, try again: ",
+       except KeyboardInterrupt:
+               sys.exit()
+
+dtype = None
+while dtype == None:
+       print "Select a data type: ",
+       try:
+               sel = int(sys.stdin.readline())
+               if (sel < 0) or (sel > 65535):
+                       raise ValueError
+               dtype = sel;
+       except (TypeError, ValueError):
+               print "Wrong selection, try again: ",
+       except KeyboardInterrupt:
+               sys.exit()
+
+pref = None
+if role == "Source":
+       while pref == None:
+               try:
+                       print "Select a preferred data channel type 1.",
+                       print "reliable 2. streaming: ",
+                       sel = int(sys.stdin.readline())
+                       if sel == 1:
+                               pref = "Reliable"
+                       elif sel == 2:
+                               pref = "Streaming"
+                       else:
+                               raise ValueError
+
+               except (TypeError, ValueError):
+                       print "Wrong selection, try again"
+               except KeyboardInterrupt:
+                       sys.exit()
+
+       app_path = hdp_manager.CreateApplication({
+                                       "DataType": dbus.types.UInt16(dtype),
+                                       "Role": role,
+                                       "Description": "Test Source",
+                                       "ChannelType": pref})
+else:
+       app_path = hdp_manager.CreateApplication({
+                                       "DataType": dbus.types.UInt16(dtype),
+                                       "Description": "Test sink",
+                                       "Role": role})
+
+print "New application created:", app_path
+
+con = None
+while con == None:
+       try:
+               print "Connect to a remote device (y/n)? ",
+               sel = sys.stdin.readline()
+               if sel in ("y\n", "yes\n", "Y\n", "YES\n"):
+                       con = True
+               elif sel in ("n\n", "no\n", "N\n", "NO\n"):
+                       con = False
+               else:
+                       print "Wrong selection, try again."
+       except KeyboardInterrupt:
+               sys.exit()
+
+if not con:
+       enter_mainloop()
+       sys.exit()
+
+manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+                                               "org.bluez.Manager")
+
+adapters = manager.ListAdapters()
+
+i = 1
+for ad in adapters:
+       print "%d. %s" % (i, ad)
+       i = i + 1
+
+print "Select an adapter: ",
+select = None
+while select == None:
+       try:
+               pos = int(sys.stdin.readline()) - 1
+               if pos < 0:
+                       raise TypeError
+               select = adapters[pos]
+       except (TypeError, IndexError, ValueError):
+               print "Wrong selection, try again: ",
+       except KeyboardInterrupt:
+               sys.exit()
+
+adapter =  dbus.Interface(bus.get_object("org.bluez", select),
+                                               "org.bluez.Adapter")
+
+devices = adapter.ListDevices()
+
+if len(devices) == 0:
+       print "No devices available"
+       sys.exit()
+
+i = 1
+for dev in devices:
+       print "%d. %s" % (i, dev)
+       i = i + 1
+
+print "Select a device: ",
+select = None
+while select == None:
+       try:
+               pos = int(sys.stdin.readline()) - 1
+               if pos < 0:
+                       raise TypeError
+               select = devices[pos]
+       except (TypeError, IndexError, ValueError):
+               print "Wrong selection, try again: ",
+       except KeyboardInterrupt:
+               sys.exit()
+
+device = dbus.Interface(bus.get_object("org.bluez", select),
+                                       "org.bluez.HealthDevice")
+
+echo = None
+while echo == None:
+       try:
+               print "Perform an echo (y/n)? ",
+               sel = sys.stdin.readline()
+               if sel in ("y\n", "yes\n", "Y\n", "YES\n"):
+                       echo = True
+               elif sel in ("n\n", "no\n", "N\n", "NO\n"):
+                       echo = False
+               else:
+                       print "Wrong selection, try again."
+       except KeyboardInterrupt:
+               sys.exit()
+
+if echo:
+       if device.Echo():
+               print "Echo was ok"
+       else:
+               print "Echo war wrong, exiting"
+               sys.exit()
+
+print "Connecting to device %s" % (select)
+
+if role == "Source":
+       chan = device.CreateChannel(app_path, "Reliable")
+else:
+       chan = device.CreateChannel(app_path, "Any")
+
+print chan
+
+enter_mainloop()
+
+hdp_manager.DestroyApplication(app_path)
diff --git a/test/test-health-sink b/test/test-health-sink
new file mode 100755 (executable)
index 0000000..cb9d434
--- /dev/null
@@ -0,0 +1,83 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import dbus
+import dbus.service
+import gobject
+from dbus.mainloop.glib import DBusGMainLoop
+import sys
+
+DBusGMainLoop(set_as_default=True)
+loop = gobject.MainLoop()
+
+bus = dbus.SystemBus()
+
+hdp_manager = dbus.Interface(bus.get_object("org.bluez", "/org/bluez"),
+                                               "org.bluez.HealthManager")
+app_path = hdp_manager.CreateApplication({"DataType": dbus.types.UInt16(4103),
+                                       "Role": "sink"})
+
+print app_path
+
+manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+                                               "org.bluez.Manager")
+
+adapters = manager.ListAdapters()
+
+i = 1
+for ad in adapters:
+       print "%d. %s" % (i, ad)
+       i = i + 1
+
+print "Select an adapter: ",
+select = None
+while select == None:
+       try:
+               pos = int(sys.stdin.readline()) - 1
+               if pos < 0:
+                       raise TypeError
+               select = adapters[pos]
+       except (TypeError, IndexError, ValueError):
+               print "Wrong selection, try again: ",
+       except KeyboardInterrupt:
+               sys.exit()
+
+adapter =  dbus.Interface(bus.get_object("org.bluez", select),
+                                               "org.bluez.Adapter")
+
+devices = adapter.ListDevices()
+
+if len(devices) == 0:
+       print "No devices available"
+       sys.exit()
+
+i = 1
+for dev in devices:
+       print "%d. %s" % (i, dev)
+       i = i + 1
+
+print "Select a device: ",
+select = None
+while select == None:
+       try:
+               pos = int(sys.stdin.readline()) - 1
+               if pos < 0:
+                       raise TypeError
+               select = devices[pos]
+       except (TypeError, IndexError, ValueError):
+               print "Wrong selection, try again: ",
+       except KeyboardInterrupt:
+               sys.exit()
+
+print "Connecting to %s" % (select)
+device = dbus.Interface(bus.get_object("org.bluez", select),
+                                       "org.bluez.HealthDevice")
+
+chan = device.CreateChannel(app_path, "Any")
+
+print chan
+
+print "Push Enter for finishing"
+sys.stdin.readline()
+
+hdp_manager.DestroyApplication(app_path)
diff --git a/test/test-nap b/test/test-nap
new file mode 100755 (executable)
index 0000000..c83d928
--- /dev/null
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+
+import sys
+import time
+import dbus
+from optparse import OptionParser, make_option
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+                                               "org.bluez.Manager")
+
+option_list = [
+               make_option("-i", "--device", action="store",
+                               type="string", dest="dev_id"),
+               ]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+       adapter_path = manager.FindAdapter(options.dev_id)
+else:
+       adapter_path = manager.DefaultAdapter()
+
+server = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+                                               "org.bluez.NetworkServer")
+
+service = "nap"
+
+if (len(args) < 1):
+       bridge = "tether"
+else:
+       bridge = args[0]
+
+server.Register(service, bridge)
+
+print "Server for %s registered for %s" % (service, bridge)
+
+print "Press CTRL-C to disconnect"
+
+try:
+       time.sleep(1000)
+       print "Terminating connection"
+except:
+       pass
+
+server.Unregister(service)
diff --git a/test/test-oob b/test/test-oob
new file mode 100755 (executable)
index 0000000..3340c00
--- /dev/null
@@ -0,0 +1,80 @@
+#!/usr/bin/python
+
+import gobject
+
+import dbus.mainloop.glib
+
+def create_device_reply(device):
+       print "Pairing succeed!"
+       mainloop.quit()
+
+def create_device_error(error):
+       print "Pairing failed."
+       mainloop.quit()
+
+if __name__ == '__main__':
+       dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+       mainloop = gobject.MainLoop()
+
+       bus = dbus.SystemBus()
+       manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+                                                       "org.bluez.Manager")
+
+       adapter0_path = manager.FindAdapter("hci0")
+       adapter1_path = manager.FindAdapter("hci1")
+
+       adapter0 = dbus.Interface(bus.get_object("org.bluez", adapter0_path),
+                                                       "org.bluez.Adapter")
+       adapter1 = dbus.Interface(bus.get_object("org.bluez", adapter1_path),
+                                                       "org.bluez.Adapter")
+
+       adapter0_address = adapter0.GetProperties()["Address"]
+       adapter1_address = adapter1.GetProperties()["Address"]
+       print "Adapters:"
+       print "    hci0: " + adapter0_address
+       print "    hci1: " + adapter1_address
+       print
+
+       print "Removing any existing bond..."
+
+       try:
+               device = adapter0.FindDevice(adapter1_address)
+               adapter0.RemoveDevice(device)
+       except:
+               pass
+
+       try:
+               device = adapter1.FindDevice(adapter0_address)
+               adapter1.RemoveDevice(device)
+       except:
+               pass
+
+       print "Done."
+       print
+       print "Reading local Out of Band data..."
+
+       oob_adapter0 = dbus.Interface(bus.get_object("org.bluez",
+                                       adapter0_path), "org.bluez.OutOfBand")
+       oob_adapter1 = dbus.Interface(bus.get_object("org.bluez",
+                                       adapter1_path), "org.bluez.OutOfBand")
+
+       oob0 = oob_adapter0.ReadLocalData()
+       oob1 = oob_adapter1.ReadLocalData()
+
+       print "Done."
+       print
+       print "Exchanging Out of Band data..."
+
+       oob_adapter0.AddRemoteData(adapter1_address, oob1[0], oob1[1])
+       oob_adapter1.AddRemoteData(adapter0_address, oob0[0], oob0[1])
+
+       print "Done."
+       print
+       print "Starting to pair."
+       adapter1.CreatePairedDevice(adapter0_address, "/test/agent_oob",
+                                       "DisplayYesNo",
+                                       reply_handler=create_device_reply,
+                                       error_handler=create_device_error)
+
+       mainloop.run()
diff --git a/test/test-proximity b/test/test-proximity
new file mode 100755 (executable)
index 0000000..289908e
--- /dev/null
@@ -0,0 +1,66 @@
+#!/usr/bin/python
+
+'''
+Proximity Monitor test script
+'''
+
+import gobject
+
+import sys
+import dbus
+import dbus.mainloop.glib
+from optparse import OptionParser, make_option
+
+def property_changed(name, value):
+
+       print "PropertyChanged('%s', '%s')" % (name, value)
+       mainloop.quit()
+
+if __name__ == "__main__":
+       dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+       bus = dbus.SystemBus()
+
+       manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+                                       "org.bluez.Manager")
+
+       option_list = [
+               make_option("-i", "--adapter", action="store",
+                       type="string", dest="dev_id"),
+               make_option("-b", "--device", action="store",
+                       type="string", dest="address"),
+
+               ]
+       parser = OptionParser(option_list=option_list)
+
+       (options, args) = parser.parse_args()
+
+       if options.dev_id:
+               adapter_path = manager.FindAdapter(options.dev_id)
+       else:
+               adapter_path = manager.DefaultAdapter()
+
+       adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+                                                       "org.bluez.Adapter")
+
+       if (len(args) < 1):
+               print "Usage: %s <command>" % (sys.argv[0])
+               print ""
+               print "  -b MAC LinkLossAlertLevel <none|mild|high>"
+               print "  -b MAC ImmediateAlertLevel <none|mild|high>"
+               sys.exit(1)
+
+       device_path = adapter.FindDevice(options.address)
+
+       bus.add_signal_receiver(property_changed, bus_name="org.bluez",
+                               dbus_interface="org.bluez.Proximity",
+                               signal_name="PropertyChanged")
+
+       proximity = dbus.Interface(bus.get_object("org.bluez",
+                                       device_path), "org.bluez.Proximity")
+
+       print "Proximity SetProperty('%s', '%s')" % (args[0], args[1])
+       proximity.SetProperty(args[0], args[1])
+
+       mainloop = gobject.MainLoop()
+       mainloop.run()
diff --git a/test/test-sap-server b/test/test-sap-server
new file mode 100755 (executable)
index 0000000..bea6ca9
--- /dev/null
@@ -0,0 +1,138 @@
+#!/usr/bin/python
+
+from sap import *
+import time
+
+def connect_disconnect_by_client(sap):
+
+    print "[Test] Connect - Disconnect by client \n"
+
+    try:
+        if not sap.isConnected():
+           sap.connect()
+
+        if sap.proc_connect():
+            if sap.proc_disconnectByClient():
+                print "OK"
+                return 0
+
+        print "NOT OK"
+        return 1
+
+    except BluetoothError , e:
+        print "Error " + str(e)
+
+
+def connect_disconnect_by_server_gracefully(sap, timeout=0):
+
+    print "[Test] Connect - Disconnect by server with timer \n"
+
+    try:
+        if not sap.isConnected():
+           sap.connect()
+
+        if sap.proc_connect():
+            if sap.proc_disconnectByServer(timeout):
+                print "OK"
+                return 0
+
+        print "NOT OK"
+        return 1
+
+    except BluetoothError , e:
+        print "Error " + str(e)
+
+
+def connect_txAPDU_disconnect_by_client(sap):
+
+    print "[Test] Connect - TX APDU - Disconnect by client \n"
+
+    try:
+        if not sap.isConnected():
+           sap.connect()
+
+        if sap.proc_connect():
+            if not sap.proc_transferAPDU():
+                print "NOT OK 1"
+                return 1
+
+            if not sap.proc_transferAPDU():
+                print "NOT OK 2"
+                return 1
+
+            if not sap.proc_transferAPDU():
+                print "NOT OK 3"
+                return 1
+
+            if not sap.proc_transferAPDU():
+                print "NOT OK 4"
+                return 1
+
+            if sap.proc_disconnectByClient():
+                print "OK"
+                return 0
+
+        print "NOT OK"
+        return 1
+
+    except BluetoothError , e:
+        print "Error " + str(e)
+
+def connect_rfcomm_only_and_wait_for_close_by_server(sap):
+
+    print "[Test] Connect rfcomm only  - Disconnect by server timeout \n"
+
+    if not sap.isConnected():
+       sap.connect()
+
+    time.sleep(40)
+    print "OK"
+
+def power_sim_off_on(sap):
+
+    print "[Test] Powe sim off \n"
+
+    try:
+        if not sap.isConnected():
+           sap.connect()
+
+        if sap.proc_connect():
+            if not sap.proc_resetSim():
+                print "NOT OK"
+                return 1
+
+            if not sap.proc_powerSimOff():
+                print "NOT OK"
+                return 1
+
+            if not sap.proc_powerSimOn():
+                print "NOT OK"
+                return 1
+
+            if sap.proc_disconnectByClient():
+                print "OK"
+                return 0
+
+        print "NOT OK"
+        return 1
+
+    except BluetoothError , e:
+        print "Error " + str(e)
+
+
+if __name__ == "__main__":
+
+    host = "00:00:00:00:00:0"  # server bd_addr
+    port = 8  # sap server port
+
+    try:
+        s = SAPClient(host, port)
+    except BluetoothError , e:
+        print "Error " + str(e)
+
+    connect_disconnect_by_client(s)
+    connect_disconnect_by_server_gracefully(s)
+    connect_disconnect_by_server_gracefully(s, 40)  #  wait 40 sec for srv to close rfcomm sock
+    connect_rfcomm_only_and_wait_for_close_by_server(s)
+    connect_txAPDU_disconnect_by_client(s)
+    power_sim_off_on(s)
diff --git a/test/test-serial-proxy b/test/test-serial-proxy
new file mode 100755 (executable)
index 0000000..f6dbd6c
--- /dev/null
@@ -0,0 +1,64 @@
+#!/usr/bin/python
+
+import sys
+import time
+import dbus
+import socket
+from optparse import OptionParser, make_option
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+                                               "org.bluez.Manager")
+option_list = [
+               make_option("-i", "--device", action="store",
+                               type="string", dest="dev_id"),
+               ]
+parser = OptionParser(option_list=option_list)
+
+(options, args) = parser.parse_args()
+
+if options.dev_id:
+       adapter_path = manager.FindAdapter(options.dev_id)
+else:
+       adapter_path = manager.DefaultAdapter()
+
+adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+                                                       "org.bluez.Adapter")
+
+if (len(args) < 1):
+       print "Usage: %s <socket_name> [service]" % (sys.argv[0])
+       sys.exit(1)
+
+socket_name = args[0]
+
+if (len(args) < 2):
+       service = "spp"
+else:
+       service = args[1]
+
+sk = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+sk.bind(socket_name)
+sk.listen(1)
+
+proxy_manager = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+                                               "org.bluez.SerialProxyManager")
+proxy_path = proxy_manager.CreateProxy(service, socket_name)
+
+proxy = dbus.Interface(bus.get_object("org.bluez", proxy_path),
+                                                       "org.bluez.SerialProxy")
+proxy.Enable()
+
+conn, addr = sk.accept()
+
+print "Waiting for message"
+
+while 1:
+       data = conn.recv(1024)
+       if data:
+               print(data)
+               break
+
+proxy.Disable()
+proxy_manager.RemoveProxy(proxy_path)
+conn.close()
index 970e9e7..e0a0c5b 100644 (file)
@@ -44,25 +44,28 @@ int main(int argc, char *argv[])
        char filename[] = "/tmp/textfile";
        char key[18], value[512], *str;
        unsigned int i, j, size, max = 10;
-       int fd, err;
+       int fd;
 
        size = getpagesize();
        printf("System uses a page size of %d bytes\n\n", size);
 
        fd = creat(filename, 0644);
-       err = ftruncate(fd, 0);
+       if (ftruncate(fd, 0) < 0)
+               return -errno;
 
        memset(value, 0, sizeof(value));
-       for (i = 0; i < (size / sizeof(value)); i++)
-               err = write(fd, value, sizeof(value));
+       for (i = 0; i < (size / sizeof(value)); i++) {
+               if (write(fd, value, sizeof(value)) < 0)
+                       return -errno;
+       }
 
        close(fd);
 
        sprintf(key, "11:11:11:11:11:11");
        str = textfile_get(filename, key);
 
-       err = truncate(filename, 0);
-
+       if (truncate(filename, 0) < 0)
+               return -errno;
 
        sprintf(key, "00:00:00:00:00:00");
        if (textfile_del(filename, key) < 0)
diff --git a/test/test-thermometer b/test/test-thermometer
new file mode 100755 (executable)
index 0000000..5f9742a
--- /dev/null
@@ -0,0 +1,88 @@
+#!/usr/bin/python
+
+'''
+Thermometer test script
+'''
+
+import gobject
+
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+from optparse import OptionParser, make_option
+
+class Watcher(dbus.service.Object):
+       @dbus.service.method("org.bluez.ThermometerWatcher",
+                                       in_signature="a{sv}", out_signature="")
+       def MeasurementReceived(self, measure):
+               print measure["Measurement"], " measurement received"
+               print "Exponent: ", measure["Exponent"]
+               print "Mantissa: ", measure["Mantissa"]
+               print "Unit: ", measure["Unit"]
+
+               if measure.has_key("Time"):
+                       print "Time: ", measure["Time"]
+
+               print "Type: ", measure["Type"]
+
+def property_changed(name, value):
+
+       print "PropertyChanged('%s', '%s')" % (name, value)
+
+if __name__ == "__main__":
+       dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+       bus = dbus.SystemBus()
+
+       manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+                                       "org.bluez.Manager")
+
+       option_list = [
+               make_option("-i", "--adapter", action="store",
+                       type="string", dest="adapter"),
+               make_option("-b", "--device", action="store",
+                       type="string", dest="address"),
+               ]
+
+       parser = OptionParser(option_list=option_list)
+
+       (options, args) = parser.parse_args()
+
+       if not options.address:
+               print "Usage: %s [-i <adapter>] -b <bdaddr> [command]" % (sys.argv[0])
+               print "Possible commands:"
+               print "\tEnableIntermediateMeasurement"
+               sys.exit(1)
+
+       if options.adapter:
+               adapter_path = manager.FindAdapter(options.adapter)
+       else:
+               adapter_path = manager.DefaultAdapter()
+
+       adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+                                                       "org.bluez.Adapter")
+
+       device_path = adapter.FindDevice(options.address)
+
+       bus.add_signal_receiver(property_changed, bus_name="org.bluez",
+                               dbus_interface="org.bluez.Thermometer",
+                               signal_name="PropertyChanged")
+
+       thermometer = dbus.Interface(bus.get_object("org.bluez",
+                                       device_path), "org.bluez.Thermometer")
+
+       path = "/test/watcher"
+       watcher = Watcher(bus, path)
+
+       thermometer.RegisterWatcher(path)
+
+       if len(args) > 0:
+               if args[0] == "EnableIntermediateMeasurement":
+                       thermometer.EnableIntermediateMeasurement(path)
+               else:
+                       print "unknown command"
+                       sys.exit(1)
+
+       mainloop = gobject.MainLoop()
+       mainloop.run()
similarity index 73%
rename from attrib/main.c
rename to thermometer/main.c
index 6c946be..471764e 100644 (file)
@@ -2,9 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2010  Nokia Corporation
- *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
- *
+ *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 #include <config.h>
 #endif
 
+#include <glib.h>
 #include <errno.h>
-
 #include <gdbus.h>
 
 #include "plugin.h"
 #include "manager.h"
 
-static DBusConnection *connection;
+static DBusConnection *connection = NULL;
 
-static int attrib_init(void)
+static int thermometer_init(void)
 {
        connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
        if (connection == NULL)
                return -EIO;
 
-       if (attrib_manager_init(connection) < 0) {
+       if (thermometer_manager_init(connection) < 0) {
                dbus_connection_unref(connection);
                return -EIO;
        }
@@ -49,12 +47,13 @@ static int attrib_init(void)
        return 0;
 }
 
-static void attrib_exit(void)
+static void thermometer_exit(void)
 {
-       attrib_manager_exit();
+       thermometer_manager_exit();
 
        dbus_connection_unref(connection);
+       connection = NULL;
 }
 
-BLUETOOTH_PLUGIN_DEFINE(attrib, VERSION,
-               BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, attrib_init, attrib_exit)
+BLUETOOTH_PLUGIN_DEFINE(thermometer, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                                       thermometer_init, thermometer_exit)
diff --git a/thermometer/manager.c b/thermometer/manager.c
new file mode 100644 (file)
index 0000000..6b98bca
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <gdbus.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "att.h"
+#include "thermometer.h"
+#include "manager.h"
+
+#define HEALTH_THERMOMETER_UUID                "00001809-0000-1000-8000-00805f9b34fb"
+
+static DBusConnection *connection = NULL;
+
+static int thermometer_driver_probe(struct btd_device *device, GSList *uuids)
+{
+       struct att_primary *tattr;
+       GSList *list;
+
+       list = device_services_from_record(device, uuids);
+       if (list == NULL)
+               return -EINVAL;
+
+       tattr = list->data;
+
+       return thermometer_register(connection, device, tattr);
+}
+
+static void thermometer_driver_remove(struct btd_device *device)
+{
+       thermometer_unregister(device);
+}
+
+static struct btd_device_driver thermometer_device_driver = {
+       .name   = "thermometer-device-driver",
+       .uuids  = BTD_UUIDS(HEALTH_THERMOMETER_UUID),
+       .probe  = thermometer_driver_probe,
+       .remove = thermometer_driver_remove
+};
+
+int thermometer_manager_init(DBusConnection *conn)
+{
+       int ret;
+
+       ret = btd_register_device_driver(&thermometer_device_driver);
+       if (ret < 0)
+                return ret;
+
+       connection = dbus_connection_ref(conn);
+       return 0;
+}
+
+void thermometer_manager_exit(void)
+{
+       btd_unregister_device_driver(&thermometer_device_driver);
+
+       dbus_connection_unref(connection);
+       connection = NULL;
+}
diff --git a/thermometer/manager.h b/thermometer/manager.h
new file mode 100644 (file)
index 0000000..ed928ad
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int thermometer_manager_init(DBusConnection *conn);
+void thermometer_manager_exit(void);
diff --git a/thermometer/thermometer.c b/thermometer/thermometer.c
new file mode 100644 (file)
index 0000000..9bf9881
--- /dev/null
@@ -0,0 +1,1253 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gdbus.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+
+#include "dbus-common.h"
+#include "adapter.h"
+#include "device.h"
+#include "error.h"
+#include "log.h"
+#include "gattrib.h"
+#include "attio.h"
+#include "att.h"
+#include "gatt.h"
+#include "thermometer.h"
+#include "glib-compat.h"
+
+#define THERMOMETER_INTERFACE "org.bluez.Thermometer"
+
+#define TEMPERATURE_MEASUREMENT_UUID   "00002a1c-0000-1000-8000-00805f9b34fb"
+#define TEMPERATURE_TYPE_UUID          "00002a1d-0000-1000-8000-00805f9b34fb"
+#define INTERMEDIATE_TEMPERATURE_UUID  "00002a1e-0000-1000-8000-00805f9b34fb"
+#define MEASUREMENT_INTERVAL_UUID      "00002a21-0000-1000-8000-00805f9b34fb"
+
+/* Temperature measurement flag fields */
+#define TEMP_UNITS             0x01
+#define TEMP_TIME_STAMP                0x02
+#define TEMP_TYPE              0x04
+
+#define FLOAT_MAX_MANTISSA     16777216 /* 2^24 */
+
+struct thermometer {
+       DBusConnection          *conn;          /* The connection to the bus */
+       struct btd_device       *dev;           /* Device reference */
+       GAttrib                 *attrib;        /* GATT connection */
+       struct att_range        *svc_range;     /* Thermometer range */
+       guint                   attioid;        /* Att watcher id */
+       guint                   attindid;       /* Att incications id */
+       guint                   attnotid;       /* Att notifications id */
+       GSList                  *chars;         /* Characteristics */
+       GSList                  *fwatchers;     /* Final measurements */
+       GSList                  *iwatchers;     /* Intermediate measurements */
+       gboolean                intermediate;
+       uint8_t                 type;
+       uint16_t                interval;
+       uint16_t                max;
+       uint16_t                min;
+       gboolean                has_type;
+       gboolean                has_interval;
+};
+
+struct characteristic {
+       struct att_char         attr;   /* Characteristic */
+       GSList                  *desc;  /* Descriptors */
+       struct thermometer      *t;     /* Thermometer where the char belongs */
+};
+
+struct descriptor {
+       struct characteristic   *ch;
+       uint16_t                handle;
+       bt_uuid_t               uuid;
+};
+
+struct watcher {
+       struct thermometer      *t;
+       guint                   id;
+       char                    *srv;
+       char                    *path;
+};
+
+struct measurement {
+       int16_t         exp;
+       int32_t         mant;
+       uint64_t        time;
+       gboolean        suptime;
+       char            *unit;
+       char            *type;
+       char            *value;
+};
+
+struct tmp_interval_data {
+       struct thermometer      *thermometer;
+       uint16_t                interval;
+};
+
+static GSList *thermometers = NULL;
+
+const char *temp_type[] = {
+       "<reserved>",
+       "Armpit",
+       "Body",
+       "Ear",
+       "Finger",
+       "Intestines",
+       "Mouth",
+       "Rectum",
+       "Toe",
+       "Tympanum"
+};
+
+static const gchar *temptype2str(uint8_t value)
+{
+        if (value > 0 && value < G_N_ELEMENTS(temp_type))
+               return temp_type[value];
+
+       error("Temperature type %d reserved for future use", value);
+       return NULL;
+}
+
+static void destroy_watcher(gpointer user_data)
+{
+       struct watcher *watcher = user_data;
+
+       if (watcher->id > 0)
+               g_dbus_remove_watch(watcher->t->conn, watcher->id);
+
+       g_free(watcher->path);
+       g_free(watcher->srv);
+       g_free(watcher);
+}
+
+static void destroy_char(gpointer user_data)
+{
+       struct characteristic *c = user_data;
+
+       g_slist_free_full(c->desc, g_free);
+       g_free(c);
+}
+
+static void destroy_thermometer(gpointer user_data)
+{
+       struct thermometer *t = user_data;
+
+       if (t->attioid > 0)
+               btd_device_remove_attio_callback(t->dev, t->attioid);
+
+       if (t->attindid > 0)
+               g_attrib_unregister(t->attrib, t->attindid);
+
+       if (t->attnotid > 0)
+               g_attrib_unregister(t->attrib, t->attnotid);
+
+       if (t->attrib != NULL)
+               g_attrib_unref(t->attrib);
+
+       if (t->chars != NULL)
+               g_slist_free_full(t->chars, destroy_char);
+
+       if (t->fwatchers != NULL)
+               g_slist_free_full(t->fwatchers, destroy_watcher);
+
+       dbus_connection_unref(t->conn);
+       btd_device_unref(t->dev);
+       g_free(t->svc_range);
+       g_free(t);
+}
+
+static gint cmp_device(gconstpointer a, gconstpointer b)
+{
+       const struct thermometer *t = a;
+       const struct btd_device *dev = b;
+
+       if (dev == t->dev)
+               return 0;
+
+       return -1;
+}
+
+static gint cmp_watcher(gconstpointer a, gconstpointer b)
+{
+       const struct watcher *watcher = a;
+       const struct watcher *match = b;
+       int ret;
+
+       ret = g_strcmp0(watcher->srv, match->srv);
+       if (ret != 0)
+               return ret;
+
+       return g_strcmp0(watcher->path, match->path);
+}
+
+static gint cmp_char_uuid(gconstpointer a, gconstpointer b)
+{
+       const struct characteristic *ch = a;
+       const char *uuid = b;
+
+       return g_strcmp0(ch->attr.uuid, uuid);
+}
+
+static gint cmp_char_val_handle(gconstpointer a, gconstpointer b)
+{
+       const struct characteristic *ch = a;
+       const uint16_t *handle = b;
+
+       return ch->attr.value_handle - *handle;
+}
+
+static gint cmp_descriptor(gconstpointer a, gconstpointer b)
+{
+       const struct descriptor *desc = a;
+       const bt_uuid_t *uuid = b;
+
+       return bt_uuid_cmp(&desc->uuid, uuid);
+}
+
+static struct characteristic *get_characteristic(struct thermometer *t,
+                                                       const char *uuid)
+{
+       GSList *l;
+
+       l = g_slist_find_custom(t->chars, uuid, cmp_char_uuid);
+       if (l == NULL)
+               return NULL;
+
+       return l->data;
+}
+
+static struct descriptor *get_descriptor(struct characteristic *ch,
+                                                       const bt_uuid_t *uuid)
+{
+       GSList *l;
+
+       l = g_slist_find_custom(ch->desc, uuid, cmp_descriptor);
+       if (l == NULL)
+               return NULL;
+
+       return l->data;
+}
+
+static void change_property(struct thermometer *t, const char *name,
+                                                       gpointer value) {
+       if (g_strcmp0(name, "Intermediate") == 0) {
+               gboolean *intermediate = value;
+               if (t->intermediate == *intermediate)
+                       return;
+
+               t->intermediate = *intermediate;
+               emit_property_changed(t->conn, device_get_path(t->dev),
+                                       THERMOMETER_INTERFACE, name,
+                                       DBUS_TYPE_BOOLEAN, &t->intermediate);
+       } else if (g_strcmp0(name, "Interval") == 0) {
+               uint16_t *interval = value;
+               if (t->has_interval && t->interval == *interval)
+                       return;
+
+               t->has_interval = TRUE;
+               t->interval = *interval;
+               emit_property_changed(t->conn, device_get_path(t->dev),
+                                       THERMOMETER_INTERFACE, name,
+                                       DBUS_TYPE_UINT16, &t->interval);
+       } else if (g_strcmp0(name, "Maximum") == 0) {
+               uint16_t *max = value;
+               if (t->max == *max)
+                       return;
+
+               t->max = *max;
+               emit_property_changed(t->conn, device_get_path(t->dev),
+                                       THERMOMETER_INTERFACE, name,
+                                       DBUS_TYPE_UINT16, &t->max);
+       } else if (g_strcmp0(name, "Minimum") == 0) {
+               uint16_t *min = value;
+               if (t->min == *min)
+                       return;
+
+               t->min = *min;
+               emit_property_changed(t->conn, device_get_path(t->dev),
+                                       THERMOMETER_INTERFACE, name,
+                                       DBUS_TYPE_UINT16, &t->min);
+       } else
+               DBG("%s is not a thermometer property", name);
+}
+
+static void valid_range_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
+                                                       gpointer user_data)
+{
+       struct descriptor *desc = user_data;
+       uint8_t value[ATT_MAX_MTU];
+       uint16_t max, min;
+       int vlen;
+
+       if (status != 0) {
+               DBG("Valid Range descriptor read failed: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       if (!dec_read_resp(pdu, len, value, &vlen)) {
+               DBG("Protocol error\n");
+               return;
+       }
+
+       if (vlen < 4) {
+               DBG("Invalid range received");
+               return;
+       }
+
+       min = att_get_u16(&value[0]);
+       max = att_get_u16(&value[2]);
+
+       if (min == 0 || min > max) {
+               DBG("Invalid range");
+               return;
+       }
+
+       change_property(desc->ch->t, "Maximum", &max);
+       change_property(desc->ch->t, "Minimum", &min);
+}
+
+static void process_thermometer_desc(struct descriptor *desc)
+{
+       struct characteristic *ch = desc->ch;
+       char uuidstr[MAX_LEN_UUID_STR];
+       bt_uuid_t btuuid;
+
+       bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+
+       if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
+               uint8_t atval[2];
+               uint16_t val;
+
+               if (g_strcmp0(ch->attr.uuid,
+                                       TEMPERATURE_MEASUREMENT_UUID) == 0) {
+                       if (g_slist_length(ch->t->fwatchers) == 0)
+                               return;
+
+                       val = ATT_CLIENT_CHAR_CONF_INDICATION;
+               } else if (g_strcmp0(ch->attr.uuid,
+                                       INTERMEDIATE_TEMPERATURE_UUID) == 0) {
+                       if (g_slist_length(ch->t->iwatchers) == 0)
+                               return;
+
+                       val = ATT_CLIENT_CHAR_CONF_NOTIFICATION;
+               } else if (g_strcmp0(ch->attr.uuid,
+                                       MEASUREMENT_INTERVAL_UUID) == 0)
+                       val = ATT_CLIENT_CHAR_CONF_INDICATION;
+               else
+                       goto done;
+
+               att_put_u16(val, atval);
+               gatt_write_char(ch->t->attrib, desc->handle, atval, 2,
+                                                               NULL, NULL);
+               return;
+       }
+
+       bt_uuid16_create(&btuuid, GATT_CHARAC_VALID_RANGE_UUID);
+
+       if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0 && g_strcmp0(ch->attr.uuid,
+                                       MEASUREMENT_INTERVAL_UUID) == 0) {
+               gatt_read_char(ch->t->attrib, desc->handle, 0,
+                                               valid_range_desc_cb, desc);
+               return;
+       }
+
+done:
+       bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
+       DBG("Ignored descriptor %s in characteristic %s", uuidstr,
+                                                               ch->attr.uuid);
+}
+
+static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
+                                                       gpointer user_data)
+{
+       struct characteristic *ch = user_data;
+       struct att_data_list *list;
+       uint8_t format;
+       int i;
+
+       if (status != 0) {
+               error("Discover all characteristic descriptors failed [%s]: %s",
+                                       ch->attr.uuid, att_ecode2str(status));
+               return;
+       }
+
+       list = dec_find_info_resp(pdu, len, &format);
+       if (list == NULL)
+               return;
+
+       for (i = 0; i < list->num; i++) {
+               struct descriptor *desc;
+               uint8_t *value;
+
+               value = list->data[i];
+               desc = g_new0(struct descriptor, 1);
+               desc->handle = att_get_u16(value);
+               desc->ch = ch;
+
+               if (format == 0x01)
+                       desc->uuid = att_get_uuid16(&value[2]);
+               else
+                       desc->uuid = att_get_uuid128(&value[2]);
+
+               ch->desc = g_slist_append(ch->desc, desc);
+               process_thermometer_desc(desc);
+       }
+
+       att_data_list_free(list);
+}
+
+static void read_temp_type_cb(guint8 status, const guint8 *pdu, guint16 len,
+                                                       gpointer user_data)
+{
+       struct characteristic *ch = user_data;
+       struct thermometer *t = ch->t;
+       uint8_t value[ATT_MAX_MTU];
+       int vlen;
+
+       if (status != 0) {
+               DBG("Temperature Type value read failed: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       if (!dec_read_resp(pdu, len, value, &vlen)) {
+               DBG("Protocol error.");
+               return;
+       }
+
+       if (vlen != 1) {
+               DBG("Invalid length for Temperature type");
+               return;
+       }
+
+       t->has_type = TRUE;
+       t->type = value[0];
+}
+
+static void read_interval_cb(guint8 status, const guint8 *pdu, guint16 len,
+                                                       gpointer user_data)
+{
+       struct characteristic *ch = user_data;
+       uint8_t value[ATT_MAX_MTU];
+       uint16_t interval;
+       int vlen;
+
+       if (status != 0) {
+               DBG("Measurement Interval value read failed: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       if (!dec_read_resp(pdu, len, value, &vlen)) {
+               DBG("Protocol error\n");
+               return;
+       }
+
+       if (vlen < 2) {
+               DBG("Invalid Interval received");
+               return;
+       }
+
+       interval = att_get_u16(&value[0]);
+       change_property(ch->t, "Interval", &interval);
+}
+
+static void process_thermometer_char(struct characteristic *ch)
+{
+       if (g_strcmp0(ch->attr.uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0) {
+               gboolean intermediate = TRUE;
+               change_property(ch->t, "Intermediate", &intermediate);
+               return;
+       } else if (g_strcmp0(ch->attr.uuid, TEMPERATURE_TYPE_UUID) == 0)
+               gatt_read_char(ch->t->attrib, ch->attr.value_handle, 0,
+                                                       read_temp_type_cb, ch);
+       else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
+               gatt_read_char(ch->t->attrib, ch->attr.value_handle, 0,
+                                                       read_interval_cb, ch);
+}
+
+static void configure_thermometer_cb(GSList *characteristics, guint8 status,
+                                                       gpointer user_data)
+{
+       struct thermometer *t = user_data;
+       GSList *l;
+
+       if (status != 0) {
+               error("Discover thermometer characteristics: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       for (l = characteristics; l; l = l->next) {
+               struct att_char *c = l->data;
+               struct characteristic *ch;
+               uint16_t start, end;
+
+               ch = g_new0(struct characteristic, 1);
+               ch->attr.handle = c->handle;
+               ch->attr.properties = c->properties;
+               ch->attr.value_handle = c->value_handle;
+               memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
+               ch->t = t;
+
+               t->chars = g_slist_append(t->chars, ch);
+
+               process_thermometer_char(ch);
+
+               start = c->value_handle + 1;
+
+               if (l->next != NULL) {
+                       struct att_char *c = l->next->data;
+                       if (start == c->handle)
+                               continue;
+                       end = c->handle - 1;
+               } else if (c->value_handle != t->svc_range->end)
+                       end = t->svc_range->end;
+               else
+                       continue;
+
+               gatt_find_info(t->attrib, start, end, discover_desc_cb, ch);
+       }
+}
+
+static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct thermometer *t = data;
+       DBusMessageIter iter;
+       DBusMessageIter dict;
+       DBusMessage *reply;
+
+       reply = dbus_message_new_method_return(msg);
+       if (reply == NULL)
+               return NULL;
+
+       dbus_message_iter_init_append(reply, &iter);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+       dict_append_entry(&dict, "Intermediate", DBUS_TYPE_BOOLEAN,
+                                                       &t->intermediate);
+
+       if (t->has_interval) {
+               dict_append_entry(&dict, "Interval", DBUS_TYPE_UINT16,
+                                                               &t->interval);
+               dict_append_entry(&dict, "Maximum", DBUS_TYPE_UINT16, &t->max);
+               dict_append_entry(&dict, "Minimum", DBUS_TYPE_UINT16, &t->min);
+       }
+
+       dbus_message_iter_close_container(&iter, &dict);
+
+       return reply;
+}
+
+static void write_interval_cb (guint8 status, const guint8 *pdu, guint16 len,
+                                                       gpointer user_data)
+{
+       struct tmp_interval_data *data = user_data;
+
+       if (status != 0) {
+               error("Interval Write Request failed %s",
+                                                       att_ecode2str(status));
+               goto done;
+       }
+
+       if (!dec_write_resp(pdu, len)) {
+               error("Interval Write Request: protocol error");
+               goto done;
+       }
+
+       change_property(data->thermometer, "Interval", &data->interval);
+
+done:
+       g_free(user_data);
+}
+
+static DBusMessage *write_attr_interval(struct thermometer *t, DBusMessage *msg,
+                                                               uint16_t value)
+{
+       struct tmp_interval_data *data;
+       struct characteristic *ch;
+       uint8_t atval[2];
+
+       if (t->attrib == NULL)
+               return btd_error_not_connected(msg);
+
+       ch = get_characteristic(t, MEASUREMENT_INTERVAL_UUID);
+       if (ch == NULL)
+               return btd_error_not_available(msg);
+
+       if (value < t->min || value > t->max)
+               return btd_error_invalid_args(msg);
+
+       att_put_u16(value, &atval[0]);
+
+       data = g_new0(struct tmp_interval_data, 1);
+       data->thermometer = t;
+       data->interval = value;
+       gatt_write_char(t->attrib, ch->attr.value_handle, atval, 2,
+                                               write_interval_cb, data);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct thermometer *t = data;
+       const char *property;
+       DBusMessageIter iter;
+       DBusMessageIter sub;
+       uint16_t value;
+
+       if (!dbus_message_iter_init(msg, &iter))
+               return btd_error_invalid_args(msg);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+               return btd_error_invalid_args(msg);
+
+       dbus_message_iter_get_basic(&iter, &property);
+       if (g_strcmp0("Interval", property) != 0)
+               return btd_error_invalid_args(msg);
+
+       if (!t->has_interval)
+               return btd_error_not_available(msg);
+
+       dbus_message_iter_next(&iter);
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+               return btd_error_invalid_args(msg);
+
+       dbus_message_iter_recurse(&iter, &sub);
+
+       if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)
+               return btd_error_invalid_args(msg);
+
+       dbus_message_iter_get_basic(&sub, &value);
+
+       return write_attr_interval(t, msg, value);
+}
+
+static void measurement_cb(guint8 status, const guint8 *pdu,
+                                               guint16 len, gpointer user_data)
+{
+       char *msg = user_data;
+
+       if (status != 0)
+               error("%s failed", msg);
+
+       g_free(msg);
+}
+
+static void enable_final_measurement(struct thermometer *t)
+{
+       struct characteristic *ch;
+       struct descriptor *desc;
+       bt_uuid_t btuuid;
+       uint8_t atval[2];
+       char *msg;
+
+       if (t->attrib == NULL)
+               return;
+
+       ch = get_characteristic(t, TEMPERATURE_MEASUREMENT_UUID);
+       if (ch == NULL) {
+               DBG("Temperature measurement characteristic not found");
+               return;
+       }
+
+       bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+       desc = get_descriptor(ch, &btuuid);
+       if (desc == NULL) {
+               DBG("Client characteristic configuration descriptor not found");
+               return;
+       }
+
+       atval[0] = 0x02;
+       atval[1] = 0x00;
+       msg = g_strdup("Enable final measurement");
+       gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
+}
+
+static void enable_intermediate_measurement(struct thermometer *t)
+{
+       struct characteristic *ch;
+       struct descriptor *desc;
+       bt_uuid_t btuuid;
+       uint8_t atval[2];
+       char *msg;
+
+       if (t->attrib == NULL)
+               return;
+
+       ch = get_characteristic(t, INTERMEDIATE_TEMPERATURE_UUID);
+       if (ch == NULL) {
+               DBG("Intermediate measurement characteristic not found");
+               return;
+       }
+
+       bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+       desc = get_descriptor(ch, &btuuid);
+       if (desc == NULL) {
+               DBG("Client characteristic configuration descriptor not found");
+               return;
+       }
+
+       atval[0] = 0x01;
+       atval[1] = 0x00;
+       msg = g_strdup("Enable intermediate measurement");
+       gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
+}
+
+static void disable_final_measurement(struct thermometer *t)
+{
+       struct characteristic *ch;
+       struct descriptor *desc;
+       bt_uuid_t btuuid;
+       uint8_t atval[2];
+       char *msg;
+
+       if (t->attrib == NULL)
+               return;
+
+       ch = get_characteristic(t, TEMPERATURE_MEASUREMENT_UUID);
+       if (ch == NULL) {
+               DBG("Temperature measurement characteristic not found");
+               return;
+       }
+
+       bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+       desc = get_descriptor(ch, &btuuid);
+       if (desc == NULL) {
+               DBG("Client characteristic configuration descriptor not found");
+               return;
+       }
+
+       atval[0] = 0x00;
+       atval[1] = 0x00;
+       msg = g_strdup("Disable final measurement");
+       gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
+}
+
+static void disable_intermediate_measurement(struct thermometer *t)
+{
+       struct characteristic *ch;
+       struct descriptor *desc;
+       bt_uuid_t btuuid;
+       uint8_t atval[2];
+       char *msg;
+
+       if (t->attrib == NULL)
+               return;
+
+       ch = get_characteristic(t, INTERMEDIATE_TEMPERATURE_UUID);
+       if (ch == NULL) {
+               DBG("Intermediate measurement characteristic not found");
+               return;
+       }
+
+       bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+       desc = get_descriptor(ch, &btuuid);
+       if (desc == NULL) {
+               DBG("Client characteristic configuration descriptor not found");
+               return;
+       }
+
+       atval[0] = 0x00;
+       atval[1] = 0x00;
+       msg = g_strdup("Disable intermediate measurement");
+       gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
+}
+
+static void remove_int_watcher(struct thermometer *t, struct watcher *w)
+{
+       if (!g_slist_find(t->iwatchers, w))
+               return;
+
+       t->iwatchers = g_slist_remove(t->iwatchers, w);
+
+       if (g_slist_length(t->iwatchers) == 0)
+               disable_intermediate_measurement(t);
+}
+
+static void watcher_exit(DBusConnection *conn, void *user_data)
+{
+       struct watcher *watcher = user_data;
+       struct thermometer *t = watcher->t;
+
+       DBG("Thermometer watcher %s disconnected", watcher->path);
+
+       remove_int_watcher(t, watcher);
+
+       t->fwatchers = g_slist_remove(t->fwatchers, watcher);
+       watcher->id = 0;
+
+       if (g_slist_length(t->fwatchers) == 0)
+               disable_final_measurement(t);
+}
+
+static struct watcher *find_watcher(GSList *list, const char *sender,
+                                                       const char *path)
+{
+       struct watcher *match;
+       GSList *l;
+
+       match = g_new0(struct watcher, 1);
+       match->srv = g_strdup(sender);
+       match->path = g_strdup(path);
+
+       l = g_slist_find_custom(list, match, cmp_watcher);
+       destroy_watcher(match);
+
+       if (l != NULL)
+               return l->data;
+
+       return NULL;
+}
+
+static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       const char *sender = dbus_message_get_sender(msg);
+       struct thermometer *t = data;
+       struct watcher *watcher;
+       char *path;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       watcher = find_watcher(t->fwatchers, sender, path);
+       if (watcher != NULL)
+               return btd_error_already_exists(msg);
+
+       DBG("Thermometer watcher %s registered", path);
+
+       watcher = g_new0(struct watcher, 1);
+       watcher->srv = g_strdup(sender);
+       watcher->path = g_strdup(path);
+       watcher->t = t;
+       watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
+                                               watcher, destroy_watcher);
+
+       if (g_slist_length(t->fwatchers) == 0)
+               enable_final_measurement(t);
+
+       t->fwatchers = g_slist_prepend(t->fwatchers, watcher);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       const char *sender = dbus_message_get_sender(msg);
+       struct thermometer *t = data;
+       struct watcher *watcher;
+       char *path;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       watcher = find_watcher(t->fwatchers, sender, path);
+       if (watcher == NULL)
+               return btd_error_does_not_exist(msg);
+
+       DBG("Thermometer watcher %s unregistered", path);
+
+       remove_int_watcher(t, watcher);
+
+       t->fwatchers = g_slist_remove(t->fwatchers, watcher);
+       destroy_watcher(watcher);
+
+       if (g_slist_length(t->fwatchers) == 0)
+               disable_final_measurement(t);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *enable_intermediate(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       const char *sender = dbus_message_get_sender(msg);
+       struct thermometer *t = data;
+       struct watcher *watcher;
+       char *path;
+
+       if (!t->intermediate)
+               return btd_error_not_supported(msg);
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       watcher = find_watcher(t->fwatchers, sender, path);
+       if (watcher == NULL)
+               return btd_error_does_not_exist(msg);
+
+       if (find_watcher(t->iwatchers, sender, path))
+               return btd_error_already_exists(msg);
+
+       DBG("Intermediate measurement watcher %s registered", path);
+
+       if (g_slist_length(t->iwatchers) == 0)
+               enable_intermediate_measurement(t);
+
+       t->iwatchers = g_slist_prepend(t->iwatchers, watcher);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *disable_intermediate(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       const char *sender = dbus_message_get_sender(msg);
+       struct thermometer *t = data;
+       struct watcher *watcher;
+       char *path;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       watcher = find_watcher(t->iwatchers, sender, path);
+       if (watcher == NULL)
+               return btd_error_does_not_exist(msg);
+
+       DBG("Intermediate measurement %s unregistered", path);
+
+       remove_int_watcher(t, watcher);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static GDBusMethodTable thermometer_methods[] = {
+       { "GetProperties",      "",     "a{sv}",        get_properties },
+       { "SetProperty",        "sv",   "",             set_property,
+                                               G_DBUS_METHOD_FLAG_ASYNC },
+       { "RegisterWatcher",    "o",    "",             register_watcher },
+       { "UnregisterWatcher",  "o",    "",             unregister_watcher },
+       { "EnableIntermediateMeasurement", "o", "", enable_intermediate },
+       { "DisableIntermediateMeasurement","o", "", disable_intermediate },
+       { }
+};
+
+static GDBusSignalTable thermometer_signals[] = {
+       { "PropertyChanged",    "sv"    },
+       { }
+};
+
+static void update_watcher(gpointer data, gpointer user_data)
+{
+       struct watcher *w = data;
+       struct measurement *m = user_data;
+       DBusConnection *conn = w->t->conn;
+       DBusMessageIter iter;
+       DBusMessageIter dict;
+       DBusMessage *msg;
+
+       msg = dbus_message_new_method_call(w->srv, w->path,
+                               "org.bluez.ThermometerWatcher",
+                               "MeasurementReceived");
+       if (msg == NULL)
+               return;
+
+       dbus_message_iter_init_append(msg, &iter);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+       dict_append_entry(&dict, "Exponent", DBUS_TYPE_INT16, &m->exp);
+       dict_append_entry(&dict, "Mantissa", DBUS_TYPE_INT32, &m->mant);
+       dict_append_entry(&dict, "Unit", DBUS_TYPE_STRING, &m->unit);
+
+       if (m->suptime)
+               dict_append_entry(&dict, "Time", DBUS_TYPE_UINT64, &m->time);
+
+       dict_append_entry(&dict, "Type", DBUS_TYPE_STRING, &m->type);
+       dict_append_entry(&dict, "Measurement", DBUS_TYPE_STRING, &m->value);
+
+       dbus_message_iter_close_container(&iter, &dict);
+
+       dbus_message_set_no_reply(msg, TRUE);
+       g_dbus_send_message(conn, msg);
+}
+
+static void recv_measurement(struct thermometer *t, struct measurement *m)
+{
+       GSList *wlist;
+
+       if (g_strcmp0(m->value, "Intermediate") == 0)
+               wlist = t->iwatchers;
+       else
+               wlist = t->fwatchers;
+
+       g_slist_foreach(wlist, update_watcher, m);
+}
+
+static void proc_measurement(struct thermometer *t, const uint8_t *pdu,
+                                               uint16_t len, gboolean final)
+{
+       struct measurement m;
+       const char *type;
+       uint8_t flags;
+       uint32_t raw;
+
+       if (len < 4) {
+               DBG("Mandatory flags are not provided");
+               return;
+       }
+
+       flags = pdu[3];
+       if (flags & TEMP_UNITS)
+               m.unit = "Fahrenheit";
+       else
+               m.unit = "Celsius";
+
+       if (len < 8) {
+               DBG("Temperature measurement value is not provided");
+               return;
+       }
+
+       raw = att_get_u32(&pdu[4]);
+       m.mant = raw & 0x00FFFFFF;
+       m.exp = ((int32_t) raw) >> 24;
+
+       if (m.mant & 0x00800000) {
+               /* convert to C2 negative value */
+               m.mant = m.mant - FLOAT_MAX_MANTISSA;
+       }
+
+       if (flags & TEMP_TIME_STAMP) {
+               struct tm ts;
+               time_t time;
+
+               if (len < 15) {
+                       DBG("Can't get time stamp value");
+                       return;
+               }
+
+               ts.tm_year = att_get_u16(&pdu[8]) - 1900;
+               ts.tm_mon = pdu[10] - 1;
+               ts.tm_mday = pdu[11];
+               ts.tm_hour = pdu[12];
+               ts.tm_min = pdu[13];
+               ts.tm_sec = pdu[14];
+               ts.tm_isdst = -1;
+
+               time = mktime(&ts);
+               m.time = (uint64_t) time;
+               m.suptime = TRUE;
+       } else
+               m.suptime = FALSE;
+
+       if (flags & TEMP_TYPE) {
+               uint8_t index;
+
+               if (m.suptime && len >= 16)
+                       index = 15;
+               else if (!m.suptime && len >= 9)
+                       index = 9;
+               else {
+                       DBG("Can't get temperature type");
+                       return;
+               }
+
+               type = temptype2str(pdu[index]);
+       } else if (t->has_type)
+               type = temptype2str(t->type);
+       else {
+               DBG("Can't get temperature type");
+               return;
+       }
+
+       if (type == NULL)
+               return;
+
+       m.type = g_strdup(type);
+       m.value = final ? "Final" : "Intermediate";
+
+       recv_measurement(t, &m);
+       g_free(m.type);
+}
+
+static void proc_measurement_interval(struct thermometer *t, const uint8_t *pdu,
+                                                               uint16_t len)
+{
+       uint16_t interval;
+
+       if (len < 5) {
+               DBG("Measurement interval value is not provided");
+               return;
+       }
+
+       interval = att_get_u16(&pdu[3]);
+
+       change_property(t, "Interval", &interval);
+}
+
+static void ind_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+       struct thermometer *t = user_data;
+       const struct characteristic *ch;
+       uint8_t opdu[ATT_MAX_MTU];
+       uint16_t handle, olen;
+       GSList *l;
+
+       if (len < 3) {
+               DBG("Bad pdu received");
+               return;
+       }
+
+       handle = att_get_u16(&pdu[1]);
+       l = g_slist_find_custom(t->chars, &handle, cmp_char_val_handle);
+       if (l == NULL) {
+               DBG("Unexpected handle: 0x%04x", handle);
+               return;
+       }
+
+       ch = l->data;
+
+       if (g_strcmp0(ch->attr.uuid, TEMPERATURE_MEASUREMENT_UUID) == 0)
+               proc_measurement(t, pdu, len, TRUE);
+       else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
+               proc_measurement_interval(t, pdu, len);
+
+       olen = enc_confirmation(opdu, sizeof(opdu));
+
+       if (olen > 0)
+               g_attrib_send(t->attrib, 0, opdu[0], opdu, olen, NULL, NULL,
+                                                                       NULL);
+}
+
+static void notif_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+       struct thermometer *t = user_data;
+       const struct characteristic *ch;
+       uint16_t handle;
+       GSList *l;
+
+       if (len < 3) {
+               DBG("Bad pdu received");
+               return;
+       }
+
+       handle = att_get_u16(&pdu[1]);
+       l = g_slist_find_custom(t->chars, &handle, cmp_char_val_handle);
+       if (l == NULL) {
+               DBG("Unexpected handle: 0x%04x", handle);
+               return;
+       }
+
+       ch = l->data;
+       if (g_strcmp0(ch->attr.uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0)
+               proc_measurement(t, pdu, len, FALSE);
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+       struct thermometer *t = user_data;
+
+       t->attrib = g_attrib_ref(attrib);
+
+       t->attindid = g_attrib_register(t->attrib, ATT_OP_HANDLE_IND,
+                                                       ind_handler, t, NULL);
+       t->attnotid = g_attrib_register(t->attrib, ATT_OP_HANDLE_NOTIFY,
+                                                       notif_handler, t, NULL);
+       gatt_discover_char(t->attrib, t->svc_range->start, t->svc_range->end,
+                                       NULL, configure_thermometer_cb, t);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+       struct thermometer *t = user_data;
+
+       DBG("GATT Disconnected");
+
+       if (t->attindid > 0) {
+               g_attrib_unregister(t->attrib, t->attindid);
+               t->attindid = 0;
+       }
+
+       if (t->attnotid > 0) {
+               g_attrib_unregister(t->attrib, t->attnotid);
+               t->attnotid = 0;
+       }
+
+       g_attrib_unref(t->attrib);
+       t->attrib = NULL;
+}
+
+int thermometer_register(DBusConnection *connection, struct btd_device *device,
+                                               struct att_primary *tattr)
+{
+       const gchar *path = device_get_path(device);
+       struct thermometer *t;
+
+       t = g_new0(struct thermometer, 1);
+       t->conn = dbus_connection_ref(connection);
+       t->dev = btd_device_ref(device);
+       t->svc_range = g_new0(struct att_range, 1);
+       t->svc_range->start = tattr->start;
+       t->svc_range->end = tattr->end;
+
+       if (!g_dbus_register_interface(t->conn, path, THERMOMETER_INTERFACE,
+                               thermometer_methods, thermometer_signals,
+                               NULL, t, destroy_thermometer)) {
+               error("D-Bus failed to register %s interface",
+                                                       THERMOMETER_INTERFACE);
+               destroy_thermometer(t);
+               return -EIO;
+       }
+
+       thermometers = g_slist_prepend(thermometers, t);
+
+       t->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
+                                               attio_disconnected_cb, t);
+       return 0;
+}
+
+void thermometer_unregister(struct btd_device *device)
+{
+       struct thermometer *t;
+       GSList *l;
+
+       l = g_slist_find_custom(thermometers, device, cmp_device);
+       if (l == NULL)
+               return;
+
+       t = l->data;
+       thermometers = g_slist_remove(thermometers, t);
+       g_dbus_unregister_interface(t->conn, device_get_path(t->dev),
+                                                       THERMOMETER_INTERFACE);
+}
diff --git a/thermometer/thermometer.h b/thermometer/thermometer.h
new file mode 100644 (file)
index 0000000..298c9ad
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int thermometer_register(DBusConnection *connection, struct btd_device *device,
+                                               struct att_primary *tattr);
+void thermometer_unregister(struct btd_device *device);
diff --git a/time/main.c b/time/main.c
new file mode 100644 (file)
index 0000000..a4de0fe
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <glib.h>
+
+#include "plugin.h"
+#include "hcid.h"
+#include "log.h"
+#include "server.h"
+
+static int time_init(void)
+{
+       if (!main_opts.attrib_server) {
+               DBG("Attribute server is disabled");
+               return -1;
+       }
+
+       return time_server_init();
+}
+
+static void time_exit(void)
+{
+       if (!main_opts.attrib_server)
+               return;
+
+       time_server_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(time, VERSION,
+                       BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                       time_init, time_exit)
diff --git a/time/server.c b/time/server.c
new file mode 100644 (file)
index 0000000..0730fbb
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <time.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+#include <adapter.h>
+
+#include "att.h"
+#include "gattrib.h"
+#include "attrib-server.h"
+#include "gatt-service.h"
+#include "log.h"
+#include "server.h"
+
+#define CURRENT_TIME_SVC_UUID          0x1805
+
+#define LOCAL_TIME_INFO_CHR_UUID       0x2A0F
+#define CT_TIME_CHR_UUID               0x2A2B
+
+static int encode_current_time(uint8_t value[10])
+{
+       struct timespec tp;
+       struct tm tm;
+
+       if (clock_gettime(CLOCK_REALTIME, &tp) == -1) {
+               int err = -errno;
+
+               error("clock_gettime: %s", strerror(-err));
+               return err;
+       }
+
+       if (localtime_r(&tp.tv_sec, &tm) == NULL) {
+               error("localtime_r() failed");
+               /* localtime_r() does not set errno */
+               return -EINVAL;
+       }
+
+       att_put_u16(1900 + tm.tm_year, &value[0]); /* Year */
+       value[2] = tm.tm_mon + 1; /* Month */
+       value[3] = tm.tm_mday; /* Day */
+       value[4] = tm.tm_hour; /* Hours */
+       value[5] = tm.tm_min; /* Minutes */
+       value[6] = tm.tm_sec; /* Seconds */
+       value[7] = tm.tm_wday == 0 ? 7 : tm.tm_wday; /* Day of Week */
+       /* From Time Profile spec: "The number of 1/256 fractions of a second."
+        * In 1s there are 256 fractions, in 1ns there are 256/10^9 fractions.
+        * To avoid integer overflow, we use the equivalent 1/3906250 ratio. */
+       value[8] = tp.tv_nsec / 3906250; /* Fractions256 */
+       value[9] = 0x00; /* Adjust Reason */
+
+       return 0;
+}
+
+static uint8_t current_time_read(struct attribute *a, gpointer user_data)
+{
+       uint8_t value[10];
+
+       if (encode_current_time(value) < 0)
+               return ATT_ECODE_IO;
+
+       /* FIXME: Provide the adapter in next function */
+       attrib_db_update(NULL, a->handle, NULL, value, sizeof(value), NULL);
+
+       return 0;
+}
+
+static uint8_t local_time_info_read(struct attribute *a, gpointer user_data)
+{
+       uint8_t value[2];
+
+       DBG("a=%p", a);
+
+       tzset();
+
+       /* FIXME: POSIX "daylight" variable only indicates whether there is DST
+        * for the local time or not. The offset is unknown. */
+       value[0] = daylight ? 0xff : 0x00;
+
+       /* Convert POSIX "timezone" (seconds West of GMT) to Time Profile
+        * format (offset from UTC in number of 15 minutes increments). */
+       value[1] = (uint8_t) (-1 * timezone / (60 * 15));
+
+       /* FIXME: Provide the adapter in next function */
+       attrib_db_update(NULL, a->handle, NULL, value, sizeof(value), NULL);
+
+       return 0;
+}
+
+static void register_current_time_service(void)
+{
+       /* Current Time service */
+       /* FIXME: Provide the adapter in next function */
+       gatt_service_add(NULL, GATT_PRIM_SVC_UUID, CURRENT_TIME_SVC_UUID,
+                               /* CT Time characteristic */
+                               GATT_OPT_CHR_UUID, CT_TIME_CHR_UUID,
+                               GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
+                                                       ATT_CHAR_PROPER_NOTIFY,
+                               GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+                                               current_time_read, NULL,
+
+                               /* Local Time Information characteristic */
+                               GATT_OPT_CHR_UUID, LOCAL_TIME_INFO_CHR_UUID,
+                               GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
+                               GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+                                               local_time_info_read, NULL,
+
+                               GATT_OPT_INVALID);
+}
+
+int time_server_init(void)
+{
+       register_current_time_service();
+
+       return 0;
+}
+
+void time_server_exit(void)
+{
+}
diff --git a/time/server.h b/time/server.h
new file mode 100644 (file)
index 0000000..621bf2b
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int time_server_init(void);
+void time_server_exit(void);
index 7f76c03..63b0da6 100644 (file)
@@ -604,7 +604,7 @@ static int l2cap_connect(bdaddr_t *src, bdaddr_t *dst)
        return sk;
 }
 
-static void usage()
+static void usage(void)
 {
        printf("avinfo - Audio/Video Info Tool ver %s\n", VERSION);
        printf("Usage:\n"
index 5cb9255..952bf13 100644 (file)
@@ -253,10 +253,8 @@ static int cmd_builddef(int transport, int argc, char *argv[])
                array[1] = def >> 8;
 
                err = transport_read(transport, CSR_VARID_GET_NEXT_BUILDDEF, array, 8);
-               if (err < 0) {
-                       errno = -err;
+               if (err < 0)
                        break;
-               }
 
                nextdef = array[2] | (array[3] << 8);
 
@@ -286,10 +284,8 @@ static int cmd_keylen(int transport, int argc, char *argv[])
        array[1] = handle >> 8;
 
        err = transport_read(transport, CSR_VARID_CRYPT_KEY_LENGTH, array, 8);
-       if (err < 0) {
-               errno = -err;
+       if (err < 0)
                return -1;
-       }
 
        handle = array[0] | (array[1] << 8);
        keylen = array[2] | (array[3] << 8);
@@ -310,10 +306,8 @@ static int cmd_clock(int transport, int argc, char *argv[])
        memset(array, 0, sizeof(array));
 
        err = transport_read(transport, CSR_VARID_BT_CLOCK, array, 8);
-       if (err < 0) {
-               errno = -err;
+       if (err < 0)
                return -1;
-       }
 
        clock = array[2] | (array[3] << 8) | (array[0] << 16) | (array[1] << 24);
 
@@ -333,10 +327,8 @@ static int cmd_rand(int transport, int argc, char *argv[])
        memset(array, 0, sizeof(array));
 
        err = transport_read(transport, CSR_VARID_RAND, array, 8);
-       if (err < 0) {
-               errno = -err;
+       if (err < 0)
                return -1;
-       }
 
        rand = array[0] | (array[1] << 8);
 
@@ -357,10 +349,8 @@ static int cmd_chiprev(int transport, int argc, char *argv[])
        memset(array, 0, sizeof(array));
 
        err = transport_read(transport, CSR_VARID_CHIPREV, array, 8);
-       if (err < 0) {
-               errno = -err;
+       if (err < 0)
                return -1;
-       }
 
        rev = array[0] | (array[1] << 8);
 
@@ -417,10 +407,8 @@ static int cmd_buildname(int transport, int argc, char *argv[])
        memset(array, 0, sizeof(array));
 
        err = transport_read(transport, CSR_VARID_READ_BUILD_NAME, array, 128);
-       if (err < 0) {
-               errno = -err;
+       if (err < 0)
                return -1;
-       }
 
        for (i = 0; i < sizeof(name); i++)
                name[i] = array[(i * 2) + 4];
@@ -441,10 +429,8 @@ static int cmd_panicarg(int transport, int argc, char *argv[])
        memset(array, 0, sizeof(array));
 
        err = transport_read(transport, CSR_VARID_PANIC_ARG, array, 8);
-       if (err < 0) {
-               errno = -err;
+       if (err < 0)
                return -1;
-       }
 
        error = array[0] | (array[1] << 8);
 
@@ -465,10 +451,8 @@ static int cmd_faultarg(int transport, int argc, char *argv[])
        memset(array, 0, sizeof(array));
 
        err = transport_read(transport, CSR_VARID_FAULT_ARG, array, 8);
-       if (err < 0) {
-               errno = -err;
+       if (err < 0)
                return -1;
-       }
 
        error = array[0] | (array[1] << 8);
 
@@ -1226,8 +1210,7 @@ int main(int argc, char *argv[])
        if (transport_open(transport, device, bcsp_rate) < 0)
                exit(1);
 
-       if (device)
-               free(device);
+       free(device);
 
        for (i = 0; commands[i].str; i++) {
                if (strcasecmp(commands[i].str, argv[0]))
index df247a2..7bfaf5a 100644 (file)
@@ -219,6 +219,7 @@ static int do_command(uint16_t command, uint16_t seqnum, uint16_t varid, uint8_t
 
                        if (timeout++ > 5000) {
                                fprintf(stderr, "Operation timed out\n");
+                               errno = ETIMEDOUT;
                                return -1;
                        }
                }
diff --git a/tools/example.psr b/tools/example.psr
new file mode 100644 (file)
index 0000000..bbbec73
--- /dev/null
@@ -0,0 +1,12 @@
+// PSKEY_BDADDR
+&0001 = 0001 2821 005b 6789
+// PSKEY_ANA_FTRIM
+&01f6 = 0025
+// PSKEY_HOST_INTERFACE
+&01f9 = 0001
+// PSKEY_UART_BAUD_RATE
+&0204 = 01d8
+// PSKEY_ANA_FREQ
+&01fe = 0004
+// PSKEY_UART_CONFIG
+&0205 = 0006
index 23aa8c5..77faf02 100644 (file)
@@ -67,6 +67,8 @@ struct uart_t {
        char *bdaddr;
        int  (*init) (int fd, struct uart_t *u, struct termios *ti);
        int  (*post) (int fd, struct uart_t *u, struct termios *ti);
+
+/* __SAMSUNG_PATCH__ */
 #ifdef __TI_PATCH__
        uint16_t device_param;
 #endif
@@ -310,7 +312,7 @@ static int digi(int fd, struct uart_t *u, struct termios *ti)
 
 static int texas(int fd, struct uart_t *u, struct termios *ti)
 {
-       return texas_init(fd, ti);
+       return texas_init(fd, &u->speed, ti);
 }
 
 static int texas2(int fd, struct uart_t *u, struct termios *ti)
@@ -365,12 +367,12 @@ static int bcsp_max_retries = 10;
 static void bcsp_tshy_sig_alarm(int sig)
 {
        unsigned char bcsp_sync_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xda,0xdc,0xed,0xed,0xc0};
-       int len;
        static int retries = 0;
 
        if (retries < bcsp_max_retries) {
                retries++;
-               len = write(serial_fd, &bcsp_sync_pkt, 10);
+               if (write(serial_fd, &bcsp_sync_pkt, 10) < 0)
+                       return;
                alarm(1);
                return;
        }
@@ -383,12 +385,12 @@ static void bcsp_tshy_sig_alarm(int sig)
 static void bcsp_tconf_sig_alarm(int sig)
 {
        unsigned char bcsp_conf_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xad,0xef,0xac,0xed,0xc0};
-       int len;
        static int retries = 0;
 
        if (retries < bcsp_max_retries){
                retries++;
-               len = write(serial_fd, &bcsp_conf_pkt, 10);
+               if (write(serial_fd, &bcsp_conf_pkt, 10) < 0)
+                       return;
                alarm(1);
                return;
        }
@@ -465,7 +467,8 @@ static int bcsp(int fd, struct uart_t *u, struct termios *ti)
                }
 
                if (!memcmp(bcspp, bcspsync, 4)) {
-                       len = write(fd, &bcsp_sync_resp_pkt,10);
+                       if (write(fd, &bcsp_sync_resp_pkt,10) < 0)
+                               return -1;
                } else if (!memcmp(bcspp, bcspsyncresp, 4))
                        break;
        }
@@ -514,6 +517,11 @@ static int bcsp(int fd, struct uart_t *u, struct termios *ti)
                        len = write(fd, &bcsp_conf_resp_pkt, 10);
                else if (!memcmp(bcspp, bcspconfresp,  4))
                        break;
+               else
+                       continue;
+
+               if (len < 0)
+                       return -errno;
        }
 
        /* State = garrulous */
@@ -788,12 +796,12 @@ static int swave(int fd, struct uart_t *u, struct termios *ti)
        nanosleep(&tm, NULL);
 
        // now the uart baud rate on the silicon wave module is set and effective.
-       // change our own baud rate as well. Then there is a reset event comming in
+       // change our own baud rate as well. Then there is a reset event coming in
        // on the *new* baud rate. This is *undocumented*! The packet looks like this:
        // 04 FF 01 0B (which would make that a confirmation of 0x0B = "Param
        // subcommand class". So: change to new baud rate, read with timeout, parse
        // data, error handling. BTW: all param access in Silicon Wave is done this way.
-       // Maybe this code would belong in a seperate file, or at least code reuse...
+       // Maybe this code would belong in a separate file, or at least code reuse...
 
        return 0;
 }
@@ -1000,6 +1008,8 @@ static int bcm2035(int fd, struct uart_t *u, struct termios *ti)
        /* Set the baud rate */
        memset(cmd, 0, sizeof(cmd));
        memset(resp, 0, sizeof(resp));
+
+/* __SAMSUNG_PATCH__ */
 #ifndef __BROADCOM_PATCH__
        cmd[0] = HCI_COMMAND_PKT;
        cmd[1] = 0x18;
@@ -1107,13 +1117,17 @@ struct uart_t uart[] = {
        { "swave",      0x0000, 0x0000, HCI_UART_H4,   115200, 115200,
                                FLOW_CTL, DISABLE_PM, NULL, swave    },
 
+/* __SAMSUNG_PATCH__ */
 #ifdef __TI_PATCH__
        /* Texas Instruments BRF63xx modules */
        { "texas",      0x0000, 0x0000, HCI_UART_LL,   115200,3000000, FLOW_CTL, NULL, texas,    NULL/*texas_continue_script*/,    BRF_DEEP_SLEEP_OPCODE},
 #else
        /* Texas Instruments Bluelink (BRF) modules */
-       { "texas",      0x0000, 0x0000, HCI_UART_LL,   115200, 115200, FLOW_CTL, NULL, texas,    texas2 },
-       { "texasalt",   0x0000, 0x0000, HCI_UART_LL,   115200, 115200, FLOW_CTL, NULL, texasalt, NULL   },
+       { "texas",      0x0000, 0x0000, HCI_UART_LL,   115200, 115200,
+                               FLOW_CTL, DISABLE_PM, NULL, texas,    texas2 },
+
+       { "texasalt",   0x0000, 0x0000, HCI_UART_LL,   115200, 115200,
+                               FLOW_CTL, DISABLE_PM, NULL, texasalt, NULL   },
 #endif
 
        /* ST Microelectronics minikits based on STLC2410/STLC2415 */
@@ -1213,6 +1227,7 @@ static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
        int fd, i;
        unsigned long flags = 0;
 
+/* __SAMSUNG_PATCH__ */
 #if defined(__TI_PATCH__) || defined(__BROADCOM_PATCH__)
        int power;
 #endif
@@ -1234,6 +1249,7 @@ static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
 
        cfmakeraw(&ti);
 
+/* __SAMSUNG_PATCH__ */
 #ifndef __BROADCOM_PATCH__
        ti.c_cflag |= CLOCAL;
        if (u->flags & FLOW_CTL)
@@ -1259,6 +1275,8 @@ static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
                tcsendbreak(fd, 0);
                usleep(500000);
        }
+
+/* __SAMSUNG_PATCH__ */
 #if defined(__TI_PATCH__) || defined(__BROADCOM_PATCH__)
        /* Power up the BRF chip */
        power = 1;
@@ -1306,6 +1324,8 @@ static void usage(void)
 {
        printf("hciattach - HCI UART driver initialization utility\n");
        printf("Usage:\n");
+
+/* __SAMSUNG_PATCH__ */
 #ifdef __TI_PATCH__
        printf("\thciattach [-n] [-p] [-b] [-g device_param] [-r] [-f] [-t timeout] [-s initial_speed] <tty> <type | id> [speed] [flow|noflow] [bdaddr]\n");
 #else
@@ -1327,6 +1347,7 @@ int main(int argc, char *argv[])
        sigset_t sigs;
        char dev[PATH_MAX];
 
+/* __SAMSUNG_PATCH__ */
 #if defined(__TI_PATCH__) || defined(__BROADCOM_PATCH__)
        int power;
 #endif
@@ -1341,7 +1362,7 @@ int main(int argc, char *argv[])
 #ifdef __TI_PATCH__
        while ((opt=getopt(argc, argv, "bnprft:g:s:l")) != EOF)
 #else
-       while ((opt=getopt(argc, argv, "bnpt:s:l")) != EOF)
+       while ((opt=getopt(argc, argv, "bnpt:s:lr")) != EOF)
 #endif
        {
                switch(opt) {
@@ -1361,6 +1382,7 @@ int main(int argc, char *argv[])
                        to = atoi(optarg);
                        break;
 
+/* __SAMSUNG_PATCH__ */
 #ifdef __TI_PATCH__
                case 'g':
                        device_param = (uint16_t)strtol(optarg, NULL, 16);
@@ -1396,6 +1418,7 @@ int main(int argc, char *argv[])
        }
 
        n = argc - optind;
+/* __SAMSUNG_PATCH__ */
 #ifdef __TI_PATCH__
        if (!reset_device || (reset_device && n < 1))
 #endif
@@ -1456,6 +1479,7 @@ int main(int argc, char *argv[])
                        break;
                }
        }
+/* __SAMSUNG_PATCH__ */
 #ifdef __TI_PATCH__
        if (reset_device)
        {
@@ -1558,6 +1582,7 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
+/* __SAMSUNG_PATCH__ */
 #if defined(__TI_PATCH__) || defined(__BROADCOM_PATCH__)
        /* Power down the BRF or BCMchip */
        power = 0;
index fed0d11..29fee33 100644 (file)
@@ -45,7 +45,7 @@
 int read_hci_event(int fd, unsigned char* buf, int size);
 int set_speed(int fd, struct termios *ti, int speed);
 
-int texas_init(int fd, struct termios *ti);
+int texas_init(int fd, int *speed, struct termios *ti);
 int texas_post(int fd, struct termios *ti);
 int texasalt_init(int fd, int speed, struct termios *ti);
 int stlc2500_init(int fd, bdaddr_t *bdaddr);
index 728e660..803cf46 100644 (file)
@@ -148,8 +148,8 @@ static int write_cmd(int fd, uint8_t *buffer, int len)
                return err;
 
        err = read_ps_event(event, HCI_PS_CMD_OCF);
-       if (event)
-               free(event);
+
+       free(event);
 
        return err;
 }
@@ -493,8 +493,7 @@ static int set_patch_ram(int dev, char *patch_loc, int len)
 
        err = read_ps_event(event, HCI_PS_CMD_OCF);
 
-       if (event)
-               free(event);
+       free(event);
 
        return err;
 }
@@ -623,8 +622,7 @@ static int get_ath3k_crc(int dev)
        if (read_ps_event(event, HCI_PS_CMD_OCF) >= 0)
                err = -EILSEQ;
 
-       if (!event)
-               free(event);
+       free(event);
 
        return err;
 }
@@ -667,8 +665,7 @@ static int get_device_type(int dev, uint32_t *code)
        *code = reg;
 
 cleanup:
-       if (event)
-               free(event);
+       free(event);
 
        return err;
 }
@@ -709,8 +706,7 @@ static int read_ath3k_version(int pConfig, uint32_t *rom_version,
        *build_version = status;
 
 cleanup:
-       if (event)
-               free(event);
+       free(event);
 
        return err;
 }
@@ -768,8 +764,7 @@ static int write_bdaddr(int pConfig, char *bdaddr)
 
        err = read_ps_event(event, HCI_PS_CMD_OCF);
 
-       if (event)
-               free(event);
+       free(event);
 
        return err;
 }
index e11397d..f087aa9 100644 (file)
@@ -57,6 +57,7 @@
 
 #define TI_MANUFACTURER_ID     13
 
+/* __SAMSUNG_PATCH__ */
 #ifdef __TI_PATCH__
 #define FIRMWARE_DIRECTORY1    "/mnt/mmc/"
 #define FIRMWARE_DIRECTORY2    "/usr/etc/bluetooth/"
@@ -124,7 +125,7 @@ static FILE *bts_load_script(const char* file_name, uint32_t* version)
        fp = fopen(file_name, "rb");
        if (!fp) {
                perror("can't open firmware file");
-               goto out;
+               return NULL;
        }
 
        if (1 != fread(&header, sizeof(struct bts_header), 1, fp)) {
@@ -140,13 +141,12 @@ static FILE *bts_load_script(const char* file_name, uint32_t* version)
        if (NULL != version)
                *version = header.version;
 
-       goto out;
+       return fp;
 
 errclose:
        fclose(fp);
-       fp = NULL;
-out:
-       return fp;
+
+       return NULL;
 }
 
 static unsigned long bts_fetch_action(FILE* fp, unsigned char* action_buf,
@@ -205,26 +205,21 @@ static const char *get_firmware_name(const uint8_t *respond)
        if (version & 0x8000)
                maj_ver |= 0x0008;
 
+/* __SAMSUNG_PATCH__ */
 #ifdef __TI_PATCH__
-    FILE *fp;
+       FILE *fp;
        sprintf(firmware_file_name, FIRMWARE_DIRECTORY1 "TIInit_%d.%d.%d.bts", chip, maj_ver, min_ver);
 
-    if( (fp = fopen(firmware_file_name, "r")) == NULL )
-    {
+       if ((fp = fopen(firmware_file_name, "r")) == NULL ) {
                extern int firmware_path;
                if (firmware_path)
-               {
-               sprintf(firmware_file_name, FIRMWARE_DIRECTORY2 "TIInit_edutm_%d.%d.%d.bts", chip, maj_ver, min_ver);
-               }
+                       sprintf(firmware_file_name, FIRMWARE_DIRECTORY2 "TIInit_edutm_%d.%d.%d.bts", chip, maj_ver, min_ver);
                else
-               {
-               sprintf(firmware_file_name, FIRMWARE_DIRECTORY2 "TIInit_%d.%d.%d.bts", chip, maj_ver, min_ver);
-               }
-    }
-    else
-    {
-        fclose(fp);
-    }
+                       sprintf(firmware_file_name, FIRMWARE_DIRECTORY2 "TIInit_%d.%d.%d.bts", chip, maj_ver, min_ver);
+       }
+       else {
+               fclose(fp);
+       }
 #else
        sprintf(firmware_file_name, FIRMWARE_DIRECTORY "TIInit_%d.%d.%d.bts", chip, maj_ver, min_ver);
 #endif
@@ -238,7 +233,7 @@ static void brf_delay(struct bts_action_delay *delay)
 }
 
 static int brf_set_serial_params(struct bts_action_serial *serial_action,
-                                               int fd, struct termios *ti)
+                                               int fd, int *speed, struct termios *ti)
 {
        fprintf(stderr, "texas: changing baud rate to %u, flow control to %u\n",
                                serial_action->baud, serial_action->flow_control );
@@ -261,6 +256,9 @@ static int brf_set_serial_params(struct bts_action_serial *serial_action,
                return -1;
        }
 
+       if (speed)
+               *speed = serial_action->baud;
+
        return 0;
 }
 
@@ -340,7 +338,7 @@ static int brf_send_command(int fd, struct bts_action_send* send_action, long si
 }
 
 static int brf_do_action(uint16_t brf_type, uint8_t *brf_action, long brf_size,
-                               int fd, struct termios *ti, int hcill_installed)
+                               int fd, int *speed, struct termios *ti, int hcill_installed)
 {
        int ret = 0;
 
@@ -354,7 +352,7 @@ static int brf_do_action(uint16_t brf_type, uint8_t *brf_action, long brf_size,
                break;
        case ACTION_SERIAL:
                DPRINTF("S");
-               ret = brf_set_serial_params((struct bts_action_serial *) brf_action, fd, ti);
+               ret = brf_set_serial_params((struct bts_action_serial *) brf_action, fd, speed, ti);
                break;
        case ACTION_DELAY:
                DPRINTF("D");
@@ -405,7 +403,7 @@ static int brf_action_is_deep_sleep(uint8_t *brf_action, long brf_size,
  * The second time it is called, it assumes HCILL protocol is set up,
  * and sends rest of brf script via the supplied socket.
  */
-static int brf_do_script(int fd, struct termios *ti, const char *bts_file)
+static int brf_do_script(int fd, int *speed, struct termios *ti, const char *bts_file)
 {
        int ret = 0,  hcill_installed = bts_file ? 0 : 1;
        uint32_t vers;
@@ -440,7 +438,7 @@ static int brf_do_script(int fd, struct termios *ti, const char *bts_file)
        /* execute current action and continue to parse brf script file */
        while (brf_size != 0) {
                ret = brf_do_action(brf_type, brf_action, brf_size,
-                                               fd, ti, hcill_installed);
+                                               fd, speed, ti, hcill_installed);
                if (ret == -1)
                        break;
 
@@ -450,12 +448,10 @@ static int brf_do_script(int fd, struct termios *ti, const char *bts_file)
                /* if this is the first time we run (no HCILL yet) */
                /* and a deep sleep command is encountered */
                /* we exit */
-#ifndef __TI_PATCH__
                if (!hcill_installed &&
                                brf_action_is_deep_sleep(brf_action,
                                                        brf_size, brf_type))
                        return 0;
-#endif
        }
 
        bts_unload_script(brf_script_file);
@@ -465,7 +461,7 @@ static int brf_do_script(int fd, struct termios *ti, const char *bts_file)
        return ret;
 }
 
-int texas_init(int fd, struct termios *ti)
+int texas_init(int fd, int *speed, struct termios *ti)
 {
        struct timespec tm = {0, 50000};
        char cmd[4];
@@ -516,7 +512,7 @@ int texas_init(int fd, struct termios *ti)
        bts_file = get_firmware_name(resp);
        fprintf(stderr, "Firmware file : %s\n", bts_file);
 
-       n = brf_do_script(fd, ti, bts_file);
+       n = brf_do_script(fd, speed, ti, bts_file);
 
        nanosleep(&tm, NULL);
 
@@ -550,7 +546,7 @@ int texas_post(int fd, struct termios *ti)
                return -1;
        }
 
-       ret = brf_do_script(dd, ti, NULL);
+       ret = brf_do_script(dd, NULL, ti, NULL);
 
        hci_close_dev(dd);
 
index aa6d009..a7249db 100644 (file)
@@ -210,9 +210,9 @@ static void cmd_le_addr(int ctl, int hdev, char *opt)
 
        dd = hci_open_dev(hdev);
        if (dd < 0) {
-               err = errno;
+               err = -errno;
                fprintf(stderr, "Could not open device: %s(%d)\n",
-                                                       strerror(err), err);
+                                                       strerror(-err), -err);
                exit(1);
        }
 
@@ -230,9 +230,9 @@ static void cmd_le_addr(int ctl, int hdev, char *opt)
 
        ret = hci_send_req(dd, &rq, 1000);
        if (status || ret < 0) {
-               err = errno;
+               err = -errno;
                fprintf(stderr, "Can't set random address for hci%d: "
-                                       "%s (%d)\n", hdev, strerror(err), err);
+                               "%s (%d)\n", hdev, strerror(-err), -err);
        }
 
        hci_close_dev(dd);
@@ -1138,7 +1138,7 @@ static void cmd_version(int ctl, int hdev, char *opt)
        }
 
        hciver = hci_vertostr(ver.hci_ver);
-       lmpver = lmp_vertostr(ver.hci_ver);
+       lmpver = lmp_vertostr(ver.lmp_ver);
 
        print_dev_hdr(&di);
        printf("\tHCI Version: %s (0x%x)  Revision: 0x%x\n"
@@ -1252,7 +1252,7 @@ static void cmd_inq_data(int ctl, int hdev, char *opt)
        }
 
        if (opt) {
-               uint8_t fec = 0, data[240];
+               uint8_t fec = 0, data[HCI_MAX_EIR_LENGTH];
                char tmp[3];
                int i, size;
 
@@ -1260,8 +1260,8 @@ static void cmd_inq_data(int ctl, int hdev, char *opt)
 
                memset(tmp, 0, sizeof(tmp));
                size = (strlen(opt) + 1) / 2;
-               if (size > 240)
-                       size = 240;
+               if (size > HCI_MAX_EIR_LENGTH)
+                       size = HCI_MAX_EIR_LENGTH;
 
                for (i = 0; i < size; i++) {
                        memcpy(tmp, opt + (i * 2), 2);
@@ -1274,7 +1274,7 @@ static void cmd_inq_data(int ctl, int hdev, char *opt)
                        exit(1);
                }
        } else {
-               uint8_t fec, data[240], len, type, *ptr;
+               uint8_t fec, data[HCI_MAX_EIR_LENGTH], len, type, *ptr;
                char *str;
 
                if (hci_read_ext_inquiry_response(dd, &fec, data, 1000) < 0) {
@@ -1285,7 +1285,7 @@ static void cmd_inq_data(int ctl, int hdev, char *opt)
 
                print_dev_hdr(&di);
                printf("\tFEC %s\n\t\t", fec ? "enabled" : "disabled");
-               for (i = 0; i < 240; i++)
+               for (i = 0; i < HCI_MAX_EIR_LENGTH; i++)
                        printf("%02x%s%s", data[i], (i + 1) % 8 ? "" : " ",
                                (i + 1) % 16 ? " " : (i < 239 ? "\n\t\t" : "\n"));
 
@@ -1870,7 +1870,7 @@ static void print_dev_info(int ctl, struct hci_dev_info *di)
                st->byte_tx, st->acl_tx, st->sco_tx, st->cmd_tx, st->err_tx);
 
        if (all && !hci_test_bit(HCI_RAW, &di->flags) &&
-                       bacmp(&di->bdaddr, BDADDR_ANY)) {
+                       (bacmp(&di->bdaddr, BDADDR_ANY) || (di->type >> 4))) {
                print_dev_features(di, 0);
                print_pkt_type(di);
                print_link_policy(di);
index a117449..5189d8d 100644 (file)
@@ -38,6 +38,7 @@
 #include <sys/param.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
+#include <signal.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
 #define FLAGS_LIMITED_MODE_BIT 0x01
 #define FLAGS_GENERAL_MODE_BIT 0x02
 
+#define EIR_FLAGS                   0x01  /* flags */
+#define EIR_UUID16_SOME             0x02  /* 16-bit UUID, more available */
+#define EIR_UUID16_ALL              0x03  /* 16-bit UUID, all listed */
+#define EIR_UUID32_SOME             0x04  /* 32-bit UUID, more available */
+#define EIR_UUID32_ALL              0x05  /* 32-bit UUID, all listed */
+#define EIR_UUID128_SOME            0x06  /* 128-bit UUID, more available */
+#define EIR_UUID128_ALL             0x07  /* 128-bit UUID, all listed */
+#define EIR_NAME_SHORT              0x08  /* shortened local name */
+#define EIR_NAME_COMPLETE           0x09  /* complete local name */
+#define EIR_TX_POWER                0x0A  /* transmit power level */
+#define EIR_DEVICE_ID               0x10  /* device ID */
+
 #define for_each_opt(opt, long, short) while ((opt=getopt_long(argc, argv, short ? short:"+", long, NULL)) != -1)
 
+static volatile int signal_received = 0;
+
 static void usage(void);
 
 static int dev_info(int s, int dev_id, long arg)
@@ -2293,7 +2308,7 @@ static void cmd_clock(int dev_id, int argc, char **argv)
 
 static int read_flags(uint8_t *flags, const uint8_t *data, size_t size)
 {
-       unsigned int offset;
+       size_t offset;
 
        if (!flags || !data)
                return -EINVAL;
@@ -2301,12 +2316,17 @@ static int read_flags(uint8_t *flags, const uint8_t *data, size_t size)
        offset = 0;
        while (offset < size) {
                uint8_t len = data[offset];
-               uint8_t type = data[offset + 1];
+               uint8_t type;
 
                /* Check if it is the end of the significant part */
                if (len == 0)
                        break;
 
+               if (len + offset > size)
+                       break;
+
+               type = data[offset + 1];
+
                if (type == FLAGS_AD_TYPE) {
                        *flags = data[offset + 2];
                        return 0;
@@ -2346,13 +2366,54 @@ static int check_report_filter(uint8_t procedure, le_advertising_info *info)
        return 0;
 }
 
+static void sigint_handler(int sig)
+{
+       signal_received = sig;
+}
+
+static void eir_parse_name(uint8_t *eir, size_t eir_len,
+                                               char *buf, size_t buf_len)
+{
+       size_t offset;
+
+       offset = 0;
+       while (offset < eir_len) {
+               uint8_t field_len = eir[0];
+               size_t name_len;
+
+               /* Check for the end of EIR */
+               if (field_len == 0)
+                       break;
+
+               if (offset + field_len > eir_len)
+                       goto failed;
+
+               switch (eir[1]) {
+               case EIR_NAME_SHORT:
+               case EIR_NAME_COMPLETE:
+                       name_len = field_len - 1;
+                       if (name_len > buf_len)
+                               goto failed;
+
+                       memcpy(buf, &eir[2], name_len);
+                       return;
+               }
+
+               offset += field_len + 1;
+               eir += field_len + 1;
+       }
+
+failed:
+       snprintf(buf, buf_len, "(unknown)");
+}
+
 static int print_advertising_devices(int dd, uint8_t filter_type)
 {
        unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr;
        struct hci_filter nf, of;
+       struct sigaction sa;
        socklen_t olen;
-       hci_event_hdr *hdr;
-       int num, len;
+       int len;
 
        olen = sizeof(of);
        if (getsockopt(dd, SOL_HCI, HCI_FILTER, &of, &olen) < 0) {
@@ -2369,20 +2430,27 @@ static int print_advertising_devices(int dd, uint8_t filter_type)
                return -1;
        }
 
-       /* Wait for 10 report events */
-       num = 10;
-       while (num--) {
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_flags = SA_NOCLDSTOP;
+       sa.sa_handler = sigint_handler;
+       sigaction(SIGINT, &sa, NULL);
+
+       while (1) {
                evt_le_meta_event *meta;
                le_advertising_info *info;
                char addr[18];
 
                while ((len = read(dd, buf, sizeof(buf))) < 0) {
+                       if (errno == EINTR && signal_received == SIGINT) {
+                               len = 0;
+                               goto done;
+                       }
+
                        if (errno == EAGAIN || errno == EINTR)
                                continue;
                        goto done;
                }
 
-               hdr = (void *) (buf + 1);
                ptr = buf + (1 + HCI_EVENT_HDR_SIZE);
                len -= (1 + HCI_EVENT_HDR_SIZE);
 
@@ -2394,8 +2462,15 @@ 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[30];
+
+                       memset(name, 0, sizeof(name));
+
                        ba2str(&info->bdaddr, addr);
-                       printf("%s\n", addr);
+                       eir_parse_name(info->data, info->length,
+                                                       name, sizeof(name) - 1);
+
+                       printf("%s %s\n", addr, name);
                }
        }
 
@@ -2413,6 +2488,7 @@ static struct option lescan_options[] = {
        { "privacy",    0, 0, 'p' },
        { "passive",    0, 0, 'P' },
        { "discovery",  1, 0, 'd' },
+       { "duplicates", 0, 0, 'D' },
        { 0, 0, 0, 0 }
 };
 
@@ -2421,7 +2497,8 @@ static const char *lescan_help =
        "\tlescan [--privacy] enable privacy\n"
        "\tlescan [--passive] set scan type passive (default active)\n"
        "\tlescan [--discovery=g|l] enable general or limited discovery"
-               "procedure\n";
+               "procedure\n"
+       "\tlescan [--duplicates] don't filter duplicates\n";
 
 static void cmd_lescan(int dev_id, int argc, char **argv)
 {
@@ -2431,6 +2508,7 @@ static void cmd_lescan(int dev_id, int argc, char **argv)
        uint8_t filter_type = 0;
        uint16_t interval = htobs(0x0010);
        uint16_t window = htobs(0x0010);
+       uint8_t filter_dup = 1;
 
        for_each_opt(opt, lescan_options, NULL) {
                switch (opt) {
@@ -2450,6 +2528,9 @@ static void cmd_lescan(int dev_id, int argc, char **argv)
                        interval = htobs(0x0012);
                        window = htobs(0x0012);
                        break;
+               case 'D':
+                       filter_dup = 0x00;
+                       break;
                default:
                        printf("%s", lescan_help);
                        return;
@@ -2473,7 +2554,7 @@ static void cmd_lescan(int dev_id, int argc, char **argv)
                exit(1);
        }
 
-       err = hci_le_set_scan_enable(dd, 0x01, 0x00, 1000);
+       err = hci_le_set_scan_enable(dd, 0x01, filter_dup, 1000);
        if (err < 0) {
                perror("Enable scan failed");
                exit(1);
@@ -2487,7 +2568,7 @@ static void cmd_lescan(int dev_id, int argc, char **argv)
                exit(1);
        }
 
-       err = hci_le_set_scan_enable(dd, 0x00, 0x00, 1000);
+       err = hci_le_set_scan_enable(dd, 0x00, filter_dup, 1000);
        if (err < 0) {
                perror("Disable scan failed");
                exit(1);
@@ -2615,9 +2696,9 @@ static void cmd_lewladd(int dev_id, int argc, char **argv)
        hci_close_dev(dd);
 
        if (err < 0) {
-               err = errno;
+               err = -errno;
                fprintf(stderr, "Can't add to white list: %s(%d)\n",
-                                                       strerror(err), err);
+                                                       strerror(-err), -err);
                exit(1);
        }
 }
@@ -2705,9 +2786,9 @@ static void cmd_lewlsz(int dev_id, int argc, char **argv)
        hci_close_dev(dd);
 
        if (err < 0) {
-               err = errno;
+               err = -errno;
                fprintf(stderr, "Can't read white list size: %s(%d)\n",
-                                                       strerror(err), err);
+                                                       strerror(-err), -err);
                exit(1);
        }
 
@@ -2750,9 +2831,9 @@ static void cmd_lewlclr(int dev_id, int argc, char **argv)
        hci_close_dev(dd);
 
        if (err < 0) {
-               err = errno;
+               err = -errno;
                fprintf(stderr, "Can't clear white list: %s(%d)\n",
-                                                       strerror(err), err);
+                                                       strerror(-err), -err);
                exit(1);
        }
 }
@@ -2880,9 +2961,9 @@ static void cmd_lecup(int dev_id, int argc, char **argv)
 
        if (hci_le_conn_update(dd, htobs(handle), htobs(min), htobs(max),
                                htobs(latency), htobs(timeout), 5000) < 0) {
-               int err = errno;
+               int err = -errno;
                fprintf(stderr, "Could not change connection params: %s(%d)\n",
-                                                       strerror(err), err);
+                                                       strerror(-err), -err);
        }
 
        hci_close_dev(dd);
index 5d35274..6ea7ed8 100644 (file)
@@ -29,23 +29,18 @@ is used to set up switch supported Bluetooth devices into the HCI
 mode and back.
 .SH OPTIONS
 .TP
-.BI -h
-Gives a list of possible options.
-.TP
-.BI -q
-Don't display any messages.
-.TP
-.BI -r [hid,hci]
+.B --mode= [hid, hci]
 Sets the mode to switch the device into
 .TP
-.BI -v
-Specifies the 4 digit vendor ID assigned to the device being switched
+.B --method= [csr, logitech-hid, dell]
+Which vendor method to use for switching the device.
 .TP
-.BI -p
-Specifies the 4 digit product ID assigned to the device being switched
+.B --devpath=
+Specifies the device path in /sys
+.TP
+.B --help
+Gives a list of possible options.
 .TP
-.BI -m [csr, logitech, dell]
-Which vendor method to use for switching the device.
 .SH AUTHOR
 Written by Marcel Holtmann <marcel@holtmann.org>.
 .br
index a640772..45a3a3d 100644 (file)
@@ -1,9 +1,10 @@
 /*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
+ * hid2hci : switch the radio on devices that support
+ *           it from HID to HCI and back
  *
  *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
- *
+ *  Copyright (C) 2008-2009  Mario Limonciello <mario_limonciello@dell.com>
+ *  Copyright (C) 2009-2011  Kay Sievers <kay.sievers@vrfy.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
 #include <string.h>
 #include <getopt.h>
 #include <sys/ioctl.h>
-
+#include <linux/types.h>
+#include <linux/hiddev.h>
 #include <usb.h>
 
-#ifdef NEED_USB_GET_BUSSES
-static inline struct usb_bus *usb_get_busses(void)
-{
-       return usb_busses;
-}
-#endif
-
-#ifndef USB_DIR_OUT
-#define USB_DIR_OUT    0x00
-#endif
-
-static char devpath[PATH_MAX + 1] = "/dev";
-
-struct hiddev_devinfo {
-       unsigned int bustype;
-       unsigned int busnum;
-       unsigned int devnum;
-       unsigned int ifnum;
-       short vendor;
-       short product;
-       short version;
-       unsigned num_applications;
-};
-
-struct hiddev_report_info {
-       unsigned report_type;
-       unsigned report_id;
-       unsigned num_fields;
-};
-
-typedef __signed__ int __s32;
-
-struct hiddev_usage_ref {
-       unsigned report_type;
-       unsigned report_id;
-       unsigned field_index;
-       unsigned usage_index;
-       unsigned usage_code;
-       __s32 value;
-};
-
-#define HIDIOCGDEVINFO         _IOR('H', 0x03, struct hiddev_devinfo)
-#define HIDIOCINITREPORT       _IO('H', 0x05)
-#define HIDIOCSREPORT          _IOW('H', 0x08, struct hiddev_report_info)
-#define HIDIOCSUSAGE           _IOW('H', 0x0C, struct hiddev_usage_ref)
-
-#define HID_REPORT_TYPE_OUTPUT 2
-
-#define HCI 0
-#define HID 1
+#include "libudev.h"
 
-struct device_info {
-       struct usb_device *dev;
-       int mode;
-       uint16_t vendor;
-       uint16_t product;
+enum mode {
+       HCI = 0,
+       HID = 1,
 };
 
-static int switch_csr(struct device_info *devinfo)
+static int usb_switch_csr(struct usb_dev_handle *dev, enum mode mode)
 {
-       struct usb_dev_handle *udev;
        int err;
 
-       udev = usb_open(devinfo->dev);
-       if (!udev)
-               return -errno;
-
-       err = usb_control_msg(udev, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               0, devinfo->mode, 0, NULL, 0, 10000);
-
+       err = usb_control_msg(dev,
+                       USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0, mode, 0, NULL, 0, 10000);
        if (err == 0) {
                err = -1;
                errno = EALREADY;
-       } else {
-               if (errno == ETIMEDOUT)
-                       err = 0;
-       }
-
-       usb_close(udev);
+       } else if (errno == ETIMEDOUT)
+               err = 0;
 
        return err;
 }
 
-static int send_report(int fd, const char *buf, size_t size)
+static int hid_logitech_send_report(int fd, const char *buf, size_t size)
 {
        struct hiddev_report_info rinfo;
        struct hiddev_usage_ref uref;
@@ -147,72 +89,42 @@ static int send_report(int fd, const char *buf, size_t size)
        return err;
 }
 
-static int switch_logitech(struct device_info *devinfo)
+static int hid_switch_logitech(const char *filename)
 {
-       char devname[PATH_MAX + 1];
-       int i, fd, err = -1;
-
-       for (i = 0; i < 16; i++) {
-               struct hiddev_devinfo dinfo;
-               char rep1[] = { 0xff, 0x80, 0x80, 0x01, 0x00, 0x00 };
-               char rep2[] = { 0xff, 0x80, 0x00, 0x00, 0x30, 0x00 };
-               char rep3[] = { 0xff, 0x81, 0x80, 0x00, 0x00, 0x00 };
-
-               sprintf(devname, "%s/hiddev%d", devpath, i);
-               fd = open(devname, O_RDWR);
-               if (fd < 0) {
-                       sprintf(devname, "%s/usb/hiddev%d", devpath, i);
-                       fd = open(devname, O_RDWR);
-                       if (fd < 0) {
-                               sprintf(devname, "%s/usb/hid/hiddev%d", devpath, i);
-                               fd = open(devname, O_RDWR);
-                               if (fd < 0)
-                                       continue;
-                       }
-               }
-
-               memset(&dinfo, 0, sizeof(dinfo));
-               err = ioctl(fd, HIDIOCGDEVINFO, &dinfo);
-               if (err < 0 || (int) dinfo.busnum != atoi(devinfo->dev->bus->dirname) ||
-                               (int) dinfo.devnum != atoi(devinfo->dev->filename)) {
-                       close(fd);
-                       continue;
-               }
-
-               err = ioctl(fd, HIDIOCINITREPORT, 0);
-               if (err < 0) {
-                       close(fd);
-                       break;
-               }
-
-               err = send_report(fd, rep1, sizeof(rep1));
-               if (err < 0) {
-                       close(fd);
-                       break;
-               }
-
-               err = send_report(fd, rep2, sizeof(rep2));
-               if (err < 0) {
-                       close(fd);
-                       break;
-               }
-
-               err = send_report(fd, rep3, sizeof(rep3));
-               close(fd);
-               break;
-       }
-
+       char rep1[] = { 0xff, 0x80, 0x80, 0x01, 0x00, 0x00 };
+       char rep2[] = { 0xff, 0x80, 0x00, 0x00, 0x30, 0x00 };
+       char rep3[] = { 0xff, 0x81, 0x80, 0x00, 0x00, 0x00 };
+       int fd;
+       int err = -1;
+
+       fd = open(filename, O_RDWR);
+       if (fd < 0)
+               return err;
+
+       err = ioctl(fd, HIDIOCINITREPORT, 0);
+       if (err < 0)
+               goto out;
+
+       err = hid_logitech_send_report(fd, rep1, sizeof(rep1));
+       if (err < 0)
+               goto out;
+
+       err = hid_logitech_send_report(fd, rep2, sizeof(rep2));
+       if (err < 0)
+               goto out;
+
+       err = hid_logitech_send_report(fd, rep3, sizeof(rep3));
+out:
+       close(fd);
        return err;
 }
 
-static int switch_dell(struct device_info *devinfo)
+static int usb_switch_dell(struct usb_dev_handle *dev, enum mode mode)
 {
        char report[] = { 0x7f, 0x00, 0x00, 0x00 };
-
-       struct usb_dev_handle *handle;
        int err;
 
-       switch (devinfo->mode) {
+       switch (mode) {
        case HCI:
                report[1] = 0x13;
                break;
@@ -221,22 +133,16 @@ static int switch_dell(struct device_info *devinfo)
                break;
        }
 
-       handle = usb_open(devinfo->dev);
-       if (!handle)
-               return -EIO;
-
        /* Don't need to check return, as might not be in use */
-       usb_detach_kernel_driver_np(handle, 0);
+       usb_detach_kernel_driver_np(dev, 0);
 
-       if (usb_claim_interface(handle, 0) < 0) {
-               usb_close(handle);
+       if (usb_claim_interface(dev, 0) < 0)
                return -EIO;
-       }
 
-       err = usb_control_msg(handle,
-               USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+       err = usb_control_msg(dev,
+                       USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
                        USB_REQ_SET_CONFIGURATION, 0x7f | (0x03 << 8), 0,
-                                               report, sizeof(report), 5000);
+                       report, sizeof(report), 5000);
 
        if (err == 0) {
                err = -1;
@@ -245,131 +151,200 @@ static int switch_dell(struct device_info *devinfo)
                if (errno == ETIMEDOUT)
                        err = 0;
        }
-
-       usb_close(handle);
-
        return err;
 }
 
-static int find_device(struct device_info* devinfo)
+/*
+ * libusb needs to scan and open all devices, just to to find the
+ * device we already have. This should be fixed in libusb.
+ */
+static struct usb_device *usb_device_open_from_udev(struct udev_device *usb_dev)
 {
        struct usb_bus *bus;
-       struct usb_device *dev;
+       const char *str;
+       int busnum;
+       int devnum;
 
+       str = udev_device_get_sysattr_value(usb_dev, "busnum");
+       if (str == NULL)
+               return NULL;
+       busnum = strtol(str, NULL, 0);
+
+       str = udev_device_get_sysattr_value(usb_dev, "devnum");
+       if (str == NULL)
+               return NULL;
+       devnum = strtol(str, NULL, 0);
+
+       usb_init();
        usb_find_busses();
        usb_find_devices();
 
-       for (bus = usb_get_busses(); bus; bus = bus->next)
+       for (bus = usb_get_busses(); bus; bus = bus->next) {
+               struct usb_device *dev;
+
+               if (strtol(bus->dirname, NULL, 10) != busnum)
+                       continue;
+
                for (dev = bus->devices; dev; dev = dev->next) {
-                       if (dev->descriptor.idVendor == devinfo->vendor &&
-                           dev->descriptor.idProduct == devinfo->product) {
-                               devinfo->dev=dev;
-                               return 1;
-                       }
+                       if (dev->devnum == devnum)
+                               return dev;
                }
-       return 0;
+       }
+
+       return NULL;
 }
 
-static void usage(char* error)
+static struct usb_dev_handle *find_device(struct udev_device *udev_dev)
+{
+       struct usb_device *dev;
+
+       dev = usb_device_open_from_udev(udev_dev);
+       if (dev == NULL)
+               return NULL;
+       return usb_open(dev);
+}
+
+static void usage(const char *error)
 {
        if (error)
                fprintf(stderr,"\n%s\n", error);
        else
                printf("hid2hci - Bluetooth HID to HCI mode switching utility\n\n");
 
-       printf("Usage:\n"
-               "\thid2hci [options]\n"
-               "\n");
-
-       printf("Options:\n"
-               "\t-h, --help           Display help\n"
-               "\t-q, --quiet          Don't display any messages\n"
-               "\t-r, --mode=          Mode to switch to [hid, hci]\n"
-               "\t-v, --vendor=        Vendor ID to act upon\n"
-               "\t-p, --product=       Product ID to act upon\n"
-               "\t-m, --method=        Method to use to switch [csr, logitech, dell]\n"
-               "\n");
-       if (error)
-               exit(1);
+       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"
+               "  --help\n\n");
 }
 
-static struct option main_options[] = {
-       { "help",       no_argument, 0, 'h' },
-       { "quiet",      no_argument, 0, 'q' },
-       { "mode",       required_argument, 0, 'r' },
-       { "vendor",     required_argument, 0, 'v' },
-       { "product",    required_argument, 0, 'p' },
-       { "method",     required_argument, 0, 'm' },
-       { 0, 0, 0, 0 }
-};
-
 int main(int argc, char *argv[])
 {
-       struct device_info dev = { NULL, HCI, 0, 0 };
-       int opt, quiet = 0;
-       int (*method)(struct device_info *dev) = NULL;
-
-       while ((opt = getopt_long(argc, argv, "+r:v:p:m:qh", main_options, NULL)) != -1) {
-               switch (opt) {
-               case 'r':
-                       if (optarg && !strcmp(optarg, "hid"))
-                               dev.mode = HID;
-                       else if (optarg && !strcmp(optarg, "hci"))
-                               dev.mode = HCI;
-                       else
-                               usage("ERROR: Undefined radio mode\n");
+       static const struct option options[] = {
+               { "help", no_argument, NULL, 'h' },
+               { "mode", required_argument, NULL, 'm' },
+               { "devpath", required_argument, NULL, 'p' },
+               { "method", required_argument, NULL, 'M' },
+               { }
+       };
+       enum method {
+               METHOD_UNDEF,
+               METHOD_CSR,
+               METHOD_LOGITECH_HID,
+               METHOD_DELL,
+       } method = METHOD_UNDEF;
+       struct udev *udev;
+       struct udev_device *udev_dev = NULL;
+       char syspath[PATH_MAX];
+       int (*usb_switch)(struct usb_dev_handle *dev, enum mode mode) = NULL;
+       enum mode mode = HCI;
+       const char *devpath = NULL;
+       int err = -1;
+       int rc = 1;
+
+       for (;;) {
+               int option;
+
+               option = getopt_long(argc, argv, "m:p:M:h", options, NULL);
+               if (option == -1)
                        break;
-               case 'v':
-                       sscanf(optarg, "%4hx", &dev.vendor);
+
+               switch (option) {
+               case 'm':
+                       if (!strcmp(optarg, "hid")) {
+                               mode = HID;
+                       } else if (!strcmp(optarg, "hci")) {
+                               mode = HCI;
+                       } else {
+                               usage("error: undefined radio mode\n");
+                               exit(1);
+                       }
                        break;
                case 'p':
-                       sscanf(optarg, "%4hx", &dev.product);
-                       break;
-               case 'm':
-                       if (optarg && !strcmp(optarg, "csr"))
-                               method = switch_csr;
-                       else if (optarg && !strcmp(optarg, "logitech"))
-                               method = switch_logitech;
-                       else if (optarg && !strcmp(optarg, "dell"))
-                               method = switch_dell;
-                       else
-                               usage("ERROR: Undefined switching method\n");
+                       devpath = optarg;
                        break;
-               case 'q':
-                       quiet = 1;
+               case 'M':
+                       if (!strcmp(optarg, "csr")) {
+                               method = METHOD_CSR;
+                               usb_switch = usb_switch_csr;
+                       } else if (!strcmp(optarg, "logitech-hid")) {
+                               method = METHOD_LOGITECH_HID;
+                       } else if (!strcmp(optarg, "dell")) {
+                               method = METHOD_DELL;
+                               usb_switch = usb_switch_dell;
+                       } else {
+                               usage("error: undefined switching method\n");
+                               exit(1);
+                       }
                        break;
                case 'h':
                        usage(NULL);
-               default:
-                       exit(0);
                }
        }
 
-       if (!quiet && (!dev.vendor || !dev.product || !method))
-               usage("ERROR: Vendor ID, Product ID, and Switching Method must all be defined.\n");
-
-       argc -= optind;
-       argv += optind;
-       optind = 0;
+       if (!devpath || method == METHOD_UNDEF) {
+               usage("error: --devpath= and --method= must be defined\n");
+               exit(1);
+       }
 
-       usb_init();
+       udev = udev_new();
+       if (udev == NULL)
+               goto exit;
 
-       if (!find_device(&dev)) {
-               if (!quiet)
-                       fprintf(stderr, "Device %04x:%04x not found on USB bus.\n",
-                               dev.vendor, dev.product);
-               exit(1);
+       snprintf(syspath, sizeof(syspath), "%s/%s", udev_get_sys_path(udev), devpath);
+       udev_dev = udev_device_new_from_syspath(udev, syspath);
+       if (udev_dev == NULL) {
+               fprintf(stderr, "error: could not find '%s'\n", devpath);
+               goto exit;
        }
 
-       if (!quiet)
-               printf("Attempting to switch device %04x:%04x to %s mode ",
-                       dev.vendor, dev.product, dev.mode ? "HID" : "HCI");
-       fflush(stdout);
+       switch (method) {
+       case METHOD_CSR:
+       case METHOD_DELL: {
+               struct udev_device *dev;
+               struct usb_dev_handle *handle;
+               const char *type;
+
+               /* get the parent usb_device if needed */
+               dev = udev_dev;
+               type = udev_device_get_devtype(dev);
+               if (type == NULL || strcmp(type, "usb_device") != 0) {
+                       dev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device");
+                       if (dev == NULL) {
+                               fprintf(stderr, "error: could not find usb_device for '%s'\n", devpath);
+                               goto exit;
+                       }
+               }
+
+               handle = find_device(dev);
+               if (handle == NULL) {
+                       fprintf(stderr, "error: unable to handle '%s'\n",
+                               udev_device_get_syspath(dev));
+                       goto exit;
+               }
+               err = usb_switch(handle, mode);
+               break;
+       }
+       case METHOD_LOGITECH_HID: {
+               const char *device;
 
-       if (method(&dev) < 0 && !quiet)
-               printf("failed (%s)\n", strerror(errno));
-       else if (!quiet)
-               printf("was successful\n");
+               device = udev_device_get_devnode(udev_dev);
+               if (device == NULL) {
+                       fprintf(stderr, "error: could not find hiddev device node\n");
+                       goto exit;
+               }
+               err = hid_switch_logitech(device);
+               break;
+       }
+       default:
+               break;
+       }
 
-       return errno;
+       if (err < 0)
+               fprintf(stderr, "error: switching device '%s' failed.\n",
+                       udev_device_get_syspath(udev_dev));
+exit:
+       udev_device_unref(udev_dev);
+       udev_unref(udev);
+       return rc;
 }
index 06252e5..06303cd 100644 (file)
@@ -99,7 +99,7 @@ If no channel is specified, it will use the channel number 1, but
 a channel must be specified before cmd. If cmd is given, it will be
 executed as soon as a client connects. When the child process
 terminates or the client disconnect, the command will terminate.
-Occurences of {} in cmd will be replaced by the name of the device
+Occurrences of {} in cmd will be replaced by the name of the device
 used by the connection. This command can be terminated with the key
 sequence CTRL-C.
 .TP
index 140a46a..aea4954 100644 (file)
@@ -4116,10 +4116,9 @@ static int cmd_records(int argc, char **argv)
                        context.handle = base[i] + n;
                        err = get_service(&bdaddr, &context, 1);
                        if (err < 0)
-                               goto done;
+                               return 0;
                }
 
-done:
        return 0;
 }
 
index 93b8c0f..b3f883a 100644 (file)
@@ -720,13 +720,13 @@ static uint8 ubcsp_recevied_packet (void)
 \r
                                activity |= UBCSP_PACKET_RECEIVED;\r
                        }\r
-               }\r
-       }\r
-\r
-       /* Just return any activity that occured */\r
-\r
-       return activity;\r
-}\r
+               }
+       }
+
+       /* Just return any activity that occurred */
+
+       return activity;
+}
 \r
 /*****************************************************************************/\r
 /**                                                                         **/\r
@@ -1143,13 +1143,13 @@ uint8 ubcsp_poll (uint8 *activity)
 \r
                        ubcsp_config.receive_index ++;\r
                }\r
-               else if (ubcsp_config.receive_index < ubcsp_config.receive_packet->length)\r
-               {\r
-                       /* We are receiving the payload */\r
-                       /* We might stop comming here if we are receiving a\r
-                          packet which is longer than the receive_packet->length\r
-                          given by the host */\r
-\r
+               else if (ubcsp_config.receive_index < ubcsp_config.receive_packet->length)
+               {
+                       /* We are receiving the payload */
+                       /* We might stop coming here if we are receiving a
+                          packet which is longer than the receive_packet->length
+                          given by the host */
+
                        ubcsp_config.receive_packet->payload[ubcsp_config.receive_index] = value;\r
 \r
                        ubcsp_config.receive_index ++;\r
index 0806ffe..3b37f59 100644 (file)
@@ -118,7 +118,7 @@ int main(int argc, char *argv[])
 
        openlog("hcitrace", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
 
-       syslog(LOG_INFO, "HCI trace deamon %s", VERSION);
+       syslog(LOG_INFO, "HCI trace daemon %s", VERSION);
 
        memset(&sa, 0, sizeof(sa));
        sa.sa_flags = SA_NOCLDSTOP;
diff --git a/unit/test-eir.c b/unit/test-eir.c
new file mode 100644 (file)
index 0000000..cefcacd
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  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 <check.h>
+
+#include <stdint.h>
+
+#include <glib.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/sdp.h>
+
+#include "eir.h"
+
+START_TEST(test_basic)
+{
+       struct eir_data data;
+       unsigned char buf[HCI_MAX_EIR_LENGTH];
+       int err;
+
+       memset(buf, 0, sizeof(buf));
+       memset(&data, 0, sizeof(data));
+
+       err = eir_parse(&data, buf, HCI_MAX_EIR_LENGTH);
+       ck_assert(err == 0);
+       ck_assert(data.services == NULL);
+       ck_assert(data.name == NULL);
+
+       eir_data_free(&data);
+}
+END_TEST
+
+static void add_test(Suite *s, const char *name, TFun func)
+{
+       TCase *t;
+
+       t = tcase_create(name);
+       tcase_add_test(t, func);
+       suite_add_tcase(s, t);
+}
+
+int main(int argc, char *argv[])
+{
+       int fails;
+       SRunner *sr;
+       Suite *s;
+
+       s = suite_create("EIR");
+
+       add_test(s, "basic", test_basic);
+
+       sr = srunner_create(s);
+
+       srunner_run_all(sr, CK_NORMAL);
+
+       fails = srunner_ntests_failed(sr);
+
+       srunner_free(sr);
+
+       if (fails > 0)
+               return -1;
+
+       return 0;
+}