Tizen 2.0 release
authorDoHyun Pyun <dh79.pyun@samsung.com>
Tue, 21 Aug 2012 10:53:00 +0000 (19:53 +0900)
committerDoHyun Pyun <dh79.pyun@samsung.com>
Tue, 21 Aug 2012 10:53:00 +0000 (19:53 +0900)
255 files changed:
AUTHORS
ChangeLog
Makefile.am
Makefile.tools
TODO
acinclude.m4
alert/main.c
attrib/att-database.h [new file with mode: 0644]
attrib/att.c
attrib/att.h
attrib/client.c
attrib/gatt-service.c
attrib/gatt-service.h
attrib/gatt.c
attrib/gatt.h
attrib/gattrib.c
attrib/gattrib.h
attrib/gatttool.c
attrib/gatttool.h
attrib/interactive.c
attrib/utils.c
audio/a2dp.c
audio/audio.conf
audio/avctp.c
audio/avctp.h
audio/avdtp.c
audio/avdtp.h
audio/avrcp.c
audio/avrcp.h
audio/control.c
audio/device.c
audio/device.h
audio/gateway.c
audio/gsta2dpsink.c
audio/gsta2dpsink.h
audio/gstavdtpsink.c
audio/gstrtpsbcpay.c
audio/gstsbcdec.c
audio/gstsbcenc.c
audio/gstsbcparse.c
audio/gstsbcutil.c
audio/gstsbcutil.h
audio/headset.c
audio/headset.h
audio/manager.c
audio/manager.h
audio/media.c
audio/pcm_bluetooth.c
audio/sink.c
audio/sink.h
audio/source.c
audio/source.h
audio/telephony-dummy.c
audio/telephony-maemo5.c
audio/telephony-maemo6.c
audio/telephony-ofono.c
audio/telephony-tizen.c
audio/telephony.h
audio/transport.c
audio/transport.h
audio/unix.c
btio/btio.c
btio/btio.h
compat/dun.c
compat/hidd.c
compat/sdp.c
configure.ac
debian/changelog
debian/rules [changed mode: 0755->0644]
deviceinfo/deviceinfo.c [new file with mode: 0644]
deviceinfo/deviceinfo.h [new file with mode: 0644]
deviceinfo/main.c [new file with mode: 0644]
deviceinfo/manager.c [new file with mode: 0644]
deviceinfo/manager.h [new file with mode: 0644]
doc/adapter-api.txt
doc/agent-api.txt
doc/audio-api.txt
doc/device-api.txt
doc/health-api.txt
doc/hfp-api.txt
doc/media-api.txt
doc/mgmt-api.txt
doc/proximity-api.txt
doc/serial-api.txt
doc/thermometer-api.txt
emulator/btdev.c [new file with mode: 0644]
emulator/btdev.h [new file with mode: 0644]
emulator/main.c [new file with mode: 0644]
emulator/server.c [new file with mode: 0644]
emulator/server.h [new file with mode: 0644]
emulator/vhci.c [new file with mode: 0644]
emulator/vhci.h [new file with mode: 0644]
gdbus/gdbus.h
gdbus/mainloop.c
gdbus/object.c
gdbus/watch.c
health/hdp.c
health/hdp_manager.c
health/hdp_types.h
health/hdp_util.c
health/mcap.c
input/device.c
input/device.h
input/fakehid.c
input/main.c
input/manager.c
input/server.c
input/sixpair.c
lib/a2mp.h [new file with mode: 0644]
lib/bluetooth.c
lib/bluetooth.h
lib/hci.c
lib/hci.h
lib/hci_lib.h
lib/l2cap.h
lib/mgmt.h
lib/sdp.c
lib/sdp.h
lib/sdp_lib.h
lib/uuid.h
mgmt/main.c
monitor/bt.h [new file with mode: 0644]
monitor/btsnoop.c [new file with mode: 0644]
monitor/btsnoop.h [new file with mode: 0644]
monitor/control.c [new file with mode: 0644]
monitor/control.h [moved from src/glib-compat.h with 76% similarity]
monitor/hcidump.c [new file with mode: 0644]
monitor/hcidump.h [new file with mode: 0644]
monitor/main.c [new file with mode: 0644]
monitor/mainloop.c [new file with mode: 0644]
monitor/mainloop.h [new file with mode: 0644]
monitor/packet.c [new file with mode: 0644]
monitor/packet.h [new file with mode: 0644]
network/common.c
network/common.h
network/connection.c
network/manager.c
network/server.c
network/server.h
packaging/bluez-ncurses.patch
packaging/bluez.spec
plugins/adaptername.c
plugins/dbusoob.c
plugins/gatt-example.c
plugins/hciops.c
plugins/maemo6.c
plugins/mgmtops.c
plugins/pnat.c
plugins/service.c
plugins/wiimote.c
proximity/immalert.c [new file with mode: 0644]
proximity/immalert.h [new file with mode: 0644]
proximity/linkloss.c [new file with mode: 0644]
proximity/linkloss.h [new file with mode: 0644]
proximity/main.c
proximity/manager.c
proximity/monitor.c
proximity/monitor.h
proximity/reporter.c
proximity/reporter.h
sap/manager.c
sap/sap-dummy.c
sap/sap-u8500.c
sap/server.c
sbc/sbc.h
sbc/sbc_primitives.h
scripts/bluetooth.rules.in [deleted file]
serial/manager.c
serial/port.c
serial/proxy.c
src/adapter.c
src/adapter.h
src/agent.c
src/agent.h
src/attrib-server.c
src/attrib-server.h
src/bluetooth.conf
src/bluetooth.service.in
src/dbus-common.c
src/dbus-common.h
src/device.c
src/device.h
src/eir.c
src/eir.h
src/event.c
src/event.h
src/glib-helper.c
src/hcid.h
src/log.c
src/log.h
src/main.c
src/main.conf
src/manager.c
src/manager.h
src/org.bluez.service [new file with mode: 0644]
src/sdp-client.c
src/sdp-client.h
src/sdpd-request.c
src/sdpd-server.c
src/sdpd-service.c
src/sdpd.h
src/storage.c
src/storage.h
src/textfile.c
src/uinput.h
test/apitest [deleted file]
test/btiotest.c
test/hciemu.c
test/l2test.c
test/list-devices [changed mode: 0755->0644]
test/monitor-bluetooth
test/simple-agent [changed mode: 0755->0644]
test/simple-endpoint [changed mode: 0755->0644]
test/simple-player [changed mode: 0755->0644]
test/simple-service
test/test-adapter [changed mode: 0755->0644]
test/test-attrib [changed mode: 0755->0644]
test/test-audio
test/test-device
test/test-discovery
test/test-health [changed mode: 0755->0644]
test/test-health-sink [changed mode: 0755->0644]
test/test-input
test/test-manager
test/test-nap [changed mode: 0755->0644]
test/test-network
test/test-oob [changed mode: 0755->0644]
test/test-proximity [changed mode: 0755->0644]
test/test-sap-server [changed mode: 0755->0644]
test/test-serial
test/test-serial-proxy [changed mode: 0755->0644]
test/test-service
test/test-telephony
test/test-thermometer [changed mode: 0755->0644]
thermometer/main.c
thermometer/manager.c
thermometer/thermometer.c
thermometer/thermometer.h
time/main.c
time/server.c
tools/csr_bcsp.c
tools/hciattach.8
tools/hciattach.c
tools/hciattach.h
tools/hciattach_ath3k.c
tools/hciattach_intel.c [new file with mode: 0644]
tools/hciattach_qualcomm.c
tools/hciattach_ti.c
tools/hciattach_tialt.c
tools/hciconfig.c
tools/hcitool.c
tools/hid2hci.c
tools/rfcomm.c
tools/sdptool.c
tracer/main.c [deleted file]

diff --git a/AUTHORS b/AUTHORS
index eeecec4..2eaa329 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -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 <padovan@profusion.mobi>
+Gustavo Padovan <gustavo@padovan.org>
 Marc-Andre Lureau <marc-andre.lureau@nokia.com>
 Bea Lam <bea.lam@nokia.com>
 Zygo Blaxell <zygo.blaxell@xandros.com>
@@ -58,3 +58,4 @@ 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>
+Syam Sidhardhan <s.syam@samsung.com>
index 2c9aaf8..0ea7db6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,49 @@
+ver 4.101:
+       Fix issue with missing BlueZ service file.
+       Fix issue with aborting A2DP setup during AVDTP start.
+       Fix issue with handling of multiple A2DP indication.
+       Fix issue with handling AVDTP abort with invalid SEID.
+       Fix issue with rejecting AVDTP abort commands.
+       Add support for handling AVDTP command collision.
+
+ver 4.100:
+       Fix issue with crashing when SCO connection fails.
+       Fix issue with HFP gateway failing on first GSM connection.
+       Fix issue with AVRCP and handling of vendor commands.
+       Fix issue with handling AVRCP subunit info command.
+       Fix issue with missing capability for AVRCP track reached end.
+       Fix issue with AVDTP signaling and GStreamer SBC NULL check.
+       Fix issue with AVDTP Reconfigure Reject message.
+       Fix issue with incorrect EIR length parsing.
+       Fix issue with SDP disconnect for HIDSDPDisable.
+       Fix issue with SDP interoperability with Mac OS X Lion.
+       Fix issue with reverse SDP discovery with some devices.
+       Fix issue with discovering state during power off operation.
+       Add support for AVRCP Volume Changed notifications.
+       Add support for AVRCP Set Absolute Volume handling.
+       Add support for display legacy PIN code agent method.
+       Add support for multiple media transports per endpoint.
+       Add support for discovering device information characteristics.
+       Add support for vendor source for Device ID setting.
+       Add support for immediate alert server.
+       Add support for link loss server.
+
+       Notes:
+       This version requires D-Bus 1.4 or later.
+       This version requires GLib 2.28 or later.
+
+ver 4.99:
+       Fix issue with missing retries for BNEP connection setup.
+       Fix issue with not showing name if first EIR has no details.
+       Fix issue with running SDP discovery for LE devices.
+       Add support for GATT using 128-bit Bluetooth UUIDs.
+       Add support for retrieving key size information.
+       Add support for storing Long Term Keys.
+       Add support for Proximity Reporter API.
+       Add support for KeyboardDisplay IO capability.
+       Add support for version 1.0 of management API.
+       Add support for monitoring interface.
+
 ver 4.98:
        Fix issue with adapter list upon initialization failure.
        Fix issue with missing legacy property for Low Energy.
index 5ed6c27..ecbe335 100644 (file)
@@ -25,10 +25,15 @@ includedir = @includedir@/bluetooth
 
 include_HEADERS =
 
+AM_CFLAGS = $(WARNING_CFLAGS) $(MISC_CFLAGS)
+AM_LDFLAGS = $(MISC_LDFLAGS)
+
 if DATAFILES
 dbusdir = $(sysconfdir)/dbus-1/system.d
+dbusservicedir = $(datadir)/dbus-1/system-services
 
 dbus_DATA = src/bluetooth.conf
+dbusservice_DATA = src/org.bluez.service
 
 confdir = $(sysconfdir)/bluetooth
 
@@ -59,7 +64,7 @@ plugin_LTLIBRARIES =
 
 lib_headers = lib/bluetooth.h lib/hci.h lib/hci_lib.h lib/mgmt.h \
                lib/sco.h lib/l2cap.h lib/sdp.h lib/sdp_lib.h lib/uuid.h \
-               lib/rfcomm.h lib/bnep.h lib/cmtp.h lib/hidp.h
+               lib/rfcomm.h lib/bnep.h lib/cmtp.h lib/hidp.h lib/a2mp.h
 local_headers = $(foreach file,$(lib_headers), lib/bluetooth/$(notdir $(file)))
 
 BUILT_SOURCES = $(local_headers) src/builtin.h
@@ -70,7 +75,7 @@ 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:5:11
+lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 16:0:13
 lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
 
 noinst_LTLIBRARIES += lib/libbluetooth-private.la
@@ -106,7 +111,8 @@ sbc_sbctest_CFLAGS = $(AM_CFLAGS) @SNDFILE_CFLAGS@
 endif
 endif
 
-attrib_sources = attrib/att.h attrib/att.c attrib/gatt.h attrib/gatt.c \
+attrib_sources = attrib/att.h attrib/att-database.h attrib/att.c \
+               attrib/gatt.h attrib/gatt.c \
                attrib/gattrib.h attrib/gattrib.c attrib/client.h \
                attrib/client.c attrib/gatt-service.h attrib/gatt-service.c
 
@@ -199,36 +205,11 @@ 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 GATT_EXAMPLE_PLUGIN
-builtin_modules += gatt_example
-builtin_sources += plugins/gatt-example.c
-endif
-
-if TIMEPLUGIN
-builtin_modules += time
-builtin_sources += time/main.c \
-                  time/server.h time/server.c
-endif
-
-if ALERTPLUGIN
-builtin_modules += alert
-builtin_sources += alert/main.c \
-                  alert/server.h alert/server.c
-endif
-
 if HEALTHPLUGIN
 builtin_modules += health
 builtin_sources += health/hdp_main.c health/hdp_types.h \
@@ -237,13 +218,26 @@ builtin_sources += health/hdp_main.c health/hdp_types.h \
                        health/hdp_util.h health/hdp_util.c
 endif
 
-if THERMOMETERPLUGIN
-builtin_modules += thermometer
+if GATTMODULES
+builtin_modules += thermometer alert time gatt_example proximity \
+                       deviceinfo
 builtin_sources += thermometer/main.c \
                        thermometer/manager.h thermometer/manager.c \
-                       thermometer/thermometer.h thermometer/thermometer.c
+                       thermometer/thermometer.h thermometer/thermometer.c \
+                       alert/main.c alert/server.h alert/server.c \
+                       time/main.c time/server.h time/server.c \
+                       plugins/gatt-example.c \
+                       proximity/main.c proximity/manager.h proximity/manager.c \
+                       proximity/monitor.h proximity/monitor.c \
+                       proximity/reporter.h proximity/reporter.c \
+                       proximity/linkloss.h proximity/linkloss.c \
+                       proximity/immalert.h proximity/immalert.c \
+                       deviceinfo/main.c \
+                       deviceinfo/manager.h deviceinfo/manager.c \
+                       deviceinfo/deviceinfo.h deviceinfo/deviceinfo.c
 endif
 
+
 builtin_modules += hciops mgmtops
 builtin_sources += plugins/hciops.c plugins/mgmtops.c
 
@@ -281,7 +275,8 @@ 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_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
+                                   -no-undefined
 plugins_external_dummy_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden
 endif
 
@@ -297,7 +292,7 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
                        src/attrib-server.h src/attrib-server.c \
                        src/sdp-xml.h src/sdp-xml.c \
                        src/sdp-client.h src/sdp-client.c \
-                       src/textfile.h src/textfile.c src/glib-compat.h \
+                       src/textfile.h src/textfile.c \
                        src/glib-helper.h src/glib-helper.c \
                        src/oui.h src/oui.c src/uinput.h src/ppoll.h \
                        src/plugin.h src/plugin.c \
@@ -311,8 +306,8 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
                        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 \
+                                                               -ldl -lrt
+src_bluetoothd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic \
                                -Wl,--version-script=$(srcdir)/src/bluetooth.ver
 
 src_bluetoothd_DEPENDENCIES = lib/libbluetooth-private.la
@@ -333,7 +328,7 @@ if DATAFILES
 conf_DATA += src/main.conf
 endif
 
-EXTRA_DIST += src/genbuiltin src/bluetooth.conf \
+EXTRA_DIST += src/genbuiltin src/bluetooth.conf src/org.bluez.service \
                        src/main.conf network/network.conf \
                        input/input.conf serial/serial.conf \
                        audio/audio.conf audio/telephony-dummy.c \
@@ -349,17 +344,19 @@ alsa_LTLIBRARIES = audio/libasound_module_pcm_bluetooth.la \
 
 audio_libasound_module_pcm_bluetooth_la_SOURCES = audio/pcm_bluetooth.c \
                                        audio/rtp.h audio/ipc.h audio/ipc.c
-audio_libasound_module_pcm_bluetooth_la_LDFLAGS = -module -avoid-version #-export-symbols-regex [_]*snd_pcm_.*
+audio_libasound_module_pcm_bluetooth_la_LDFLAGS = $(AM_LDFLAGS) -module \
+                                                 -avoid-version
 audio_libasound_module_pcm_bluetooth_la_LIBADD = sbc/libsbc.la \
                                        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_LDFLAGS = $(AM_LDFLAGS) -module \
+                                                 -avoid-version
 audio_libasound_module_ctl_bluetooth_la_LIBADD = \
                                        lib/libbluetooth-private.la @ALSA_LIBS@
-audio_libasound_module_ctl_bluetooth_la_CFLAGS = $(AM_CLAGS) @ALSA_CFLAGS@
+audio_libasound_module_ctl_bluetooth_la_CFLAGS = $(AM_CFLAGS) @ALSA_CFLAGS@
 
 if DATAFILES
 alsaconfdir = $(datadir)/alsa
@@ -383,12 +380,12 @@ audio_libgstbluetooth_la_SOURCES = audio/gstbluetooth.c audio/gstpragma.h \
                                audio/gstsbcutil.h audio/gstsbcutil.c \
                                audio/gstrtpsbcpay.h audio/gstrtpsbcpay.c \
                                audio/rtp.h audio/ipc.h audio/ipc.c
-audio_libgstbluetooth_la_LDFLAGS = -module -avoid-version
+audio_libgstbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version
 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) @DBUS_CFLAGS@ @GSTREAMER_CFLAGS@
+                               $(AM_CFLAGS) @DBUS_CFLAGS@ @GSTREAMER_CFLAGS@
 endif
 endif
 
@@ -400,7 +397,7 @@ include Makefile.tools
 if DATAFILES
 rulesdir = @UDEV_DIR@/rules.d
 
-udev_files = scripts/bluetooth.rules
+udev_files =
 
 if HID2HCI
 udev_files += scripts/bluetooth-hid2hci.rules
@@ -419,8 +416,7 @@ endif
 
 CLEANFILES += $(rules_DATA)
 
-EXTRA_DIST += scripts/bluetooth.rules \
-               scripts/bluetooth-hid2hci.rules scripts/bluetooth-serial.rules
+EXTRA_DIST += scripts/bluetooth-hid2hci.rules scripts/bluetooth-serial.rules
 
 EXTRA_DIST += doc/manager-api.txt \
                doc/adapter-api.txt doc/device-api.txt \
@@ -432,12 +428,12 @@ EXTRA_DIST += doc/manager-api.txt \
 
 AM_YFLAGS = -d
 
-AM_CFLAGS = @DBUS_CFLAGS@ @GLIB_CFLAGS@ @CAPNG_CFLAGS@
+AM_CFLAGS += @DBUS_CFLAGS@ @GLIB_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)/tools \
-                       -I$(builddir)/tools
+                       -I$(builddir)/tools -I$(srcdir)/monitor
 
 if MCAP
 INCLUDES += -I$(builddir)/health
index eea1a9b..5b1efb8 100644 (file)
@@ -27,7 +27,8 @@ tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
                                                tools/hciattach_ti.c \
                                                tools/hciattach_tialt.c \
                                                tools/hciattach_ath3k.c \
-                                               tools/hciattach_qualcomm.c
+                                               tools/hciattach_qualcomm.c \
+                                               tools/hciattach_intel.c
 tools_hciattach_LDADD = lib/libbluetooth-private.la
 
 tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c \
@@ -49,9 +50,24 @@ tools_ppporc_LDADD = lib/libbluetooth-private.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
+noinst_PROGRAMS += mgmt/btmgmt monitor/btmon emulator/btvirt
+
+mgmt_btmgmt_SOURCES = mgmt/main.c src/glib-helper.c
+mgmt_btmgmt_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@
+
+monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
+                                       monitor/mainloop.h monitor/mainloop.c \
+                                       monitor/hcidump.h monitor/hcidump.c \
+                                       monitor/btsnoop.h monitor/btsnoop.c \
+                                       monitor/control.h monitor/control.c \
+                                       monitor/packet.h monitor/packet.c
+monitor_btmon_LDADD = lib/libbluetooth-private.la
+
+emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
+                                       monitor/mainloop.h monitor/mainloop.c \
+                                       emulator/server.h emulator/server.c \
+                                       emulator/vhci.h emulator/vhci.c \
+                                       emulator/btdev.h emulator/btdev.c
 
 if READLINE
 bin_PROGRAMS += attrib/gatttool
@@ -59,7 +75,7 @@ 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/utils.c src/log.c
 attrib_gatttool_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @READLINE_LIBS@
 endif
 
@@ -76,15 +92,6 @@ CLEANFILES += tools/lexer.c tools/parser.c tools/parser.h
 
 EXTRA_DIST += tools/rfcomm.conf
 
-if TRACER
-sbin_PROGRAMS += tracer/hcitrace
-
-tracer_hcitrace_SOURCES = tracer/main.c
-tracer_hcitrace_LDADD = lib/libbluetooth-private.la \
-                               @GLIB_LIBS@ @DBUS_LIBS@ @CAPNG_LIBS@
-tracer_hcitrace_DEPENDENCIES = lib/libbluetooth-private.la
-endif
-
 if BCCMD
 sbin_PROGRAMS += tools/bccmd
 
@@ -195,6 +202,7 @@ test_btiotest_LDADD = @GLIB_LIBS@ lib/libbluetooth-private.la
 test_uuidtest_SOURCES = test/uuidtest.c
 test_uuidtest_LDADD = lib/libbluetooth-private.la
 
+test_mpris_player_SOURCES = test/mpris-player.c
 test_mpris_player_LDADD = @DBUS_LIBS@ @GLIB_LIBS@
 
 test_test_textfile_SOURCES = test/test-textfile.c src/textfile.h src/textfile.c
@@ -206,18 +214,18 @@ else
 EXTRA_DIST += test/rctest.1 test/hciemu.1 test/bdaddr.8
 endif
 
-EXTRA_DIST += test/apitest test/sap-client test/hsplay test/hsmicro \
+EXTRA_DIST += 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/test-input test/test-sap-server test/test-oob \
+               test/test-attrib test/test-proximity test/test-thermometer \
+               test/test-serial-proxy 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
-
+               test/service-spp.xml test/service-opp.xml test/service-ftp.xml \
+               test/simple-player test/test-nap
 
 if HIDD
 bin_PROGRAMS += compat/hidd
diff --git a/TODO b/TODO
index fab3ec0..17e9848 100644 (file)
--- a/TODO
+++ b/TODO
@@ -222,21 +222,6 @@ ATT/GATT
 Management Interface
 ====================
 
-- Device discovery support (both for BR/EDR & LE)
-
-  Priority: High
-  Complexity: C3
-
-- Blacklist support
-
-  Priority: Medium
-  Complexity: C1
-
-- mgmt_set_fast_connectable
-
-  Priority: Medium
-  Complexity: C1
-
 - Whitelist support (initially only for LE)
 
   Priority: Medium
index 57fc5e0..1d6d736 100644 (file)
@@ -11,19 +11,19 @@ AC_DEFUN([AC_PROG_CC_PIE], [
 ])
 
 AC_DEFUN([COMPILER_FLAGS], [
-       if (test "${CFLAGS}" = ""); then
-               CFLAGS="-Wall -O2"
-       fi
+       with_cflags=""
        if (test "$USE_MAINTAINER_MODE" = "yes"); then
-               CFLAGS="$CFLAGS -Werror -Wextra"
-               CFLAGS="$CFLAGS -Wno-unused-parameter"
-               CFLAGS="$CFLAGS -Wno-missing-field-initializers"
-               CFLAGS="$CFLAGS -Wdeclaration-after-statement"
-               CFLAGS="$CFLAGS -Wmissing-declarations"
-               CFLAGS="$CFLAGS -Wredundant-decls"
-               CFLAGS="$CFLAGS -Wcast-align"
-               CFLAGS="$CFLAGS -DG_DISABLE_DEPRECATED"
+               with_cflags="$with_cflags -Wall -Werror -Wextra"
+               with_cflags="$with_cflags -Wno-unused-parameter"
+               with_cflags="$with_cflags -Wno-missing-field-initializers"
+               with_cflags="$with_cflags -Wdeclaration-after-statement"
+               with_cflags="$with_cflags -Wmissing-declarations"
+               with_cflags="$with_cflags -Wredundant-decls"
+               with_cflags="$with_cflags -Wcast-align"
+               with_cflags="$with_cflags -DG_DISABLE_DEPRECATED"
        fi
+
+       AC_SUBST([WARNING_CFLAGS], $with_cflags)
 ])
 
 AC_DEFUN([AC_FUNC_PPOLL], [
@@ -92,25 +92,15 @@ AC_DEFUN([AC_INIT_BLUEZ], [
 ])
 
 AC_DEFUN([AC_PATH_DBUS], [
-       PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.0, dummy=yes,
-                               AC_MSG_ERROR(D-Bus library is required))
-       AC_CHECK_LIB(dbus-1, dbus_watch_get_unix_fd, dummy=yes,
-               AC_DEFINE(NEED_DBUS_WATCH_GET_UNIX_FD, 1,
-                       [Define to 1 if you need the dbus_watch_get_unix_fd() function.]))
-       AC_CHECK_LIB(dbus-1, dbus_connection_can_send_type, dummy=yes,
-               AC_DEFINE(NEED_DBUS_CONNECTION_CAN_SEND_TYPE, 1,
-                       [Define to 1 if you need the dbus_connection_can_send_type() function.]
-))
+       PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.4, dummy=yes,
+                               AC_MSG_ERROR(D-Bus >= 1.4 is required))
        AC_SUBST(DBUS_CFLAGS)
        AC_SUBST(DBUS_LIBS)
 ])
 
 AC_DEFUN([AC_PATH_GLIB], [
-       PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
-                               AC_MSG_ERROR(GLib library version 2.16 or later is required))
-       AC_CHECK_LIB(glib-2.0, g_slist_free_full, dummy=yes,
-               AC_DEFINE(NEED_G_SLIST_FREE_FULL, 1,
-                       [Define to 1 if you need g_slist_free_full() function.]))
+       PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.28, dummy=yes,
+                               AC_MSG_ERROR(GLib >= 2.28 is required))
        AC_SUBST(GLIB_CFLAGS)
        AC_SUBST(GLIB_LIBS)
 ])
@@ -193,14 +183,9 @@ 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=no
        pnat_enable=no
-       gatt_example_enable=no
-       tracer_enable=no
        tools_enable=yes
        hidd_enable=no
        pand_enable=no
@@ -217,7 +202,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
        sap_driver=dummy
        dbusoob_enable=no
        wiimote_enable=no
-       thermometer_enable=no
+       gatt_enable=no
 
        AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization], [disable code optimization]), [
                optimization_enable=${enableval}
@@ -244,18 +229,6 @@ AC_DEFUN([AC_ARG_BLUEZ], [
        ])
        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}
        ])
@@ -280,10 +253,6 @@ AC_DEFUN([AC_ARG_BLUEZ], [
                pnat_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]), [
                gstreamer_enable=${enableval}
        ])
@@ -296,10 +265,6 @@ AC_DEFUN([AC_ARG_BLUEZ], [
                usb_enable=${enableval}
        ])
 
-       AC_ARG_ENABLE(tracer, AC_HELP_STRING([--enable-tracer], [install Tracing daemon]), [
-               tracer_enable=${enableval}
-       ])
-
        AC_ARG_ENABLE(tools, AC_HELP_STRING([--enable-tools], [install Bluetooth utilities]), [
                tools_enable=${enableval}
        ])
@@ -370,27 +335,33 @@ AC_DEFUN([AC_ARG_BLUEZ], [
                hal_enable=${enableval}
        ])
 
-       AC_ARG_ENABLE(thermometer, AC_HELP_STRING([--enable-thermometer], [enable thermometer plugin]), [
-               thermometer_enable=${enableval}
+       AC_ARG_ENABLE(gatt, AC_HELP_STRING([--enable-gatt], [enable gatt module]), [
+               gatt_enable=${enableval}
        ])
 
+       misc_cflags=""
+       misc_ldflags=""
+
        if (test "${fortify_enable}" = "yes"); then
-               CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2"
+               misc_cflags="$misc_cflags -D_FORTIFY_SOURCE=2"
        fi
 
        if (test "${pie_enable}" = "yes" && test "${ac_cv_prog_cc_pie}" = "yes"); then
-               CFLAGS="$CFLAGS -fPIC"
-               LDFLAGS="$LDFLAGS -pie"
+               misc_cflags="$misc_cflags -fPIC"
+               misc_ldflags="$misc_ldflags -pie"
        fi
 
        if (test "${debug_enable}" = "yes" && test "${ac_cv_prog_cc_g}" = "yes"); then
-               CFLAGS="$CFLAGS -g"
+               misc_cflags="$misc_cflags -g"
        fi
 
        if (test "${optimization_enable}" = "no"); then
-               CFLAGS="$CFLAGS -O0"
+               misc_cflags="$misc_cflags -O0"
        fi
 
+       AC_SUBST([MISC_CFLAGS], $misc_cflags)
+       AC_SUBST([MISC_LDFLAGS], $misc_ldflags)
+
        if (test "${usb_enable}" = "yes" && test "${usb_found}" = "yes"); then
                AC_DEFINE(HAVE_LIBUSB, 1, [Define to 1 if you have USB library.])
        fi
@@ -406,17 +377,12 @@ 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(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")
@@ -431,5 +397,5 @@ AC_DEFUN([AC_ARG_BLUEZ], [
        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")
+       AM_CONDITIONAL(GATTMODULES, test "${gatt_enable}" = "yes")
 ])
index 25100e9..ec4ab6d 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <stdint.h>
 #include <glib.h>
+#include <errno.h>
 
 #include "plugin.h"
 #include "hcid.h"
@@ -36,9 +37,9 @@
 
 static int alert_init(void)
 {
-       if (!main_opts.attrib_server) {
-               DBG("Attribute server is disabled");
-               return -1;
+       if (!main_opts.gatt_enabled) {
+               DBG("GATT is disabled");
+               return -ENOTSUP;
        }
 
        return alert_server_init();
@@ -46,7 +47,7 @@ static int alert_init(void)
 
 static void alert_exit(void)
 {
-       if (!main_opts.attrib_server)
+       if (!main_opts.gatt_enabled)
                return;
 
        alert_server_exit();
diff --git a/attrib/att-database.h b/attrib/att-database.h
new file mode 100644 (file)
index 0000000..3e854aa
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments 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
+ *
+ */
+
+/* Requirements for read/write operations */
+enum {
+       ATT_NONE,               /* No restrictions */
+       ATT_AUTHENTICATION,     /* Authentication required */
+       ATT_AUTHORIZATION,      /* Authorization required */
+       ATT_NOT_PERMITTED,      /* Operation not permitted */
+};
+
+struct attribute {
+       uint16_t handle;
+       bt_uuid_t uuid;
+       int read_reqs;
+       int write_reqs;
+       uint8_t (*read_cb)(struct attribute *a, struct btd_device *device,
+                                                       gpointer user_data);
+       uint8_t (*write_cb)(struct attribute *a, struct btd_device *device,
+                                                       gpointer user_data);
+       gpointer cb_user_data;
+       int len;
+       uint8_t *data;
+};
index a3a8947..c8e2e1d 100644 (file)
@@ -72,6 +72,10 @@ const char *att_ecode2str(uint8_t status)
                return "Insufficient Resources to complete the request";
        case ATT_ECODE_IO:
                return "Internal application error: I/O";
+       case ATT_ECODE_TIMEOUT:
+               return "A timeout occured";
+       case ATT_ECODE_ABORTED:
+               return "The operation was aborted";
        default:
                return "Unexpected error code";
        }
index dc266f1..144513f 100644 (file)
  *
  */
 
-/* GATT Profile Attribute types */
-#define GATT_PRIM_SVC_UUID             0x2800
-#define GATT_SND_SVC_UUID              0x2801
-#define GATT_INCLUDE_UUID              0x2802
-#define GATT_CHARAC_UUID               0x2803
-
-/* GATT Characteristic Types */
-#define GATT_CHARAC_DEVICE_NAME                        0x2A00
-#define GATT_CHARAC_APPEARANCE                 0x2A01
-#define GATT_CHARAC_PERIPHERAL_PRIV_FLAG       0x2A02
-#define GATT_CHARAC_RECONNECTION_ADDRESS       0x2A03
-#define GATT_CHARAC_PERIPHERAL_PREF_CONN       0x2A04
-#define GATT_CHARAC_SERVICE_CHANGED            0x2A05
-
-/* GATT Characteristic Descriptors */
-#define GATT_CHARAC_EXT_PROPER_UUID    0x2900
-#define GATT_CHARAC_USER_DESC_UUID     0x2901
-#define GATT_CLIENT_CHARAC_CFG_UUID    0x2902
-#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_OP_MTU_REQ                 0x02
@@ -94,7 +71,9 @@
 #define ATT_ECODE_UNSUPP_GRP_TYPE              0x10
 #define ATT_ECODE_INSUFF_RESOURCES             0x11
 /* Application error */
-#define ATT_ECODE_IO                           0xFF
+#define ATT_ECODE_IO                           0x80
+#define ATT_ECODE_TIMEOUT                      0x81
+#define ATT_ECODE_ABORTED                      0x82
 
 /* Characteristic Property bit field */
 #define ATT_CHAR_PROPER_BROADCAST              0x01
 #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 */
-       ATT_AUTHENTICATION,     /* Authentication required */
-       ATT_AUTHORIZATION,      /* Authorization required */
-       ATT_NOT_PERMITTED,      /* Operation not permitted */
-};
-
-struct attribute {
-       uint16_t handle;
-       bt_uuid_t uuid;
-       int read_reqs;
-       int write_reqs;
-       uint8_t (*read_cb)(struct attribute *a, gpointer user_data);
-       uint8_t (*write_cb)(struct attribute *a, gpointer user_data);
-       gpointer cb_user_data;
-       int len;
-       uint8_t *data;
-};
-
 struct att_data_list {
        uint16_t num;
        uint16_t len;
@@ -148,19 +103,6 @@ struct att_range {
        uint16_t end;
 };
 
-struct att_primary {
-       char uuid[MAX_LEN_UUID_STR + 1];
-       uint16_t start;
-       uint16_t end;
-};
-
-struct att_char {
-       char uuid[MAX_LEN_UUID_STR + 1];
-       uint16_t handle;
-       uint8_t properties;
-       uint16_t value_handle;
-};
-
 /* These functions do byte conversion */
 static inline uint8_t att_get_u8(const void *ptr)
 {
index 60cff01..8d119df 100644 (file)
@@ -34,7 +34,6 @@
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/uuid.h>
 
-#include "glib-compat.h"
 #include "adapter.h"
 #include "device.h"
 #include "log.h"
@@ -62,13 +61,12 @@ struct format {
 
 struct query {
        DBusMessage *msg;
-       guint attioid;
        GSList *list;
 };
 
 struct gatt_service {
        struct btd_device *dev;
-       struct att_primary *prim;
+       struct gatt_primary *prim;
        DBusConnection *conn;
        GAttrib *attrib;
        guint attioid;
@@ -141,15 +139,31 @@ static void gatt_service_free(struct gatt_service *gatt)
        g_free(gatt);
 }
 
-static void gatt_get_address(struct gatt_service *gatt,
-                               bdaddr_t *sba, bdaddr_t *dba)
+static void remove_attio(struct gatt_service *gatt)
+{
+       if (gatt->offline_chars || gatt->watchers || gatt->query)
+               return;
+
+       if (gatt->attioid) {
+               btd_device_remove_attio_callback(gatt->dev, gatt->attioid);
+               gatt->attioid = 0;
+       }
+
+       if (gatt->attrib) {
+               g_attrib_unref(gatt->attrib);
+               gatt->attrib = NULL;
+       }
+}
+
+static void gatt_get_address(struct gatt_service *gatt, bdaddr_t *sba,
+                                       bdaddr_t *dba, uint8_t *bdaddr_type)
 {
        struct btd_device *device = gatt->dev;
        struct btd_adapter *adapter;
 
        adapter = device_get_adapter(device);
        adapter_get_address(adapter, sba);
-       device_get_address(device, dba, NULL);
+       device_get_address(device, dba, bdaddr_type);
 }
 
 static int characteristic_handle_cmp(gconstpointer a, gconstpointer b)
@@ -212,6 +226,8 @@ static void watcher_exit(DBusConnection *conn, void *user_data)
        DBG("%s watcher %s exited", gatt->path, watcher->name);
 
        gatt->watchers = g_slist_remove(gatt->watchers, watcher);
+       g_dbus_remove_watch(gatt->conn, watcher->id);
+       remove_attio(gatt);
 }
 
 static int characteristic_set_value(struct characteristic *chr,
@@ -298,11 +314,7 @@ static void offline_char_written(gpointer user_data)
 
        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;
+       remove_attio(gatt);
 }
 
 static void offline_char_write(gpointer data, gpointer user_data)
@@ -314,6 +326,9 @@ static void offline_char_write(gpointer data, gpointer user_data)
                                                offline_char_written, chr);
 }
 
+static void char_discovered_cb(GSList *characteristics, guint8 status,
+                                                       gpointer user_data);
+
 static void attio_connected(GAttrib *attrib, gpointer user_data)
 {
        struct gatt_service *gatt = user_data;
@@ -326,12 +341,36 @@ static void attio_connected(GAttrib *attrib, gpointer user_data)
                                        events_handler, gatt, NULL);
 
        g_slist_foreach(gatt->offline_chars, offline_char_write, attrib);
+
+       if (gatt->query) {
+               struct gatt_primary *prim = gatt->prim;
+               struct query_data *qchr;
+
+               qchr = g_slist_nth_data(gatt->query->list, 0);
+               gatt_discover_char(gatt->attrib, prim->range.start,
+                                               prim->range.end, NULL,
+                                               char_discovered_cb, qchr);
+       }
 }
 
 static void attio_disconnected(gpointer user_data)
 {
        struct gatt_service *gatt = user_data;
 
+       if (gatt->query && gatt->query->msg) {
+               DBusMessage *reply;
+
+               reply = btd_error_failed(gatt->query->msg,
+                                       "ATT IO channel was disconnected");
+               g_dbus_send_message(gatt->conn, reply);
+               dbus_message_unref(gatt->query->msg);
+       }
+
+       if (gatt->query) {
+               g_slist_free_full(gatt->query->list, g_free);
+               gatt->query = NULL;
+       }
+
        if (gatt->attrib) {
                g_attrib_unref(gatt->attrib);
                gatt->attrib = NULL;
@@ -390,14 +429,9 @@ static DBusMessage *unregister_watcher(DBusConnection *conn,
                return btd_error_not_authorized(msg);
 
        watcher = l->data;
-       g_dbus_remove_watch(conn, watcher->id);
        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;
-       }
+       g_dbus_remove_watch(conn, watcher->id);
+       remove_attio(gatt);
 
        return dbus_message_new_method_return(msg);
 }
@@ -481,10 +515,13 @@ static DBusMessage *set_property(DBusConnection *conn,
        return btd_error_invalid_args(msg);
 }
 
-static GDBusMethodTable char_methods[] = {
-       { "GetProperties",      "",     "a{sv}", get_properties },
-       { "SetProperty",        "sv",   "",     set_property,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
+static const GDBusMethodTable char_methods[] = {
+       { GDBUS_METHOD("GetProperties",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       get_properties) },
+       { GDBUS_METHOD("SetProperty",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
+                       set_property) },
        { }
 };
 
@@ -511,13 +548,15 @@ static char *characteristic_list_to_string(GSList *chars)
 }
 
 static void store_characteristics(const bdaddr_t *sba, const bdaddr_t *dba,
-                                               uint16_t start, GSList *chars)
+                                       uint8_t bdaddr_type, uint16_t start,
+                                                               GSList *chars)
 {
        char *characteristics;
 
        characteristics = characteristic_list_to_string(chars);
 
-       write_device_characteristics(sba, dba, start, characteristics);
+       write_device_characteristics(sba, dba, bdaddr_type, start,
+                                                       characteristics);
 
        g_free(characteristics);
 }
@@ -577,11 +616,12 @@ static GSList *load_characteristics(struct gatt_service *gatt, uint16_t start)
 {
        GSList *chrs_list;
        bdaddr_t sba, dba;
+       uint8_t bdaddr_type;
        char *str;
 
-       gatt_get_address(gatt, &sba, &dba);
+       gatt_get_address(gatt, &sba, &dba, &bdaddr_type);
 
-       str = read_device_characteristics(&sba, &dba, start);
+       str = read_device_characteristics(&sba, &dba, bdaddr_type, start);
        if (str == NULL)
                return NULL;
 
@@ -595,7 +635,9 @@ static GSList *load_characteristics(struct gatt_service *gatt, uint16_t start)
 static void store_attribute(struct gatt_service *gatt, uint16_t handle,
                                uint16_t type, uint8_t *value, gsize len)
 {
+       struct btd_device *device = gatt->dev;
        bdaddr_t sba, dba;
+       uint8_t bdaddr_type;
        bt_uuid_t uuid;
        char *str, *tmp;
        guint i;
@@ -610,9 +652,11 @@ 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]);
 
-       gatt_get_address(gatt, &sba, &dba);
+       gatt_get_address(gatt, &sba, &dba, NULL);
 
-       write_device_attribute(&sba, &dba, handle, str);
+       bdaddr_type = device_get_addr_type(device);
+
+       write_device_attribute(&sba, &dba, bdaddr_type, handle, str);
 
        g_free(str);
 }
@@ -632,10 +676,10 @@ static void query_list_remove(struct gatt_service *gatt, struct query_data *data
        if (query->list != NULL)
                return;
 
-       btd_device_remove_attio_callback(gatt->dev, query->attioid);
        g_free(query);
-
        gatt->query = NULL;
+
+       remove_attio(gatt);
 }
 
 static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len,
@@ -658,9 +702,17 @@ static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len,
                                (void *) chr->desc, len);
        } else if (status == ATT_ECODE_INSUFF_ENC) {
                GIOChannel *io = g_attrib_get_channel(gatt->attrib);
+               BtIOSecLevel level = BT_IO_SEC_HIGH;
+
+               bt_io_get(io, BT_IO_L2CAP, NULL,
+                               BT_IO_OPT_SEC_LEVEL, &level,
+                               BT_IO_OPT_INVALID);
+
+               if (level < BT_IO_SEC_HIGH)
+                       level++;
 
                if (bt_io_set(io, BT_IO_L2CAP, NULL,
-                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH,
+                               BT_IO_OPT_SEC_LEVEL, level,
                                BT_IO_OPT_INVALID)) {
                        gatt_read_char(gatt->attrib, current->handle, 0,
                                        update_char_desc, current);
@@ -814,17 +866,42 @@ static void update_all_chars(gpointer data, gpointer user_data)
        gatt_read_char(gatt->attrib, chr->handle, 0, update_char_value, qvalue);
 }
 
+static DBusMessage *create_discover_char_reply(DBusMessage *msg, GSList *chars)
+{
+       DBusMessage *reply;
+       DBusMessageIter iter, array_iter;
+       GSList *l;
+
+       reply = dbus_message_new_method_return(msg);
+
+       dbus_message_iter_init_append(reply, &iter);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                               DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
+
+       for (l = chars; l; l = l->next) {
+               struct characteristic *chr = l->data;
+
+               dbus_message_iter_append_basic(&array_iter,
+                                       DBUS_TYPE_OBJECT_PATH, &chr->path);
+       }
+
+       dbus_message_iter_close_container(&iter, &array_iter);
+
+       return reply;
+}
+
 static void char_discovered_cb(GSList *characteristics, guint8 status,
                                                        gpointer user_data)
 {
        DBusMessage *reply;
-       DBusMessageIter iter, array_iter;
        struct query_data *current = user_data;
        struct gatt_service *gatt = current->gatt;
-       struct att_primary *prim = gatt->prim;
+       struct gatt_primary *prim = gatt->prim;
        uint16_t *previous_end = NULL;
        GSList *l;
        bdaddr_t sba, dba;
+       uint8_t bdaddr_type;
 
        if (status != 0) {
                const char *str = att_ecode2str(status);
@@ -835,7 +912,7 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
        }
 
        for (l = characteristics; l; l = l->next) {
-               struct att_char *current_chr = l->data;
+               struct gatt_char *current_chr = l->data;
                struct characteristic *chr;
                guint handle = current_chr->value_handle;
                GSList *lchr;
@@ -857,61 +934,29 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
                previous_end = &chr->end;
 
                gatt->chars = g_slist_append(gatt->chars, chr);
+               register_characteristic(chr, gatt->path);
        }
 
        if (previous_end)
-               *previous_end = prim->end;
-
-       gatt_get_address(gatt, &sba, &dba);
-       store_characteristics(&sba, &dba, prim->start, gatt->chars);
-
-       g_slist_foreach(gatt->chars, register_characteristic, gatt->path);
-
-       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 = gatt->chars; l; l = l->next) {
-               struct characteristic *chr = l->data;
-
-               dbus_message_iter_append_basic(&array_iter,
-                                       DBUS_TYPE_OBJECT_PATH, &chr->path);
-       }
+               *previous_end = prim->range.end;
 
-       dbus_message_iter_close_container(&iter, &array_iter);
+       gatt_get_address(gatt, &sba, &dba, &bdaddr_type);
+       store_characteristics(&sba, &dba, bdaddr_type, prim->range.start,
+                                                               gatt->chars);
 
        g_slist_foreach(gatt->chars, update_all_chars, gatt);
 
+       reply = create_discover_char_reply(gatt->query->msg, gatt->chars);
+
 fail:
+       dbus_message_unref(gatt->query->msg);
+       gatt->query->msg = NULL;
+
        g_dbus_send_message(gatt->conn, reply);
        query_list_remove(gatt, current);
        g_free(current);
 }
 
-static 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)
 {
@@ -928,10 +973,18 @@ static DBusMessage *discover_char(DBusConnection *conn, DBusMessage *msg,
        qchr->gatt = gatt;
 
        query->msg = dbus_message_ref(msg);
-       query->attioid = btd_device_add_attio_callback(gatt->dev,
-                                                       send_discover,
-                                                       cancel_discover,
-                                                       qchr);
+
+       if (gatt->attioid == 0) {
+               gatt->attioid = btd_device_add_attio_callback(gatt->dev,
+                                                       attio_connected,
+                                                       attio_disconnected,
+                                                       gatt);
+       } else if (gatt->attrib) {
+               struct gatt_primary *prim = gatt->prim;
+               gatt_discover_char(gatt->attrib, prim->range.start,
+                                               prim->range.end, NULL,
+                                               char_discovered_cb, qchr);
+       }
 
        gatt->query = query;
 
@@ -982,20 +1035,25 @@ static DBusMessage *prim_get_properties(DBusConnection *conn, DBusMessage *msg,
        return reply;
 }
 
-static GDBusMethodTable prim_methods[] = {
-       { "DiscoverCharacteristics",    "",     "ao",   discover_char,
-                                       G_DBUS_METHOD_FLAG_ASYNC        },
-       { "RegisterCharacteristicsWatcher",     "o", "",
-                                               register_watcher        },
-       { "UnregisterCharacteristicsWatcher",   "o", "",
-                                               unregister_watcher      },
-       { "GetProperties",      "",     "a{sv}",prim_get_properties     },
+static const GDBusMethodTable prim_methods[] = {
+       { GDBUS_ASYNC_METHOD("DiscoverCharacteristics",
+                       NULL, GDBUS_ARGS({ "characteristics", "ao" }),
+                       discover_char) },
+       { GDBUS_METHOD("RegisterCharacteristicsWatcher",
+                       GDBUS_ARGS({ "agent", "o" }), NULL,
+                       register_watcher) },
+       { GDBUS_METHOD("UnregisterCharacteristicsWatcher",
+                       GDBUS_ARGS({ "agent", "o" }), NULL,
+                       unregister_watcher) },
+       { GDBUS_METHOD("GetProperties",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       prim_get_properties) },
        { }
 };
 
 static struct gatt_service *primary_register(DBusConnection *conn,
                                                struct btd_device *device,
-                                               struct att_primary *prim,
+                                               struct gatt_primary *prim,
                                                int psm)
 {
        struct gatt_service *gatt;
@@ -1009,12 +1067,12 @@ static struct gatt_service *primary_register(DBusConnection *conn,
        gatt->psm = psm;
        gatt->conn = dbus_connection_ref(conn);
        gatt->path = g_strdup_printf("%s/service%04x", device_path,
-                                                               prim->start);
+                                                               prim->range.start);
 
        g_dbus_register_interface(gatt->conn, gatt->path,
                                        CHAR_INTERFACE, prim_methods,
                                        NULL, NULL, gatt, NULL);
-       gatt->chars = load_characteristics(gatt, prim->start);
+       gatt->chars = load_characteristics(gatt, prim->range.start);
        g_slist_foreach(gatt->chars, register_characteristic, gatt->path);
 
        return gatt;
@@ -1027,7 +1085,7 @@ GSList *attrib_client_register(DBusConnection *connection,
        GSList *l, *services;
 
        for (l = primaries, services = NULL; l; l = l->next) {
-               struct att_primary *prim = l->data;
+               struct gatt_primary *prim = l->data;
                struct gatt_service *gatt;
 
                gatt = primary_register(connection, device, prim, psm);
@@ -1046,9 +1104,6 @@ static void primary_unregister(struct gatt_service *gatt)
 {
        GSList *l;
 
-       if (gatt->attioid)
-               btd_device_remove_attio_callback(gatt->dev, gatt->attioid);
-
        for (l = gatt->chars; l; l = l->next) {
                struct characteristic *chr = l->data;
                g_dbus_unregister_interface(gatt->conn, chr->path,
@@ -1056,6 +1111,8 @@ static void primary_unregister(struct gatt_service *gatt)
        }
 
        g_dbus_unregister_interface(gatt->conn, gatt->path, CHAR_INTERFACE);
+
+       remove_attio(gatt);
 }
 
 static int path_cmp(gconstpointer data, gconstpointer user_data)
index bfefdee..a9de98c 100644 (file)
 #include <bluetooth/sdp.h>
 #include <adapter.h>
 
-#include "att.h"
 #include "gattrib.h"
+#include "att.h"
+#include "gatt.h"
+#include "att-database.h"
 #include "attrib-server.h"
 #include "gatt-service.h"
 #include "log.h"
-#include "glib-compat.h"
 
 struct gatt_info {
        bt_uuid_t uuid;
@@ -116,6 +117,28 @@ static GSList *parse_opts(gatt_option opt1, va_list args)
        return l;
 }
 
+static struct attribute *add_service_declaration(struct btd_adapter *adapter,
+                               uint16_t handle, uint16_t svc, bt_uuid_t *uuid)
+{
+       bt_uuid_t bt_uuid;
+       uint8_t atval[16];
+       int len;
+
+       if (uuid->type == BT_UUID16) {
+               att_put_u16(uuid->value.u16, &atval[0]);
+               len = 2;
+       } else if (uuid->type == BT_UUID128) {
+               att_put_u128(uuid->value.u128, &atval[0]);
+               len = 16;
+       } else
+               return NULL;
+
+       bt_uuid16_create(&bt_uuid, svc);
+
+       return attrib_db_add(adapter, handle, &bt_uuid, ATT_NONE,
+                                               ATT_NOT_PERMITTED, atval, len);
+}
+
 static int att_read_reqs(int authorization, int authentication, uint8_t props)
 {
        if (authorization == GATT_CHR_VALUE_READ ||
@@ -268,51 +291,52 @@ static void service_attr_del(struct btd_adapter *adapter, uint16_t start_handle,
 }
 
 gboolean gatt_service_add(struct btd_adapter *adapter, uint16_t uuid,
-                               uint16_t svc_uuid, gatt_option opt1, ...)
+                               bt_uuid_t *svc_uuid, gatt_option opt1, ...)
 {
+       char uuidstr[MAX_LEN_UUID_STR];
        uint16_t start_handle, h;
        unsigned int size;
-       bt_uuid_t bt_uuid;
-       uint8_t atval[2];
        va_list args;
        GSList *chrs, *l;
 
+       bt_uuid_to_string(svc_uuid, uuidstr, MAX_LEN_UUID_STR);
+
+       if (svc_uuid->type != BT_UUID16 && svc_uuid->type != BT_UUID128) {
+               error("Invalid service uuid: %s", uuidstr);
+               return FALSE;
+       }
+
        va_start(args, opt1);
        chrs = parse_opts(opt1, args);
+       va_end(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);
+
+       start_handle = attrib_db_find_avail(adapter, svc_uuid, size);
        if (start_handle == 0) {
                error("Not enough free handles to register service");
-               g_slist_free_full(chrs, free_gatt_info);
-               return FALSE;
+               goto fail;
        }
 
-       DBG("New service: handle 0x%04x, UUID 0x%04x, %d attributes",
-                                               start_handle, svc_uuid, size);
+       DBG("New service: handle 0x%04x, UUID %s, %d attributes",
+                                               start_handle, uuidstr, 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;
-       }
+       if (add_service_declaration(adapter, h++, uuid, svc_uuid) == NULL)
+               goto fail;
 
        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;
+                       goto fail;
                }
        }
 
@@ -321,4 +345,8 @@ gboolean gatt_service_add(struct btd_adapter *adapter, uint16_t uuid,
        g_slist_free_full(chrs, free_gatt_info);
 
        return TRUE;
+
+fail:
+       g_slist_free_full(chrs, free_gatt_info);
+       return FALSE;
 }
index 7af2d3e..b810e2e 100644 (file)
@@ -48,4 +48,4 @@ typedef enum {
 } attrib_event_t;
 
 gboolean gatt_service_add(struct btd_adapter *adapter, uint16_t uuid,
-                               uint16_t svc_uuid, gatt_option opt1, ...);
+                                       bt_uuid_t *svc_uuid, gatt_option opt1, ...);
index 452a4cf..6f9a11d 100644 (file)
@@ -33,8 +33,6 @@
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
-#include "glib-compat.h"
-
 #include "att.h"
 #include "gattrib.h"
 #include "gatt.h"
@@ -172,7 +170,7 @@ static void primary_all_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
 
        for (i = 0, end = 0; i < list->num; i++) {
                const uint8_t *data = list->data[i];
-               struct att_primary *primary;
+               struct gatt_primary *primary;
                bt_uuid_t uuid;
 
                start = att_get_u16(&data[0]);
@@ -188,13 +186,13 @@ static void primary_all_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
                        continue;
                }
 
-               primary = g_try_new0(struct att_primary, 1);
+               primary = g_try_new0(struct gatt_primary, 1);
                if (!primary) {
                        err = ATT_ECODE_INSUFF_RESOURCES;
                        goto done;
                }
-               primary->start = start;
-               primary->end = end;
+               primary->range.start = start;
+               primary->range.end = end;
                bt_uuid_to_string(&uuid, primary->uuid, sizeof(primary->uuid));
                dp->primaries = g_slist_append(dp->primaries, primary);
        }
@@ -274,7 +272,7 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
 
        for (i = 0; i < list->num; i++) {
                uint8_t *value = list->data[i];
-               struct att_char *chars;
+               struct gatt_char *chars;
                bt_uuid_t uuid;
 
                last = att_get_u16(value);
@@ -285,7 +283,7 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
                } else
                        uuid = att_get_uuid128(&value[5]);
 
-               chars = g_try_new0(struct att_char, 1);
+               chars = g_try_new0(struct gatt_char, 1);
                if (!chars) {
                        err = ATT_ECODE_INSUFF_RESOURCES;
                        goto done;
@@ -305,7 +303,7 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
        att_data_list_free(list);
        err = 0;
 
-       if (last != 0) {
+       if (last != 0 && (last + 1 < dc->end)) {
                buf = g_attrib_get_buffer(dc->attrib, &buflen);
 
                bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
index c5f95ac..9ffe58f 100644 (file)
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+
 #include <bluetooth/sdp.h>
 
+/* GATT Profile Attribute types */
+#define GATT_PRIM_SVC_UUID             0x2800
+#define GATT_SND_SVC_UUID              0x2801
+#define GATT_INCLUDE_UUID              0x2802
+#define GATT_CHARAC_UUID               0x2803
+
+/* GATT Characteristic Types */
+#define GATT_CHARAC_DEVICE_NAME                        0x2A00
+#define GATT_CHARAC_APPEARANCE                 0x2A01
+#define GATT_CHARAC_PERIPHERAL_PRIV_FLAG       0x2A02
+#define GATT_CHARAC_RECONNECTION_ADDRESS       0x2A03
+#define GATT_CHARAC_PERIPHERAL_PREF_CONN       0x2A04
+#define GATT_CHARAC_SERVICE_CHANGED            0x2A05
+
+/* GATT Characteristic Descriptors */
+#define GATT_CHARAC_EXT_PROPER_UUID    0x2900
+#define GATT_CHARAC_USER_DESC_UUID     0x2901
+#define GATT_CLIENT_CHARAC_CFG_UUID    0x2902
+#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
+
+/* Client Characteristic Configuration bit field */
+#define GATT_CLIENT_CHARAC_CFG_NOTIF_BIT       0x0001
+#define GATT_CLIENT_CHARAC_CFG_IND_BIT         0x0002
+
 typedef void (*gatt_cb_t) (GSList *l, guint8 status, gpointer user_data);
 
+struct gatt_primary {
+       char uuid[MAX_LEN_UUID_STR + 1];
+       struct att_range range;
+};
+
+struct gatt_char {
+       char uuid[MAX_LEN_UUID_STR + 1];
+       uint16_t handle;
+       uint8_t properties;
+       uint16_t value_handle;
+};
+
 guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
                                                        gpointer user_data);
 
index 4d901f1..00f59d7 100644 (file)
@@ -31,6 +31,7 @@
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/uuid.h>
 
+#include "log.h"
 #include "att.h"
 #include "btio.h"
 #include "gattrib.h"
@@ -45,14 +46,13 @@ struct _GAttrib {
        guint read_watch;
        guint write_watch;
        guint timeout_watch;
-       GQueue *queue;
+       GQueue *requests;
+       GQueue *responses;
        GSList *events;
        guint next_cmd_id;
-       guint next_evt_id;
        GDestroyNotify destroy;
-       GAttribDisconnectFunc disconnect;
        gpointer destroy_user_data;
-       gpointer disc_user_data;
+       gboolean stale;
 };
 
 struct command {
@@ -147,6 +147,8 @@ GAttrib *g_attrib_ref(GAttrib *attrib)
 
        g_atomic_int_inc(&attrib->refs);
 
+       DBG("%p: ref=%d", attrib, attrib->refs);
+
        return attrib;
 }
 
@@ -172,11 +174,17 @@ static void attrib_destroy(GAttrib *attrib)
        GSList *l;
        struct command *c;
 
-       while ((c = g_queue_pop_head(attrib->queue)))
+       while ((c = g_queue_pop_head(attrib->requests)))
+               command_destroy(c);
+
+       while ((c = g_queue_pop_head(attrib->responses)))
                command_destroy(c);
 
-       g_queue_free(attrib->queue);
-       attrib->queue = NULL;
+       g_queue_free(attrib->requests);
+       attrib->requests = NULL;
+
+       g_queue_free(attrib->responses);
+       attrib->responses = NULL;
 
        for (l = attrib->events; l; l = l->next)
                event_destroy(l->data);
@@ -190,10 +198,11 @@ static void attrib_destroy(GAttrib *attrib)
        if (attrib->write_watch > 0)
                g_source_remove(attrib->write_watch);
 
-       if (attrib->read_watch > 0) {
+       if (attrib->read_watch > 0)
                g_source_remove(attrib->read_watch);
+
+       if (attrib->io)
                g_io_channel_unref(attrib->io);
-       }
 
        g_free(attrib->buf);
 
@@ -205,10 +214,16 @@ static void attrib_destroy(GAttrib *attrib)
 
 void g_attrib_unref(GAttrib *attrib)
 {
+       gboolean ret;
+
        if (!attrib)
                return;
 
-       if (g_atomic_int_dec_and_test(&attrib->refs) == FALSE)
+       ret = g_atomic_int_dec_and_test(&attrib->refs);
+
+       DBG("%p: ref=%d", attrib, attrib->refs);
+
+       if (ret == FALSE)
                return;
 
        attrib_destroy(attrib);
@@ -222,18 +237,6 @@ GIOChannel *g_attrib_get_channel(GAttrib *attrib)
        return attrib->io;
 }
 
-gboolean g_attrib_set_disconnect_function(GAttrib *attrib,
-               GAttribDisconnectFunc disconnect, gpointer user_data)
-{
-       if (attrib == NULL)
-               return FALSE;
-
-       attrib->disconnect = disconnect;
-       attrib->disc_user_data = user_data;
-
-       return TRUE;
-}
-
 gboolean g_attrib_set_destroy_function(GAttrib *attrib,
                GDestroyNotify destroy, gpointer user_data)
 {
@@ -249,8 +252,29 @@ gboolean g_attrib_set_destroy_function(GAttrib *attrib,
 static gboolean disconnect_timeout(gpointer data)
 {
        struct _GAttrib *attrib = data;
+       struct command *c;
 
-       attrib_destroy(attrib);
+       g_attrib_ref(attrib);
+
+       c = g_queue_pop_head(attrib->requests);
+       if (c == NULL)
+               goto done;
+
+       if (c->func)
+               c->func(ATT_ECODE_TIMEOUT, NULL, 0, c->user_data);
+
+       command_destroy(c);
+
+       while ((c = g_queue_pop_head(attrib->requests))) {
+               if (c->func)
+                       c->func(ATT_ECODE_ABORTED, NULL, 0, c->user_data);
+               command_destroy(c);
+       }
+
+done:
+       attrib->stale = TRUE;
+
+       g_attrib_unref(attrib);
 
        return FALSE;
 }
@@ -263,25 +287,37 @@ static gboolean can_write_data(GIOChannel *io, GIOCondition cond,
        GError *gerr = NULL;
        gsize len;
        GIOStatus iostat;
+       GQueue *queue;
 
-       if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
-               if (attrib->disconnect)
-                       attrib->disconnect(attrib->disc_user_data);
+       if (attrib->stale)
+               return FALSE;
 
+       if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
                return FALSE;
-       }
 
-       cmd = g_queue_peek_head(attrib->queue);
+       queue = attrib->responses;
+       cmd = g_queue_peek_head(queue);
+       if (cmd == NULL) {
+               queue = attrib->requests;
+               cmd = g_queue_peek_head(queue);
+       }
        if (cmd == NULL)
                return FALSE;
 
+       /*
+        * Verify that we didn't already send this command. This can only
+        * happen with elementes from attrib->requests.
+        */
+       if (cmd->sent)
+               return FALSE;
+
        iostat = g_io_channel_write_chars(io, (gchar *) cmd->pdu, cmd->len,
                                                                &len, &gerr);
        if (iostat != G_IO_STATUS_NORMAL)
                return FALSE;
 
        if (cmd->expected == 0) {
-               g_queue_pop_head(attrib->queue);
+               g_queue_pop_head(queue);
                command_destroy(cmd);
 
                return TRUE;
@@ -301,14 +337,18 @@ static void destroy_sender(gpointer data)
        struct _GAttrib *attrib = data;
 
        attrib->write_watch = 0;
+       g_attrib_unref(attrib);
 }
 
 static void wake_up_sender(struct _GAttrib *attrib)
 {
-       if (attrib->write_watch == 0)
-               attrib->write_watch = g_io_add_watch_full(attrib->io,
-                       G_PRIORITY_DEFAULT, G_IO_OUT, can_write_data,
-                       attrib, destroy_sender);
+       if (attrib->write_watch > 0)
+               return;
+
+       attrib = g_attrib_ref(attrib);
+       attrib->write_watch = g_io_add_watch_full(attrib->io,
+                               G_PRIORITY_DEFAULT, G_IO_OUT,
+                               can_write_data, attrib, destroy_sender);
 }
 
 static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
@@ -319,17 +359,13 @@ static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
        uint8_t buf[512], status;
        gsize len;
        GIOStatus iostat;
-       gboolean qempty;
+       gboolean norequests, noresponses;
 
-       if (attrib->timeout_watch > 0) {
-               g_source_remove(attrib->timeout_watch);
-               attrib->timeout_watch = 0;
-       }
+       if (attrib->stale)
+               return FALSE;
 
        if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
                attrib->read_watch = 0;
-               if (attrib->disconnect)
-                       attrib->disconnect(attrib->disc_user_data);
                return FALSE;
        }
 
@@ -355,7 +391,12 @@ static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
        if (is_response(buf[0]) == FALSE)
                return TRUE;
 
-       cmd = g_queue_pop_head(attrib->queue);
+       if (attrib->timeout_watch > 0) {
+               g_source_remove(attrib->timeout_watch);
+               attrib->timeout_watch = 0;
+       }
+
+       cmd = g_queue_pop_head(attrib->requests);
        if (cmd == NULL) {
                /* Keep the watch if we have events to report */
                return attrib->events != NULL;
@@ -374,7 +415,10 @@ static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
        status = 0;
 
 done:
-       qempty = attrib->queue == NULL || g_queue_is_empty(attrib->queue);
+       norequests = attrib->requests == NULL ||
+                       g_queue_is_empty(attrib->requests);
+       noresponses = attrib->responses == NULL ||
+                       g_queue_is_empty(attrib->responses);
 
        if (cmd) {
                if (cmd->func)
@@ -383,7 +427,7 @@ done:
                command_destroy(cmd);
        }
 
-       if (!qempty)
+       if (!norequests || !noresponses)
                wake_up_sender(attrib);
 
        return TRUE;
@@ -392,33 +436,42 @@ done:
 GAttrib *g_attrib_new(GIOChannel *io)
 {
        struct _GAttrib *attrib;
-       uint16_t omtu;
+       uint16_t imtu;
+       uint16_t att_mtu;
+       uint16_t cid;
+       GError *gerr = NULL;
 
        g_io_channel_set_encoding(io, NULL, NULL);
        g_io_channel_set_buffered(io, FALSE);
 
+       bt_io_get(io, BT_IO_L2CAP, &gerr,
+                       BT_IO_OPT_IMTU, &imtu,
+                       BT_IO_OPT_CID, &cid,
+                       BT_IO_OPT_INVALID);
+
+       if (gerr) {
+               error("%s", gerr->message);
+               g_error_free(gerr);
+               return NULL;
+       }
+
        attrib = g_try_new0(struct _GAttrib, 1);
        if (attrib == NULL)
                return NULL;
 
+       att_mtu = (cid == ATT_CID) ? ATT_DEFAULT_LE_MTU : imtu;
+
+       attrib->buf = g_malloc0(att_mtu);
+       attrib->buflen = att_mtu;
+
        attrib->io = g_io_channel_ref(io);
-       attrib->queue = g_queue_new();
+       attrib->requests = g_queue_new();
+       attrib->responses = g_queue_new();
 
        attrib->read_watch = g_io_add_watch(attrib->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);
 }
 
@@ -427,6 +480,10 @@ guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode,
                        gpointer user_data, GDestroyNotify notify)
 {
        struct command *c;
+       GQueue *queue;
+
+       if (attrib->stale)
+               return 0;
 
        c = g_try_new0(struct command, 1);
        if (c == NULL)
@@ -441,15 +498,29 @@ guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode,
        c->user_data = user_data;
        c->notify = notify;
 
+       if (is_response(opcode))
+               queue = attrib->responses;
+       else
+               queue = attrib->requests;
+
        if (id) {
                c->id = id;
-               g_queue_push_head(attrib->queue, c);
+               if (!is_response(opcode))
+                       g_queue_push_head(queue, c);
+               else
+                       /* Don't re-order responses even if an ID is given */
+                       g_queue_push_tail(queue, c);
        } else {
                c->id = ++attrib->next_cmd_id;
-               g_queue_push_tail(attrib->queue, c);
+               g_queue_push_tail(queue, c);
        }
 
-       if (g_queue_get_length(attrib->queue) == 1)
+       /*
+        * If a command was added to the queue and it was empty before, wake up
+        * the sender. If the sender was already woken up by the second queue,
+        * wake_up_sender will just return.
+        */
+       if (g_queue_get_length(queue) == 1)
                wake_up_sender(attrib);
 
        return c->id;
@@ -465,38 +536,49 @@ static gint command_cmp_by_id(gconstpointer a, gconstpointer b)
 
 gboolean g_attrib_cancel(GAttrib *attrib, guint id)
 {
-       GList *l;
+       GList *l = NULL;
        struct command *cmd;
+       GQueue *queue;
 
-       if (attrib == NULL || attrib->queue == NULL)
+       if (attrib == NULL)
                return FALSE;
 
-       l = g_queue_find_custom(attrib->queue, GUINT_TO_POINTER(id),
-                                                       command_cmp_by_id);
+       queue = attrib->requests;
+       if (queue)
+               l = g_queue_find_custom(queue, GUINT_TO_POINTER(id),
+                                       command_cmp_by_id);
+       if (l == NULL) {
+               queue = attrib->responses;
+               if (!queue)
+                       return FALSE;
+               l = g_queue_find_custom(queue, GUINT_TO_POINTER(id),
+                                       command_cmp_by_id);
+       }
+
        if (l == NULL)
                return FALSE;
 
        cmd = l->data;
 
-       if (cmd == g_queue_peek_head(attrib->queue) && cmd->sent)
+       if (cmd == g_queue_peek_head(queue) && cmd->sent)
                cmd->func = NULL;
        else {
-               g_queue_remove(attrib->queue, cmd);
+               g_queue_remove(queue, cmd);
                command_destroy(cmd);
        }
 
        return TRUE;
 }
 
-gboolean g_attrib_cancel_all(GAttrib *attrib)
+static gboolean cancel_all_per_queue(GQueue *queue)
 {
        struct command *c, *head = NULL;
        gboolean first = TRUE;
 
-       if (attrib == NULL || attrib->queue == NULL)
+       if (queue == NULL)
                return FALSE;
 
-       while ((c = g_queue_pop_head(attrib->queue))) {
+       while ((c = g_queue_pop_head(queue))) {
                if (first && c->sent) {
                        /* If the command was sent ignore its callback ... */
                        c->func = NULL;
@@ -510,12 +592,25 @@ gboolean g_attrib_cancel_all(GAttrib *attrib)
 
        if (head) {
                /* ... and put it back in the queue */
-               g_queue_push_head(attrib->queue, head);
+               g_queue_push_head(queue, head);
        }
 
        return TRUE;
 }
 
+gboolean g_attrib_cancel_all(GAttrib *attrib)
+{
+       gboolean ret;
+
+       if (attrib == NULL)
+               return FALSE;
+
+       ret = cancel_all_per_queue(attrib->requests);
+       ret = cancel_all_per_queue(attrib->responses) && ret;
+
+       return ret;
+}
+
 gboolean g_attrib_set_debug(GAttrib *attrib,
                GAttribDebugFunc func, gpointer user_data)
 {
@@ -535,14 +630,6 @@ uint8_t *g_attrib_get_buffer(GAttrib *attrib, int *len)
 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);
@@ -556,6 +643,7 @@ guint g_attrib_register(GAttrib *attrib, guint8 opcode,
                                GAttribNotifyFunc func, gpointer user_data,
                                GDestroyNotify notify)
 {
+       static guint next_evt_id = 0;
        struct event *event;
 
        event = g_try_new0(struct event, 1);
@@ -566,7 +654,7 @@ guint g_attrib_register(GAttrib *attrib, guint8 opcode,
        event->func = func;
        event->user_data = user_data;
        event->notify = notify;
-       event->id = ++attrib->next_evt_id;
+       event->id = ++next_evt_id;
 
        attrib->events = g_slist_append(attrib->events, event);
 
index 47c0d60..f73b741 100644 (file)
@@ -47,9 +47,6 @@ void g_attrib_unref(GAttrib *attrib);
 
 GIOChannel *g_attrib_get_channel(GAttrib *attrib);
 
-gboolean g_attrib_set_disconnect_function(GAttrib *attrib,
-               GAttribDisconnectFunc disconnect, gpointer user_data);
-
 gboolean g_attrib_set_destroy_function(GAttrib *attrib,
                GDestroyNotify destroy, gpointer user_data);
 
index 17ee913..8a43ec1 100644 (file)
@@ -44,6 +44,7 @@
 
 static gchar *opt_src = NULL;
 static gchar *opt_dst = NULL;
+static gchar *opt_dst_type = NULL;
 static gchar *opt_value = NULL;
 static gchar *opt_sec_level = NULL;
 static bt_uuid_t *opt_uuid = NULL;
@@ -146,9 +147,9 @@ static void primary_all_cb(GSList *services, guint8 status, gpointer user_data)
        }
 
        for (l = services; l; l = l->next) {
-               struct att_primary *prim = l->data;
+               struct gatt_primary *prim = l->data;
                g_print("attr handle = 0x%04x, end grp handle = 0x%04x "
-                       "uuid: %s\n", prim->start, prim->end, prim->uuid);
+                       "uuid: %s\n", prim->range.start, prim->range.end, prim->uuid);
        }
 
 done:
@@ -201,7 +202,7 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
        }
 
        for (l = characteristics; l; l = l->next) {
-               struct att_char *chars = l->data;
+               struct gatt_char *chars = l->data;
 
                g_print("handle = 0x%04x, char properties = 0x%02x, char value "
                        "handle = 0x%04x, uuid = %s\n", chars->handle,
@@ -523,6 +524,8 @@ static GOptionEntry options[] = {
                "Specify local adapter interface", "hciX" },
        { "device", 'b', 0, G_OPTION_ARG_STRING, &opt_dst,
                "Specify remote Bluetooth address", "MAC" },
+       { "addr-type", 't', 0, G_OPTION_ARG_STRING, &opt_dst_type,
+               "Set LE address type. Default: public", "[public | random]"},
        { "mtu", 'm', 0, G_OPTION_ARG_INT, &opt_mtu,
                "Specify the MTU size", "MTU" },
        { "psm", 'p', 0, G_OPTION_ARG_INT, &opt_psm,
@@ -539,6 +542,7 @@ int main(int argc, char *argv[])
        GError *gerr = NULL;
        GIOChannel *chan;
 
+       opt_dst_type = g_strdup("public");
        opt_sec_level = g_strdup("low");
 
        context = g_option_context_new(NULL);
@@ -573,7 +577,7 @@ int main(int argc, char *argv[])
        }
 
        if (opt_interactive) {
-               interactive(opt_src, opt_dst, opt_psm);
+               interactive(opt_src, opt_dst, opt_dst_type, opt_psm);
                goto done;
        }
 
@@ -597,7 +601,7 @@ int main(int argc, char *argv[])
                goto done;
        }
 
-       chan = gatt_connect(opt_src, opt_dst, opt_sec_level,
+       chan = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
                                        opt_psm, opt_mtu, connect_cb);
        if (chan == NULL) {
                got_error = TRUE;
index 89ac282..a38339b 100644 (file)
@@ -21,8 +21,9 @@
  *
  */
 
-int interactive(const gchar *src, const gchar *dst, gboolean le);
+int interactive(const gchar *src, const gchar *dst, const gchar *dst_type,
+               gboolean le);
 GIOChannel *gatt_connect(const gchar *src, const gchar *dst,
-                       const gchar *sec_level, int psm, int mtu,
-                       BtIOConnect connect_cb);
+                       const gchar *dst_type, const gchar *sec_level,
+                       int psm, int mtu, BtIOConnect connect_cb);
 size_t gatt_attr_data_from_string(const char *str, uint8_t **data);
index a772362..0a01cdf 100644 (file)
@@ -44,6 +44,7 @@ static GString *prompt;
 
 static gchar *opt_src = NULL;
 static gchar *opt_dst = NULL;
+static gchar *opt_dst_type = NULL;
 static gchar *opt_sec_level = NULL;
 static int opt_psm = 0;
 static int opt_mtu = 0;
@@ -149,6 +150,22 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
        set_state(STATE_CONNECTED);
 }
 
+static void disconnect_io()
+{
+       if (conn_state == STATE_DISCONNECTED)
+               return;
+
+       g_attrib_unref(attrib);
+       attrib = NULL;
+       opt_mtu = 0;
+
+       g_io_channel_shutdown(iochannel, FALSE, NULL);
+       g_io_channel_unref(iochannel);
+       iochannel = NULL;
+
+       set_state(STATE_DISCONNECTED);
+}
+
 static void primary_all_cb(GSList *services, guint8 status, gpointer user_data)
 {
        GSList *l;
@@ -161,9 +178,9 @@ static void primary_all_cb(GSList *services, guint8 status, gpointer user_data)
 
        printf("\n");
        for (l = services; l; l = l->next) {
-               struct att_primary *prim = l->data;
+               struct gatt_primary *prim = l->data;
                printf("attr handle: 0x%04x, end grp handle: 0x%04x "
-                       "uuid: %s\n", prim->start, prim->end, prim->uuid);
+                       "uuid: %s\n", prim->range.start, prim->range.end, prim->uuid);
        }
 
        rl_forced_update_display();
@@ -202,7 +219,7 @@ static void char_cb(GSList *characteristics, guint8 status, gpointer user_data)
 
        printf("\n");
        for (l = characteristics; l; l = l->next) {
-               struct att_char *chars = l->data;
+               struct gatt_char *chars = l->data;
 
                printf("handle: 0x%04x, char properties: 0x%02x, char value "
                                "handle: 0x%04x, uuid: %s\n", chars->handle,
@@ -327,6 +344,14 @@ static void cmd_exit(int argcp, char **argvp)
        g_main_loop_quit(event_loop);
 }
 
+static gboolean channel_watcher(GIOChannel *chan, GIOCondition cond,
+                               gpointer user_data)
+{
+       disconnect_io();
+
+       return FALSE;
+}
+
 static void cmd_connect(int argcp, char **argvp)
 {
        if (conn_state != STATE_DISCONNECTED)
@@ -335,6 +360,12 @@ static void cmd_connect(int argcp, char **argvp)
        if (argcp > 1) {
                g_free(opt_dst);
                opt_dst = g_strdup(argvp[1]);
+
+               g_free(opt_dst_type);
+               if (argcp > 2)
+                       opt_dst_type = g_strdup(argvp[2]);
+               else
+                       opt_dst_type = g_strdup("public");
        }
 
        if (opt_dst == NULL) {
@@ -343,26 +374,17 @@ static void cmd_connect(int argcp, char **argvp)
        }
 
        set_state(STATE_CONNECTING);
-       iochannel = gatt_connect(opt_src, opt_dst, opt_sec_level, opt_psm,
-                                               opt_mtu, connect_cb);
+       iochannel = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
+                                               opt_psm, opt_mtu, connect_cb);
        if (iochannel == NULL)
                set_state(STATE_DISCONNECTED);
+       else
+               g_io_add_watch(iochannel, G_IO_HUP, channel_watcher, NULL);
 }
 
 static void cmd_disconnect(int argcp, char **argvp)
 {
-       if (conn_state == STATE_DISCONNECTED)
-               return;
-
-       g_attrib_unref(attrib);
-       attrib = NULL;
-       opt_mtu = 0;
-
-       g_io_channel_shutdown(iochannel, FALSE, NULL);
-       g_io_channel_unref(iochannel);
-       iochannel = NULL;
-
-       set_state(STATE_DISCONNECTED);
+       disconnect_io();
 }
 
 static void cmd_primary(int argcp, char **argvp)
@@ -586,8 +608,8 @@ static void cmd_char_write(int argcp, char **argvp)
                return;
        }
 
-       handle = strtoll(argvp[1], NULL, 16);
-       if (errno != 0 || handle <= 0) {
+       handle = strtohandle(argvp[1]);
+       if (handle <= 0) {
                printf("A valid handle is required\n");
                return;
        }
@@ -720,7 +742,7 @@ static struct {
                "Exit interactive mode" },
        { "quit",               cmd_exit,       "",
                "Exit interactive mode" },
-       { "connect",            cmd_connect,    "[address]",
+       { "connect",            cmd_connect,    "[address [address type]]",
                "Connect to a remote device" },
        { "disconnect",         cmd_disconnect, "",
                "Disconnect from a remote device" },
@@ -800,7 +822,35 @@ static gboolean prompt_read(GIOChannel *chan, GIOCondition cond,
        return TRUE;
 }
 
-int interactive(const gchar *src, const gchar *dst, int psm)
+static char *completion_generator(const char *text, int state)
+{
+       static int index = 0, len = 0;
+       const char *cmd = NULL;
+
+       if (state == 0) {
+               index = 0;
+               len = strlen(text);
+       }
+
+       while ((cmd = commands[index].cmd) != NULL) {
+               index++;
+               if (strncmp(cmd, text, len) == 0)
+                       return strdup(cmd);
+       }
+
+       return NULL;
+}
+
+static char **commands_completion(const char *text, int start, int end)
+{
+       if (start == 0)
+               return rl_completion_matches(text, &completion_generator);
+       else
+               return NULL;
+}
+
+int interactive(const gchar *src, const gchar *dst,
+               const gchar *dst_type, int psm)
 {
        GIOChannel *pchan;
        gint events;
@@ -809,6 +859,7 @@ int interactive(const gchar *src, const gchar *dst, int psm)
 
        opt_src = g_strdup(src);
        opt_dst = g_strdup(dst);
+       opt_dst_type = g_strdup(dst_type);
        opt_psm = psm;
 
        prompt = g_string_new(NULL);
@@ -820,6 +871,7 @@ int interactive(const gchar *src, const gchar *dst, int psm)
        events = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
        g_io_add_watch(pchan, events, prompt_read, NULL);
 
+       rl_attempted_completion_function = commands_completion;
        rl_callback_handler_install(get_prompt(), parse_line);
 
        g_main_loop_run(event_loop);
index 22d23a4..d856fe2 100644 (file)
 #include "btio.h"
 #include "gatttool.h"
 
-/* Minimum MTU for ATT connections */
-#define ATT_MIN_MTU_LE         23
-#define ATT_MIN_MTU_L2CAP      48
-
 GIOChannel *gatt_connect(const gchar *src, const gchar *dst,
-                               const gchar *sec_level, int psm, int mtu,
-                               BtIOConnect connect_cb)
+                               const gchar *dst_type, const gchar *sec_level,
+                               int psm, int mtu, BtIOConnect connect_cb)
 {
        GIOChannel *chan;
        bdaddr_t sba, dba;
+       uint8_t dest_type;
        GError *err = NULL;
        BtIOSecLevel sec;
-       int minimum_mtu;
-
-       /* This check is required because currently setsockopt() returns no
-        * errors for MTU values smaller than the allowed minimum. */
-       minimum_mtu = psm ? ATT_MIN_MTU_L2CAP : ATT_MIN_MTU_LE;
-       if (mtu != 0 && mtu < minimum_mtu) {
-               g_printerr("MTU cannot be smaller than %d\n", minimum_mtu);
-               return NULL;
-       }
 
        /* Remote device */
        if (dst == NULL) {
@@ -74,6 +62,12 @@ GIOChannel *gatt_connect(const gchar *src, const gchar *dst,
        } else
                bacpy(&sba, BDADDR_ANY);
 
+       /* Not used for BR/EDR */
+       if (strcmp(dst_type, "random") == 0)
+               dest_type = BDADDR_LE_RANDOM;
+       else
+               dest_type = BDADDR_LE_PUBLIC;
+
        if (strcmp(sec_level, "medium") == 0)
                sec = BT_IO_SEC_MEDIUM;
        else if (strcmp(sec_level, "high") == 0)
@@ -85,8 +79,8 @@ 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_DEST_TYPE, dest_type,
                                BT_IO_OPT_CID, ATT_CID,
-                               BT_IO_OPT_OMTU, mtu,
                                BT_IO_OPT_SEC_LEVEL, sec,
                                BT_IO_OPT_INVALID);
        else
@@ -94,7 +88,7 @@ GIOChannel *gatt_connect(const gchar *src, const gchar *dst,
                                BT_IO_OPT_SOURCE_BDADDR, &sba,
                                BT_IO_OPT_DEST_BDADDR, &dba,
                                BT_IO_OPT_PSM, psm,
-                               BT_IO_OPT_OMTU, mtu,
+                               BT_IO_OPT_IMTU, mtu,
                                BT_IO_OPT_SEC_LEVEL, sec,
                                BT_IO_OPT_INVALID);
 
index cd6d327..404be53 100644 (file)
@@ -37,7 +37,6 @@
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
-#include "glib-compat.h"
 #include "log.h"
 #include "device.h"
 #include "manager.h"
@@ -884,11 +883,22 @@ static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep,
                                void *user_data)
 {
        struct a2dp_sep *a2dp_sep = user_data;
+       struct a2dp_setup *setup;
 
        if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
                DBG("Sink %p: Open_Ind", sep);
        else
                DBG("Source %p: Open_Ind", sep);
+
+       setup = find_setup_by_session(session);
+       if (!setup)
+               return TRUE;
+
+       if (setup->reconfigure)
+               setup->reconfigure = FALSE;
+
+       finalize_config(setup);
+
        return TRUE;
 }
 
@@ -944,10 +954,6 @@ static gboolean start_ind(struct avdtp *session, struct avdtp_local_sep *sep,
        else
                DBG("Source %p: Start_Ind", sep);
 
-       setup = find_setup_by_session(session);
-       if (setup)
-               finalize_resume(setup);
-
        if (!a2dp_sep->locked) {
                a2dp_sep->session = avdtp_ref(session);
                a2dp_sep->suspend_timer = g_timeout_add_seconds(SUSPEND_TIMEOUT,
@@ -955,6 +961,15 @@ static gboolean start_ind(struct avdtp *session, struct avdtp_local_sep *sep,
                                                a2dp_sep);
        }
 
+       if (!a2dp_sep->starting)
+               return TRUE;
+
+       a2dp_sep->starting = FALSE;
+
+       setup = find_setup_by_session(session);
+       if (setup)
+               finalize_resume(setup);
+
        return TRUE;
 }
 
@@ -970,6 +985,8 @@ static void start_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
        else
                DBG("Source %p: Start_Cfm", sep);
 
+       a2dp_sep->starting = FALSE;
+
        setup = find_setup_by_session(session);
        if (!setup)
                return;
@@ -987,6 +1004,9 @@ static gboolean suspend_ind(struct avdtp *session, struct avdtp_local_sep *sep,
                                void *user_data)
 {
        struct a2dp_sep *a2dp_sep = user_data;
+       struct a2dp_setup *setup;
+       gboolean start;
+       int start_err;
 
        if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
                DBG("Sink %p: Suspend_Ind", sep);
@@ -1000,6 +1020,30 @@ static gboolean suspend_ind(struct avdtp *session, struct avdtp_local_sep *sep,
                a2dp_sep->session = NULL;
        }
 
+       if (!a2dp_sep->suspending)
+               return TRUE;
+
+       a2dp_sep->suspending = FALSE;
+
+       setup = find_setup_by_session(session);
+       if (!setup)
+               return TRUE;
+
+       start = setup->start;
+       setup->start = FALSE;
+
+       finalize_suspend(setup);
+
+       if (!start)
+               return TRUE;
+
+       start_err = avdtp_start(session, a2dp_sep->stream);
+       if (start_err < 0 && start_err != -EINPROGRESS) {
+               error("avdtp_start: %s (%d)", strerror(-start_err),
+                                                               -start_err);
+               finalize_setup_errno(setup, start_err, finalize_resume);
+       }
+
        return TRUE;
 }
 
@@ -1010,7 +1054,7 @@ static void suspend_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
        struct a2dp_sep *a2dp_sep = user_data;
        struct a2dp_setup *setup;
        gboolean start;
-       int perr;
+       int start_err;
 
        if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
                DBG("Sink %p: Suspend_Cfm", sep);
@@ -1041,10 +1085,11 @@ static void suspend_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
                return;
        }
 
-       perr = avdtp_start(session, a2dp_sep->stream);
-       if (perr < 0) {
-               error("Error on avdtp_start %s (%d)", strerror(-perr), -perr);
-               finalize_setup_errno(setup, -EIO, finalize_suspend, NULL);
+       start_err = avdtp_start(session, a2dp_sep->stream);
+       if (start_err < 0 && start_err != -EINPROGRESS) {
+               error("avdtp_start: %s (%d)", strerror(-start_err),
+                                                               -start_err);
+               finalize_setup_errno(setup, start_err, finalize_suspend, NULL);
        }
 }
 
@@ -1132,11 +1177,12 @@ static void close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
                g_timeout_add(RECONFIGURE_TIMEOUT, a2dp_reconfigure, setup);
 }
 
-static gboolean abort_ind(struct avdtp *session, struct avdtp_local_sep *sep,
+static void abort_ind(struct avdtp *session, struct avdtp_local_sep *sep,
                                struct avdtp_stream *stream, uint8_t *err,
                                void *user_data)
 {
        struct a2dp_sep *a2dp_sep = user_data;
+       struct a2dp_setup *setup;
 
        if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
                DBG("Sink %p: Abort_Ind", sep);
@@ -1145,7 +1191,15 @@ static gboolean abort_ind(struct avdtp *session, struct avdtp_local_sep *sep,
 
        a2dp_sep->stream = NULL;
 
-       return TRUE;
+       setup = find_setup_by_session(session);
+       if (!setup)
+               return;
+
+       finalize_setup_errno(setup, -ECONNRESET, finalize_suspend,
+                                                       finalize_resume,
+                                                       finalize_config);
+
+       return;
 }
 
 static void abort_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
@@ -1388,9 +1442,9 @@ static struct a2dp_server *find_server(GSList *list, const bdaddr_t *src)
 
 int a2dp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config)
 {
-       int sbc_srcs = 1, sbc_sinks = 1;
+       int sbc_srcs = 0, sbc_sinks = 0;
        int mpeg12_srcs = 0, mpeg12_sinks = 0;
-       gboolean source = TRUE, sink = FALSE, socket = TRUE;
+       gboolean source = TRUE, sink = FALSE, socket = FALSE;
        gboolean delay_reporting = FALSE;
        char *str;
        GError *err = NULL;
@@ -1410,6 +1464,8 @@ int a2dp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config)
                        source = TRUE;
                if (strstr(str, "Source"))
                        sink = TRUE;
+               if (strstr(str, "Socket"))
+                       socket = TRUE;
                g_free(str);
        }
 
@@ -1429,18 +1485,14 @@ int a2dp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config)
        }
 
        /* Don't register any local sep if Socket is disabled */
-       if (socket == FALSE) {
-               sbc_srcs = 0;
-               sbc_sinks = 0;
-               mpeg12_srcs = 0;
-               mpeg12_sinks = 0;
+       if (socket == FALSE)
                goto proceed;
-       }
 
        str = g_key_file_get_string(config, "A2DP", "SBCSources", &err);
        if (err) {
                DBG("audio.conf: %s", err->message);
                g_clear_error(&err);
+               sbc_srcs = 1;
        } else {
                sbc_srcs = atoi(str);
                g_free(str);
@@ -1459,6 +1511,7 @@ int a2dp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config)
        if (err) {
                DBG("audio.conf: %s", err->message);
                g_clear_error(&err);
+               sbc_sinks = 1;
        } else {
                sbc_sinks = atoi(str);
                g_free(str);
@@ -1590,7 +1643,7 @@ struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
        server = find_server(servers, src);
        if (server == NULL) {
                if (err)
-                       *err = -EINVAL;
+                       *err = -EPROTONOSUPPORT;
                return NULL;
        }
 
@@ -1753,11 +1806,7 @@ static uint8_t default_bitpool(uint8_t freq, uint8_t mode)
                        return 31;
                case SBC_CHANNEL_MODE_STEREO:
                case SBC_CHANNEL_MODE_JOINT_STEREO:
-#ifdef USE_SBC_ORIGINAL_BITPOOL
                        return 53;
-#else
-                       return 32;
-#endif
                default:
                        error("Invalid channel mode %u", mode);
                        return 53;
@@ -2184,6 +2233,7 @@ unsigned int a2dp_resume(struct avdtp *session, struct a2dp_sep *sep,
                        error("avdtp_start failed");
                        goto failed;
                }
+               sep->starting = TRUE;
                break;
        case AVDTP_STATE_STREAMING:
                if (!sep->suspending && sep->suspend_timer) {
index 55e5d0d..d955f79 100644 (file)
@@ -9,10 +9,10 @@
 
 # If we want to disable support for specific services
 # Defaults to supporting all implemented services
-#Disable=Control,Source
+#Disable=Gateway,Source,Socket
 
 #ifdef __TIZEN_PATCH__
-Enable=Socket
+Disable=Socket
 #endif
 
 # SCO routing. Either PCM or HCI (in which case audio is routed to/from ALSA)
@@ -41,18 +41,13 @@ HFP=true
 MaxConnected=1
 
 # Set to true to enable use of fast connectable mode (faster page scanning)
-# for HFP when incomming call starts. Default settings are restored after
+# for HFP when incoming call starts. Default settings are restored after
 # call is answered or rejected. Page scan interval is much shorter and page
 # scan type changed to interlaced. Such allows faster connection initiated
 # by a headset.
 FastConnectable=false
 
 # Just an example of potential config options for the other interfaces
-#ifdef __TIZEN_PATCH__
-[A2DP]
-SBCSources=1
-#else
 #[A2DP]
 #SBCSources=1
 #MPEG12Sources=0
-#endif
index 5bd5db1..ae3c04e 100644 (file)
@@ -40,6 +40,7 @@
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
+#include <bluetooth/uuid.h>
 
 #include <glib.h>
 
@@ -53,6 +54,7 @@
 #include "manager.h"
 #include "device.h"
 #include "avctp.h"
+#include "avrcp.h"
 
 #define QUIRK_NO_RELEASE 1 << 0
 
@@ -120,6 +122,12 @@ struct avctp_server {
        GSList *sessions;
 };
 
+struct avctp_rsp_handler {
+       uint8_t id;
+       avctp_rsp_cb func;
+       void *user_data;
+};
+
 struct avctp {
        struct avctp_server *server;
        bdaddr_t dst;
@@ -134,6 +142,7 @@ struct avctp {
        uint16_t mtu;
 
        uint8_t key_quirks[256];
+       GSList *handlers;
 };
 
 struct avctp_pdu_handler {
@@ -161,6 +170,7 @@ static struct {
 static GSList *callbacks = NULL;
 static GSList *servers = NULL;
 static GSList *handlers = NULL;
+static uint8_t id = 0;
 
 static void auth_cb(DBusError *derr, void *user_data);
 
@@ -235,9 +245,12 @@ static size_t handle_panel_passthrough(struct avctp *session,
                break;
        }
 
-       if (key_map[i].name == NULL)
+       if (key_map[i].name == NULL) {
                DBG("AV/C: unknown button 0x%02X %s",
                                                operands[0] & 0x7F, status);
+               *code = AVC_CTYPE_NOT_IMPLEMENTED;
+               return 0;
+       }
 
 done:
        *code = AVC_CTYPE_ACCEPTED;
@@ -267,7 +280,7 @@ static size_t handle_unit_info(struct avctp *session,
 
        DBG("reply to AVC_OP_UNITINFO");
 
-       return 0;
+       return operand_count;
 }
 
 static size_t handle_subunit_info(struct avctp *session,
@@ -291,7 +304,7 @@ static size_t handle_subunit_info(struct avctp *session,
 
        DBG("reply to AVC_OP_SUBUNITINFO");
 
-       return 0;
+       return operand_count;
 }
 
 static struct avctp_pdu_handler *find_handler(GSList *list, uint8_t opcode)
@@ -308,7 +321,7 @@ static struct avctp_pdu_handler *find_handler(GSList *list, uint8_t opcode)
 
 static void avctp_disconnected(struct avctp *session)
 {
-       struct avctp_server *server = session->server;
+       struct avctp_server *server;
 
        if (!session)
                return;
@@ -344,7 +357,9 @@ static void avctp_disconnected(struct avctp *session)
                session->uinput = -1;
        }
 
+       server = session->server;
        server->sessions = g_slist_remove(server->sessions, session);
+       g_slist_free_full(session->handlers, g_free);
        g_free(session);
 }
 
@@ -392,6 +407,31 @@ static void avctp_set_state(struct avctp *session, avctp_state_t new_state)
        }
 }
 
+static void handle_response(struct avctp *session, struct avctp_header *avctp,
+                               struct avc_header *avc, uint8_t *operands,
+                               size_t operand_count)
+{
+       GSList *l;
+
+       for (l = session->handlers; l; l = l->next) {
+               struct avctp_rsp_handler *handler = l->data;
+
+               if (handler->id != avctp->transaction)
+                       continue;
+
+               if (handler->func && handler->func(session, avc->code,
+                                               avc->subunit_type,
+                                               operands, operand_count,
+                                               handler->user_data))
+                       return;
+
+               session->handlers = g_slist_remove(session->handlers, handler);
+               g_free(handler);
+
+               return;
+       }
+}
+
 static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
                                gpointer data)
 {
@@ -444,8 +484,10 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
                        avc->code, avc->subunit_type, avc->subunit_id,
                        avc->opcode, operand_count);
 
-       if (avctp->cr == AVCTP_RESPONSE)
+       if (avctp->cr == AVCTP_RESPONSE) {
+               handle_response(session, avctp, avc, operands, operand_count);
                return TRUE;
+       }
 
        packet_size = AVCTP_HEADER_LENGTH + AVC_HEADER_LENGTH;
        avctp->cr = AVCTP_RESPONSE;
@@ -464,7 +506,8 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
        handler = find_handler(handlers, avc->opcode);
        if (!handler) {
                DBG("handler not found for 0x%02x", avc->opcode);
-               avc->code = AVC_CTYPE_REJECTED;
+               packet_size += avrcp_handle_vendor_reject(&code, operands);
+               avc->code = code;
                goto done;
        }
 
@@ -851,14 +894,13 @@ int avctp_send_passthrough(struct avctp *session, uint8_t op)
        struct avc_header *avc = (void *) &buf[AVCTP_HEADER_LENGTH];
        uint8_t *operands = &buf[AVCTP_HEADER_LENGTH + AVC_HEADER_LENGTH];
        int sk;
-       static uint8_t transaction = 0;
 
        if (session->state != AVCTP_STATE_CONNECTED)
                return -ENOTCONN;
 
        memset(buf, 0, sizeof(buf));
 
-       avctp->transaction = transaction++;
+       avctp->transaction = id++;
        avctp->packet_type = AVCTP_PACKET_SINGLE;
        avctp->cr = AVCTP_COMMAND;
        avctp->pid = htons(AV_REMOTE_SVCLASS_ID);
@@ -876,7 +918,7 @@ int avctp_send_passthrough(struct avctp *session, uint8_t op)
                return -errno;
 
        /* Button release */
-       avctp->transaction = transaction++;
+       avctp->transaction = id++;
        operands[0] |= 0x80;
 
        if (write(sk, buf, sizeof(buf)) < 0)
@@ -885,8 +927,8 @@ int avctp_send_passthrough(struct avctp *session, uint8_t op)
        return 0;
 }
 
-int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
-                               uint8_t code, uint8_t subunit,
+static int avctp_send(struct avctp *session, uint8_t transaction, uint8_t cr,
+                               uint8_t code, uint8_t subunit, uint8_t opcode,
                                uint8_t *operands, size_t operand_count)
 {
        uint8_t *buf;
@@ -909,12 +951,12 @@ int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
 
        avctp->transaction = transaction;
        avctp->packet_type = AVCTP_PACKET_SINGLE;
-       avctp->cr = AVCTP_RESPONSE;
+       avctp->cr = cr;
        avctp->pid = htons(AV_REMOTE_SVCLASS_ID);
 
        avc->code = code;
        avc->subunit_type = subunit;
-       avc->opcode = AVC_OP_VENDORDEP;
+       avc->opcode = opcode;
 
        memcpy(pdu, operands, operand_count);
 
@@ -925,6 +967,39 @@ int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
        return err;
 }
 
+int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
+                               uint8_t code, uint8_t subunit,
+                               uint8_t *operands, size_t operand_count)
+{
+       return avctp_send(session, transaction, AVCTP_RESPONSE, code, subunit,
+                                       AVC_OP_VENDORDEP, operands, operand_count);
+}
+
+int avctp_send_vendordep_req(struct avctp *session, uint8_t code,
+                                       uint8_t subunit, uint8_t *operands,
+                                       size_t operand_count,
+                                       avctp_rsp_cb func, void *user_data)
+{
+       struct avctp_rsp_handler *handler;
+       int err;
+
+       err = avctp_send(session, id, AVCTP_COMMAND, code, subunit,
+                               AVC_OP_VENDORDEP, operands, operand_count);
+       if (err < 0)
+               return err;
+
+       handler = g_new0(struct avctp_rsp_handler, 1);
+       handler->id = id;
+       handler->func = func;
+       handler->user_data = user_data;
+
+       session->handlers = g_slist_prepend(session->handlers, handler);
+
+       id++;
+
+       return 0;
+}
+
 unsigned int avctp_add_state_cb(avctp_state_cb cb, void *user_data)
 {
        struct avctp_state_callback *state_cb;
index 9727485..d0cbd97 100644 (file)
@@ -78,6 +78,9 @@ typedef size_t (*avctp_pdu_cb) (struct avctp *session, uint8_t transaction,
                                        uint8_t *code, uint8_t *subunit,
                                        uint8_t *operands, size_t operand_count,
                                        void *user_data);
+typedef gboolean (*avctp_rsp_cb) (struct avctp *session, uint8_t code,
+                                       uint8_t subunit, uint8_t *operands,
+                                       size_t operand_count, void *user_data);
 
 unsigned int avctp_add_state_cb(avctp_state_cb cb, void *user_data);
 gboolean avctp_remove_state_cb(unsigned int id);
@@ -97,3 +100,7 @@ int avctp_send_passthrough(struct avctp *session, uint8_t op);
 int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
                                uint8_t code, uint8_t subunit,
                                uint8_t *operands, size_t operand_count);
+int avctp_send_vendordep_req(struct avctp *session, uint8_t code,
+                                       uint8_t subunit, uint8_t *operands,
+                                       size_t operand_count,
+                                       avctp_rsp_cb func, void *user_data);
index 5b7ba90..004cd0f 100644 (file)
@@ -38,6 +38,7 @@
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
@@ -52,7 +53,6 @@
 #include "manager.h"
 #include "control.h"
 #include "avdtp.h"
-#include "glib-compat.h"
 #include "btio.h"
 #include "sink.h"
 #include "source.h"
@@ -94,7 +94,6 @@
 #else
 #define REQ_TIMEOUT 6
 #endif
-
 #define ABORT_TIMEOUT 2
 #define DISCONNECT_TIMEOUT 1
 #define STREAM_TIMEOUT 20
@@ -319,6 +318,7 @@ struct pending_req {
        size_t data_size;
        struct avdtp_stream *stream; /* Set if the request targeted a stream */
        guint timeout;
+       gboolean collided;
 };
 
 struct avdtp_remote_sep {
@@ -1072,12 +1072,19 @@ static void avdtp_sep_set_state(struct avdtp *session,
                break;
        case AVDTP_STATE_OPEN:
                stream->starting = FALSE;
-               if (old_state > AVDTP_STATE_OPEN && session->auto_dc)
+               if ((old_state > AVDTP_STATE_OPEN && session->auto_dc) ||
+                                                       stream->open_acp)
                        stream->idle_timer = g_timeout_add_seconds(STREAM_TIMEOUT,
                                                                stream_timeout,
                                                                stream);
                break;
        case AVDTP_STATE_STREAMING:
+               if (stream->idle_timer) {
+                       g_source_remove(stream->idle_timer);
+                       stream->idle_timer = 0;
+               }
+               stream->open_acp = FALSE;
+               break;
        case AVDTP_STATE_CLOSING:
        case AVDTP_STATE_ABORTING:
                if (stream->idle_timer) {
@@ -1525,7 +1532,7 @@ static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction,
        case AVDTP_SEP_TYPE_SINK:
                if (!dev->source) {
                        btd_device_add_uuid(dev->btd_dev, A2DP_SOURCE_UUID);
-                       if (!dev->sink) {
+                       if (!dev->source) {
                                error("Unable to get a audio source object");
                                err = AVDTP_BAD_STATE;
                                goto failed;
@@ -1639,7 +1646,76 @@ failed:
 static gboolean avdtp_reconf_cmd(struct avdtp *session, uint8_t transaction,
                                        struct seid_req *req, int size)
 {
-       return avdtp_unknown_cmd(session, transaction, AVDTP_RECONFIGURE);
+       struct conf_rej rej;
+
+       rej.error = AVDTP_NOT_SUPPORTED_COMMAND;
+       rej.category = 0x00;
+
+       return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
+                                       AVDTP_RECONFIGURE, &rej, sizeof(rej));
+}
+
+static void check_seid_collision(struct pending_req *req, uint8_t id)
+{
+       struct seid_req *seid = req->data;
+
+       if (seid->acp_seid == id)
+               req->collided = TRUE;
+}
+
+static void check_start_collision(struct pending_req *req, uint8_t id)
+{
+       struct start_req *start = req->data;
+       struct seid *seid = &start->first_seid;
+       int count = 1 + req->data_size - sizeof(struct start_req);
+       int i;
+
+       for (i = 0; i < count; i++, seid++) {
+               if (seid->seid == id) {
+                       req->collided = TRUE;
+                       return;
+               }
+       }
+}
+
+static void check_suspend_collision(struct pending_req *req, uint8_t id)
+{
+       struct suspend_req *suspend = req->data;
+       struct seid *seid = &suspend->first_seid;
+       int count = 1 + req->data_size - sizeof(struct suspend_req);
+       int i;
+
+       for (i = 0; i < count; i++, seid++) {
+               if (seid->seid == id) {
+                       req->collided = TRUE;
+                       return;
+               }
+       }
+}
+
+static void avdtp_check_collision(struct avdtp *session, uint8_t cmd,
+                                       struct avdtp_stream *stream)
+{
+       struct pending_req *req = session->req;
+
+       if (req == NULL || (req->signal_id != cmd && cmd != AVDTP_ABORT))
+               return;
+
+       if (cmd == AVDTP_ABORT)
+               cmd = req->signal_id;
+
+       switch (cmd) {
+       case AVDTP_OPEN:
+       case AVDTP_CLOSE:
+               check_seid_collision(req, stream->rseid);
+               break;
+       case AVDTP_START:
+               check_start_collision(req, stream->rseid);
+               break;
+       case AVDTP_SUSPEND:
+               check_suspend_collision(req, stream->rseid);
+               break;
+       }
 }
 
 static gboolean avdtp_open_cmd(struct avdtp *session, uint8_t transaction,
@@ -1673,6 +1749,8 @@ static gboolean avdtp_open_cmd(struct avdtp *session, uint8_t transaction,
                        goto failed;
        }
 
+       avdtp_check_collision(session, AVDTP_OPEN, stream);
+
        if (!avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
                                                AVDTP_OPEN, NULL, 0))
                return FALSE;
@@ -1721,9 +1799,8 @@ static gboolean avdtp_start_cmd(struct avdtp *session, uint8_t transaction,
 
                stream = sep->stream;
 
-               /* Also reject start cmd if we already initiated start */
-               if (sep->state != AVDTP_STATE_OPEN ||
-                                               stream->starting == TRUE) {
+               /* Also reject start cmd if state is not open */
+               if (sep->state != AVDTP_STATE_OPEN) {
                        err = AVDTP_BAD_STATE;
                        goto failed;
                }
@@ -1735,6 +1812,8 @@ static gboolean avdtp_start_cmd(struct avdtp *session, uint8_t transaction,
                                goto failed;
                }
 
+               avdtp_check_collision(session, AVDTP_START, stream);
+
                avdtp_sep_set_state(session, sep, AVDTP_STATE_STREAMING);
        }
 
@@ -1782,6 +1861,8 @@ static gboolean avdtp_close_cmd(struct avdtp *session, uint8_t transaction,
                        goto failed;
        }
 
+       avdtp_check_collision(session, AVDTP_CLOSE, stream);
+
        avdtp_sep_set_state(session, sep, AVDTP_STATE_CLOSING);
 
        if (!avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
@@ -1841,6 +1922,8 @@ static gboolean avdtp_suspend_cmd(struct avdtp *session, uint8_t transaction,
                                goto failed;
                }
 
+               avdtp_check_collision(session, AVDTP_SUSPEND, stream);
+
                avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN);
        }
 
@@ -1868,16 +1951,14 @@ static gboolean avdtp_abort_cmd(struct avdtp *session, uint8_t transaction,
        }
 
        sep = find_local_sep_by_seid(session->server, req->acp_seid);
-       if (!sep || !sep->stream) {
-               err = AVDTP_BAD_ACP_SEID;
-               goto failed;
-       }
+       if (!sep || !sep->stream)
+               return TRUE;
 
-       if (sep->ind && sep->ind->abort) {
-               if (!sep->ind->abort(session, sep, sep->stream, &err,
-                                       sep->user_data))
-                       goto failed;
-       }
+       if (sep->ind && sep->ind->abort)
+               sep->ind->abort(session, sep, sep->stream, &err,
+                                                       sep->user_data);
+
+       avdtp_check_collision(session, AVDTP_ABORT, sep->stream);
 
        ret = avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT,
                                                AVDTP_ABORT, NULL, 0);
@@ -1885,10 +1966,6 @@ static gboolean avdtp_abort_cmd(struct avdtp *session, uint8_t transaction,
                avdtp_sep_set_state(session, sep, AVDTP_STATE_ABORTING);
 
        return ret;
-
-failed:
-       return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT,
-                                       AVDTP_ABORT, &err, sizeof(err));
 }
 
 static gboolean avdtp_secctl_cmd(struct avdtp *session, uint8_t transaction,
@@ -2171,6 +2248,11 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
                if (session->streams && session->dc_timer)
                        remove_disconnect_timer(session);
 
+               if (session->req && session->req->collided) {
+                       DBG("Collision detected");
+                       goto next;
+               }
+
                return TRUE;
        }
 
@@ -2221,6 +2303,7 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
                break;
        }
 
+next:
        pending_req_free(session->req);
        session->req = NULL;
 
@@ -2530,6 +2613,7 @@ static GIOChannel *l2cap_connect(struct avdtp *session)
                                BT_IO_OPT_SOURCE_BDADDR, &session->server->src,
                                BT_IO_OPT_DEST_BDADDR, &session->dst,
                                BT_IO_OPT_PSM, AVDTP_PSM,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
                                BT_IO_OPT_INVALID);
        if (!io) {
                error("%s", err->message);
@@ -3578,6 +3662,15 @@ int avdtp_start(struct avdtp *session, struct avdtp_stream *stream)
        if (stream->lsep->state != AVDTP_STATE_OPEN)
                return -EINVAL;
 
+       /* Recommendation 12:
+        *  If the RD has configured and opened a stream it is also responsible
+        *  to start the streaming via GAVDP_START.
+        */
+       if (stream->open_acp) {
+               stream->starting = TRUE;
+               return 0;
+       }
+
        if (stream->close_int == TRUE) {
                error("avdtp_start: rejecting start since close is initiated");
                return -EINVAL;
@@ -3585,7 +3678,7 @@ int avdtp_start(struct avdtp *session, struct avdtp_stream *stream)
 
        if (stream->starting == TRUE) {
                DBG("stream already started");
-               return -EINVAL;
+               return -EINPROGRESS;
        }
 
        memset(&req, 0, sizeof(req));
index 5f37dc3..dac093b 100644 (file)
@@ -198,7 +198,7 @@ struct avdtp_sep_ind {
        gboolean (*close) (struct avdtp *session, struct avdtp_local_sep *sep,
                                struct avdtp_stream *stream, uint8_t *err,
                                void *user_data);
-       gboolean (*abort) (struct avdtp *session, struct avdtp_local_sep *sep,
+       void (*abort) (struct avdtp *session, struct avdtp_local_sep *sep,
                                struct avdtp_stream *stream, uint8_t *err,
                                void *user_data);
        gboolean (*reconfigure) (struct avdtp *session,
index c9ec314..0af69bf 100644 (file)
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
 #include <gdbus.h>
 
+#include "../src/adapter.h"
+#include "../src/device.h"
+
 #include "log.h"
 #include "error.h"
 #include "device.h"
@@ -52,7 +56,6 @@
 #include "avctp.h"
 #include "avrcp.h"
 #include "sdpd.h"
-#include "glib-compat.h"
 #include "dbus-common.h"
 
 /* Company IDs for vendor dependent commands */
 #define AVRCP_REGISTER_NOTIFICATION    0x31
 #define AVRCP_REQUEST_CONTINUING       0x40
 #define AVRCP_ABORT_CONTINUING         0x41
+#define AVRCP_SET_ABSOLUTE_VOLUME      0x50
 
 /* Capabilities for AVRCP_GET_CAPABILITIES pdu */
 #define CAP_COMPANY_ID         0x02
 #define CAP_EVENTS_SUPPORTED   0x03
 
+#define AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH 5
+
+#define AVRCP_FEATURE_CATEGORY_1       0x0001
+#define AVRCP_FEATURE_CATEGORY_2       0x0002
+#define AVRCP_FEATURE_CATEGORY_3       0x0004
+#define AVRCP_FEATURE_CATEGORY_4       0x0008
+#define AVRCP_FEATURE_PLAYER_SETTINGS  0x0010
+
 enum battery_status {
        BATTERY_STATUS_NORMAL =         0,
        BATTERY_STATUS_WARNING =        1,
@@ -166,6 +178,8 @@ static uint32_t company_ids[] = {
        IEEEID_BTSIG,
 };
 
+static void register_volume_notification(struct avrcp_player *player);
+
 static sdp_record_t *avrcp_ct_record(void)
 {
        sdp_list_t *svclass_id, *pfseq, *apseq, *root;
@@ -175,7 +189,11 @@ static sdp_record_t *avrcp_ct_record(void)
        sdp_record_t *record;
        sdp_data_t *psm, *version, *features;
        uint16_t lp = AVCTP_PSM;
-       uint16_t avrcp_ver = 0x0100, avctp_ver = 0x0103, feat = 0x000f;
+       uint16_t avrcp_ver = 0x0100, avctp_ver = 0x0103;
+       uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 |
+                                               AVRCP_FEATURE_CATEGORY_2 |
+                                               AVRCP_FEATURE_CATEGORY_3 |
+                                               AVRCP_FEATURE_CATEGORY_4 );
 
        record = sdp_record_alloc();
        if (!record)
@@ -239,7 +257,12 @@ static sdp_record_t *avrcp_tg_record(void)
        sdp_record_t *record;
        sdp_data_t *psm, *version, *features;
        uint16_t lp = AVCTP_PSM;
-       uint16_t avrcp_ver = 0x0103, avctp_ver = 0x0103, feat = 0x000f;
+       uint16_t avrcp_ver = 0x0104, avctp_ver = 0x0103;
+       uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 |
+                                       AVRCP_FEATURE_CATEGORY_2 |
+                                       AVRCP_FEATURE_CATEGORY_3 |
+                                       AVRCP_FEATURE_CATEGORY_4 |
+                                       AVRCP_FEATURE_PLAYER_SETTINGS );
 
        record = sdp_record_alloc();
        if (!record)
@@ -557,12 +580,13 @@ static uint8_t avrcp_handle_get_capabilities(struct avrcp_player *player,
 
                return AVC_CTYPE_STABLE;
        case CAP_EVENTS_SUPPORTED:
-               pdu->params_len = htons(5);
-               pdu->params[1] = 3;
+               pdu->params[1] = 4;
                pdu->params[2] = AVRCP_EVENT_STATUS_CHANGED;
                pdu->params[3] = AVRCP_EVENT_TRACK_CHANGED;
                pdu->params[4] = AVRCP_EVENT_TRACK_REACHED_START;
+               pdu->params[5] = AVRCP_EVENT_TRACK_REACHED_END;
 
+               pdu->params_len = htons(2 + pdu->params[1]);
                return AVC_CTYPE_STABLE;
        }
 
@@ -791,7 +815,7 @@ static uint8_t avrcp_handle_set_player_value(struct avrcp_player *player,
        if (len) {
                pdu->params_len = 0;
 
-               return AVC_CTYPE_STABLE;
+               return AVC_CTYPE_ACCEPTED;
        }
 
 err:
@@ -960,8 +984,11 @@ static uint8_t avrcp_handle_request_continuing(struct avrcp_player *player,
        }
 
        pdu->params_len = htons(len);
-
+#ifdef __TIZEN_PATCH__
+       return AVC_CTYPE_ACCEPTED;
+#else
        return AVC_CTYPE_STABLE;
+#endif
 err:
        pdu->params_len = htons(1);
        pdu->params[0] = E_INVALID_PARAM;
@@ -986,7 +1013,7 @@ static uint8_t avrcp_handle_abort_continuing(struct avrcp_player *player,
        player_abort_pending_pdu(player);
        pdu->params_len = 0;
 
-       return AVC_CTYPE_STABLE;
+       return AVC_CTYPE_ACCEPTED;
 
 err:
        pdu->params_len = htons(1);
@@ -994,7 +1021,6 @@ err:
        return AVC_CTYPE_REJECTED;
 }
 
-
 static struct pdu_handler {
        uint8_t pdu_id;
        uint8_t code;
@@ -1092,6 +1118,21 @@ err_metadata:
        return AVRCP_HEADER_LENGTH + 1;
 }
 
+size_t avrcp_handle_vendor_reject(uint8_t *code, uint8_t *operands)
+{
+    struct avrcp_header *pdu = (void *) operands;
+    uint32_t company_id = get_company_id(pdu->company_id);
+
+    *code = AVC_CTYPE_REJECTED;
+    pdu->params_len = htons(1);
+    pdu->params[0] = E_INTERNAL;
+
+    DBG("rejecting AVRCP PDU 0x%02X, company 0x%06X len 0x%04X",
+            pdu->pdu_id, company_id, pdu->params_len);
+
+    return AVRCP_HEADER_LENGTH + 1;
+}
+
 static struct avrcp_server *find_server(GSList *list, const bdaddr_t *src)
 {
        for (; list; list = list->next) {
@@ -1104,11 +1145,59 @@ static struct avrcp_server *find_server(GSList *list, const bdaddr_t *src)
        return NULL;
 }
 
+static gboolean avrcp_handle_volume_changed(struct avctp *session,
+                                       uint8_t code, uint8_t subunit,
+                                       uint8_t *operands, size_t operand_count,
+                                       void *user_data)
+{
+       struct avrcp_player *player = user_data;
+       struct avrcp_header *pdu = (void *) operands;
+       uint8_t volume;
+
+       if (code != AVC_CTYPE_INTERIM && code != AVC_CTYPE_CHANGED)
+               return FALSE;
+
+       volume = pdu->params[1] & 0x7F;
+
+       player->cb->set_volume(volume, player->dev, player->user_data);
+
+       if (code == AVC_CTYPE_CHANGED) {
+               register_volume_notification(player);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static void register_volume_notification(struct avrcp_player *player)
+{
+       uint8_t buf[AVRCP_HEADER_LENGTH + AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH];
+       struct avrcp_header *pdu = (void *) buf;
+       uint8_t length;
+
+       memset(buf, 0, sizeof(buf));
+
+       set_company_id(pdu->company_id, IEEEID_BTSIG);
+       pdu->pdu_id = AVRCP_REGISTER_NOTIFICATION;
+       pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
+       pdu->params[0] = AVRCP_EVENT_VOLUME_CHANGED;
+       pdu->params_len = htons(AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH);
+
+       length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len);
+
+       avctp_send_vendordep_req(player->session, AVC_CTYPE_NOTIFY,
+                                       AVC_SUBUNIT_PANEL, buf, length,
+                                       avrcp_handle_volume_changed, player);
+}
+
 static void state_changed(struct audio_device *dev, avctp_state_t old_state,
                                avctp_state_t new_state, void *user_data)
 {
        struct avrcp_server *server;
        struct avrcp_player *player;
+       const sdp_record_t *rec;
+       sdp_list_t *list;
+       sdp_profile_desc_t *desc;
 
        server = find_server(servers, &dev->src);
        if (!server)
@@ -1121,6 +1210,7 @@ static void state_changed(struct audio_device *dev, avctp_state_t old_state,
        switch (new_state) {
        case AVCTP_STATE_DISCONNECTED:
                player->session = NULL;
+               player->dev = NULL;
                player->registered_events = 0;
 
                if (player->handler) {
@@ -1131,6 +1221,7 @@ static void state_changed(struct audio_device *dev, avctp_state_t old_state,
                break;
        case AVCTP_STATE_CONNECTING:
                player->session = avctp_connect(&dev->src, &dev->dst);
+               player->dev = dev;
 
                if (!player->handler)
                        player->handler = avctp_register_pdu_handler(
@@ -1138,6 +1229,20 @@ static void state_changed(struct audio_device *dev, avctp_state_t old_state,
                                                        handle_vendordep_pdu,
                                                        player);
                break;
+       case AVCTP_STATE_CONNECTED:
+               rec = btd_device_get_record(dev->btd_dev, AVRCP_TARGET_UUID);
+               if (rec == NULL)
+                       return;
+
+               if (sdp_get_profile_descs(rec, &list) < 0)
+                       return;
+
+               desc = list->data;
+
+               if (desc && desc->version >= 0x0104)
+                       register_volume_notification(player);
+
+               sdp_list_free(list, free);
        default:
                return;
        }
@@ -1312,3 +1417,55 @@ void avrcp_unregister_player(struct avrcp_player *player)
 
        player_destroy(player);
 }
+
+static gboolean avrcp_handle_set_volume(struct avctp *session,
+                                       uint8_t code, uint8_t subunit,
+                                       uint8_t *operands, size_t operand_count,
+                                       void *user_data)
+{
+       struct avrcp_player *player = user_data;
+       struct avrcp_header *pdu = (void *) operands;
+       uint8_t volume;
+
+       if (code == AVC_CTYPE_REJECTED || code == AVC_CTYPE_NOT_IMPLEMENTED)
+               return FALSE;
+
+       volume = pdu->params[0] & 0x7F;
+
+       player->cb->set_volume(volume, player->dev, player->user_data);
+
+       return FALSE;
+}
+
+int avrcp_set_volume(struct audio_device *dev, uint8_t volume)
+{
+       struct avrcp_server *server;
+       struct avrcp_player *player;
+       uint8_t buf[AVRCP_HEADER_LENGTH + 1];
+       struct avrcp_header *pdu = (void *) buf;
+
+       server = find_server(servers, &dev->src);
+       if (server == NULL)
+               return -EINVAL;
+
+       player = server->active_player;
+       if (player == NULL)
+               return -ENOTSUP;
+
+       if (player->session == NULL)
+               return -ENOTCONN;
+
+       memset(buf, 0, sizeof(buf));
+
+       set_company_id(pdu->company_id, IEEEID_BTSIG);
+
+       pdu->pdu_id = AVRCP_SET_ABSOLUTE_VOLUME;
+       pdu->params[0] = volume;
+       pdu->params_len = htons(1);
+
+       DBG("volume=%u", volume);
+
+       return avctp_send_vendordep_req(player->session, AVC_CTYPE_CONTROL,
+                                       AVC_SUBUNIT_PANEL, buf, sizeof(buf),
+                                       avrcp_handle_set_volume, player);
+}
index fb64f3b..bf11a6c 100644 (file)
@@ -73,7 +73,8 @@
 #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
+#define AVRCP_EVENT_VOLUME_CHANGED     0x0d
+#define AVRCP_EVENT_LAST               AVRCP_EVENT_VOLUME_CHANGED
 
 struct avrcp_player_cb {
        int (*get_setting) (uint8_t attr, void *user_data);
@@ -83,6 +84,8 @@ struct avrcp_player_cb {
        GList *(*list_metadata) (void *user_data);
        uint8_t (*get_status) (void *user_data);
        uint32_t (*get_position) (void *user_data);
+       void (*set_volume) (uint8_t volume, struct audio_device *dev,
+                                                       void *user_data);
 };
 
 int avrcp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config);
@@ -90,6 +93,7 @@ void avrcp_unregister(const bdaddr_t *src);
 
 gboolean avrcp_connect(struct audio_device *dev);
 void avrcp_disconnect(struct audio_device *dev);
+int avrcp_set_volume(struct audio_device *dev, uint8_t volume);
 
 struct avrcp_player *avrcp_register_player(const bdaddr_t *src,
                                                struct avrcp_player_cb *cb,
@@ -98,3 +102,6 @@ struct avrcp_player *avrcp_register_player(const bdaddr_t *src,
 void avrcp_unregister_player(struct avrcp_player *player);
 
 int avrcp_player_event(struct avrcp_player *player, uint8_t id, void *data);
+
+
+size_t avrcp_handle_vendor_reject(uint8_t *code, uint8_t *operands);
index a75e992..c5a6a58 100644 (file)
@@ -197,20 +197,24 @@ static DBusMessage *control_get_properties(DBusConnection *conn,
        return reply;
 }
 
-static GDBusMethodTable control_methods[] = {
-       { "IsConnected",        "",     "b",    control_is_connected,
-                                               G_DBUS_METHOD_FLAG_DEPRECATED },
-       { "GetProperties",      "",     "a{sv}",control_get_properties },
-       { "VolumeUp",           "",     "",     volume_up },
-       { "VolumeDown",         "",     "",     volume_down },
-       { NULL, NULL, NULL, NULL }
+static const GDBusMethodTable control_methods[] = {
+       { GDBUS_ASYNC_METHOD("IsConnected",
+                               NULL, GDBUS_ARGS({ "connected", "b" }),
+                               control_is_connected) },
+       { GDBUS_METHOD("GetProperties",
+                               NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                               control_get_properties) },
+       { GDBUS_METHOD("VolumeUp", NULL, NULL, volume_up) },
+       { GDBUS_METHOD("VolumeDown", NULL, NULL, volume_down) },
+       { }
 };
 
-static GDBusSignalTable control_signals[] = {
-       { "Connected",                  "",     G_DBUS_SIGNAL_FLAG_DEPRECATED},
-       { "Disconnected",               "",     G_DBUS_SIGNAL_FLAG_DEPRECATED},
-       { "PropertyChanged",            "sv"    },
-       { NULL, NULL }
+static const GDBusSignalTable control_signals[] = {
+       { GDBUS_DEPRECATED_SIGNAL("Connected", NULL) },
+       { GDBUS_DEPRECATED_SIGNAL("Disconnected", NULL) },
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+       { }
 };
 
 static void path_unregister(void *data)
index a9d35f9..b7b993e 100644 (file)
@@ -618,17 +618,19 @@ static DBusMessage *dev_get_properties(DBusConnection *conn, DBusMessage *msg,
        return reply;
 }
 
-static GDBusMethodTable dev_methods[] = {
-       { "Connect",            "",     "",     dev_connect,
-                                               G_DBUS_METHOD_FLAG_ASYNC },
-       { "Disconnect",         "",     "",     dev_disconnect },
-       { "GetProperties",      "",     "a{sv}",dev_get_properties },
-       { NULL, NULL, NULL, NULL }
+static const GDBusMethodTable dev_methods[] = {
+       { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, dev_connect) },
+       { GDBUS_METHOD("Disconnect", NULL, NULL, dev_disconnect) },
+       { GDBUS_METHOD("GetProperties",
+               NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+               dev_get_properties) },
+       { }
 };
 
-static GDBusSignalTable dev_signals[] = {
-       { "PropertyChanged",            "sv"    },
-       { NULL, NULL }
+static const GDBusSignalTable dev_signals[] = {
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+       { }
 };
 
 struct audio_device *audio_device_register(DBusConnection *conn,
@@ -701,7 +703,7 @@ gboolean audio_device_is_active(struct audio_device *dev,
                                control_is_active(dev))
                return TRUE;
        else if (!strcmp(interface, AUDIO_GATEWAY_INTERFACE) && dev->gateway &&
-                               gateway_is_connected(dev))
+                               gateway_is_active(dev))
                return TRUE;
 
        return FALSE;
index 5117fca..75f1da9 100644 (file)
  *
  */
 
-#define GENERIC_AUDIO_UUID     "00001203-0000-1000-8000-00805f9b34fb"
-
-#define HSP_HS_UUID            "00001108-0000-1000-8000-00805f9b34fb"
-#define HSP_AG_UUID            "00001112-0000-1000-8000-00805f9b34fb"
-
-#define HFP_HS_UUID            "0000111e-0000-1000-8000-00805f9b34fb"
-#define HFP_AG_UUID            "0000111f-0000-1000-8000-00805f9b34fb"
-
-#define ADVANCED_AUDIO_UUID    "0000110d-0000-1000-8000-00805f9b34fb"
-
-#define A2DP_SOURCE_UUID       "0000110a-0000-1000-8000-00805f9b34fb"
-#define A2DP_SINK_UUID         "0000110b-0000-1000-8000-00805f9b34fb"
-
-#define AVRCP_REMOTE_UUID      "0000110e-0000-1000-8000-00805f9b34fb"
-#define AVRCP_TARGET_UUID      "0000110c-0000-1000-8000-00805f9b34fb"
-
 struct source;
 struct control;
 struct target;
index 9b1aab3..6162948 100644 (file)
@@ -42,7 +42,6 @@
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
-#include "glib-compat.h"
 #include "sdp-client.h"
 #include "device.h"
 #include "gateway.h"
 #include "btio.h"
 #include "dbus-common.h"
 
-#ifndef DBUS_TYPE_UNIX_FD
-#define DBUS_TYPE_UNIX_FD -1
-#endif
-
 struct hf_agent {
        char *name;     /* Bus id */
        char *path;     /* D-Bus path */
@@ -182,8 +177,11 @@ static gboolean agent_sendfd(struct hf_agent *agent, int fd,
                                        DBUS_TYPE_UINT16, &gw->version,
                                        DBUS_TYPE_INVALID);
 
-       if (dbus_connection_send_with_reply(dev->conn, msg, &call, -1) == FALSE)
+       if (dbus_connection_send_with_reply(dev->conn, msg,
+                                                       &call, -1) == FALSE) {
+               dbus_message_unref(msg);
                return FALSE;
+       }
 
        dbus_pending_call_set_notify(call, notify, dev, NULL);
        dbus_pending_call_unref(call);
@@ -255,7 +253,7 @@ static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 
        if (err) {
                error("sco_connect_cb(): %s", err->message);
-               gateway_close(dev);
+               gateway_suspend_stream(dev);
                return;
        }
 
@@ -501,6 +499,7 @@ static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
        io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, dev, NULL, &gerr,
                                BT_IO_OPT_SOURCE_BDADDR, &dev->src,
                                BT_IO_OPT_DEST_BDADDR, &dev->dst,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
                                BT_IO_OPT_CHANNEL, ch,
                                BT_IO_OPT_INVALID);
        if (!io) {
@@ -594,13 +593,13 @@ static DBusMessage *ag_disconnect(DBusConnection *conn, DBusMessage *msg,
        if (!device->conn)
                return NULL;
 
+       if (!gw->rfcomm)
+               return btd_error_not_connected(msg);
+
        reply = dbus_message_new_method_return(msg);
        if (!reply)
                return NULL;
 
-       if (!gw->rfcomm)
-               return  btd_error_not_connected(msg);
-
        gateway_close(device);
        ba2str(&device->dst, gw_addr);
        DBG("Disconnected from %s, %s", gw_addr, device->path);
@@ -709,18 +708,23 @@ done:
        return dbus_message_new_method_return(msg);
 }
 
-static GDBusMethodTable gateway_methods[] = {
-       { "Connect", "", "", ag_connect, G_DBUS_METHOD_FLAG_ASYNC },
-       { "Disconnect", "", "", ag_disconnect, G_DBUS_METHOD_FLAG_ASYNC },
-       { "GetProperties", "", "a{sv}", ag_get_properties },
-       { "RegisterAgent", "o", "", register_agent },
-       { "UnregisterAgent", "o", "", unregister_agent },
-       { NULL, NULL, NULL, NULL }
+static const GDBusMethodTable gateway_methods[] = {
+       { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, ag_connect) },
+       { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, ag_disconnect) },
+       { GDBUS_METHOD("GetProperties",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       ag_get_properties) },
+       { GDBUS_METHOD("RegisterAgent",
+                       GDBUS_ARGS({ "agent", "o" }), NULL, register_agent) },
+       { GDBUS_METHOD("UnregisterAgent",
+                       GDBUS_ARGS({ "agent", "o" }), NULL, unregister_agent) },
+       { }
 };
 
-static GDBusSignalTable gateway_signals[] = {
-       { "PropertyChanged", "sv" },
-       { NULL, NULL }
+static const GDBusSignalTable gateway_signals[] = {
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+       { }
 };
 
 static void path_unregister(void *data)
@@ -747,9 +751,6 @@ void gateway_unregister(struct audio_device *dev)
 
 struct gateway *gateway_init(struct audio_device *dev)
 {
-       if (DBUS_TYPE_UNIX_FD < 0)
-               return NULL;
-
        if (!g_dbus_register_interface(dev->conn, dev->path,
                                        AUDIO_GATEWAY_INTERFACE,
                                        gateway_methods, gateway_signals,
@@ -835,18 +836,16 @@ unsigned int gateway_request_stream(struct audio_device *dev,
                                gateway_stream_cb_t cb, void *user_data)
 {
        struct gateway *gw = dev->gateway;
-       unsigned int id;
        GError *err = NULL;
        GIOChannel *io;
 
-       id = connect_cb_new(gw, cb, user_data);
-
        if (!gw->rfcomm)
                get_records(dev);
        else if (!gw->sco) {
                io = bt_io_connect(BT_IO_SCO, sco_connect_cb, dev, NULL, &err,
                                BT_IO_OPT_SOURCE_BDADDR, &dev->src,
                                BT_IO_OPT_DEST_BDADDR, &dev->dst,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
                                BT_IO_OPT_INVALID);
                if (!io) {
                        error("%s", err->message);
@@ -856,7 +855,7 @@ unsigned int gateway_request_stream(struct audio_device *dev,
        } else
                g_idle_add(request_stream_cb, dev);
 
-       return id;
+       return connect_cb_new(gw, cb, user_data);
 }
 
 int gateway_config_stream(struct audio_device *dev, gateway_stream_cb_t cb,
index 930d14e..c8f6346 100644 (file)
@@ -727,4 +727,3 @@ gboolean gst_a2dp_sink_plugin_init(GstPlugin *plugin)
        return gst_element_register(plugin, "a2dpsink",
                        GST_RANK_MARGINAL, GST_TYPE_A2DP_SINK);
 }
-
index 5f96a3e..1a591b2 100644 (file)
@@ -82,4 +82,3 @@ GstCaps *gst_a2dp_sink_get_device_caps(GstA2dpSink *self);
 G_END_DECLS
 
 #endif
-
index c5392c5..1f374fc 100644 (file)
@@ -64,10 +64,6 @@ GST_DEBUG_CATEGORY_STATIC(avdtp_sink_debug);
                g_mutex_unlock(s->sink_lock);           \
        } G_STMT_END
 
-#ifndef DBUS_TYPE_UNIX_FD
-#define DBUS_TYPE_UNIX_FD -1
-#endif
-
 struct bluetooth_data {
        struct bt_get_capabilities_rsp *caps; /* Bluetooth device caps */
        guint link_mtu;
@@ -1121,6 +1117,11 @@ static gboolean gst_avdtp_sink_update_caps(GstAvdtpSink *self)
        sbc = (void *) gst_avdtp_find_caps(self, BT_A2DP_SBC_SINK);
        mpeg = (void *) gst_avdtp_find_caps(self, BT_A2DP_MPEG12_SINK);
 
+       if (!sbc) {
+               GST_ERROR_OBJECT(self, "Failed to find mandatory SBC sink");
+               return FALSE;
+       }
+
        sbc_structure = gst_avdtp_sink_parse_sbc_caps(self, sbc);
        mpeg_structure = gst_avdtp_sink_parse_mpeg_caps(self, mpeg);
 
@@ -1139,7 +1140,7 @@ static gboolean gst_avdtp_sink_update_caps(GstAvdtpSink *self)
 
 static gboolean gst_avdtp_sink_get_capabilities(GstAvdtpSink *self)
 {
-       gchar *buf[BT_SUGGESTED_BUFFER_SIZE];
+       gchar buf[BT_SUGGESTED_BUFFER_SIZE];
        struct bt_get_capabilities_req *req = (void *) buf;
        struct bt_get_capabilities_rsp *rsp = (void *) buf;
        int err;
@@ -1336,6 +1337,8 @@ static gboolean gst_avdtp_sink_transport_acquire(GstAvdtpSink *self)
        reply = dbus_connection_send_with_reply_and_block(self->data->conn,
                                                        msg, -1, &err);
 
+       dbus_message_unref(msg);
+
        if (dbus_error_is_set(&err))
                goto fail;
 
@@ -1362,7 +1365,7 @@ fail:
        dbus_error_free(&err);
 
        if (reply)
-               dbus_message_unref(msg);
+               dbus_message_unref(reply);
 
        return FALSE;
 }
index 1159bfe..11aa733 100644 (file)
@@ -349,4 +349,3 @@ gboolean gst_rtp_sbc_pay_plugin_init(GstPlugin *plugin)
        return gst_element_register(plugin, "rtpsbcpay", GST_RANK_NONE,
                                                        GST_TYPE_RTP_SBC_PAY);
 }
-
index 2e5cb0a..c52834e 100644 (file)
@@ -219,5 +219,3 @@ gboolean gst_sbc_dec_plugin_init(GstPlugin *plugin)
        return gst_element_register(plugin, "sbcdec", GST_RANK_PRIMARY,
                                                        GST_TYPE_SBC_DEC);
 }
-
-
index d2de4ee..8948371 100644 (file)
@@ -599,5 +599,3 @@ gboolean gst_sbc_enc_plugin_init(GstPlugin *plugin)
        return gst_element_register(plugin, "sbcenc",
                        GST_RANK_NONE, GST_TYPE_SBC_ENC);
 }
-
-
index a44b52c..bc4c0c7 100644 (file)
@@ -217,4 +217,3 @@ gboolean gst_sbc_parse_plugin_init(GstPlugin *plugin)
        return gst_element_register(plugin, "sbcparse", GST_RANK_NONE,
                                                        GST_TYPE_SBC_PARSE);
 }
-
index ac5fcbf..f596b41 100644 (file)
@@ -518,4 +518,3 @@ gboolean gst_sbc_util_fill_sbc_params(sbc_t *sbc, GstCaps *caps)
 
        return TRUE;
 }
-
index a7f84d5..5e47119 100644 (file)
@@ -72,4 +72,3 @@ void gst_sbc_util_set_structure_string_param(GstStructure *structure,
                        GValue *value);
 
 gboolean gst_sbc_util_fill_sbc_params(sbc_t *sbc, GstCaps *caps);
-
index 59d2068..bd83a65 100644 (file)
@@ -53,7 +53,6 @@
 #include "error.h"
 #include "telephony.h"
 #include "headset.h"
-#include "glib-compat.h"
 #include "sdp-client.h"
 #include "btio.h"
 #include "dbus-common.h"
@@ -166,9 +165,6 @@ struct headset {
 
        guint dc_timer;
 
-#ifdef __TIZEN_PATCH__
-       guint rfcomm_io_id;
-#endif
        gboolean hfp_active;
        gboolean search_hfp;
        gboolean rfcomm_initiator;
@@ -1205,82 +1201,86 @@ static int voice_dial(struct audio_device *device, const char *buf)
 }
 
 #ifdef __TIZEN_PATCH__
-int telephony_list_phonebook_store_rsp(void *telephony_device, const char *buf, cme_error_t err)
+int telephony_select_phonebook_memory_status_rsp(void *telephony_device, const char *path,
+                                               uint32_t total, uint32_t used,
+                                               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) {
                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");
        }
 
-       if (NULL != buf) {
+       if (0 != total && 0 != used) {
                if (!active_devices)
                        return -ENODEV;
 
                send_foreach_headset(active_devices, hfp_cmp,
-                                       "\r\n+CPBS: %s\r\n", buf);
-
+                                       "\r\n+CPBS: %s,%d,%d\r\n",
+                                       path, used, total);
        }
        return headset_send(hs, "\r\nOK\r\n");
 }
 
-int telephony_read_phonebook_store_rsp(void *telephony_device, char* pb_store, uint32_t total, uint32_t used, cme_error_t err)
+int telephony_select_phonebook_memory_list_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) {
+       if ((err != CME_ERROR_NONE) || (NULL == buf)) {
                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");
        }
 
-       if (0 != total && 0 != used) {
+       if (NULL != buf) {
                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\r\n", buf);
+
        }
        return headset_send(hs, "\r\nOK\r\n");
 }
 
+int telephony_select_phonebook_memory_rsp(void *telephony_device, cme_error_t err)
+{
+       return telephony_generic_rsp(telephony_device, err);
+}
+
 static int select_phonebook_memory(struct audio_device *device, const char *buf)
 {
-       struct headset *hs = device->headset;
-       int err;
+       if (strlen(buf) < 8)
+               return -EINVAL;
 
-       if (NULL != buf) {
-               if (strlen(buf) < 9)
-                       return -EINVAL;
+       if (buf[7] == '?') {
+               telephony_select_phonebook_memory_status(device);
+               return 0;
+       }
 
-               if (buf[7] == '?') {
-                       telephony_read_phonebook_store(device);
+       if (buf[7] == '=') {
+               if (buf[8] == '?') {
+                       telephony_select_phonebook_memory_list(device);
                        return 0;
                }
-
-               if (buf[8] == '=') {
-                       if (buf[9] == '?') {
-                               telephony_list_phonebook_store(device);
-                       } else {
-                               telephony_set_phonebook_store(device, &buf[9]);
-                               return headset_send(hs, "\r\nOK\r\n");
-                       }
-               }
+               telephony_select_phonebook_memory(device, &buf[8]);
+               return 0;
        }
-       return 0;
+
+       return -EINVAL;
 }
 
-int telephony_read_phonebook_attributes_rsp(void *telephony_device,
-                                               uint32_t total,
+int telephony_read_phonebook_entries_list_rsp(void *telephony_device,
+                                               uint32_t used,
                                                uint32_t number_length,
                                                uint32_t name_length,
                                                cme_error_t err)
@@ -1289,6 +1289,9 @@ int telephony_read_phonebook_attributes_rsp(void *telephony_device,
        struct headset *hs = device->headset;
        struct headset_slc *slc = hs->slc;
 
+       uint32_t index = 0;
+       int send_err = 0;
+
        if (err != CME_ERROR_NONE) {
                if (slc->cme_enabled)
                        return headset_send(hs, "\r\n+CME ERROR: %d\r\n", err);
@@ -1296,100 +1299,113 @@ 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 (!active_devices)
-                       return -ENODEV;
+       if (used < 0)
+               index = 1;
+
+       send_err = headset_send(hs, "\r\n+CPBR: (%d-%d),%d,%d\r\n",
+                       index, used, number_length, name_length);
+       if (send_err < 0)
+               return send_err;
 
-               send_foreach_headset(active_devices, hfp_cmp,
-                                       "\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_entries_rsp(void *telephony_device, cme_error_t err)
 {
-       struct audio_device *device = telephony_device;
-       struct headset *hs = device->headset;
-       struct headset_slc *slc = hs->slc;
+       return telephony_generic_rsp(telephony_device, err);
+}
 
-       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");
-       }
+int telephony_read_phonebook_entries_ind(const char *name, const char *number,
+                                       uint32_t handle)
+{
+       int type = 129;
+       const char *pos = NULL;
 
-       if (NULL != data) {
-               if (!active_devices)
-                       return -ENODEV;
+       pos = number;
+       while (*pos == ' ' || *pos == '\t')
+               pos++;
 
-               send_foreach_headset(active_devices, hfp_cmp,
-                                       "\r\n+CPBR:  %s\r\n", data);
-       }
+       /* 145 means international access code, otherwise 129 is used */
+       if (*pos == '+')
+               type = 145;
+
+       send_foreach_headset(active_devices, hfp_cmp,
+                       "\r\n+CPBR: %d,\"%s\",%d,\"%s\"\r\n",
+                       handle, number, type, name);
+       return 0;
 }
 
 static int read_phonebook_entries(struct audio_device *device, const char *buf)
 {
-       struct headset *hs = device->headset;
-       int err;
+       if (strlen(buf) < 8)
+               return -EINVAL;
 
-       if (NULL != buf) {
-               if (strlen(buf) < 8)
-                       return -EINVAL;
+       if (buf[7] != '=')
+               return -EINVAL;
+
+       if (buf[8] == '?')
+               telephony_read_phonebook_entries_list(device);
+       else
+               telephony_read_phonebook_entries(device, &buf[8]);
 
-               if (buf[9] == '?') {
-                       telephony_read_phonebook_attributes(device);
-               } 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,
+int telephony_find_phonebook_entries_status_rsp(void *telephony_device,
                                                cme_error_t err)
 {
-       struct audio_device *device = telephony_device;
-       struct headset *hs = device->headset;
-       struct headset_slc *slc = hs->slc;
+       return telephony_generic_rsp(telephony_device, err);
+}
 
-       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");
-       }
+int telephony_find_phonebook_entries_rsp(void *telephony_device,
+                                       cme_error_t err)
+{
+       return telephony_generic_rsp(telephony_device, err);
+}
 
-       if (max_name_length != 0 && max_number_length != 0) {
-               if (!active_devices)
-                       return -ENODEV;
+int telephony_find_phonebook_entries_status_ind( uint32_t number_length,
+                                       uint32_t name_length)
+{
+       send_foreach_headset(active_devices, hfp_cmp,
+                       "\r\n+CPBF: %d,%d\r\n",
+                       number_length, name_length);
 
-               send_foreach_headset(active_devices, hfp_cmp,
-                                       "\r\n+CPBF: %d,%d\r\n",
-                                       max_number_length,
-                                       max_name_length);
-       }
-       return headset_send(hs, "\r\nOK\r\n");
+       return 0;
+}
+
+int telephony_find_phonebook_entries_ind(const char *name, const char *number,
+                                       uint32_t handle)
+{
+       int type = 129;
+       const char *pos = NULL;
+
+       pos = number;
+       while (*pos == ' ' || *pos == '\t')
+               pos++;
+
+       /* 145 means international access code, otherwise 129 is used */
+       if (*pos == '+')
+               type = 145;
+
+       send_foreach_headset(active_devices, hfp_cmp,
+                       "\r\n+CPBF: %d,\"%s\",%d,\"%s\"\r\n",
+                       handle, number, type, name);
+       return 0;
 }
 
 static int find_phonebook_entires(struct audio_device *device, const char *buf)
 {
-       struct headset *hs = device->headset;
-       int err;
+       if (strlen(buf) < 8)
+               return -EINVAL;
 
-       if (NULL != buf)  {
-               if (strlen(buf) < 8)
-                       return -EINVAL;
+       if (buf[7] != '=')
+               return -EINVAL;
+
+       if (buf[8] == '?')
+               telephony_find_phonebook_entries_status(device);
+       else
+               telephony_find_phonebook_entries(device, &buf[8]);
 
-               if (buf[9] == '?')
-                       telephony_find_phonebook_entry_properties(device);
-               else
-                       telephony_find_phonebook_entry(device, &buf[9]);
-       }
        return 0;
 }
 
@@ -1446,7 +1462,6 @@ int telephony_get_preffered_store_capacity_rsp(void *telephony_device,
 static int preffered_message_storage(struct audio_device *device, const char *buf)
 {
        struct headset *hs = device->headset;
-       int err;
 
        if (NULL != buf) {
                if (strlen(buf) < 9)
@@ -1497,7 +1512,7 @@ int telephony_supported_character_generic_rsp(void *telephony_device,
 static int select_character_set(struct audio_device *device, const char *buf)
 {
        struct headset *hs = device->headset;
-       int err;
+
        if (NULL != buf) {
                if (strlen(buf) < 9)
                        return -EINVAL;
@@ -1519,6 +1534,59 @@ static int select_character_set(struct audio_device *device, const char *buf)
        return 0;
 
 }
+
+int telephony_battery_charge_status_rsp(void *telephony_device,
+                                               int32_t bcs,
+                                               int32_t bcl,
+                                               cme_error_t err)
+{
+       struct audio_device *device = telephony_device;
+
+       if (err == CME_ERROR_NONE) {
+               send_foreach_headset(active_devices, hfp_cmp,
+                                       "\r\n+CBC: %d,%d\r\n", bcs, bcl);
+       }
+
+       return telephony_generic_rsp(device, err);
+}
+
+static int get_battery_charge_status(struct audio_device *device, const char *buf)
+{
+       if (strlen(buf) < 8)
+               return -EINVAL;
+
+       if (buf[7] == '?')
+               telephony_get_battery_property(device);
+
+       return 0;
+}
+
+int telephony_signal_quality_rsp(void *telephony_device,
+                                               int32_t rssi,
+                                               int32_t ber,
+                                               cme_error_t err)
+{
+       struct audio_device *device = telephony_device;
+
+       if (err == CME_ERROR_NONE) {
+               send_foreach_headset(active_devices, hfp_cmp,
+                                       "\r\n+CSQ: %d,%d\r\n", rssi, ber);
+       }
+       return telephony_generic_rsp(device,err);
+}
+
+static int get_signal_quality(struct audio_device *device, const char *buf)
+{
+       if (strlen(buf) < 8)
+               return -EINVAL;
+
+       if (buf[7] == '?')
+               telephony_get_signal_quality(device);
+
+       return 0;
+
+}
+
 #endif
 
 static int apple_command(struct audio_device *device, const char *buf)
@@ -1552,12 +1620,13 @@ static struct event event_callbacks[] = {
        { "AT+XAPL", apple_command },
        { "AT+IPHONEACCEV", apple_command },
 #ifdef __TIZEN_PATCH__
-       /*TIZEN 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 },
+       { "AT+CSQ", get_signal_quality },
+       { "AT+CBC", get_battery_charge_status },
 #endif
        { 0 }
 };
@@ -1608,10 +1677,6 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
                return FALSE;
 
        hs = device->headset;
-#ifdef __TIZEN_PATCH__
-       if (!hs)
-               return FALSE;
-#endif
        slc = hs->slc;
 
        if (cond & (G_IO_ERR | G_IO_HUP)) {
@@ -1631,7 +1696,7 @@ static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
        if (free_space < (size_t) bytes_read) {
                /* Very likely that the HS is sending us garbage so
                 * just ignore the data and disconnect */
-               error("Too much data to fit incomming buffer");
+               error("Too much data to fit incoming buffer");
                goto failed;
        }
 
@@ -1730,14 +1795,8 @@ void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
        else
                hs->auto_dc = FALSE;
 
-#ifdef __TIZEN_PATCH__
-       hs->rfcomm_io_id = g_io_add_watch(chan,
-                               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,
                        (GIOFunc) rfcomm_io_cb, dev);
-#endif
 
        DBG("%s: Connected to %s", dev->path, hs_address);
 
@@ -1803,9 +1862,11 @@ static int headset_set_channel(struct headset *headset,
 
        if (svc == HANDSFREE_SVCLASS_ID) {
                headset->hfp_handle = record->handle;
+               headset->hsp_handle = 0;
                DBG("Discovered Handsfree service on channel %d", ch);
        } else {
                headset->hsp_handle = record->handle;
+               headset->hfp_handle = 0;
                DBG("Discovered Headset service on channel %d", ch);
        }
 
@@ -1958,17 +2019,12 @@ 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) {
-               g_source_remove(hs->rfcomm_io_id);
-               hs->rfcomm_io_id = 0;
-       }
-#endif
        hs->tmp_rfcomm = bt_io_connect(BT_IO_RFCOMM, headset_connect_cb, dev,
                                        NULL, &err,
                                        BT_IO_OPT_SOURCE_BDADDR, &dev->src,
                                        BT_IO_OPT_DEST_BDADDR, &dev->dst,
                                        BT_IO_OPT_CHANNEL, hs->rfcomm_ch,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
                                        BT_IO_OPT_INVALID);
 
        hs->rfcomm_ch = -1;
@@ -2399,43 +2455,100 @@ static DBusMessage *hs_set_property(DBusConnection *conn,
        return btd_error_invalid_args(msg);
 }
 
-static GDBusMethodTable headset_methods[] = {
-       { "Connect",            "",     "",     hs_connect,
-                                               G_DBUS_METHOD_FLAG_ASYNC },
-       { "Disconnect",         "",     "",     hs_disconnect },
-       { "IsConnected",        "",     "b",    hs_is_connected },
-       { "IndicateCall",       "",     "",     hs_ring },
-       { "CancelCall",         "",     "",     hs_cancel_call },
-       { "Play",               "",     "",     hs_play,
-                                               G_DBUS_METHOD_FLAG_ASYNC |
-                                               G_DBUS_METHOD_FLAG_DEPRECATED },
-       { "Stop",               "",     "",     hs_stop },
-       { "IsPlaying",          "",     "b",    hs_is_playing,
-                                               G_DBUS_METHOD_FLAG_DEPRECATED },
-       { "GetSpeakerGain",     "",     "q",    hs_get_speaker_gain,
-                                               G_DBUS_METHOD_FLAG_DEPRECATED },
-       { "GetMicrophoneGain",  "",     "q",    hs_get_mic_gain,
-                                               G_DBUS_METHOD_FLAG_DEPRECATED },
-       { "SetSpeakerGain",     "q",    "",     hs_set_speaker_gain,
-                                               G_DBUS_METHOD_FLAG_DEPRECATED },
-       { "SetMicrophoneGain",  "q",    "",     hs_set_mic_gain,
-                                               G_DBUS_METHOD_FLAG_DEPRECATED },
-       { "GetProperties",      "",     "a{sv}",hs_get_properties },
-       { "SetProperty",        "sv",   "",     hs_set_property },
-       { NULL, NULL, NULL, NULL }
+#ifdef __TIZEN_PATCH__
+static DBusMessage *hs_set_voice_dial(DBusConnection *conn, DBusMessage *msg,
+                                               void *data)
+{
+       struct audio_device *device = data;
+       struct headset *hs = device->headset;
+       struct headset_slc *slc = hs->slc;
+       DBusMessage *reply;
+       int err;
+       dbus_bool_t enable;
+
+       if (hs->state < HEADSET_STATE_CONNECTED)
+               return btd_error_not_connected(msg);
+
+       if (!(slc->hf_features & HF_FEATURE_VOICE_RECOGNITION)) {
+               DBG("Voice Recognition is not supported by HF \n");
+               return btd_error_not_supported(msg);
+       }
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &enable,
+                                               DBUS_TYPE_INVALID))
+               return NULL;
+
+       DBG("hs_set_voice_dial = %d \n", enable);
+
+       reply = dbus_message_new_method_return(msg);
+
+       if (!reply)
+               return NULL;
+
+       err = headset_send(hs, "\r\n+BVRA: %d\r\n", enable);
+
+       if (err < 0) {
+               dbus_message_unref(reply);
+               return btd_error_failed(msg, strerror(-err));
+       }
+
+       return reply;
+}
+#endif
+
+static const GDBusMethodTable headset_methods[] = {
+       { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, hs_connect) },
+       { GDBUS_METHOD("Disconnect", NULL, NULL, hs_disconnect) },
+       { GDBUS_METHOD("IsConnected",
+                       NULL, GDBUS_ARGS({ "connected", "b" }),
+                       hs_is_connected) },
+       { GDBUS_METHOD("IndicateCall", NULL, NULL, hs_ring) },
+       { GDBUS_METHOD("CancelCall", NULL, NULL, hs_cancel_call) },
+       { GDBUS_DEPRECATED_ASYNC_METHOD("Play", NULL, NULL, hs_play) },
+       { GDBUS_METHOD("Stop", NULL, NULL, hs_stop) },
+       { GDBUS_DEPRECATED_METHOD("IsPlaying",
+                                       NULL, GDBUS_ARGS({ "playing", "b" }),
+                                       hs_is_playing) },
+       { GDBUS_DEPRECATED_METHOD("GetSpeakerGain",
+                                       NULL, GDBUS_ARGS({ "gain", "q" }),
+                                       hs_get_speaker_gain) },
+       { GDBUS_DEPRECATED_METHOD("GetMicrophoneGain",
+                                       NULL, GDBUS_ARGS({ "gain", "q" }),
+                                       hs_get_mic_gain) },
+       { GDBUS_DEPRECATED_METHOD("SetSpeakerGain",
+                                       GDBUS_ARGS({ "gain", "q" }), NULL,
+                                       hs_set_speaker_gain) },
+       { GDBUS_DEPRECATED_METHOD("SetMicrophoneGain",
+                                       GDBUS_ARGS({ "gain", "q" }), NULL,
+                                       hs_set_mic_gain) },
+       { GDBUS_METHOD("GetProperties",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       hs_get_properties) },
+       { GDBUS_METHOD("SetProperty",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
+                       hs_set_property) },
+#ifdef __TIZEN_PATCH__
+       { GDBUS_METHOD("SetVoiceDial",
+                       GDBUS_ARGS({ "enable", "b" }), NULL,
+                       hs_set_voice_dial) },
+#endif
+       { }
 };
 
-static GDBusSignalTable headset_signals[] = {
-       { "Connected",                  "",     G_DBUS_SIGNAL_FLAG_DEPRECATED },
-       { "Disconnected",               "",     G_DBUS_SIGNAL_FLAG_DEPRECATED },
-       { "AnswerRequested",            ""      },
-       { "Stopped",                    "",     G_DBUS_SIGNAL_FLAG_DEPRECATED },
-       { "Playing",                    "",     G_DBUS_SIGNAL_FLAG_DEPRECATED },
-       { "SpeakerGainChanged",         "q",    G_DBUS_SIGNAL_FLAG_DEPRECATED },
-       { "MicrophoneGainChanged",      "q",    G_DBUS_SIGNAL_FLAG_DEPRECATED },
-       { "CallTerminated",             ""      },
-       { "PropertyChanged",            "sv"    },
-       { NULL, NULL }
+static const GDBusSignalTable headset_signals[] = {
+       { GDBUS_DEPRECATED_SIGNAL("Connected", NULL) },
+       { GDBUS_DEPRECATED_SIGNAL("Disconnected", NULL) },
+       { GDBUS_DEPRECATED_SIGNAL("AnswerRequested", NULL) },
+       { GDBUS_DEPRECATED_SIGNAL("Stopped", NULL) },
+       { GDBUS_DEPRECATED_SIGNAL("Playing", NULL) },
+       { GDBUS_DEPRECATED_SIGNAL("SpeakerGainChanged",
+                                               GDBUS_ARGS({ "gain", "q" })) },
+       { GDBUS_DEPRECATED_SIGNAL("MicrophoneGainChanged",
+                                               GDBUS_ARGS({ "gain", "q" })) },
+       { GDBUS_SIGNAL("CallTerminated", NULL) },
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+       { }
 };
 
 void headset_update(struct audio_device *dev, uint16_t svc,
@@ -2492,12 +2605,6 @@ static int headset_close_rfcomm(struct audio_device *dev)
                hs->rfcomm = NULL;
        }
 
-#ifdef __TIZEN_PATCH__
-       if (hs->rfcomm_io_id) {
-               g_source_remove(hs->rfcomm_io_id);
-               hs->rfcomm_io_id = 0;
-       }
-#endif
        g_free(hs->slc);
        hs->slc = NULL;
 
index 99eeca8..465c2d6 100644 (file)
@@ -86,7 +86,6 @@ gboolean headset_get_rfcomm_initiator(struct audio_device *dev);
 void headset_set_rfcomm_initiator(struct audio_device *dev,
                                                        gboolean initiator);
 
-void headset_set_authorized(struct audio_device *dev);
 int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *chan);
 int headset_connect_sco(struct audio_device *dev, GIOChannel *io);
 
index e9187ce..c88fd05 100644 (file)
@@ -41,6 +41,7 @@
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
 #include "telephony.h"
 #include "unix.h"
 
-#ifndef DBUS_TYPE_UNIX_FD
-#define DBUS_TYPE_UNIX_FD -1
-#endif
-
 typedef enum {
        HEADSET = 1 << 0,
        GATEWAY = 1 << 1,
@@ -578,8 +575,8 @@ static void hf_io_cb(GIOChannel *chan, gpointer data)
                return;
        }
 
-       server_uuid = HFP_AG_UUID;
-       remote_uuid = HFP_HS_UUID;
+       server_uuid = HFP_HS_UUID;
+       remote_uuid = HFP_AG_UUID;
 
        device = manager_get_device(&src, &dst, TRUE);
        if (!device)
@@ -604,7 +601,7 @@ static void hf_io_cb(GIOChannel *chan, gpointer data)
        perr = audio_device_request_authorization(device, server_uuid,
                                                gateway_auth_cb, device);
        if (perr < 0) {
-               DBG("Authorization denied!");
+               DBG("Authorization denied: %s", strerror(-perr));
                gateway_set_state(device, GATEWAY_STATE_DISCONNECTED);
        }
 
@@ -755,20 +752,24 @@ static int gateway_server_init(struct audio_adapter *adapter)
        record = hfp_hs_record(chan);
        if (!record) {
                error("Unable to allocate new service record");
-               return -1;
+               goto failed;
        }
 
        if (add_record_to_server(&src, record) < 0) {
                error("Unable to register HFP HS service record");
                sdp_record_free(record);
-               g_io_channel_unref(adapter->hfp_hs_server);
-               adapter->hfp_hs_server = NULL;
-               return -1;
+               goto failed;
        }
 
        adapter->hfp_hs_record_id = record->handle;
 
        return 0;
+
+failed:
+       g_io_channel_shutdown(adapter->hfp_hs_server, TRUE, NULL);
+       g_io_channel_unref(adapter->hfp_hs_server);
+       adapter->hfp_hs_server = NULL;
+       return -1;
 }
 
 static int audio_probe(struct btd_device *device, GSList *uuids)
@@ -848,8 +849,6 @@ static struct audio_adapter *audio_adapter_get(struct btd_adapter *adapter)
        adp = find_adapter(adapters, adapter);
        if (!adp) {
                adp = audio_adapter_create(adapter);
-               if (!adp)
-                       return NULL;
                adapters = g_slist_append(adapters, adp);
        } else
                audio_adapter_ref(adp);
@@ -880,8 +879,15 @@ static void state_changed(struct btd_adapter *adapter, gboolean powered)
                /* telephony driver already initialized*/
                if (telephony == TRUE)
                        return;
+#ifdef __TIZEN_PATCH__
+               if (telephony_init())
+                       telephony = FALSE;
+               else
+                       telephony = TRUE;
+#else
                telephony_init();
                telephony = TRUE;
+#endif
                return;
        }
 
@@ -912,15 +918,14 @@ static int headset_server_probe(struct btd_adapter *adapter)
        if (!adp)
                return -EINVAL;
 
-       btd_adapter_register_powered_callback(adapter, state_changed);
-       state_changed(adapter, TRUE);
-
        err = headset_server_init(adp);
        if (err < 0) {
                audio_adapter_unref(adp);
                return err;
        }
 
+       btd_adapter_register_powered_callback(adapter, state_changed);
+
        return 0;
 }
 
@@ -931,6 +936,8 @@ static void headset_server_remove(struct btd_adapter *adapter)
 
        DBG("path %s", path);
 
+       btd_adapter_unregister_powered_callback(adapter, state_changed);
+
        adp = find_adapter(adapters, adapter);
        if (!adp)
                return;
@@ -957,20 +964,23 @@ static void headset_server_remove(struct btd_adapter *adapter)
                adp->hfp_ag_server = NULL;
        }
 
-       btd_adapter_unregister_powered_callback(adapter, state_changed);
-
        audio_adapter_unref(adp);
 }
 
 static int gateway_server_probe(struct btd_adapter *adapter)
 {
        struct audio_adapter *adp;
+       int err;
 
        adp = audio_adapter_get(adapter);
        if (!adp)
                return -EINVAL;
 
-       return gateway_server_init(adp);
+       err = gateway_server_init(adp);
+       if (err < 0)
+               audio_adapter_unref(adp);
+
+       return err;
 }
 
 static void gateway_server_remove(struct btd_adapter *adapter)
@@ -990,6 +1000,7 @@ static void gateway_server_remove(struct btd_adapter *adapter)
        }
 
        if (adp->hfp_hs_server) {
+               g_io_channel_shutdown(adp->hfp_hs_server, TRUE, NULL);
                g_io_channel_unref(adp->hfp_hs_server);
                adp->hfp_hs_server = NULL;
        }
@@ -1041,6 +1052,7 @@ static int avrcp_server_probe(struct btd_adapter *adapter)
        struct audio_adapter *adp;
        const gchar *path = adapter_get_path(adapter);
        bdaddr_t src;
+       int err;
 
        DBG("path %s", path);
 
@@ -1050,7 +1062,11 @@ static int avrcp_server_probe(struct btd_adapter *adapter)
 
        adapter_get_address(adapter, &src);
 
-       return avrcp_register(connection, &src, config);
+       err = avrcp_register(connection, &src, config);
+       if (err < 0)
+               audio_adapter_unref(adp);
+
+       return err;
 }
 
 static void avrcp_server_remove(struct btd_adapter *adapter)
@@ -1075,6 +1091,7 @@ static int media_server_probe(struct btd_adapter *adapter)
        struct audio_adapter *adp;
        const gchar *path = adapter_get_path(adapter);
        bdaddr_t src;
+       int err;
 
        DBG("path %s", path);
 
@@ -1084,7 +1101,11 @@ static int media_server_probe(struct btd_adapter *adapter)
 
        adapter_get_address(adapter, &src);
 
-       return media_register(connection, path, &src);
+       err = media_register(connection, path, &src);
+       if (err < 0)
+               audio_adapter_unref(adp);
+
+       return err;
 }
 
 static void media_server_remove(struct btd_adapter *adapter)
@@ -1281,12 +1302,13 @@ void audio_manager_exit(void)
        btd_unregister_device_driver(&audio_driver);
 }
 
-struct audio_device *manager_find_device(const char *path,
+GSList *manager_find_devices(const char *path,
                                        const bdaddr_t *src,
                                        const bdaddr_t *dst,
                                        const char *interface,
                                        gboolean connected)
 {
+       GSList *result = NULL;
        GSList *l;
 
        for (l = devices; l != NULL; l = l->next) {
@@ -1324,10 +1346,28 @@ struct audio_device *manager_find_device(const char *path,
                if (connected && !audio_device_is_active(dev, interface))
                        continue;
 
-               return dev;
+               result = g_slist_append(result, dev);
        }
 
-       return NULL;
+       return result;
+}
+
+struct audio_device *manager_find_device(const char *path,
+                                       const bdaddr_t *src,
+                                       const bdaddr_t *dst,
+                                       const char *interface,
+                                       gboolean connected)
+{
+       struct audio_device *result;
+       GSList *l;
+
+       l = manager_find_devices(path, src, dst, interface, connected);
+       if (l == NULL)
+               return NULL;
+
+       result = l->data;
+       g_slist_free(l);
+       return result;
 }
 
 struct audio_device *manager_get_device(const bdaddr_t *src,
index cfc646c..f1d3021 100644 (file)
@@ -46,6 +46,12 @@ struct audio_device *manager_find_device(const char *path,
                                        const char *interface,
                                        gboolean connected);
 
+GSList *manager_find_devices(const char *path,
+                                       const bdaddr_t *src,
+                                       const bdaddr_t *dst,
+                                       const char *interface,
+                                       gboolean connected);
+
 struct audio_device *manager_get_device(const bdaddr_t *src,
                                        const bdaddr_t *dst,
                                        gboolean create);
index a363b8e..1956653 100644 (file)
@@ -29,6 +29,8 @@
 
 #include <errno.h>
 
+#include <bluetooth/uuid.h>
+
 #include <glib.h>
 #include <gdbus.h>
 
 #include "gateway.h"
 #include "manager.h"
 
-#ifndef DBUS_TYPE_UNIX_FD
-#define DBUS_TYPE_UNIX_FD -1
-#endif
-
 #define MEDIA_INTERFACE "org.bluez.Media"
 #define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint"
 #define MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer"
@@ -67,6 +65,7 @@ struct media_adapter {
 };
 
 struct endpoint_request {
+       struct media_endpoint   *endpoint;
        DBusMessage             *msg;
        DBusPendingCall         *call;
        media_endpoint_cb_t     cb;
@@ -85,9 +84,9 @@ struct media_endpoint {
        guint                   hs_watch;
        guint                   ag_watch;
        guint                   watch;
-       struct endpoint_request *request;
-       struct media_transport  *transport;
+       GSList                  *requests;
        struct media_adapter    *adapter;
+       GSList                  *transports;
 };
 
 struct media_player {
@@ -102,6 +101,7 @@ struct media_player {
        guint                   track_watch;
        uint8_t                 status;
        uint32_t                position;
+       uint8_t                 volume;
        GTimer                  *timer;
 };
 
@@ -127,15 +127,22 @@ static void endpoint_request_free(struct endpoint_request *request)
        g_free(request);
 }
 
-static void media_endpoint_cancel(struct media_endpoint *endpoint)
+static void media_endpoint_cancel(struct endpoint_request *request)
 {
-       struct endpoint_request *request = endpoint->request;
+       struct media_endpoint *endpoint = request->endpoint;
 
        if (request->call)
                dbus_pending_call_cancel(request->call);
 
+       endpoint->requests = g_slist_remove(endpoint->requests, request);
+
        endpoint_request_free(request);
-       endpoint->request = NULL;
+}
+
+static void media_endpoint_cancel_all(struct media_endpoint *endpoint)
+{
+       while (endpoint->requests != NULL)
+               media_endpoint_cancel(endpoint->requests->data);
 }
 
 static void media_endpoint_destroy(struct media_endpoint *endpoint)
@@ -150,11 +157,10 @@ static void media_endpoint_destroy(struct media_endpoint *endpoint)
        if (endpoint->ag_watch)
                gateway_remove_state_cb(endpoint->ag_watch);
 
-       if (endpoint->request)
-               media_endpoint_cancel(endpoint);
+       media_endpoint_cancel_all(endpoint);
 
-       if (endpoint->transport)
-               media_transport_destroy(endpoint->transport);
+       g_slist_free_full(endpoint->transports,
+                               (GDestroyNotify) media_transport_destroy);
 
        g_dbus_remove_watch(adapter->conn, endpoint->watch);
        g_free(endpoint->capabilities);
@@ -200,18 +206,12 @@ static void headset_setconf_cb(struct media_endpoint *endpoint, void *ret,
        headset_shutdown(dev);
 }
 
-static void clear_configuration(struct media_endpoint *endpoint)
+static void clear_configuration(struct media_endpoint *endpoint,
+                                       struct media_transport *transport)
 {
        DBusConnection *conn;
        DBusMessage *msg;
        const char *path;
-       struct media_transport *transport = endpoint->transport;
-
-       if (endpoint->transport == NULL)
-               return;
-
-       if (endpoint->request)
-               media_endpoint_cancel(endpoint);
 
        conn = endpoint->adapter->conn;
 
@@ -223,19 +223,27 @@ static void clear_configuration(struct media_endpoint *endpoint)
                goto done;
        }
 
-       path = media_transport_get_path(endpoint->transport);
+       path = media_transport_get_path(transport);
        dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &path,
                                                        DBUS_TYPE_INVALID);
        g_dbus_send_message(conn, msg);
 done:
-       endpoint->transport = NULL;
+       endpoint->transports = g_slist_remove(endpoint->transports, transport);
        media_transport_destroy(transport);
 }
 
+static void clear_endpoint(struct media_endpoint *endpoint)
+{
+       media_endpoint_cancel_all(endpoint);
+
+       while (endpoint->transports != NULL)
+               clear_configuration(endpoint, endpoint->transports->data);
+}
+
 static void endpoint_reply(DBusPendingCall *call, void *user_data)
 {
-       struct media_endpoint *endpoint = user_data;
-       struct endpoint_request *request = endpoint->request;
+       struct endpoint_request *request = user_data;
+       struct media_endpoint *endpoint = request->endpoint;
        DBusMessage *reply;
        DBusError err;
        gboolean value;
@@ -256,7 +264,7 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data)
                        if (request->cb)
                                request->cb(endpoint, NULL, size,
                                                        request->user_data);
-                       clear_configuration(endpoint);
+                       clear_endpoint(endpoint);
                        dbus_message_unref(reply);
                        dbus_error_free(&err);
                        return;
@@ -266,7 +274,6 @@ static void endpoint_reply(DBusPendingCall *call, void *user_data)
                goto done;
        }
 
-       dbus_error_init(&err);
        if (dbus_message_is_method_call(request->msg, MEDIA_ENDPOINT_INTERFACE,
                                "SelectConfiguration")) {
                DBusMessageIter args, array;
@@ -296,9 +303,8 @@ done:
        if (request->cb)
                request->cb(endpoint, ret, size, request->user_data);
 
-       if (endpoint->request)
-               endpoint_request_free(endpoint->request);
-       endpoint->request = NULL;
+       endpoint->requests = g_slist_remove(endpoint->requests, request);
+       endpoint_request_free(request);
 }
 
 static gboolean media_endpoint_async_call(DBusConnection *conn,
@@ -310,9 +316,6 @@ static gboolean media_endpoint_async_call(DBusConnection *conn,
 {
        struct endpoint_request *request;
 
-       if (endpoint->request)
-               return FALSE;
-
        request = g_new0(struct endpoint_request, 1);
 
        /* Timeout should be less than avdtp request timeout (4 seconds) */
@@ -323,13 +326,16 @@ static gboolean media_endpoint_async_call(DBusConnection *conn,
                return FALSE;
        }
 
-       dbus_pending_call_set_notify(request->call, endpoint_reply, endpoint, NULL);
+       dbus_pending_call_set_notify(request->call, endpoint_reply, request,
+                                                                       NULL);
 
+       request->endpoint = endpoint;
        request->msg = msg;
        request->cb = cb;
        request->destroy = destroy;
        request->user_data = user_data;
-       endpoint->request = request;
+
+       endpoint->requests = g_slist_append(endpoint->requests, request);
 
        DBG("Calling %s: name = %s path = %s", dbus_message_get_member(msg),
                        dbus_message_get_destination(msg),
@@ -348,9 +354,6 @@ static gboolean select_configuration(struct media_endpoint *endpoint,
        DBusConnection *conn;
        DBusMessage *msg;
 
-       if (endpoint->request != NULL)
-               return FALSE;
-
        conn = endpoint->adapter->conn;
 
        msg = dbus_message_new_method_call(endpoint->sender, endpoint->path,
@@ -369,6 +372,31 @@ static gboolean select_configuration(struct media_endpoint *endpoint,
                                                                destroy);
 }
 
+static gint transport_device_cmp(gconstpointer data, gconstpointer user_data)
+{
+       struct media_transport *transport = (struct media_transport *) data;
+       const struct audio_device *device = user_data;
+
+       if (device == media_transport_get_dev(transport))
+               return 0;
+
+       return -1;
+}
+
+static struct media_transport *find_device_transport(
+                                       struct media_endpoint *endpoint,
+                                       struct audio_device *device)
+{
+       GSList *match;
+
+       match = g_slist_find_custom(endpoint->transports, device,
+                                                       transport_device_cmp);
+       if (match == NULL)
+               return NULL;
+
+       return match->data;
+}
+
 static gboolean set_configuration(struct media_endpoint *endpoint,
                                        struct audio_device *device,
                                        uint8_t *configuration, size_t size,
@@ -380,15 +408,18 @@ static gboolean set_configuration(struct media_endpoint *endpoint,
        DBusMessage *msg;
        const char *path;
        DBusMessageIter iter;
+       struct media_transport *transport;
 
-       if (endpoint->transport != NULL || endpoint->request != NULL)
+       transport = find_device_transport(endpoint, device);
+
+       if (transport != NULL)
                return FALSE;
 
        conn = endpoint->adapter->conn;
 
-       endpoint->transport = media_transport_create(conn, endpoint, device,
+       transport = media_transport_create(conn, endpoint, device,
                                                configuration, size);
-       if (endpoint->transport == NULL)
+       if (transport == NULL)
                return FALSE;
 
        msg = dbus_message_new_method_call(endpoint->sender, endpoint->path,
@@ -396,15 +427,18 @@ static gboolean set_configuration(struct media_endpoint *endpoint,
                                                "SetConfiguration");
        if (msg == NULL) {
                error("Couldn't allocate D-Bus message");
+               media_transport_destroy(transport);
                return FALSE;
        }
 
+       endpoint->transports = g_slist_append(endpoint->transports, transport);
+
        dbus_message_iter_init_append(msg, &iter);
 
-       path = media_transport_get_path(endpoint->transport);
+       path = media_transport_get_path(transport);
        dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
 
-       transport_get_properties(endpoint->transport, &iter);
+       transport_get_properties(transport, &iter);
 
        return media_endpoint_async_call(conn, msg, endpoint, cb, user_data,
                                                                destroy);
@@ -440,16 +474,20 @@ static void headset_state_changed(struct audio_device *dev,
                                        void *user_data)
 {
        struct media_endpoint *endpoint = user_data;
+       struct media_transport *transport;
 
        DBG("");
 
+       if (bacmp(&endpoint->adapter->src, &dev->src) != 0)
+               return;
+
        switch (new_state) {
        case HEADSET_STATE_DISCONNECTED:
-               if (endpoint->transport &&
-                       media_transport_get_dev(endpoint->transport) == dev) {
+               transport = find_device_transport(endpoint, dev);
 
+               if (transport != NULL) {
                        DBG("Clear endpoint %p", endpoint);
-                       clear_configuration(endpoint);
+                       clear_configuration(endpoint, transport);
                }
                break;
        case HEADSET_STATE_CONNECTING:
@@ -551,17 +589,17 @@ static void clear_config(struct a2dp_sep *sep, void *user_data)
 {
        struct media_endpoint *endpoint = user_data;
 
-       clear_configuration(endpoint);
+       clear_endpoint(endpoint);
 }
 
 static void set_delay(struct a2dp_sep *sep, uint16_t delay, void *user_data)
 {
        struct media_endpoint *endpoint = user_data;
 
-       if (endpoint->transport == NULL)
+       if (endpoint->transports == NULL)
                return;
 
-       media_transport_update_delay(endpoint->transport, delay);
+       media_transport_update_delay(endpoint->transports->data, delay);
 }
 
 static struct a2dp_endpoint a2dp_endpoint = {
@@ -577,10 +615,7 @@ static void a2dp_destroy_endpoint(void *user_data)
 {
        struct media_endpoint *endpoint = user_data;
 
-       if (endpoint->transport) {
-               media_transport_destroy(endpoint->transport);
-               endpoint->transport = NULL;
-       }
+       clear_endpoint(endpoint);
 
        endpoint->sep = NULL;
        release_endpoint(endpoint);
@@ -603,16 +638,19 @@ static void gateway_state_changed(struct audio_device *dev,
                                        void *user_data)
 {
        struct media_endpoint *endpoint = user_data;
+       struct media_transport *transport;
 
        DBG("");
 
+       if (bacmp(&endpoint->adapter->src, &dev->src) != 0)
+               return;
+
        switch (new_state) {
        case GATEWAY_STATE_DISCONNECTED:
-               if (endpoint->transport &&
-                       media_transport_get_dev(endpoint->transport) == dev) {
-
+               transport = find_device_transport(endpoint, dev);
+               if (transport != NULL) {
                        DBG("Clear endpoint %p", endpoint);
-                       clear_configuration(endpoint);
+                       clear_configuration(endpoint, transport);
                }
                break;
        case GATEWAY_STATE_CONNECTING:
@@ -626,6 +664,78 @@ static void gateway_state_changed(struct audio_device *dev,
        }
 }
 
+static gboolean endpoint_init_a2dp_source(struct media_endpoint *endpoint,
+                                               gboolean delay_reporting,
+                                               int *err)
+{
+       endpoint->sep = a2dp_add_sep(&endpoint->adapter->src,
+                                       AVDTP_SEP_TYPE_SOURCE, endpoint->codec,
+                                       delay_reporting, &a2dp_endpoint,
+                                       endpoint, a2dp_destroy_endpoint, err);
+       if (endpoint->sep == NULL)
+               return FALSE;
+
+       return TRUE;
+}
+
+static gboolean endpoint_init_a2dp_sink(struct media_endpoint *endpoint,
+                                               gboolean delay_reporting,
+                                               int *err)
+{
+       endpoint->sep = a2dp_add_sep(&endpoint->adapter->src,
+                                       AVDTP_SEP_TYPE_SINK, endpoint->codec,
+                                       delay_reporting, &a2dp_endpoint,
+                                       endpoint, a2dp_destroy_endpoint, err);
+       if (endpoint->sep == NULL)
+               return FALSE;
+
+       return TRUE;
+}
+
+static gboolean endpoint_init_ag(struct media_endpoint *endpoint, int *err)
+{
+       GSList *list;
+       GSList *l;
+
+       endpoint->hs_watch = headset_add_state_cb(headset_state_changed,
+                                                               endpoint);
+       list = manager_find_devices(NULL, &endpoint->adapter->src, BDADDR_ANY,
+                                               AUDIO_HEADSET_INTERFACE, TRUE);
+
+       for (l = list; l != NULL; l = l->next) {
+               struct audio_device *dev = l->data;
+
+               set_configuration(endpoint, dev, NULL, 0,
+                                               headset_setconf_cb, dev, NULL);
+       }
+
+       g_slist_free(list);
+
+       return TRUE;
+}
+
+static gboolean endpoint_init_hs(struct media_endpoint *endpoint, int *err)
+{
+       GSList *list;
+       GSList *l;
+
+       endpoint->ag_watch = gateway_add_state_cb(gateway_state_changed,
+                                                               endpoint);
+       list = manager_find_devices(NULL, &endpoint->adapter->src, BDADDR_ANY,
+                                               AUDIO_GATEWAY_INTERFACE, TRUE);
+
+       for (l = list; l != NULL; l = l->next) {
+               struct audio_device *dev = l->data;
+
+               set_configuration(endpoint, dev, NULL, 0,
+                                               gateway_setconf_cb, dev, NULL);
+       }
+
+       g_slist_free(list);
+
+       return TRUE;
+}
+
 static struct media_endpoint *media_endpoint_create(struct media_adapter *adapter,
                                                const char *sender,
                                                const char *path,
@@ -637,6 +747,7 @@ static struct media_endpoint *media_endpoint_create(struct media_adapter *adapte
                                                int *err)
 {
        struct media_endpoint *endpoint;
+       gboolean succeeded;
 
        endpoint = g_new0(struct media_endpoint, 1);
        endpoint->sender = g_strdup(sender);
@@ -652,46 +763,28 @@ static struct media_endpoint *media_endpoint_create(struct media_adapter *adapte
 
        endpoint->adapter = adapter;
 
-       if (strcasecmp(uuid, A2DP_SOURCE_UUID) == 0) {
-               endpoint->sep = a2dp_add_sep(&adapter->src,
-                                       AVDTP_SEP_TYPE_SOURCE, codec,
-                                       delay_reporting, &a2dp_endpoint,
-                                       endpoint, a2dp_destroy_endpoint, err);
-               if (endpoint->sep == NULL)
-                       goto failed;
-       } else if (strcasecmp(uuid, A2DP_SINK_UUID) == 0) {
-               endpoint->sep = a2dp_add_sep(&adapter->src,
-                                       AVDTP_SEP_TYPE_SINK, codec,
-                                       delay_reporting, &a2dp_endpoint,
-                                       endpoint, a2dp_destroy_endpoint, err);
-               if (endpoint->sep == NULL)
-                       goto failed;
-       } else if (strcasecmp(uuid, HFP_AG_UUID) == 0 ||
-                                       strcasecmp(uuid, HSP_AG_UUID) == 0) {
-               struct audio_device *dev;
+       if (strcasecmp(uuid, A2DP_SOURCE_UUID) == 0)
+               succeeded = endpoint_init_a2dp_source(endpoint,
+                                                       delay_reporting, err);
+       else if (strcasecmp(uuid, A2DP_SINK_UUID) == 0)
+               succeeded = endpoint_init_a2dp_sink(endpoint,
+                                                       delay_reporting, err);
+       else if (strcasecmp(uuid, HFP_AG_UUID) == 0 ||
+                                       strcasecmp(uuid, HSP_AG_UUID) == 0)
+               succeeded = endpoint_init_ag(endpoint, err);
+       else if (strcasecmp(uuid, HFP_HS_UUID) == 0 ||
+                                       strcasecmp(uuid, HSP_HS_UUID) == 0)
+               succeeded = endpoint_init_hs(endpoint, err);
+       else {
+               succeeded = FALSE;
 
-               endpoint->hs_watch = headset_add_state_cb(headset_state_changed,
-                                                               endpoint);
-               dev = manager_find_device(NULL, &adapter->src, BDADDR_ANY,
-                                               AUDIO_HEADSET_INTERFACE, TRUE);
-               if (dev)
-                       set_configuration(endpoint, dev, NULL, 0,
-                                               headset_setconf_cb, dev, NULL);
-       } else if (strcasecmp(uuid, HFP_HS_UUID) == 0 ||
-                                       strcasecmp(uuid, HSP_HS_UUID) == 0) {
-               struct audio_device *dev;
-
-               endpoint->ag_watch = gateway_add_state_cb(gateway_state_changed,
-                                                               endpoint);
-               dev = manager_find_device(NULL, &adapter->src, BDADDR_ANY,
-                                               AUDIO_GATEWAY_INTERFACE, TRUE);
-               if (dev)
-                       set_configuration(endpoint, dev, NULL, 0,
-                                               gateway_setconf_cb, dev, NULL);
-       } else {
                if (err)
                        *err = -EINVAL;
-               goto failed;
+       }
+
+       if (!succeeded) {
+               g_free(endpoint);
+               return NULL;
        }
 
        endpoint->watch = g_dbus_add_disconnect_watch(adapter->conn, sender,
@@ -704,10 +797,6 @@ static struct media_endpoint *media_endpoint_create(struct media_adapter *adapte
        if (err)
                *err = 0;
        return endpoint;
-
-failed:
-       g_free(endpoint);
-       return NULL;
 }
 
 static struct media_endpoint *media_adapter_find_endpoint(
@@ -1255,6 +1344,32 @@ static uint32_t get_position(void *user_data)
        return mp->position + sec * 1000 + msec;
 }
 
+static void set_volume(uint8_t volume, struct audio_device *dev, void *user_data)
+{
+       struct media_player *mp = user_data;
+       GSList *l;
+
+       if (mp->volume == volume)
+               return;
+
+       mp->volume = volume;
+
+       for (l = mp->adapter->endpoints; l; l = l->next) {
+               struct media_endpoint *endpoint = l->data;
+               struct media_transport *transport;
+
+               /* Volume is A2DP only */
+               if (endpoint->sep == NULL)
+                       continue;
+
+               transport = find_device_transport(endpoint, dev);
+               if (transport == NULL)
+                       continue;
+
+               media_transport_update_volume(transport, volume);
+       }
+}
+
 static struct avrcp_player_cb player_cb = {
        .get_setting = get_setting,
        .set_setting = set_setting,
@@ -1262,7 +1377,8 @@ static struct avrcp_player_cb player_cb = {
        .get_uid = get_uid,
        .get_metadata = get_metadata,
        .get_position = get_position,
-       .get_status = get_status
+       .get_status = get_status,
+       .set_volume = set_volume
 };
 
 static void media_player_exit(DBusConnection *connection, void *user_data)
@@ -1371,9 +1487,6 @@ static gboolean set_property(struct media_player *mp, const char *key,
 
        DBG("%s=%s", key, value);
 
-       if (!mp->settings)
-               mp->settings = g_hash_table_new(g_direct_hash, g_direct_equal);
-
        g_hash_table_replace(mp->settings, GUINT_TO_POINTER(attr),
                                                GUINT_TO_POINTER(val));
 
@@ -1595,6 +1708,8 @@ static struct media_player *media_player_create(struct media_adapter *adapter,
                return NULL;
        }
 
+       mp->settings = g_hash_table_new(g_direct_hash, g_direct_equal);
+
        adapter->players = g_slist_append(adapter->players, mp);
 
        info("Player registered: sender=%s path=%s", sender, path);
@@ -1706,11 +1821,18 @@ static DBusMessage *unregister_player(DBusConnection *conn, DBusMessage *msg,
        return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 }
 
-static GDBusMethodTable media_methods[] = {
-       { "RegisterEndpoint",   "oa{sv}",       "",     register_endpoint },
-       { "UnregisterEndpoint", "o",            "",     unregister_endpoint },
-       { "RegisterPlayer",     "oa{sv}a{sv}","",       register_player },
-       { "UnregisterPlayer",   "o",            "",     unregister_player },
+static const GDBusMethodTable media_methods[] = {
+       { GDBUS_METHOD("RegisterEndpoint",
+               GDBUS_ARGS({ "endpoint", "o" }, { "properties", "a{sv}" }),
+               NULL, register_endpoint) },
+       { GDBUS_METHOD("UnregisterEndpoint",
+               GDBUS_ARGS({ "endpoint", "o" }), NULL, unregister_endpoint) },
+       { GDBUS_METHOD("RegisterPlayer",
+               GDBUS_ARGS({ "player", "o" }, { "properties", "a{sv}" },
+                                               { "metadata", "a{sv}" }),
+               NULL, register_player) },
+       { GDBUS_METHOD("UnregisterPlayer",
+               GDBUS_ARGS({ "player", "o" }), NULL, unregister_player) },
        { },
 };
 
@@ -1733,9 +1855,6 @@ int media_register(DBusConnection *conn, const char *path, const bdaddr_t *src)
 {
        struct media_adapter *adapter;
 
-       if (DBUS_TYPE_UNIX_FD < 0)
-               return -EPERM;
-
        adapter = g_new0(struct media_adapter, 1);
        adapter->conn = dbus_connection_ref(conn);
        bacpy(&adapter->src, src);
index 85566a3..b9da805 100644 (file)
@@ -212,7 +212,7 @@ static void *playback_hw_thread(void *param)
                        char c = 'w';
                        int frags = periods - prev_periods, n;
 
-                       data->hw_ptr += frags * data->io.period_size;
+                       data->hw_ptr += frags * data->io.period_size;
                        data->hw_ptr %= data->io.buffer_size;
 
                        for (n = 0; n < frags; n++) {
index 2d5db18..6b21e47 100644 (file)
@@ -555,24 +555,26 @@ static DBusMessage *sink_get_properties(DBusConnection *conn,
        return reply;
 }
 
-static GDBusMethodTable sink_methods[] = {
-       { "Connect",            "",     "",     sink_connect,
-                                               G_DBUS_METHOD_FLAG_ASYNC },
-       { "Disconnect",         "",     "",     sink_disconnect,
-                                               G_DBUS_METHOD_FLAG_ASYNC },
-       { "IsConnected",        "",     "b",    sink_is_connected,
-                                               G_DBUS_METHOD_FLAG_DEPRECATED },
-       { "GetProperties",      "",     "a{sv}",sink_get_properties },
-       { NULL, NULL, NULL, NULL }
+static const GDBusMethodTable sink_methods[] = {
+       { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, sink_connect) },
+       { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, sink_disconnect) },
+       { GDBUS_DEPRECATED_METHOD("IsConnected",
+                       NULL, GDBUS_ARGS({ "connected", "b" }),
+                       sink_is_connected) },
+       { GDBUS_METHOD("GetProperties",
+                               NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                               sink_get_properties) },
+       { }
 };
 
-static GDBusSignalTable sink_signals[] = {
-       { "Connected",                  "",     G_DBUS_SIGNAL_FLAG_DEPRECATED },
-       { "Disconnected",               "",     G_DBUS_SIGNAL_FLAG_DEPRECATED },
-       { "Playing",                    "",     G_DBUS_SIGNAL_FLAG_DEPRECATED },
-       { "Stopped",                    "",     G_DBUS_SIGNAL_FLAG_DEPRECATED },
-       { "PropertyChanged",            "sv"    },
-       { NULL, NULL }
+static const GDBusSignalTable sink_signals[] = {
+       { GDBUS_DEPRECATED_SIGNAL("Connected", NULL) },
+       { GDBUS_DEPRECATED_SIGNAL("Disconnected", NULL) },
+       { GDBUS_DEPRECATED_SIGNAL("Playing", NULL) },
+       { GDBUS_DEPRECATED_SIGNAL("Stopped", NULL) },
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+       { }
 };
 
 static void sink_free(struct audio_device *dev)
@@ -649,11 +651,11 @@ gboolean sink_is_active(struct audio_device *dev)
        return FALSE;
 }
 
-avdtp_state_t sink_get_state(struct audio_device *dev)
+sink_state_t sink_get_state(struct audio_device *dev)
 {
        struct sink *sink = dev->sink;
 
-       return sink->stream_state;
+       return sink->state;
 }
 
 gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session,
index 7b1902b..4fea5ba 100644 (file)
@@ -42,7 +42,7 @@ gboolean sink_remove_state_cb(unsigned int id);
 struct sink *sink_init(struct audio_device *dev);
 void sink_unregister(struct audio_device *dev);
 gboolean sink_is_active(struct audio_device *dev);
-avdtp_state_t sink_get_state(struct audio_device *dev);
+sink_state_t sink_get_state(struct audio_device *dev);
 gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session,
                                struct avdtp_stream *stream);
 gboolean sink_setup_stream(struct sink *sink, struct avdtp *session);
index 6d266f2..dbba5b9 100644 (file)
@@ -476,18 +476,19 @@ static DBusMessage *source_get_properties(DBusConnection *conn,
        return reply;
 }
 
-static GDBusMethodTable source_methods[] = {
-       { "Connect",            "",     "",     source_connect,
-                                               G_DBUS_METHOD_FLAG_ASYNC },
-       { "Disconnect",         "",     "",     source_disconnect,
-                                               G_DBUS_METHOD_FLAG_ASYNC },
-       { "GetProperties",      "",     "a{sv}",source_get_properties },
-       { NULL, NULL, NULL, NULL }
+static const GDBusMethodTable source_methods[] = {
+       { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, source_connect) },
+       { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, source_disconnect) },
+       { GDBUS_METHOD("GetProperties",
+                               NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                               source_get_properties) },
+       { }
 };
 
-static GDBusSignalTable source_signals[] = {
-       { "PropertyChanged",            "sv"    },
-       { NULL, NULL }
+static const GDBusSignalTable source_signals[] = {
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+       { }
 };
 
 static void source_free(struct audio_device *dev)
@@ -564,11 +565,11 @@ gboolean source_is_active(struct audio_device *dev)
        return FALSE;
 }
 
-avdtp_state_t source_get_state(struct audio_device *dev)
+source_state_t source_get_state(struct audio_device *dev)
 {
        struct source *source = dev->source;
 
-       return source->stream_state;
+       return source->state;
 }
 
 gboolean source_new_stream(struct audio_device *dev, struct avdtp *session,
index 7837284..695bded 100644 (file)
@@ -43,7 +43,7 @@ gboolean source_remove_state_cb(unsigned int id);
 struct source *source_init(struct audio_device *dev);
 void source_unregister(struct audio_device *dev);
 gboolean source_is_active(struct audio_device *dev);
-avdtp_state_t source_get_state(struct audio_device *dev);
+source_state_t source_get_state(struct audio_device *dev);
 gboolean source_new_stream(struct audio_device *dev, struct avdtp *session,
                                struct avdtp_stream *stream);
 gboolean source_setup_stream(struct source *source, struct avdtp *session);
index 1f89079..2f89139 100644 (file)
@@ -378,20 +378,34 @@ static DBusMessage *set_subscriber_number(DBusConnection *conn,
        return dbus_message_new_method_return(msg);
 }
 
-static GDBusMethodTable dummy_methods[] = {
-       { "OutgoingCall",       "s",    "",     outgoing_call           },
-       { "IncomingCall",       "s",    "",     incoming_call           },
-       { "CancelCall",         "",     "",     cancel_call             },
-       { "SignalStrength",     "u",    "",     signal_strength         },
-       { "BatteryLevel",       "u",    "",     battery_level           },
-       { "RoamingStatus",      "b",    "",     roaming_status          },
-       { "RegistrationStatus", "b",    "",     registration_status     },
-       { "SetSubscriberNumber","s",    "",     set_subscriber_number   },
+static const GDBusMethodTable dummy_methods[] = {
+       { GDBUS_METHOD("OutgoingCall",
+                       GDBUS_ARGS({ "number", "s" }), NULL,
+                       outgoing_call) },
+       { GDBUS_METHOD("IncomingCall",
+                       GDBUS_ARGS({ "number", "s" }), NULL,
+                       incoming_call) },
+       { GDBUS_METHOD("CancelCall", NULL, NULL, cancel_call) },
+       { GDBUS_METHOD("SignalStrength",
+                       GDBUS_ARGS({ "strength", "u" }), NULL,
+                       signal_strength) },
+       { GDBUS_METHOD("BatteryLevel",
+                       GDBUS_ARGS({ "level", "u" }), NULL,
+                       battery_level) },
+       { GDBUS_METHOD("RoamingStatus",
+                       GDBUS_ARGS({ "roaming", "b" }), NULL,
+                       roaming_status) },
+       { GDBUS_METHOD("RegistrationStatus",
+                       GDBUS_ARGS({ "registration", "b" }), NULL,
+                       registration_status) },
+       { GDBUS_METHOD("SetSubscriberNumber",
+                       GDBUS_ARGS({ "number", "s" }), NULL,
+                       set_subscriber_number) },
        { }
 };
 
-static GDBusSignalTable dummy_signals[] = {
-       { "VoiceDial",  "" },
+static const GDBusSignalTable dummy_signals[] = {
+       { GDBUS_SIGNAL("VoiceDial", NULL) },
        { }
 };
 
index 2832062..8a00296 100644 (file)
@@ -1014,7 +1014,7 @@ static void handle_call_status(DBusMessage *msg, const char *call_path)
                                        DBUS_TYPE_UINT32, &cause_type,
                                        DBUS_TYPE_UINT32, &cause,
                                        DBUS_TYPE_INVALID)) {
-               error("Unexpected paramters in Instance.CallStatus() signal");
+               error("Unexpected parameters in Instance.CallStatus() signal");
                return;
        }
 
@@ -1951,9 +1951,10 @@ static DBusMessage *set_callerid(DBusConnection *conn, DBusMessage *msg,
                return btd_error_invalid_args(msg);
 }
 
-static GDBusMethodTable telephony_maemo_methods[] = {
-       {"SetCallerId",         "s",    "",     set_callerid,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
+static const GDBusMethodTable telephony_maemo_methods[] = {
+       { GDBUS_ASYNC_METHOD("SetCallerId",
+                               GDBUS_ARGS({ "id", "s" }), NULL,
+                               set_callerid) },
        { }
 };
 
index dd75422..0727ffe 100644 (file)
@@ -38,7 +38,6 @@
 
 #include <bluetooth/sdp.h>
 
-#include "glib-compat.h"
 #include "log.h"
 #include "telephony.h"
 #include "error.h"
@@ -1386,7 +1385,7 @@ static void handle_call_status(DBusMessage *msg, const char *call_path)
                                        DBUS_TYPE_UINT32, &cause_type,
                                        DBUS_TYPE_UINT32, &cause,
                                        DBUS_TYPE_INVALID)) {
-               error("Unexpected paramters in Instance.CallStatus() signal");
+               error("Unexpected parameters in Instance.CallStatus() signal");
                return;
        }
 
index 3607d7f..961fedd 100644 (file)
@@ -37,7 +37,6 @@
 
 #include <bluetooth/sdp.h>
 
-#include "glib-compat.h"
 #include "log.h"
 #include "telephony.h"
 
index d038d26..d3f4fa4 100644 (file)
 #define CSD_CALL_BUS_NAME      "org.tizen.csd"
 #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_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_REGISTRATION "org.tizen.csd.CSNet.NetworkRegistration"
-#define CSD_CSNET_OPERATOR     "org.tizen.csd.CSNet.NetworkOperator"
-#define CSD_CSNET_SIGNAL       "org.tizen.csd.CSNet.SignalStrength"
-#define CSD_TELEPHONE_BATTERY  "org.tizen.csd.CSNet.BatteryStrength"
-#define CSD_CSNET_SUBSCRIBER   "org.tizen.csd.CSNet.SubscriberNumber"
+#define CSD_DEVICE_INTERFACE   "org.tizen.device"
 
+/* Phonebook definitions */
+#define PHONEBOOK_BUS_NAME     "org.bluez.pb_agent"
+#define PHONEBOOK_PATH         "/org/bluez/pb_agent"
+#define PHONEBOOK_INTERFACE    "org.bluez.PbAgent.At"
 
 #define CALL_FLAG_NONE 0
 #define CALL_FLAG_PRESENTATION_ALLOWED         0x01
 #define CALL_FLAG_PRESENTATION_RESTRICTED      0x02
 
+#define TELEPHONY_CSD_INTERFACE        "org.tizen.telephony.csd"
+#define TELEPHONY_CSD_OBJECT_PATH      "/org/tizen/csd"
+
+#define HFP_AGENT_SERVICE "org.bluez.hfp_agent"
+#define HFP_AGENT_PATH "/org/bluez/hfp_agent"
+#define HFP_AGENT_INTERFACE "Org.Hfp.Bluez.Interface"
+
 /* Call status values as exported by the CSD CALL plugin */
 #define CSD_CALL_STATUS_IDLE                   0
 #define CSD_CALL_STATUS_CREATE                 1
 #define CSD_CALL_STATUS_TERMINATED             15
 #define CSD_CALL_STATUS_SWAP_INITIATED         16
 
-#define CALL_FLAG_NONE                         0
-#define CALL_FLAG_PRESENTATION_ALLOWED         0x01
-#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 PHONEBOOK_STORE_LIST "(\"SM\",\"ME\",\"DC\",\"MC\",\"RC\")"
-#define PHONEBOOK_STORE_LIST_BLUENME "(\"ME\",\"DC\",\"MC\",\"RC\")"
 #define PREFFERED_MESSAGE_STORAGE_LIST "(\"ME\",\"MT\",\"SM\",\"SR\"),(\"ME\",\"MT\",\"SM\",\"SR\"),(\"ME\",\"MT\",\"SM\",\"SR\")"
 #define PHONEBOOK_CHARACTER_SET_LIST "(\"IRA\",\"GSM\",\"UCS2\")"
 #define PHONEBOOK_CHARACTER_SET_SUPPORTED "\"GSM\""
 #define CALL_LOG_COUNT_MAX 30
 #define PHONEBOOK_COUNT_MAX 1000
 
-#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
 
+static const gchar *phonebook_store_list[] =  {
+       "\"ME\"", "\"DC\"", "\"MC\"", "\"RC\""
+};
+
+#define PHONEBOOK_STORE_LIST_SIZE (sizeof(phonebook_store_list)/sizeof(const gchar *))
+
 typedef struct {
        uint8_t utf_8;
        uint8_t gsm;
@@ -114,17 +109,17 @@ typedef struct {
 
  /*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},
-       {0x86,0x1C},{0xA6,0x1D},{0x9F,0x1E},{0x89,0x1F},{0x84,0x5B},
-       {0x96,0x5C},{0x91,0x5D},{0x9C,0x5E},{0x80,0x5F},{0xA4,0x7B},
-       {0xB6,0x7C},{0xB1,0x7D},{0xBC,0x7E},{0xA0,0x7F},
+       {0xA8,0x04}, {0xA9,0x05}, {0xB9,0x06}, {0xAC,0x07}, {0xB2,0x08},
+       {0xB7,0x09}, {0x98,0x0B}, {0xB8,0x0C}, {0x85,0x0E}, {0xA5,0x0F},
+       {0x86,0x1C}, {0xA6,0x1D}, {0x9F,0x1E}, {0x89,0x1F}, {0x84,0x5B},
+       {0x96,0x5C}, {0x91,0x5D}, {0x9C,0x5E}, {0x80,0x5F}, {0xA4,0x7B},
+       {0xB6,0x7C}, {0xB1,0x7D}, {0xBC,0x7E}, {0xA0,0x7F},
 };
 
 /*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},
+       {0x85,0x14}, {0xA1,0x50}, {0x98,0x19}, {0xA0,0x16}, {0x94,0x10},
+       {0xA6,0x12}, {0x93,0x13}, {0x9E,0x1A}, {0x9B,0x14}, {0xA8,0x17},
        {0xA9,0x15},
 };
 
@@ -135,13 +130,19 @@ const GsmUnicodeTable gsm_unicode_CE[] = {
 static DBusConnection *ag_connection = NULL;
 
 static GSList *calls = NULL;
-static GSList *watches = NULL;
 
 static gboolean events_enabled = FALSE;
 static uint32_t callerid = 0;
 
 /* Reference count for determining the call indicator status */
 static GSList *active_calls = NULL;
+static GSList *sender_paths = NULL;
+
+typedef struct {
+       gchar *sender;
+       gchar *path;
+       unsigned int watch_id;
+} sender_path_t;
 
 static struct indicator telephony_ag_indicators[] =
 {
@@ -191,7 +192,7 @@ enum net_registration_status {
 };
 
 struct csd_call {
-       char *object_path;
+       char *path;
        int status;
        gboolean originating;
        gboolean emergency;
@@ -200,6 +201,7 @@ struct csd_call {
        char *number;
        gboolean setup;
        uint32_t call_id;
+       char *sender;
 };
 
 static struct {
@@ -224,19 +226,142 @@ static char *subscriber_number = NULL;   /* Subscriber number */
 
 
 static struct {
-       char path[PHONEBOOK_PATH_LENGTH];
+       int32_t path_id;
        uint32_t type;
        uint32_t max_size;
        uint32_t used;
 } ag_pb_info = {
-       .path = {0,},
+       .path_id = 0,
        .type = 0,
        .max_size = 0,
-       .used =0,
+       .used = 0,
 };
 
+static void free_sender_path(sender_path_t *s_path)
+{
+       if (s_path == NULL)
+               return;
+
+       g_free(s_path->path);
+       g_free(s_path->sender);
+       g_free(s_path);
+}
+
+static void free_sender_list()
+{
+       GSList *l;
+
+       for (l = sender_paths; l != NULL; l = l->next) {
+               free_sender_path(l->data);
+       }
+       g_slist_free(sender_paths);
+       sender_paths = NULL;
+       return;
+}
+
+static int telephony_remove_from_sender_list(const char *sender, const char *path)
+{
+       GSList *l;
+       sender_path_t *s_path;
+
+       if (sender == NULL || path == NULL)
+               return  -EINVAL;
+
+       for (l = sender_paths; l != NULL; l = l->next) {
+               s_path = l->data;
+               if (s_path == NULL)
+                       return -ENOENT;
+               if (g_strcmp0(s_path->path, path) == 0) {
+                       g_dbus_remove_watch(ag_connection, s_path->watch_id);
+                       sender_paths = g_slist_remove(sender_paths, s_path);
+                       free_sender_path(s_path);
+
+                       /*Free sender_paths if no application is registered*/
+                       if (0 == g_slist_length(sender_paths)) {
+                               g_slist_free(sender_paths);
+                               sender_paths = NULL;
+                       }
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+
+static void telephony_app_exit_cb(DBusConnection *conn, void *user_data)
+{
+       sender_path_t *s_path = (sender_path_t *)user_data;
+
+       DBG("+\n");
+       if (!telephony_remove_from_sender_list(s_path->sender, s_path->path))
+               DBG("Application removed \n");
+       else
+               DBG("Application not removed \n");
+       DBG("-\n");
+}
+
+static gboolean telephony_is_registered(const char *path)
+{
+       GSList *l;
+       sender_path_t *s_path;
+
+       if (path == NULL || sender_paths == NULL)
+               return FALSE;
+
+       for (l = sender_paths; l != NULL; l = l->next) {
+               s_path = l->data;
+               if (s_path == NULL)
+                       break;
+
+               if (g_strcmp0(s_path->path, path) == 0) {
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+static gboolean telephony_is_call_allowed(const char *path)
+{
+       GSList *l;
+
+       if (path == NULL)
+               return FALSE;
+
+       /*if call list doesn't exist the call should be allowed, since its a new call*/
+       if (!calls)
+               return TRUE;
+
+       for (l = calls; l != NULL; l = l->next) {
+               struct csd_call *call = l->data;
+
+               if (g_strcmp0(call->path, path) == 0)
+                       return TRUE;
+
+       }
+       return FALSE;
+}
+
+static int telephony_add_to_sender_list(const char *sender, const char *path)
+{
+       sender_path_t *s_path;
+
+       if (sender == NULL || path == NULL)
+               return -EINVAL;
+
+       /*check if already registered*/
+       if (telephony_is_registered(path)) {
+               return -EEXIST;
+       }
+
+       s_path = g_new0(sender_path_t, 1);
+       s_path->path = g_strdup(path);
+       s_path->sender = g_strdup(sender);
+       s_path->watch_id = g_dbus_add_disconnect_watch(ag_connection, sender,
+                                       telephony_app_exit_cb, s_path, NULL);
+       sender_paths = g_slist_append(sender_paths, s_path);
+       return 0;
+}
 
-static struct csd_call *find_call(uint32_t call_id)
+static struct csd_call *find_call_with_id(uint32_t call_id)
 
 {
        GSList *l;
@@ -297,26 +422,14 @@ static struct csd_call *find_call_with_status(int status)
        return NULL;
 }
 
-static void foreach_call_with_status(int status,
-                                       int (*func)(struct csd_call *call))
-{
-       GSList *l;
-
-       for (l = calls; l != NULL; l = l->next) {
-               struct csd_call *call = l->data;
-
-               if (call->status == status)
-                       func(call);
-       }
-}
-
 static void csd_call_free(struct csd_call *call)
 {
        if (!call)
                return;
 
-       g_free(call->object_path);
+       g_free(call->path);
        g_free(call->number);
+       g_free(call->sender);
 
        g_free(call);
 }
@@ -327,6 +440,8 @@ static int release_conference(void)
 
        DBG("+\n");
 
+       DBG("telephony-tizen: releasing conference call");
+
        msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
                                                CSD_CALL_CONFERENCE_PATH,
                                                CSD_CALL_INSTANCE,
@@ -349,19 +464,21 @@ static int reject_call(struct csd_call *call)
 
        DBG("+\n");
 
-       msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-                                               call->object_path,
-                                               CSD_CALL_INSTANCE,
-                                               "Reject");
+       DBG("telephony-tizen: reject_call ");
+
+       msg = dbus_message_new_method_call(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
+                                       HFP_AGENT_INTERFACE, "RejectCall");
        if (!msg) {
                error("Unable to allocate new D-Bus message");
                return -ENOMEM;
        }
-       DBG(" Object Path =[ %s] and Call id = [%d]\n", call->object_path, call->call_id);
+       DBG(" Path =[ %s] and Call id = [%d]\n", call->path, call->call_id);
        if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
+                       DBUS_TYPE_STRING, &call->path,
+                       DBUS_TYPE_STRING, &call->sender,
                        DBUS_TYPE_INVALID)) {
 
-               DBG("dbus_message_append_args -ERROR\n");
+               DBG("dbus_message_append_args -ENOMEM\n");
                dbus_message_unref(msg);
                return -ENOMEM;
        }
@@ -373,25 +490,28 @@ static int reject_call(struct csd_call *call)
        return 0;
 
 }
+
 static int release_call(struct csd_call *call)
 {
        DBusMessage *msg;
 
        DBG("+\n");
 
-       msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-                                               call->object_path,
-                                               CSD_CALL_INSTANCE,
-                                               "Release");
+       DBG("telephony-tizen: release_call ");
+
+       msg = dbus_message_new_method_call(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
+                                       HFP_AGENT_INTERFACE, "ReleaseCall");
        if (!msg) {
                error("Unable to allocate new D-Bus message");
                return -ENOMEM;
        }
-       DBG(" Object Path =[ %s] and Call id = [%d]\n", call->object_path, call->call_id);
+       DBG("Path =[ %s] and Call id = [%d]\n", call->path, call->call_id);
        if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
+                       DBUS_TYPE_STRING, &call->path,
+                       DBUS_TYPE_STRING, &call->sender,
                        DBUS_TYPE_INVALID)) {
 
-               DBG("dbus_message_append_args -ERROR\n");
+               DBG("dbus_message_append_args -ENOMEM\n");
                dbus_message_unref(msg);
                return -ENOMEM;
        }
@@ -453,19 +573,19 @@ static int answer_call(struct csd_call *call)
        DBusMessage *msg;
        DBG("+\n");
 
-       msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-                                               call->object_path,
-                                               CSD_CALL_INSTANCE,
-                                               "Answer");
+       msg = dbus_message_new_method_call(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
+                                       HFP_AGENT_INTERFACE, "AnswerCall");
        if (!msg) {
                error("Unable to allocate new D-Bus message");
                return -ENOMEM;
        }
 
        if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
+                       DBUS_TYPE_STRING, &call->path,
+                       DBUS_TYPE_STRING, &call->sender,
                        DBUS_TYPE_INVALID)) {
 
-               DBG("dbus_message_append_args -ERROR\n");
+               DBG("dbus_message_append_args -ENOMEM\n");
                dbus_message_unref(msg);
                return -ENOMEM;
        }
@@ -495,7 +615,7 @@ static void call_set_status(struct csd_call *call, dbus_uint32_t status)
        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,
+       DBG("Call %s Call id %d changed from %s to %s", call->path, call->call_id,
                call_status_str[prev_status], call_status_str[status]);
 
        if (prev_status == status) {
@@ -647,188 +767,6 @@ static void call_set_status(struct csd_call *call, dbus_uint32_t status)
        DBG("-\n");
 }
 
-/**
- * This API shall invoke a dbus method call to bluetooth framework to split the call
- *
- * @return             This function returns zero on success.
- * @param[in]          call    Pointer to the Call information structure.
- * @param[out]         NONE.
- */
-static int split_call(struct csd_call *call)
-{
-       DBusMessage *msg;
-
-       DBG("+n");
-
-       if (NULL != call) {
-               msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-                                                       call->object_path,
-                                                       CSD_CALL_INSTANCE,
-                                                       "Split");
-               if (!msg) {
-                       error("Unable to allocate new D-Bus message");
-                       return -ENOMEM;
-               }
-
-               g_dbus_send_message(ag_connection, msg);
-       }
-       DBG("-\n");
-
-       return 0;
-}
-/**
- * This API shall invoke a dbus method call to bluetooth framework to swap the calls
- *
- * @return             This function returns zero on success.
- * @param[in]          NONE.
- * @param[out]         NONE.
- */
-static int swap_calls(void)
-{
-       DBusMessage *msg;
-       DBG("+\n");
-
-       msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                                               CSD_CALL_INTERFACE,
-                                               "Swap");
-       if (!msg) {
-               error("Unable to allocate new D-Bus message");
-               return -ENOMEM;
-       }
-
-       g_dbus_send_message(ag_connection, msg);
-       DBG("-\n");
-
-       return 0;
-}
-
-/**
- * This API shall invoke a dbus method call to bluetooth framework to hold the call
- *
- * @return             This function returns zero on success.
- * @param[in]          call    Pointer to the Call information structure.
- * @param[out]         NONE.
- */
-static int hold_call(struct csd_call *call)
-{
-       DBusMessage *msg;
-       DBG("+\n");
-
-       msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                                               CSD_CALL_INTERFACE,
-                                               "Hold");
-       if (!msg) {
-               error("Unable to allocate new D-Bus message");
-               return -ENOMEM;
-       }
-       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)) {
-
-                       DBG("dbus_message_append_args -ERROR\n");
-                       dbus_message_unref(msg);
-                       return -ENOMEM;
-               }
-
-               g_dbus_send_message(ag_connection, msg);
-       }
-       DBG("-\n");
-
-       return 0;
-}
-
-
-/**
- * This API shall invoke a dbus method call to bluetooth framework to unhold the call
- *
- * @return             This function returns zero on success.
- * @param[in]          call    Pointer to the Call information structure.
- * @param[out]         NONE.
- */
-static int unhold_call(struct csd_call *call)
-{
-       DBusMessage *msg;
-       DBG("+\n");
-
-       msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                                               CSD_CALL_INTERFACE,
-                                               "Unhold");
-       if (!msg) {
-               error("Unable to allocate new D-Bus message");
-               return -ENOMEM;
-       }
-
-       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)) {
-
-                       DBG("dbus_message_append_args -ERROR\n");
-                       dbus_message_unref(msg);
-                       return -ENOMEM;
-               }
-
-               g_dbus_send_message(ag_connection, msg);
-       }
-       DBG("-\n");
-
-       return 0;
-}
-
-/**
- * This API shall invoke a dbus method call to bluetooth framework to create conmference calls
- *
- * @return             This function returns zero on success.
- * @param[in]          NONE.
- * @param[out]         NONE.
- */
-static int create_conference(void)
-{
-       DBusMessage *msg;
-       DBG("+\n");
-
-       msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                                               CSD_CALL_INTERFACE,
-                                               "Conference");
-       if (!msg) {
-               error("Unable to allocate new D-Bus message");
-               return -ENOMEM;
-       }
-
-       g_dbus_send_message(ag_connection, msg);
-       DBG("-\n");
-
-       return 0;
-}
-/**
- * This API shall invoke a dbus method call to bluetooth framework to transfer the call
- *
- * @return             This function returns zero on success.
- * @param[in]          NONE.
- * @param[out]         NONE.
- */
-static int call_transfer(void)
-{
-       DBusMessage *msg;
-       DBG("+\n");
-
-       msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                                               CSD_CALL_INTERFACE,
-                                               "Transfer");
-       if (!msg) {
-               error("Unable to allocate new D-Bus message");
-               return -ENOMEM;
-       }
-
-       g_dbus_send_message(ag_connection, msg);
-       DBG("-\n");
-
-       return 0;
-}
-
 static void telephony_chld_reply(DBusPendingCall *call, void *data)
 {
        DBusMessage *reply = dbus_pending_call_steal_reply(call);
@@ -857,174 +795,94 @@ 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;
+       uint32_t chld_value;
+       GSList *l = NULL;
+       sender_path_t *s_path = NULL;
 
        DBG("+\n");
 
-       if (strlen(cmd) > 1)
-               idx = &cmd[1];
-       else
-               idx = NULL;
+       DBG("telephony-tizen: got call hold request %s", cmd);
 
-       if (idx)
-               call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
-       else
-               call = NULL;
-#if 0
-       switch (cmd[0]) {
-       case '0':
-               if (find_call_with_status(CSD_CALL_STATUS_WAITING))
-                       foreach_call_with_status(CSD_CALL_STATUS_WAITING,
-                                                               release_call);
-               else
-                       foreach_call_with_status(CSD_CALL_STATUS_HOLD,
-                                                               release_call);
-               break;
-       case '1':
-               if (idx) {
-                       if (call)
-                               err = release_call(call);
-                       break;
-               }
-               foreach_call_with_status(CSD_CALL_STATUS_ACTIVE, release_call);
-               call = find_call_with_status(CSD_CALL_STATUS_WAITING);
-               if (call) {
-                       err = answer_call(call);
-               }
-               else {
-                       struct csd_call *held;
-                       held = find_call_with_status(CSD_CALL_STATUS_HOLD);
-                       if(held)
-                               err = unhold_call(held);
-               }
-               break;
-       case '2':
-               if (idx) {
-                       if (call)
-                               err = split_call(call);
-               } else {
-                       struct csd_call *held, *wait;
-
-                       call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
-                       held = find_call_with_status(CSD_CALL_STATUS_HOLD);
-                       wait = find_call_with_status(CSD_CALL_STATUS_WAITING);
-
-                       if (wait)
-                               err = answer_call(wait);
-                       else if (call && held)
-                               err = swap_calls();
-                       else {
-                               if (call)
-                                       err = hold_call(call);
-                               if (held)
-                                       err = unhold_call(held);
+       /* Find any Ongoing call, in active/held/waiting */
+       if (NULL == (call = find_call_with_status(CSD_CALL_STATUS_ACTIVE)))
+               if (NULL == (call = find_call_with_status(
+                                               CSD_CALL_STATUS_HOLD)))
+                       if (NULL == (call = find_call_with_status(
+                                               CSD_CALL_STATUS_WAITING))) {
+                               DBG("No Onging Call \n");
+                               telephony_call_hold_rsp(telephony_device,
+                                                       CME_ERROR_AG_FAILURE);
+                               return;
                        }
+
+       /*Get sender path using call path*/
+       for (l = sender_paths; l != NULL; l = l->next) {
+               s_path = l->data;
+               if (s_path == NULL) {
+                       telephony_call_hold_rsp(telephony_device,
+                                                       CME_ERROR_AG_FAILURE);
+                       return;
                }
-               break;
-       case '3':
-               if (find_call_with_status(CSD_CALL_STATUS_HOLD) ||
-                               find_call_with_status(CSD_CALL_STATUS_WAITING))
-                       err = create_conference();
-               break;
-       case '4':
-               err = call_transfer();
-               break;
-       default:
-               DBG("Unknown call hold request");
-               break;
+               if (g_strcmp0(s_path->path, call->path) == 0)
+                       break;
        }
 
-       if (err)
-               telephony_call_hold_rsp(telephony_device,
-                                       CME_ERROR_AG_FAILURE);
-       else
-               telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
-#else
-       idx = &cmd[0];
-       chld_value = strtol(idx, NULL, 0);
-
-       err = dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                                       CSD_CALL_INSTANCE, "Threeway",
-                                       telephony_chld_reply, telephony_device,
-                                       DBUS_TYPE_INT32, &chld_value,
-                                       DBUS_TYPE_INVALID);
-
-       if (err)
+       if (s_path == NULL) {
                telephony_call_hold_rsp(telephony_device,
-                                       CME_ERROR_AG_FAILURE);
-#endif
-       DBG("-\n");
-}
-
-static void handle_incoming_call(DBusMessage *msg)
-{
-
-       const char *number, *call_path;
-       struct csd_call *call;
-       uint32_t call_id;
-
-       DBG("+\n");
-       DBG("handle_incoming_call()\n");
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_OBJECT_PATH, &call_path,
-                                       DBUS_TYPE_STRING, &number,
-                                       DBUS_TYPE_UINT32, &call_id,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in Call.Coming() signal");
+                                               CME_ERROR_AG_FAILURE);
                return;
        }
 
-       call = g_new0(struct csd_call, 1);
-       call->object_path = g_strdup(call_path);
-       call->call_id = call_id;
-       call->number = g_strdup(number);
-       calls = g_slist_append(calls, call);
+       idx = &cmd[0];
+       chld_value = strtoul(idx, NULL, 0);
 
-       DBG("Incoming call to %s from number %s call id %d", call_path, number, call_id);
+       DBG("Sender = %s path = %s \n", s_path->sender, s_path->path);
 
-       if (find_call_with_status(CSD_CALL_STATUS_ACTIVE) ||
-                       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 {
-               telephony_incoming_call_ind(call->number,
-                                               number_type(call->number));
+       err = dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
+                               HFP_AGENT_INTERFACE, "ThreewayCall",
+                               telephony_chld_reply, telephony_device,
+                               DBUS_TYPE_UINT32, &chld_value,
+                               DBUS_TYPE_STRING, &call->path,
+                               DBUS_TYPE_STRING, &call->sender,
+                               DBUS_TYPE_INVALID);
 
-               call_set_status(call, CSD_CALL_STATUS_COMING);
-       }
-       telephony_update_indicator(telephony_ag_indicators, "callsetup",
-                                       EV_CALLSETUP_INCOMING);
+       if (err)
+               telephony_call_hold_rsp(telephony_device,
+                                       CME_ERROR_AG_FAILURE);
        DBG("-\n");
 }
 
-static void update_registration_status(uint8_t status)
+static int update_registration_status(uint8_t status)
 {
        uint8_t new_status;
+       int ret = 0;
        DBG("+\n");
 
        new_status = status;
 
        if (net.status == new_status)
-               return;
+               return ret;
 
        switch (new_status) {
        case NETWORK_REG_STATUS_HOME:
-               telephony_update_indicator(telephony_ag_indicators, "roam",
+               ret = telephony_update_indicator(telephony_ag_indicators, "roam",
                                                        EV_ROAM_INACTIVE);
-               if (net.status > NETWORK_REG_STATUS_ROAMING)
-                       telephony_update_indicator(telephony_ag_indicators,
+
+               if (net.status > NETWORK_REG_STATUS_ROAMING) {
+                       ret = telephony_update_indicator(telephony_ag_indicators,
                                                        "service",
                                                        EV_SERVICE_PRESENT);
+               }
                break;
        case NETWORK_REG_STATUS_ROAMING:
-               telephony_update_indicator(telephony_ag_indicators, "roam",
+               ret = telephony_update_indicator(telephony_ag_indicators, "roam",
                                                        EV_ROAM_ACTIVE);
-               if (net.status > NETWORK_REG_STATUS_ROAMING)
-                       telephony_update_indicator(telephony_ag_indicators,
+
+               if (net.status > NETWORK_REG_STATUS_ROAMING) {
+                       ret = telephony_update_indicator(telephony_ag_indicators,
                                                        "service",
                                                        EV_SERVICE_PRESENT);
+               }
                break;
        case NETWORK_REG_STATUS_OFFLINE:
        case NETWORK_REG_STATUS_SEARCHING:
@@ -1034,19 +892,23 @@ static void update_registration_status(uint8_t status)
        case NETWORK_REG_STATUS_NO_COVERAGE:
        case NETWORK_REG_STATUS_REJECTED:
        case NETWORK_REG_STATUS_UNKOWN:
-               if (net.status < NETWORK_REG_STATUS_OFFLINE)
-                       telephony_update_indicator(telephony_ag_indicators,
+               if (net.status < NETWORK_REG_STATUS_OFFLINE) {
+                       ret = telephony_update_indicator(telephony_ag_indicators,
                                                        "service",
                                                        EV_SERVICE_NONE);
+               }
                break;
        }
 
        net.status = new_status;
 
+       DBG("telephony-tizen: registration status changed: %d", status);
        DBG("-\n");
+
+       return ret;
 }
 
-static void update_signal_strength(int32_t signal_bars)
+static int update_signal_strength(int32_t signal_bars)
 {
        DBG("+\n");
 
@@ -1061,16 +923,15 @@ static void update_signal_strength(int32_t signal_bars)
        }
 
        if (net.signal_bars == signal_bars)
-               return;
-
-       telephony_update_indicator(telephony_ag_indicators, "signal", signal_bars);
+               return 0;
 
        net.signal_bars = signal_bars;
+       DBG("telephony-tizen: signal strength updated: %d/5", signal_bars);
 
-       DBG("-\n");
+       return telephony_update_indicator(telephony_ag_indicators, "signal", signal_bars);
 }
 
-static void update_battery_strength(int32_t battery_level)
+static int update_battery_strength(int32_t battery_level)
 {
        int current_battchg = 0;
 
@@ -1088,299 +949,407 @@ static void update_battery_strength(int32_t battery_level)
                battery_level = 5;
        }
        if (current_battchg == battery_level)
-               return;
+               return 0;
+
+       DBG("telephony-tizen: battery strength updated: %d/5", battery_level);
+       DBG("-\n");
 
-       telephony_update_indicator(telephony_ag_indicators,
+       return telephony_update_indicator(telephony_ag_indicators,
                        "battchg", battery_level);
+}
 
 
+static int update_operator_name(const char *name)
+{
+       DBG("+\n");
+       if (name == NULL)
+               return -EINVAL;
+
+       g_free(net.operator_name);
+       net.operator_name = g_strndup(name, 16);
+       DBG("telephony-tizen: operator name updated: %s", name);
        DBG("-\n");
+       return 0;
 }
 
-
-static void handle_outgoing_call(DBusMessage *msg)
+static int update_subscriber_number(const char *number)
 {
-       const char *number, *call_path;
-       struct csd_call *call;
-       uint32_t call_id;
-
        DBG("+\n");
-       DBG("handle_outgoing_call()\n");
+       if (number == NULL)
+               return -EINVAL;
 
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_OBJECT_PATH, &call_path,
-                                       DBUS_TYPE_STRING, &number,
-                                       DBUS_TYPE_UINT32, &call_id,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in Call.Coming() signal");
-               return;
+       g_free(subscriber_number);
+       subscriber_number = g_strdup(number);
+       DBG("telephony-tizen: subscriber_number updated: %s", subscriber_number);
+       DBG("-\n");
+       return 0;
+}
+
+static DBusMessage *telephony_error_reply(DBusMessage *msg, int error)
+{
+       switch (error) {
+       case -ENOENT:
+               return btd_error_not_available(msg);
+       case -ENODEV:
+               return btd_error_not_connected(msg);
+       case -EBUSY:
+               return btd_error_busy(msg);
+       case -EINVAL:
+               return btd_error_invalid_args(msg);
+       case -EEXIST:
+               return btd_error_already_exists(msg);
+       case -ENOMEM:
+               return btd_error_failed(msg, "No memory");
+       case -EIO:
+               return btd_error_failed(msg, "I/O error");
+       default:
+               return dbus_message_new_method_return(msg);
        }
+}
+
+static struct csd_call *create_call(DBusMessage *msg, const char *path,
+                                       const char *number, uint32_t call_id,
+                                       const char *sender)
+
+{
+       struct csd_call *call;
 
        call = g_new0(struct csd_call, 1);
-       call->object_path = g_strdup(call_path);
+       call->path = g_strdup(path);
        call->call_id = call_id;
        call->number = g_strdup(number);
+       call->sender = g_strdup(sender);
        calls = g_slist_append(calls, call);
 
-       DBG("Outgoing call to %s from number %s call id %d", call_path, number, call_id);
-
-       call_set_status(call, CSD_CALL_STATUS_CREATE);
-
-       telephony_update_indicator(telephony_ag_indicators, "callsetup",
-                                       EV_CALLSETUP_OUTGOING);
-       DBG("-\n");
+       return call;
 }
 
-static void handle_create_requested(DBusMessage *msg)
-{
-       DBG("+\n");
-       DBG("handle_create_requested()\n");
-       DBG("-\n");
-}
-
-static void handle_call_status(DBusMessage *msg, const char *call_path)
+static DBusMessage *incoming(DBusConnection *conn, DBusMessage *msg,
+                                       void *data)
 {
+       const char *number, *call_path;
+       const char *sender;
        struct csd_call *call;
-       dbus_uint32_t status, call_id;
+       uint32_t call_id;
+       int ret;
        DBG("+\n");
+       DBG("telephony_incoming()\n");
 
        if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_UINT32, &status,
+                                       DBUS_TYPE_STRING, &call_path,
+                                       DBUS_TYPE_STRING, &number,
                                        DBUS_TYPE_UINT32, &call_id,
+                                       DBUS_TYPE_STRING, &sender,
                                        DBUS_TYPE_INVALID)) {
-               error("Unexpected paramters in Instance.CallStatus() signal");
-               return;
+
+               return btd_error_invalid_args(msg);
        }
 
-       DBG("status = [%d] and call_id = [%d]\n", status, call_id);
-       call = find_call(call_id);
-       if (!call) {
-/*
-       call_path is equal to CSD_CALL_PATH then we should update the call list
-       since the call_path is sent from native AG applicaton
+       ret = telephony_is_registered(call_path);
+       if (!ret)
+               return telephony_error_reply(msg,  -ENOENT);
 
-       Added for updation of the call status if the call is not added inthe call list
-*/
-               if (g_str_equal(CSD_CALL_PATH, call_path)) {
-                       call = g_new0(struct csd_call, 1);
-                       call->object_path = g_strdup(call_path);
-                       call->call_id = call_id;
-                       calls = g_slist_append(calls, call);
-               }
-       }
+       /*Check in the active call list, if any of the call_path exists if not don't allow
+       the call since it is initated by other applicatoin*/
 
-       if (status > 16) {
-               error("Invalid call status %u", status);
-               return;
-       }
+       ret = telephony_is_call_allowed(call_path);
+       if (!ret)
+               return telephony_error_reply(msg,  -ENOENT);
 
-       call_set_status(call, status);
-       DBG("-\n");
-}
 
-static void update_operator_name(const char *name)
-{
-       DBG("+\n");
-       if (name == NULL)
-               return;
+       call = create_call(msg, call_path, number, call_id, sender);
 
-       g_free(net.operator_name);
-       net.operator_name = g_strndup(name, 16);
-       DBG("-\n");
-}
+       DBG("Incoming call to %s from number %s call id %d", call_path, number, call_id);
+       ret = telephony_update_indicator(telephony_ag_indicators, "callsetup",
+                                       EV_CALLSETUP_INCOMING);
+       if (ret)
+               return telephony_error_reply(msg, ret);
 
-static void update_subscriber_number(const char *number)
-{
-       DBG("+\n");
-       if (number == NULL)
-               return;
+       if (find_call_with_status(CSD_CALL_STATUS_ACTIVE) ||
+                       find_call_with_status(CSD_CALL_STATUS_HOLD)) {
+               ret = telephony_call_waiting_ind(call->number,
+                                               number_type(call->number));
+               if (ret)
+                       return telephony_error_reply(msg, ret);
 
-       g_free(subscriber_number);
-       subscriber_number = g_strdup(number);
-       DBG("-\n");
-}
+               call_set_status(call, CSD_CALL_STATUS_WAITING);
+       } else {
+               ret = telephony_incoming_call_ind(call->number,
+                                               number_type(call->number));
+               if (ret)
+                       return telephony_error_reply(msg, ret);
 
-static void handle_conference(DBusMessage *msg, gboolean joined)
-{
-       DBG("+\n");
-       DBG("handle_conference()\n");
+               call_set_status(call, CSD_CALL_STATUS_COMING);
+       }
        DBG("-\n");
+       return dbus_message_new_method_return(msg);
 }
 
-static void handle_registration_changed(DBusMessage *msg)
+static DBusMessage *outgoing(DBusConnection *conn, DBusMessage *msg,
+                                       void *data)
 {
-       uint8_t status;
+       const char *number, *call_path;
+       const char *sender;
+       struct csd_call *call;
+       uint32_t call_id;
+       int ret;
 
        DBG("+\n");
-       DBG("handle_registration_changed()\n");
+       DBG("telephony_outgoing_call()\n");
 
        if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_BYTE, &status,
+                                       DBUS_TYPE_STRING, &call_path,
+                                       DBUS_TYPE_STRING, &number,
+                                       DBUS_TYPE_UINT32, &call_id,
+                                       DBUS_TYPE_STRING, &sender,
                                        DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in RegistrationChanged");
-               return;
+               return btd_error_invalid_args(msg);
        }
 
-       update_registration_status((uint8_t) status);
-       DBG("-\n");
-}
+       ret = telephony_is_registered(call_path);
+       if (!ret)
+               return telephony_error_reply(msg, -ENOENT);
 
-static void handle_operator_name_changed(DBusMessage *msg)
-{
-       const char *name;
+       /*Check in the active call list, if any of the call_path exists if not don't allow
+       the call since it is initated by other applicatoin*/
 
-       DBG("+\n");
+       ret = telephony_is_call_allowed(call_path);
+       if (!ret)
+               return telephony_error_reply(msg, -ENOENT);
 
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_STRING, &name,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in OperatorNameChanged");
-               return;
-       }
+       call = create_call(msg, call_path, number, call_id, sender);
+
+       DBG("Outgoing call to %s from number %s call id %d", call_path, number, call_id);
+
+       call_set_status(call, CSD_CALL_STATUS_CREATE);
+
+       ret = telephony_update_indicator(telephony_ag_indicators, "callsetup",
+                                       EV_CALLSETUP_OUTGOING);
+       if (ret)
+               return telephony_error_reply(msg, ret);
 
-       update_operator_name(name);
        DBG("-\n");
+       return dbus_message_new_method_return(msg);
 }
 
-static void handle_signal_bars_changed(DBusMessage *msg)
+static DBusMessage *set_call_status(DBusConnection *conn, DBusMessage *msg,
+                                       void *data)
 {
-       int32_t signal_bars;
+       struct csd_call *call;
+       dbus_uint32_t status, call_id;
+       const char *call_path;
+       const char *sender;
+       int ret;
 
        DBG("+\n");
 
        if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_INT32, &signal_bars,
+                                       DBUS_TYPE_STRING, &call_path,
+                                       DBUS_TYPE_UINT32, &status,
+                                       DBUS_TYPE_UINT32, &call_id,
+                                       DBUS_TYPE_STRING, &sender,
                                        DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in SignalBarsChanged");
-               return;
+               error("Unexpected paramters in Instance.CallStatus() signal");
+               return btd_error_invalid_args(msg);
        }
 
-       update_signal_strength(signal_bars);
-       DBG("-\n");
-}
+       if (status > 16) {
+               return btd_error_invalid_args(msg);
+       }
 
-static void handle_battery_bars_changed(DBusMessage *msg)
-{
-       int32_t battery_level;
+       ret = telephony_is_registered(call_path);
+       if (!ret)
+               return telephony_error_reply(msg, -ENOENT);
 
-       DBG("+\n");
+       ret = telephony_is_call_allowed(call_path);
+       if (!ret)
+               return telephony_error_reply(msg, -ENOENT);
 
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_INT32, &battery_level,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in SignalBarsChanged");
-               return;
-       }
+       DBG("status = [%d] and call_id = [%d] \n", status, call_id);
+
+       call = find_call_with_id(call_id);
+       if (!call) {
+/*
+       call_path is equal to CSD_CALL_PATH then we should update the call list
+       since the call_path is sent from native AG applicaton
 
-       update_battery_strength(battery_level);
+       Added for updation of the call status if the call is not added in the call list
+*/
+               call = create_call(msg, call_path, NULL, call_id, sender);
+       }
+       call_set_status(call, status);
        DBG("-\n");
+       return dbus_message_new_method_return(msg);
 }
 
-static void handle_subscriber_number_changed(DBusMessage *msg)
+static DBusMessage *register_telephony_agent(DBusConnection *conn, DBusMessage *msg,
+                                       void *data)
 {
-       const char *number;
+       gboolean flag;
+       const char *sender;
+       const char *path;
+       int ret;
 
        DBG("+\n");
 
        if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_STRING, &number,
+                                       DBUS_TYPE_BOOLEAN, &flag,
+                                       DBUS_TYPE_STRING, &path,
+                                       DBUS_TYPE_STRING, &sender,
                                        DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in SubscriberNumberChanged");
-               return;
+               error("Unexpected parameters in RegisterSenderPath");
+               return btd_error_invalid_args(msg);
        }
 
-       update_subscriber_number(number);
-       DBG("-\n");
-}
-static gboolean signal_filter(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       const char *path = NULL;
+       DBG("flag = %d \n", flag);
+       DBG("Sender = %s \n", sender);
+       DBG("path = %s \n", path);
 
-       DBG("+\n");
+       if (flag)
+               ret = telephony_add_to_sender_list(sender, path);
+       else
+               ret = telephony_remove_from_sender_list(sender, path);
 
-       path = dbus_message_get_path(msg);
-
-       if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
-               handle_incoming_call(msg);
-       else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
-               handle_outgoing_call(msg);
-       else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
-                                                       "CreateRequested"))
-               handle_create_requested(msg);
-       else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
-               handle_call_status(msg, path);
-       else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
-               handle_conference(msg, TRUE);
-       else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
-               handle_conference(msg, FALSE);
-       else if (dbus_message_is_signal(msg, CSD_CSNET_REGISTRATION,
-                               "RegistrationChanged"))
-               handle_registration_changed(msg);
-       else if (dbus_message_is_signal(msg, CSD_CSNET_OPERATOR,
-                               "OperatorNameChanged"))
-               handle_operator_name_changed(msg);
-       else if (dbus_message_is_signal(msg, CSD_CSNET_SIGNAL,
-                               "SignalBarsChanged"))
-               handle_signal_bars_changed(msg);
-       else if (dbus_message_is_signal(msg, CSD_TELEPHONE_BATTERY,
-                               "BatteryBarsChanged"))
-               handle_battery_bars_changed(msg);
-       else if (dbus_message_is_signal(msg, CSD_CSNET_SUBSCRIBER,
-                               "SubscriberNumberChanged"))
-               handle_subscriber_number_changed(msg);
+       if (ret)
+               return telephony_error_reply(msg, ret);
 
        DBG("-\n");
-       return TRUE;
+
+       return dbus_message_new_method_return(msg);
 }
 
-static void dbus_add_watch(const char *sender, const char *path,
-                               const char *interface, const char *member)
+static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
+                                       void *data)
 {
-       guint watch;
-
-       watch = g_dbus_add_signal_watch(ag_connection, sender, path, interface,
-                                       member, signal_filter, NULL, NULL);
-
-       watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
-}
+       const char *property;
+       DBusMessageIter iter;
+       DBusMessageIter sub;
+       int ret;
+
+       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 (g_str_equal("RegistrationChanged", property)) {
+               uint8_t value;
+               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BYTE)
+                       return btd_error_invalid_args(msg);
+
+               dbus_message_iter_get_basic(&sub, &value);
+
+               ret = update_registration_status(value);
+               if (ret)
+                       return telephony_error_reply(msg, ret);
+       } else if (g_str_equal("OperatorNameChanged", property)) {
+               const char *name;
+               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
+                       return btd_error_invalid_args(msg);
+
+               dbus_message_iter_get_basic(&sub, &name);
+
+               ret = update_operator_name(name);
+               if (ret)
+                       return telephony_error_reply(msg, ret);
+       } else if (g_str_equal("SignalBarsChanged", property)) {
+               int32_t value;
+               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INT32)
+                       return btd_error_invalid_args(msg);
+
+               dbus_message_iter_get_basic(&sub, &value);
+               ret = update_signal_strength(value);
+               if (ret)
+                       return telephony_error_reply(msg, ret);
+
+       } else if (g_str_equal("BatteryBarsChanged", property)) {
+               int32_t value;
+               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INT32)
+                       return btd_error_invalid_args(msg);
+
+               dbus_message_iter_get_basic(&sub, &value);
+               ret = update_battery_strength(value);
+               if (ret)
+                       return telephony_error_reply(msg, ret);
+
+       } else if (g_str_equal("SubscriberNumberChanged", property)) {
+               const char *number;
+               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
+                       return btd_error_invalid_args(msg);
+
+               dbus_message_iter_get_basic(&sub, &number);
+               ret = update_subscriber_number(number);
+               if (ret)
+                       return telephony_error_reply(msg, ret);
+       }
+
+       return dbus_message_new_method_return(msg);
+}
+
+static GDBusMethodTable telephony_methods[] = {
+       { GDBUS_METHOD("Incoming",
+                       GDBUS_ARGS({ "path", "s" }, { "number", "s" },
+                                       { "id", "u" }, { "sender", "s" }),
+                       NULL,
+                       incoming) },
+       { GDBUS_METHOD("Outgoing",
+                       GDBUS_ARGS({ "path", "s" }, { "number", "s" },
+                                       { "id", "u" }, { "sender", "s" }),
+                       NULL,
+                       outgoing) },
+       { GDBUS_METHOD("SetCallStatus",
+                       GDBUS_ARGS({ "path", "s" }, { "status", "u" },
+                                       { "id", "u" }, { "sender", "s" }),
+                       NULL,
+                       set_call_status) },
+       { GDBUS_METHOD("RegisterTelephonyAgent",
+                       GDBUS_ARGS({ "flag", "b" }, { "path", "s" },
+                                       { "sender", "s" }),
+                       NULL,
+                       register_telephony_agent) },
+       { GDBUS_METHOD("SetProperty",
+                       GDBUS_ARGS({ "name", "s" }, { "property", "v" }),
+                       NULL,
+                       set_property) },
+       { }
+};
 
-static const char *telephony_memory_dial_lookup(int location)
+static void path_unregister(void *data)
 {
-       /*memory dial not supported*/
-       if (location == 1)
-               return NULL;
-       else
-               return NULL;
+       DBG("+\n");
+       g_dbus_unregister_interface(ag_connection, TELEPHONY_CSD_OBJECT_PATH,
+                                       TELEPHONY_CSD_INTERFACE);
+       DBG("-\n");
 }
 
 /*API's that shall be ported*/
-
 int telephony_init(void)
 {
        uint32_t features = AG_FEATURE_EC_ANDOR_NR |
                                AG_FEATURE_REJECT_A_CALL |
                                AG_FEATURE_ENHANCED_CALL_STATUS |
-                               AG_FEATURE_THREE_WAY_CALLING;
+                               AG_FEATURE_THREE_WAY_CALLING |
+                               AG_FEATURE_VOICE_RECOGNITION;
        int i;
 
        DBG("");
 
        ag_connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
 
-       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");
+       if (!g_dbus_register_interface(ag_connection, TELEPHONY_CSD_OBJECT_PATH,
+                                       TELEPHONY_CSD_INTERFACE,
+                                       telephony_methods, NULL, NULL,
+                                       NULL, path_unregister)) {
+               error("D-Bus failed to register %s interface", TELEPHONY_CSD_INTERFACE);
+               return -1;
+       }
 
        /* Reset indicators */
        for (i = 0; telephony_ag_indicators[i].desc != NULL; i++) {
@@ -1391,17 +1360,13 @@ int telephony_init(void)
        }
 
        /*Initializatoin of the indicators*/
-       telephony_ready_ind(features, telephony_ag_indicators, BTRH_NOT_SUPPORTED,
-                                                               telephony_chld_str);
+       telephony_ready_ind(features, telephony_ag_indicators,
+                                       BTRH_NOT_SUPPORTED,
+                                       telephony_chld_str);
 
        return 0;
 }
 
-static void remove_watch(gpointer data)
-{
-       g_dbus_remove_watch(ag_connection, GPOINTER_TO_UINT(data));
-}
-
 void telephony_exit(void)
 {
        DBG("");
@@ -1422,9 +1387,10 @@ void telephony_exit(void)
        g_slist_free(calls);
        calls = NULL;
 
-       g_slist_foreach(watches, (GFunc) remove_watch, NULL);
-       g_slist_free(watches);
-       watches = NULL;
+       free_sender_list();
+
+       g_dbus_unregister_interface(ag_connection, TELEPHONY_CSD_OBJECT_PATH,
+                                               TELEPHONY_CSD_INTERFACE);
 
        dbus_connection_unref(ag_connection);
        ag_connection = NULL;
@@ -1434,10 +1400,12 @@ void telephony_exit(void)
 
 void telephony_device_connected(void *telephony_device)
 {
+       DBG("telephony-tizen: device %p connected", telephony_device);
 }
 
 void telephony_device_disconnected(void *telephony_device)
 {
+       DBG("telephony-tizen: device %p disconnected", telephony_device);
        events_enabled = FALSE;
 }
 
@@ -1450,6 +1418,9 @@ void telephony_event_reporting_req(void *telephony_device, int ind)
 
 void telephony_response_and_hold_req(void *telephony_device, int rh)
 {
+       DBG("telephony-tizen: response_and_hold_req - device %p disconnected",
+               telephony_device);
+
        telephony_response_and_hold_rsp(telephony_device,
                                                CME_ERROR_NOT_SUPPORTED);
 }
@@ -1481,6 +1452,8 @@ void telephony_dial_number_req(void *telephony_device, const char *number)
 {
        uint32_t flags = callerid;
 
+       DBG("telephony-tizen: dial request to %s", number);
+
        if (strncmp(number, "*31#", 4) == 0) {
                number += 4;
                flags = CALL_FLAG_PRESENTATION_ALLOWED;
@@ -1490,19 +1463,20 @@ void telephony_dial_number_req(void *telephony_device, const char *number)
        } else if (number[0] == '>') {
                int location = strtol(&number[1], NULL, 0);
 
-               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 (0 != dbus_method_call_send(HFP_AGENT_SERVICE,
+                               HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
+                               "DialMemory",
+                               telephony_dial_number_reply, telephony_device,
+                               DBUS_TYPE_INT32, &location,
+                               DBUS_TYPE_INVALID)) {
                        telephony_dial_number_rsp(telephony_device,
                                                        CME_ERROR_AG_FAILURE);
                }
                return;
        }
 
-       if (0 != dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                               CSD_CALL_INTERFACE, "DialNo",
+       if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
+                               HFP_AGENT_INTERFACE, "DialNum",
                                NULL, NULL,
                                DBUS_TYPE_STRING, &number,
                                DBUS_TYPE_UINT32, &flags,
@@ -1588,6 +1562,8 @@ void telephony_key_press_req(void *telephony_device, const char *keys)
        struct csd_call *active, *waiting;
        int err;
 
+       DBG("telephony-tizen: got key press request for %s", keys);
+
        waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
        if (!waiting)
                waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
@@ -1612,8 +1588,10 @@ void telephony_key_press_req(void *telephony_device, const char *keys)
 
 void telephony_last_dialed_number_req(void *telephony_device)
 {
-       if (0 != dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                               CSD_CALL_INTERFACE, "DialLastNo",
+       DBG("telephony-tizen: last dialed number request");
+
+       if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
+                               HFP_AGENT_INTERFACE, "DialLastNum",
                                telephony_dial_number_reply, telephony_device,
                                DBUS_TYPE_INVALID)) {
                telephony_dial_number_rsp(telephony_device,
@@ -1624,11 +1602,28 @@ void telephony_last_dialed_number_req(void *telephony_device)
 void telephony_transmit_dtmf_req(void *telephony_device, char tone)
 {
        char buf[2] = { tone, '\0' }, *buf_ptr = buf;
+       struct csd_call *call;
 
-       if (0 != dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                               CSD_CALL_INTERFACE, "SendDtmf",
+       DBG("telephony-tizen: transmit dtmf: %s", buf);
+
+       /* Find any Ongoing call, in active/held/waiting */
+       if (NULL == (call = find_call_with_status(CSD_CALL_STATUS_ACTIVE)))
+               if (NULL == (call = find_call_with_status(
+                                               CSD_CALL_STATUS_HOLD)))
+                       if (NULL == (call = find_call_with_status(
+                                               CSD_CALL_STATUS_WAITING))) {
+                               DBG("No Onging Call \n");
+                               telephony_transmit_dtmf_rsp(telephony_device,
+                                               CME_ERROR_AG_FAILURE);
+                               return;
+                       }
+
+       if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
+                               HFP_AGENT_INTERFACE, "SendDtmf",
                                NULL, NULL,
                                DBUS_TYPE_STRING, &buf_ptr,
+                               DBUS_TYPE_STRING, &call->path,
+                               DBUS_TYPE_STRING, &call->sender,
                                DBUS_TYPE_INVALID)) {
                telephony_transmit_dtmf_rsp(telephony_device,
                                                CME_ERROR_AG_FAILURE);
@@ -1691,6 +1686,8 @@ void telephony_list_current_calls_req(void *telephony_device)
        GSList *l;
        int i;
 
+       DBG("telephony-tizen: list current calls request");
+
        for (l = calls, i = 1; l != NULL; l = l->next, i++) {
                struct csd_call *call = l->data;
                int status, direction, multiparty;
@@ -1724,16 +1721,32 @@ void telephony_operator_selection_req(void *telephony_device)
 
 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
 {
+       DBG("telephony-tizen: got %s NR and EC request",
+                       enable ? "enable" : "disable");
        telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
 }
 
 void telephony_voice_dial_req(void *telephony_device, gboolean enable)
 {
-       telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
+
+       DBG("telephony-tizen: got %s voice dial request",
+                               enable ? "enable" : "disable");
+
+       if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
+                               HFP_AGENT_INTERFACE, "VoiceDial",
+                               NULL, NULL, DBUS_TYPE_BOOLEAN, &enable,
+                               DBUS_TYPE_INVALID)) {
+               telephony_voice_dial_rsp(telephony_device,
+                                               CME_ERROR_AG_FAILURE);
+               return;
+       }
+
+       telephony_voice_dial_rsp(telephony_device, CME_ERROR_NONE);
 }
 
 void telephony_subscriber_number_req(void *telephony_device)
 {
+       DBG("telephony-tizen: subscriber number request");
        if (subscriber_number)
                telephony_subscriber_number_ind(subscriber_number,
                                                number_type(subscriber_number),
@@ -1741,22 +1754,65 @@ void telephony_subscriber_number_req(void *telephony_device)
        telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
 }
 
-void telephony_list_phonebook_store(void *telephony_device)
+static int convert_utf8_gsm(uint8_t ascii, uint8_t utf_8, uint8_t *gsm)
 {
-/*
-       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);
+       uint32_t i;
+
+       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) {
+                               *gsm = gsm_unicode_CE[i].gsm;
+                               return 0;
+                       }
+               }
+       }
+
+       return 1;
+}
+
+static void get_unicode_string(const char *name, char *unicodename)
+{
+       if (NULL != name && NULL != unicodename) {
+               int len = strlen(name);
+               int x, y;
+
+               if (len == 0)
+                       return;
+
+               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] == '_') {
+                                unicodename[y] = ' ';
+                                continue;
+                       }
+
+                       unicodename[y] = name[x];
+               }
+       }
+       return;
 }
 
 static int get_phonebook_count(const char *path, uint32_t *max_size,
-                                                                               uint32_t *used)
+                               uint32_t *used)
 {
        DBusConnection *conn;
-       DBusMessageIter iter;
-       DBusMessageIter value;
        DBusMessage *message, *reply;
        DBusError error;
 
@@ -1766,19 +1822,19 @@ static int get_phonebook_count(const char *path, uint32_t *max_size,
                return -1;
        }
 
-       message = dbus_message_new_method_call("org.bluez.pb_agent",
-                                                                               "/org/bluez/pb_agent",
-                                                                               "org.bluez.PbAgent",
-                                                                               "GetCallLogSize");
+       message = dbus_message_new_method_call(PHONEBOOK_BUS_NAME,
+                                       PHONEBOOK_PATH,
+                                       PHONEBOOK_INTERFACE,
+                                       "GetPhonebookSizeAt");
        if (!message) {
                DBG("Can't allocate new message");
                dbus_connection_unref(conn);
                return -1;
        }
-       dbus_message_iter_init_append(message, &iter);
-       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &path);
 
-       dbus_message_iter_close_container(&iter, &value);
+       dbus_message_append_args(message, DBUS_TYPE_STRING, &path,
+                               DBUS_TYPE_INVALID);
+
        dbus_error_init(&error);
 
        reply = dbus_connection_send_with_reply_and_block(conn,
@@ -1810,14 +1866,16 @@ static int get_phonebook_count(const char *path, uint32_t *max_size,
                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)
                        *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)
@@ -1831,149 +1889,12 @@ static int get_phonebook_count(const char *path, uint32_t *max_size,
        return 0;
 }
 
-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);
-       }
-}
-
-void telephony_set_phonebook_store(void *telephony_device, const char *path)
-{
-       if (NULL != path) {
-               DBG("set phonebook type to [%s]\n", path);
-               g_strlcpy(ag_pb_info.path, path, sizeof(ag_pb_info.path));
-       }
-}
-
-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);
-       }
-}
-
-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) {
-                               *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) {
-                               *gsm = gsm_unicode_CE[i].gsm;
-                               return 0;
-                       }
-               }
-       }
-}
-
-static void get_unicode_string(const char *name, char *unicodename)
-{
-       if (NULL != name || NULL != unicodename) {
-               int len = strlen(name);
-               if (len > 0) {
-                       int x = 0;
-                       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] == '_') {
-                                        unicodename[y] = ' ';
-                                        continue;
-                               }
-
-                               unicodename[y] = name[x];
-                       }
-               }
-       }
-       return;
-}
-
-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);
-
-       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);
-
-               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);
-
-               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 read_phonebook_entries(int start_index, int end_index)
 {
        DBusConnection *conn;
        DBusMessage *message, *reply;
+       DBusMessageIter iter, iter_struct;
        DBusError error;
-       DBusMessageIter iter, iter_struct, entry;
-       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 > (int) ag_pb_info.max_size)
-               end_index = PHONEBOOK_COUNT_MAX ;
 
        conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
        if (!conn) {
@@ -1981,14 +1902,23 @@ static int get_phonebook_list(void *telephony_device, const char* path,
                return -1;
        }
 
-       message = dbus_message_new_method_call("org.bluez.pb_agent",
-                                               "/org/bluez/pb_agent",
-                                               "org.bluez.PbAgent",
-                                               "GetPhonebookList");
+       message = dbus_message_new_method_call(PHONEBOOK_BUS_NAME,
+                                       PHONEBOOK_PATH,
+                                       PHONEBOOK_INTERFACE,
+                                       "GetPhonebookEntriesAt");
        if (!message) {
                DBG("Can't allocate new message");
+               dbus_connection_unref(conn);
                return -1;
        }
+
+       dbus_message_append_args(message,
+                               DBUS_TYPE_STRING,
+                               &phonebook_store_list[ag_pb_info.path_id],
+                               DBUS_TYPE_INT32, &start_index,
+                               DBUS_TYPE_INT32, &end_index,
+                               DBUS_TYPE_INVALID);
+
        dbus_error_init(&error);
 
        reply = dbus_connection_send_with_reply_and_block(conn,
@@ -2001,80 +1931,65 @@ static int get_phonebook_list(void *telephony_device, const char* path,
                } else {
                        DBG("Failed to get contacts");
                }
+
+               dbus_message_unref(message);
+               dbus_connection_unref(conn);
+
                return -1;
        }
 
        dbus_message_iter_init(reply, &iter);
        dbus_message_iter_recurse(&iter, &iter_struct);
 
-       idx = start_index;
-       while (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_STRUCT) {
+       while(dbus_message_iter_get_arg_type(&iter_struct) ==
+                       DBUS_TYPE_STRUCT) {
                const char *name = NULL;
-               const char *tel = NULL;
-               uint32_t handle = 0;
+               const char *number = NULL;
 
-               dbus_message_iter_recurse(&iter_struct, &entry);
+               char *uni_name;
+               char *uni_number;
 
-               dbus_message_iter_get_basic(&entry, &name);
-               dbus_message_iter_next(&entry);
-               dbus_message_iter_get_basic(&entry, &tel);
-               dbus_message_iter_next(&entry);
-               dbus_message_iter_get_basic(&entry, &handle);
+               uint32_t handle = 0;
 
-               DBG("[%d] handle:%d name:%s tel:%s]\n", handle, name, tel);
+               DBusMessageIter entry_iter;
 
-               /*form the packet and sent to the remote headset*/
-               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)) {
-                                       DBG("send_read_phonebook_resp - ERROR\n");
-                                       telephony_read_phonebook_rsp(telephony_device, NULL,
-                                                       CME_ERROR_AG_FAILURE);
+               dbus_message_iter_recurse(&iter_struct,&entry_iter);
 
-                                       dbus_message_unref(message);
-                                       dbus_message_unref(reply);
-                                       dbus_connection_unref(conn);
+               dbus_message_iter_get_basic(&entry_iter, &name);
+               dbus_message_iter_next(&entry_iter);
+               dbus_message_iter_get_basic(&entry_iter, &number);
+               dbus_message_iter_next(&entry_iter);
+               dbus_message_iter_get_basic(&entry_iter, &handle);
+               dbus_message_iter_next(&entry_iter);
 
-                                       return -1;
-                               }
-                               idx++;
-                       }
-               }
                dbus_message_iter_next(&iter_struct);
-       }
 
-       telephony_read_phonebook_rsp(telephony_device, NULL, CME_ERROR_NONE);
+               uni_name = g_strndup(name, PHONEBOOK_NAME_MAX_LENGTH);
+               uni_number = g_strndup(number, PHONEBOOK_NAME_MAX_LENGTH);
+
+               get_unicode_string(name, uni_name);
+               get_unicode_string(number, uni_number);
+
+               telephony_read_phonebook_entries_ind(uni_name,
+                               uni_number, handle);
+
+               g_free(uni_name);
+               g_free(uni_number);
+       }
 
        dbus_message_unref(message);
        dbus_message_unref(reply);
        dbus_connection_unref(conn);
 
-       /*Process the List and send response*/
        return 0;
 }
 
-static int get_call_log_list(void *telephony_device, char* path ,
-                       int32_t start_index, int32_t end_index)
+static int find_phonebook_entries(const char *str)
 {
        DBusConnection *conn;
-       DBusMessage *message = NULL, *reply;
+       DBusMessage *message, *reply;
+       DBusMessageIter iter, iter_struct;
        DBusError error;
-       DBusMessageIter iter, iter_struct, entry;
-       int32_t idx = 0;
-
-       if ((start_index > (int) ag_pb_info.max_size) || (start_index <= 0) ||
-                       (start_index > CALL_LOG_COUNT_MAX)) {
-               return -1;
-       }
-
-       if (end_index > (int) ag_pb_info.max_size)
-               end_index = CALL_LOG_COUNT_MAX ;
-
 
        conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
        if (!conn) {
@@ -2082,27 +1997,22 @@ static int get_call_log_list(void *telephony_device, char* path ,
                return -1;
        }
 
-       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) {
-               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) {
-               message = dbus_message_new_method_call("org.bluez.pb_agent",
-                                                       "/org/bluez/pb_agent",
-                                                       "org.bluez.PbAgent",
-                                                       "GetIncomingCallsList");
-       }
+       message = dbus_message_new_method_call(PHONEBOOK_BUS_NAME,
+                                       PHONEBOOK_PATH,
+                                       PHONEBOOK_INTERFACE,
+                                       "GetPhonebookEntriesFindAt");
        if (!message) {
                DBG("Can't allocate new message");
                dbus_connection_unref(conn);
                return -1;
        }
+
+       dbus_message_append_args(message,
+                               DBUS_TYPE_STRING,
+                               &phonebook_store_list[ag_pb_info.path_id],
+                               DBUS_TYPE_STRING, &str,
+                               DBUS_TYPE_INVALID);
+
        dbus_error_init(&error);
 
        reply = dbus_connection_send_with_reply_and_block(conn,
@@ -2115,132 +2025,238 @@ static int get_call_log_list(void *telephony_device, char* path ,
                } else {
                        DBG("Failed to get contacts");
                }
+
                dbus_message_unref(message);
                dbus_connection_unref(conn);
+
                return -1;
        }
 
        dbus_message_iter_init(reply, &iter);
        dbus_message_iter_recurse(&iter, &iter_struct);
 
-       idx = start_index;
-       while (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_STRUCT) {
+       while(dbus_message_iter_get_arg_type(&iter_struct) ==
+                       DBUS_TYPE_STRUCT) {
                const char *name = NULL;
-               const char *tel = NULL;
-               uint32_t handle = 0;
+               const char *number = NULL;
 
-               dbus_message_iter_recurse(&iter_struct, &entry);
+               char *uni_name;
+               char *uni_number;
 
-               dbus_message_iter_get_basic(&entry, &name);
-               dbus_message_iter_next(&entry);
-               dbus_message_iter_get_basic(&entry, &tel);
-               dbus_message_iter_next(&entry);
-               dbus_message_iter_get_basic(&entry, &handle);
+               uint32_t handle = 0;
 
-               DBG("[%d] handle:%d name:%s tel:%s]\n", handle, name, tel);
+               DBusMessageIter entry_iter;
 
-               /*form the packet and sent to the remote headset*/
-               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) {
-                               /* Need to form the time stamp pkt  also */
-                               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);
+               dbus_message_iter_recurse(&iter_struct,&entry_iter);
 
-                                       dbus_message_unref(message);
-                                       dbus_message_unref(reply);
-                                       dbus_connection_unref(conn);
+               dbus_message_iter_get_basic(&entry_iter, &name);
+               dbus_message_iter_next(&entry_iter);
+               dbus_message_iter_get_basic(&entry_iter, &number);
+               dbus_message_iter_next(&entry_iter);
+               dbus_message_iter_get_basic(&entry_iter, &handle);
+               dbus_message_iter_next(&entry_iter);
 
-                                       return -1;
-                               }
-                               idx++;
-                       }
-               }
                dbus_message_iter_next(&iter_struct);
-       }
 
-       telephony_read_phonebook_rsp(telephony_device, NULL, CME_ERROR_NONE);
+               uni_name = g_strndup(name, PHONEBOOK_NAME_MAX_LENGTH);
+               uni_number = g_strndup(number, PHONEBOOK_NAME_MAX_LENGTH);
+
+               get_unicode_string(name, uni_name);
+               get_unicode_string(number, uni_number);
+
+               telephony_find_phonebook_entries_ind(uni_name, uni_number, handle);
+
+               g_free(uni_name);
+               g_free(uni_number);
+       }
 
        dbus_message_unref(message);
        dbus_message_unref(reply);
        dbus_connection_unref(conn);
 
-       /*Process the List and send response*/
        return 0;
+}
+
+void telephony_select_phonebook_memory_status(void *telephony_device)
+{
+       int32_t path_id = ag_pb_info.path_id;
+       cme_error_t err = CME_ERROR_NONE;
+
+       DBG("telephony-tizen: telephony_read_phonebook_store\n");
 
+       if (path_id < 0 || path_id >= PHONEBOOK_STORE_LIST_SIZE)
+               path_id = 0;
+
+       if (get_phonebook_count(phonebook_store_list[path_id],
+                               &ag_pb_info.max_size, &ag_pb_info.used))
+               err = CME_ERROR_AG_FAILURE;
+
+       telephony_select_phonebook_memory_status_rsp(telephony_device,
+                       phonebook_store_list[path_id],
+                       ag_pb_info.max_size,
+                       ag_pb_info.used,
+                       err);
 }
-void telephony_read_phonebook(void *telephony_device, const char *cmd)
+
+void telephony_select_phonebook_memory_list(void *telephony_device)
 {
-       char *ptr = 0;
+       DBG("telephony-tizen: telephony_select_phonebook_memory_list %d\n", PHONEBOOK_STORE_LIST_SIZE);
+/*
+       For Blue & Me car kit we may have to add  the
+       patch here(similar to the patch done in H1 and H2 )
+*/
+       GString *str;
+       int i  = 0;
 
-       if (NULL != cmd) {
-               int32_t start_index;
-               int32_t end_index;
-               ptr = (char *) strchr(cmd, (int32_t)',');
-               if (NULL == ptr) {
-                       start_index = strtol(cmd, NULL, 0);
-                       end_index = -1;
-                       DBG("start_index = [%d] \n", start_index);
-               } else {
-                       ptr++;
-                       start_index = strtol(cmd, NULL, 0);
-                       end_index = strtol(ptr, NULL, 0);
-                       DBG("start_index = [%d], end_index = [%d] \n",
-                                       start_index, end_index);
+       str = g_string_new("(");
+       while (i < PHONEBOOK_STORE_LIST_SIZE) {
+               if (i  > 0) {
+                       g_string_append(str, ",");
                }
+               g_string_append(str, phonebook_store_list[i]);
+               i++;
+       }
 
-               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;
-                       }
+       g_string_append(str, ")");
+
+       telephony_select_phonebook_memory_list_rsp(telephony_device,
+                       g_string_free(str, FALSE), CME_ERROR_NONE);
+}
+
+void telephony_select_phonebook_memory(void *telephony_device, const gchar *path)
+{
+
+       int i = 0;
+       cme_error_t err;
+
+       DBG("telephony-tizen: telephony_select_phonebook_memory\n");
+       DBG("set phonebook type to [%s]\n", path);
+
+       while (i < PHONEBOOK_STORE_LIST_SIZE) {
+               if (strcmp(phonebook_store_list[i], path) == 0)
+                       break;
+
+               i++;
+       }
+
+       if  (i >= 0 && i < PHONEBOOK_STORE_LIST_SIZE) {
+               err = CME_ERROR_NONE;
+               if (ag_pb_info.path_id != i) {
+                       ag_pb_info.type = 0;
+                       ag_pb_info.max_size = 0;
+                       ag_pb_info.used = 0;
                }
-               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;
+
+               ag_pb_info.path_id = i;
+       } else {
+               err = CME_ERROR_INVALID_TEXT_STRING;
+       }
+       telephony_select_phonebook_memory_rsp(telephony_device, err);
+}
+
+void telephony_read_phonebook_entries_list(void *telephony_device)
+{
+       cme_error_t err = CME_ERROR_NONE;
+       int32_t path_id = ag_pb_info.path_id;
+
+       DBG("telephony-tizen: telephony_read_phonebook_entries_list\n");
+
+       if (path_id < 0 || path_id >= PHONEBOOK_STORE_LIST_SIZE)
+               err = CME_ERROR_INVALID_INDEX;
+       else {
+               if(ag_pb_info.max_size == 0 && ag_pb_info.used == 0) {
+                       if (get_phonebook_count(phonebook_store_list[path_id],
+                                               &ag_pb_info.max_size, &ag_pb_info.used) != 0) {
+                               err = CME_ERROR_NOT_ALLOWED;
                        }
                }
+       }
 
-/*
-       Using the start and end index get the contact list from the pbap agent and
-       send the data to remote headset.
-*/
+       telephony_read_phonebook_entries_list_rsp(telephony_device, ag_pb_info.used,
+                       PHONEBOOK_NUMBER_MAX_LENGTH, PHONEBOOK_NAME_MAX_LENGTH,
+                       err);
+}
+
+void telephony_read_phonebook_entries(void *telephony_device, const char *cmd)
+{
+       int start_index = 0;
+       int end_index = 0;
+
+       char *str = NULL;
+       char *next = NULL;
+
+       cme_error_t err = CME_ERROR_NONE;
+
+       DBG("telephony-tizen: telephony_read_phonebook_entries\n");
+
+       if (cmd == NULL)
+               return;
+
+       str = g_strdup(cmd);
+       next = strchr(str, ',');
+
+       if (next) {
+               *next = '\0';
+               next++;
+
+               end_index = strtol(next, NULL, 10);
        }
- }
 
-void telephony_find_phonebook_entry_properties(void *telephony_device)
+       start_index = strtol(str, NULL, 10);
+
+       g_free(str);
+
+       if(read_phonebook_entries(start_index, end_index))
+               err = CME_ERROR_AG_FAILURE;
+
+       telephony_read_phonebook_entries_rsp(telephony_device, err);
+}
+
+void telephony_find_phonebook_entries_status(void *telephony_device)
 {
-       telephony_find_phonebook_entry_properties_rsp(telephony_device,
+       telephony_find_phonebook_entries_status_ind(
                        PHONEBOOK_NUMBER_MAX_LENGTH,
-                       PHONEBOOK_NAME_MAX_LENGTH,
-                       CME_ERROR_NONE);
+                       PHONEBOOK_NAME_MAX_LENGTH);
 
+       telephony_find_phonebook_entries_status_rsp(telephony_device,
+                                               CME_ERROR_NONE);
 }
 
-void telephony_find_phonebook_entry(void *telephony_device, const char *cmd)
+void telephony_find_phonebook_entries(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
-*/
+       gchar *st = NULL;
+       gchar *unquoted = NULL;
+
+       cme_error_t err = CME_ERROR_NONE;
+
+       DBG("telephony-tizen: telephony_find_phonebook_entry\n");
+
+       /* remove quote and compress */
+       st = strchr(cmd, '"');
+       if (st == NULL)
+               unquoted = g_strdup(cmd);
+       else {
+               gchar *end = NULL;
+
+               end = strrchr(cmd, '"');
+               if(end == NULL)
+                       unquoted = g_strdup(cmd);
+               else
+                       unquoted = g_strndup(st + 1, end - st - 1);
+       }
+
+       if (find_phonebook_entries(unquoted))
+               err = CME_ERROR_AG_FAILURE;
+
+       telephony_find_phonebook_entries_rsp(telephony_device, err);
 
+       g_free(unquoted);
 }
+
 void telephony_get_preffered_store_capacity(void *telephony_device)
 {
+       DBG("telephony-tizen: telephony_list_preffered_store_capcity\n");
+
        telephony_get_preffered_store_capacity_rsp(telephony_device,
                        PREFFERED_MESSAGE_STORAGE_MAX,
                        CME_ERROR_NONE);
@@ -2248,6 +2264,8 @@ void telephony_get_preffered_store_capacity(void *telephony_device)
 
 void telephony_list_preffered_store(void *telephony_device)
 {
+       DBG("telephony-tizen: telephony_list_preffered_store_capcity\n");
+
        telephony_list_preffered_store_rsp(telephony_device,
                        PREFFERED_MESSAGE_STORAGE_LIST,
                        CME_ERROR_NONE);
@@ -2258,8 +2276,11 @@ void telephony_set_preffered_store_capcity(void *telephony_device, const char *c
 {
 }
 */
+
 void telephony_get_character_set(void *telephony_device)
 {
+       DBG("telephony-tizen: telephony_get_character_set\n");
+
        telephony_supported_character_generic_rsp(telephony_device,
                        PHONEBOOK_CHARACTER_SET_SUPPORTED,
                        CME_ERROR_NONE);
@@ -2268,11 +2289,114 @@ void telephony_get_character_set(void *telephony_device)
 
 void telephony_list_supported_character(void *telephony_device)
 {
+       DBG("telephony-tizen: telephony_list_supported_character_set\n");
+
        telephony_supported_character_generic_rsp(telephony_device,
                        PHONEBOOK_CHARACTER_SET_LIST,
                        CME_ERROR_NONE);
 }
 
+static void telephony_get_battery_property_reply(
+                       DBusPendingCall *call, void *data)
+{
+       DBusMessage *reply = dbus_pending_call_steal_reply(call);
+       DBusError derr;
+       int32_t bcs = 0;
+       int32_t bcl = 0;
+
+       DBG("battery_property_reply");
+
+       dbus_error_init(&derr);
+       if (dbus_set_error_from_message(&derr, reply)) {
+               DBG("battery_property_reply: %s", derr.message);
+               dbus_error_free(&derr);
+               telephony_battery_charge_status_rsp(data, bcs,
+                       bcl, CME_ERROR_AG_FAILURE);
+               goto done;
+       }
+
+       if (dbus_message_get_args(reply, NULL,
+                       DBUS_TYPE_INT32, &bcs,
+                       DBUS_TYPE_INT32, &bcl,
+                       DBUS_TYPE_INVALID) == FALSE) {
+               DBG("get_signal_quality_reply: Invalid arguments");
+               telephony_battery_charge_status_rsp(data, bcs,
+                       bcl, CME_ERROR_AG_FAILURE);
+               goto done;
+
+       }
+
+       telephony_battery_charge_status_rsp(data, bcs,
+               bcl, CME_ERROR_NONE);
+
+done:
+       dbus_message_unref(reply);
+}
+
+void telephony_get_battery_property(void *telephony_device)
+{
+       DBG("telephony-tizen: telephony_get_battery_property\n");
+
+       if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
+                               HFP_AGENT_INTERFACE, "GetBatteryStatus",
+                               telephony_get_battery_property_reply,
+                               telephony_device, DBUS_TYPE_INVALID)) {
+               telephony_battery_charge_status_rsp(telephony_device, 0, 0,
+                                               CME_ERROR_AG_FAILURE);
+       }
+}
+
+static void telephony_get_signal_quality_reply(DBusPendingCall *call,
+                       void *data)
+{
+       DBusMessage *reply = dbus_pending_call_steal_reply(call);
+       DBusError derr;
+       int32_t rssi = 0;
+       int32_t ber = 0;
+
+       DBG("get_signal_quality_reply");
+
+       dbus_error_init(&derr);
+       if (dbus_set_error_from_message(&derr, reply)) {
+               DBG("get_signal_quality_reply: %s", derr.message);
+               dbus_error_free(&derr);
+               telephony_signal_quality_rsp(data, rssi,
+                       ber, CME_ERROR_AG_FAILURE);
+               goto done;
+       }
+
+       if (dbus_message_get_args(reply, NULL,
+                       DBUS_TYPE_INT32, &rssi,
+                       DBUS_TYPE_INT32, &ber,
+                       DBUS_TYPE_INVALID) == FALSE) {
+               DBG("get_signal_quality_reply: Invalid arguments");
+               telephony_signal_quality_rsp(data, rssi,
+                       ber, CME_ERROR_AG_FAILURE);
+               goto done;
+
+       }
+
+       telephony_signal_quality_rsp(data, rssi,
+               ber, CME_ERROR_NONE);
+
+done:
+       dbus_message_unref(reply);
+}
+
+void telephony_get_signal_quality(void *telephony_device)
+{
+       DBG("telephony-tizen: telephony_get_signal_quality\n");
+
+       if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
+                               HFP_AGENT_INTERFACE, "GetSignalQuality",
+                               telephony_get_signal_quality_reply,
+                               telephony_device, DBUS_TYPE_INVALID)) {
+               telephony_signal_quality_rsp(telephony_device, 0, 0,
+                                               CME_ERROR_AG_FAILURE);
+       }
+
+}
+
 /*
 void telephony_set_characterset(void *telephony_device, const char *cmd)
 {
index 73b390c..482e565 100644 (file)
@@ -165,6 +165,63 @@ void telephony_nr_and_ec_req(void *telephony_device, gboolean enable);
 void telephony_voice_dial_req(void *telephony_device, gboolean enable);
 void telephony_key_press_req(void *telephony_device, const char *keys);
 
+#ifdef __TIZEN_PATCH__
+void telephony_select_phonebook_memory_status(void *telephony_device);
+void telephony_select_phonebook_memory_list(void *telephony_device);
+void telephony_select_phonebook_memory(void *telephony_device, const gchar *path);
+void telephony_read_phonebook_entries_list(void *telephony_device);
+void telephony_read_phonebook_entries(void *telephony_device, const char *cmd);
+void telephony_find_phonebook_entries_status(void *telephony_device);
+void telephony_find_phonebook_entries(void *telephony_device, const char *cmd);
+void telephony_get_preffered_store_capacity(void *telephony_device);
+void telephony_list_preffered_store(void *telephony_device);
+void telephony_get_character_set(void *telephony_device);
+void telephony_list_supported_character(void *telephony_device);
+void telephony_get_battery_property(void *telephony_device);
+void telephony_get_signal_quality(void *telephony_device);
+
+int telephony_select_phonebook_memory_status_rsp(void *telephony_device, const gchar *path,
+                                       uint32_t total, uint32_t used,
+                                       cme_error_t err);
+int telephony_select_phonebook_memory_list_rsp(void *telephony_device, const char *buf,
+                                       cme_error_t err);
+int telephony_select_phonebook_memory_rsp(void *telephony_device, cme_error_t err);
+int telephony_read_phonebook_entries_list_rsp(void *telephony_device,
+                                       uint32_t used,
+                                       uint32_t number_length,
+                                       uint32_t name_length,
+                                       cme_error_t err);
+int telephony_find_phonebook_entries_status_rsp(void *telephony_device,
+                                               cme_error_t err);
+int telephony_read_phonebook_entries_rsp(void *telephony_device,
+                                       cme_error_t err);
+int telephony_find_phonebook_entries_rsp(void *telephony_device,
+                                       cme_error_t err);
+int telephony_list_preffered_store_rsp(void *telephony_device,
+                                       char *prefrd_list, cme_error_t err);
+int telephony_get_preffered_store_capacity_rsp(void *telephony_device,
+                                               uint32_t store_capacity,
+                                               cme_error_t err);
+int telephony_supported_character_generic_rsp(void *telephony_device,
+                                               char *character_set_list,
+                                               cme_error_t err);
+int telephony_battery_charge_status_rsp(void *telephony_device,
+                                               int32_t bcs,
+                                               int32_t bcl,
+                                               cme_error_t err);
+int telephony_signal_quality_rsp(void *telephony_device,
+                                               int32_t rssi,
+                                               int32_t ber,
+                                               cme_error_t err);
+
+int telephony_read_phonebook_entries_ind(const char *name, const char *number,
+                                       uint32_t handle);
+int telephony_find_phonebook_entries_status_ind( uint32_t number_length,
+                                       uint32_t name_length);
+int telephony_find_phonebook_entries_ind(const char *name, const char *number,
+                                       uint32_t handle);
+#endif
+
 /* AG responses to HF requests. These are implemented by headset.c */
 int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err);
 int telephony_response_and_hold_rsp(void *telephony_device, cme_error_t err);
index 7bde32d..b015625 100644 (file)
@@ -28,6 +28,8 @@
 
 #include <errno.h>
 
+#include <bluetooth/uuid.h>
+
 #include <glib.h>
 #include <gdbus.h>
 
 #include "a2dp.h"
 #include "headset.h"
 #include "gateway.h"
-
-#ifndef DBUS_TYPE_UNIX_FD
-#define DBUS_TYPE_UNIX_FD -1
-#endif
+#include "avrcp.h"
 
 #define MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport"
 
@@ -63,11 +62,21 @@ struct media_owner {
        guint                   watch;
 };
 
+struct a2dp_transport {
+       struct avdtp            *session;
+       uint16_t                delay;
+       uint16_t                volume;
+};
+
+struct headset_transport {
+       struct audio_device     *device;
+       unsigned int            nrec_id;
+};
+
 struct media_transport {
        DBusConnection          *conn;
        char                    *path;          /* Transport object path */
        struct audio_device     *device;        /* Transport device */
-       struct avdtp            *session;       /* Signalling session (a2dp only) */
        struct media_endpoint   *endpoint;      /* Transport endpoint */
        GSList                  *owners;        /* Transport owners */
        uint8_t                 *configuration; /* Transport configuration */
@@ -75,8 +84,6 @@ struct media_transport {
        int                     fd;             /* Transport file descriptor */
        uint16_t                imtu;           /* Transport input mtu */
        uint16_t                omtu;           /* Transport output mtu */
-       uint16_t                delay;          /* Transport delay (a2dp only) */
-       unsigned int            nrec_id;        /* Transport nrec watch (headset only) */
        gboolean                read_lock;
        gboolean                write_lock;
        gboolean                in_use;
@@ -93,6 +100,8 @@ struct media_transport {
                                        struct media_transport *transport,
                                        const char *property,
                                        DBusMessageIter *value);
+       GDestroyNotify          destroy;
+       void                    *data;
 };
 
 void media_transport_destroy(struct media_transport *transport)
@@ -276,26 +285,26 @@ fail:
 static guint resume_a2dp(struct media_transport *transport,
                                struct media_owner *owner)
 {
+       struct a2dp_transport *a2dp = transport->data;
        struct media_endpoint *endpoint = transport->endpoint;
        struct audio_device *device = transport->device;
        struct a2dp_sep *sep = media_endpoint_get_sep(endpoint);
 
-       if (transport->session == NULL) {
-               transport->session = avdtp_get(&device->src, &device->dst);
-               if (transport->session == NULL)
+       if (a2dp->session == NULL) {
+               a2dp->session = avdtp_get(&device->src, &device->dst);
+               if (a2dp->session == NULL)
                        return 0;
        }
 
        if (transport->in_use == TRUE)
                goto done;
 
-       transport->in_use = a2dp_sep_lock(sep, transport->session);
+       transport->in_use = a2dp_sep_lock(sep, a2dp->session);
        if (transport->in_use == FALSE)
                return 0;
 
 done:
-       return a2dp_resume(transport->session, sep, a2dp_resume_complete,
-                               owner);
+       return a2dp_resume(a2dp->session, sep, a2dp_resume_complete, owner);
 }
 
 static void a2dp_suspend_complete(struct avdtp *session,
@@ -303,6 +312,7 @@ static void a2dp_suspend_complete(struct avdtp *session,
 {
        struct media_owner *owner = user_data;
        struct media_transport *transport = owner->transport;
+       struct a2dp_transport *a2dp = transport->data;
        struct a2dp_sep *sep = media_endpoint_get_sep(transport->endpoint);
 
        /* Release always succeeds */
@@ -312,7 +322,7 @@ static void a2dp_suspend_complete(struct avdtp *session,
                media_owner_remove(owner);
        }
 
-       a2dp_sep_unlock(sep, transport->session);
+       a2dp_sep_unlock(sep, a2dp->session);
        transport->in_use = FALSE;
        media_transport_remove(transport, owner);
 }
@@ -320,17 +330,17 @@ static void a2dp_suspend_complete(struct avdtp *session,
 static guint suspend_a2dp(struct media_transport *transport,
                                                struct media_owner *owner)
 {
+       struct a2dp_transport *a2dp = transport->data;
        struct media_endpoint *endpoint = transport->endpoint;
        struct a2dp_sep *sep = media_endpoint_get_sep(endpoint);
 
        if (!owner) {
-               a2dp_sep_unlock(sep, transport->session);
+               a2dp_sep_unlock(sep, a2dp->session);
                transport->in_use = FALSE;
                return 0;
        }
 
-       return a2dp_suspend(transport->session, sep, a2dp_suspend_complete,
-                               owner);
+       return a2dp_suspend(a2dp->session, sep, a2dp_suspend_complete, owner);
 }
 
 static void cancel_a2dp(struct media_transport *transport, guint id)
@@ -510,6 +520,7 @@ static gboolean gateway_suspend_complete(gpointer user_data)
 {
        struct media_owner *owner = user_data;
        struct media_transport *transport = owner->transport;
+       struct audio_device *device = transport->device;
 
        /* Release always succeeds */
        if (owner->pending) {
@@ -518,6 +529,7 @@ static gboolean gateway_suspend_complete(gpointer user_data)
                media_owner_remove(owner);
        }
 
+       gateway_unlock(device, GATEWAY_LOCK_READ | GATEWAY_LOCK_WRITE);
        transport->in_use = FALSE;
        media_transport_remove(transport, owner);
        return FALSE;
@@ -536,7 +548,6 @@ static guint suspend_gateway(struct media_transport *transport,
        }
 
        gateway_suspend_stream(device);
-       gateway_unlock(device, GATEWAY_LOCK_READ | GATEWAY_LOCK_WRITE);
        g_idle_add(gateway_suspend_complete, owner);
        return id++;
 }
@@ -598,6 +609,9 @@ static void media_transport_add(struct media_transport *transport,
        DBG("Transport %s Owner %s", transport->path, owner->name);
        transport->owners = g_slist_append(transport->owners, owner);
        owner->transport = transport;
+       owner->watch = g_dbus_add_disconnect_watch(transport->conn, owner->name,
+                                                       media_owner_exit,
+                                                       owner, NULL);
 }
 
 static struct media_owner *media_owner_create(DBusConnection *conn,
@@ -609,9 +623,6 @@ static struct media_owner *media_owner_create(DBusConnection *conn,
        owner = g_new0(struct media_owner, 1);
        owner->name = g_strdup(dbus_message_get_sender(msg));
        owner->accesstype = g_strdup(accesstype);
-       owner->watch = g_dbus_add_disconnect_watch(conn, owner->name,
-                                                       media_owner_exit,
-                                                       owner, NULL);
 
        DBG("Owner created: sender=%s accesstype=%s", owner->name,
                        accesstype);
@@ -744,13 +755,30 @@ static int set_property_a2dp(struct media_transport *transport,
                                                const char *property,
                                                DBusMessageIter *value)
 {
+       struct a2dp_transport *a2dp = transport->data;
+
        if (g_strcmp0(property, "Delay") == 0) {
                if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16)
                        return -EINVAL;
-               dbus_message_iter_get_basic(value, &transport->delay);
+               dbus_message_iter_get_basic(value, &a2dp->delay);
 
                /* FIXME: send new delay */
                return 0;
+       } else if (g_strcmp0(property, "Volume") == 0) {
+               uint16_t volume;
+
+               if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16)
+                       return -EINVAL;
+
+               dbus_message_iter_get_basic(value, &volume);
+
+               if (volume > 127)
+                       return -EINVAL;
+
+               if (a2dp->volume == volume)
+                       return 0;
+
+               return avrcp_set_volume(transport->device, volume);
        }
 
        return -EINVAL;
@@ -839,7 +867,13 @@ static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
 static void get_properties_a2dp(struct media_transport *transport,
                                                DBusMessageIter *dict)
 {
-       dict_append_entry(dict, "Delay", DBUS_TYPE_UINT16, &transport->delay);
+       struct a2dp_transport *a2dp = transport->data;
+
+       dict_append_entry(dict, "Delay", DBUS_TYPE_UINT16, &a2dp->delay);
+
+       if (a2dp->volume <= 127)
+               dict_append_entry(dict, "Volume", DBUS_TYPE_UINT16,
+                                                       &a2dp->volume);
 }
 
 static void get_properties_headset(struct media_transport *transport,
@@ -913,21 +947,50 @@ static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
        return reply;
 }
 
-static GDBusMethodTable transport_methods[] = {
-       { "GetProperties",      "",     "a{sv}",        get_properties },
-       { "Acquire",            "s",    "h",            acquire,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "Release",            "s",    "",             release,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "SetProperty",        "sv",   "",             set_property },
+static const GDBusMethodTable transport_methods[] = {
+       { GDBUS_METHOD("GetProperties",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       get_properties) },
+       { GDBUS_ASYNC_METHOD("Acquire",
+                       GDBUS_ARGS({ "access_type", "s" }),
+                       GDBUS_ARGS({ "fd", "h" }, { "mtu_r", "q" },
+                                                       { "mtu_w", "q" } ),
+                       acquire) },
+       { GDBUS_ASYNC_METHOD("Release",
+                       GDBUS_ARGS({ "access_type", "s" }), NULL,
+                       release ) },
+       { GDBUS_ASYNC_METHOD("SetProperty",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
+                       NULL, set_property) },
        { },
 };
 
-static GDBusSignalTable transport_signals[] = {
-       { "PropertyChanged",    "sv"    },
+static const GDBusSignalTable transport_signals[] = {
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
        { }
 };
 
+static void destroy_a2dp(void *data)
+{
+       struct a2dp_transport *a2dp = data;
+
+       if (a2dp->session)
+               avdtp_unref(a2dp->session);
+
+       g_free(a2dp);
+}
+
+static void destroy_headset(void *data)
+{
+       struct headset_transport *headset = data;
+
+       if (headset->nrec_id > 0)
+               headset_remove_nrec_cb(headset->device, headset->nrec_id);
+
+       g_free(headset);
+}
+
 static void media_transport_free(void *data)
 {
        struct media_transport *transport = data;
@@ -941,11 +1004,8 @@ static void media_transport_free(void *data)
 
        g_slist_free(transport->owners);
 
-       if (transport->session)
-               avdtp_unref(transport->session);
-
-       if (transport->nrec_id)
-               headset_remove_nrec_cb(transport->device, transport->nrec_id);
+       if (transport->destroy != NULL)
+               transport->destroy(transport->data);
 
        if (transport->conn)
                dbus_connection_unref(transport->conn);
@@ -990,21 +1050,35 @@ struct media_transport *media_transport_create(DBusConnection *conn,
        uuid = media_endpoint_get_uuid(endpoint);
        if (strcasecmp(uuid, A2DP_SOURCE_UUID) == 0 ||
                        strcasecmp(uuid, A2DP_SINK_UUID) == 0) {
+               struct a2dp_transport *a2dp;
+
+               a2dp = g_new0(struct a2dp_transport, 1);
+               a2dp->volume = -1;
+
                transport->resume = resume_a2dp;
                transport->suspend = suspend_a2dp;
                transport->cancel = cancel_a2dp;
                transport->get_properties = get_properties_a2dp;
                transport->set_property = set_property_a2dp;
+               transport->data = a2dp;
+               transport->destroy = destroy_a2dp;
        } else if (strcasecmp(uuid, HFP_AG_UUID) == 0 ||
                        strcasecmp(uuid, HSP_AG_UUID) == 0) {
+               struct headset_transport *headset;
+
+               headset = g_new0(struct headset_transport, 1);
+               headset->device = device;
+               headset->nrec_id = headset_add_nrec_cb(device,
+                                                       headset_nrec_changed,
+                                                       transport);
+
                transport->resume = resume_headset;
                transport->suspend = suspend_headset;
                transport->cancel = cancel_headset;
                transport->get_properties = get_properties_headset;
                transport->set_property = set_property_headset;
-               transport->nrec_id = headset_add_nrec_cb(device,
-                                                       headset_nrec_changed,
-                                                       transport);
+               transport->data = headset;
+               transport->destroy = destroy_headset;
        } else if (strcasecmp(uuid, HFP_HS_UUID) == 0 ||
                        strcasecmp(uuid, HSP_HS_UUID) == 0) {
                transport->resume = resume_gateway;
@@ -1038,18 +1112,36 @@ const char *media_transport_get_path(struct media_transport *transport)
 void media_transport_update_delay(struct media_transport *transport,
                                                        uint16_t delay)
 {
+       struct a2dp_transport *a2dp = transport->data;
+
        /* Check if delay really changed */
-       if (transport->delay == delay)
+       if (a2dp->delay == delay)
                return;
 
-       transport->delay = delay;
+       a2dp->delay = delay;
 
        emit_property_changed(transport->conn, transport->path,
                                MEDIA_TRANSPORT_INTERFACE, "Delay",
-                               DBUS_TYPE_UINT16, &transport->delay);
+                               DBUS_TYPE_UINT16, &a2dp->delay);
 }
 
 struct audio_device *media_transport_get_dev(struct media_transport *transport)
 {
        return transport->device;
 }
+
+void media_transport_update_volume(struct media_transport *transport,
+                                                               uint8_t volume)
+{
+       struct a2dp_transport *a2dp = transport->data;
+
+       /* Check if volume really changed */
+       if (a2dp->volume == volume)
+               return;
+
+       a2dp->volume = volume;
+
+       emit_property_changed(transport->conn, transport->path,
+                               MEDIA_TRANSPORT_INTERFACE, "Volume",
+                               DBUS_TYPE_UINT16, &a2dp->volume);
+}
index 1f86cde..d20c327 100644 (file)
@@ -35,5 +35,7 @@ const char *media_transport_get_path(struct media_transport *transport);
 struct audio_device *media_transport_get_dev(struct media_transport *transport);
 void media_transport_update_delay(struct media_transport *transport,
                                                        uint16_t delay);
+void media_transport_update_volume(struct media_transport *transport,
+                                                               uint8_t volume);
 void transport_get_properties(struct media_transport *transport,
                                                        DBusMessageIter *iter);
index 5199831..9a10764 100644 (file)
@@ -52,7 +52,6 @@
 #include "source.h"
 #include "gateway.h"
 #include "unix.h"
-#include "glib-compat.h"
 
 #define check_nul(str) (str[sizeof(str) - 1] == '\0')
 
@@ -534,7 +533,7 @@ static int a2dp_append_codec(struct bt_get_capabilities_rsp *rsp,
 
        space_left = BT_SUGGESTED_BUFFER_SIZE - rsp->h.length;
 
-       /* endianess prevent direct cast */
+       /* endianness prevents direct cast */
        if (codec_cap->media_codec_type == A2DP_CODEC_SBC) {
                struct sbc_codec_cap *sbc_cap = (void *) codec_cap;
                sbc_capabilities_t *sbc = (void *) codec;
index 0d177a3..e81fb75 100644 (file)
@@ -33,8 +33,6 @@
 #include <bluetooth/l2cap.h>
 #include <bluetooth/rfcomm.h>
 #include <bluetooth/sco.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
 
 #include <glib.h>
 
@@ -53,6 +51,7 @@
 struct set_opts {
        bdaddr_t src;
        bdaddr_t dst;
+       uint8_t dst_type;
        int defer;
        int sec_level;
        uint8_t channel;
@@ -282,8 +281,8 @@ static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm,
        return 0;
 }
 
-static int l2cap_connect(int sock, const bdaddr_t *dst,
-                                       uint16_t psm, uint16_t cid)
+static int l2cap_connect(int sock, const bdaddr_t *dst, uint8_t dst_type,
+                                               uint16_t psm, uint16_t cid)
 {
        int err;
        struct sockaddr_l2 addr;
@@ -296,6 +295,8 @@ static int l2cap_connect(int sock, const bdaddr_t *dst,
        else
                addr.l2_psm = htobs(psm);
 
+       addr.l2_bdaddr_type = dst_type;
+
        err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
        if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
                return -errno;
@@ -513,6 +514,21 @@ static int set_priority(int sock, uint32_t prio)
        return 0;
 }
 
+static gboolean get_key_size(int sock, int *size, GError **err)
+{
+       struct bt_security sec;
+       socklen_t len;
+
+       memset(&sec, 0, sizeof(sec));
+       len = sizeof(sec);
+       if (getsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec, &len) == 0) {
+               *size = sec.key_size;
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
 static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu,
                                uint16_t omtu, uint8_t mode, int master,
                                int flushable, uint32_t priority, GError **err)
@@ -682,19 +698,16 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
        /* Set defaults */
        opts->defer = DEFAULT_DEFER_TIMEOUT;
        opts->master = -1;
-       opts->sec_level = BT_IO_SEC_MEDIUM;
        opts->mode = L2CAP_MODE_BASIC;
        opts->flushable = -1;
        opts->priority = 0;
+       opts->dst_type = BDADDR_BREDR;
 
        while (opt != BT_IO_OPT_INVALID) {
                switch (opt) {
                case BT_IO_OPT_SOURCE:
                        str = va_arg(args, const char *);
-                       if (strncasecmp(str, "hci", 3) == 0)
-                               hci_devba(atoi(str + 3), &opts->src);
-                       else
-                               str2ba(str, &opts->src);
+                       str2ba(str, &opts->src);
                        break;
                case BT_IO_OPT_SOURCE_BDADDR:
                        bacpy(&opts->src, va_arg(args, const bdaddr_t *));
@@ -705,6 +718,9 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
                case BT_IO_OPT_DEST_BDADDR:
                        bacpy(&opts->dst, va_arg(args, const bdaddr_t *));
                        break;
+               case BT_IO_OPT_DEST_TYPE:
+                       opts->dst_type = va_arg(args, int);
+                       break;
                case BT_IO_OPT_DEFER_TIMEOUT:
                        opts->defer = va_arg(args, int);
                        break;
@@ -866,6 +882,10 @@ static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
                case BT_IO_OPT_DEST_BDADDR:
                        bacpy(va_arg(args, bdaddr_t *), &dst.l2_bdaddr);
                        break;
+               case BT_IO_OPT_DEST_TYPE:
+                       g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+                                                       "Not implemented");
+                       return FALSE;
                case BT_IO_OPT_DEFER_TIMEOUT:
                        len = sizeof(int);
                        if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP,
@@ -880,6 +900,10 @@ static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
                                                va_arg(args, int *), err))
                                return FALSE;
                        break;
+               case BT_IO_OPT_KEY_SIZE:
+                       if (!get_key_size(sock, va_arg(args, int *), err))
+                               return FALSE;
+                       break;
                case BT_IO_OPT_PSM:
                        *(va_arg(args, uint16_t *)) = src.l2_psm ?
                                        btohs(src.l2_psm) : btohs(dst.l2_psm);
@@ -1148,6 +1172,7 @@ static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err,
        switch (type) {
        case BT_IO_L2RAW:
        case BT_IO_L2CAP:
+       case BT_IO_L2ERTM:
                return l2cap_get(sock, err, opt1, args);
        case BT_IO_RFCOMM:
                return rfcomm_get(sock, err, opt1, args);
@@ -1210,6 +1235,7 @@ gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
        switch (type) {
        case BT_IO_L2RAW:
        case BT_IO_L2CAP:
+       case BT_IO_L2ERTM:
                return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu,
                                opts.mode, opts.master, opts.flushable,
                                opts.priority, err);
@@ -1270,6 +1296,20 @@ static GIOChannel *create_io(BtIOType type, gboolean server,
                                opts->priority, err))
                        goto failed;
                break;
+       case BT_IO_L2ERTM:
+               sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_L2CAP);
+               if (sock < 0) {
+                       ERROR_FAILED(err, "socket(STREAM, L2CAP)", errno);
+                       return NULL;
+               }
+               if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0,
+                                                       opts->cid, err) < 0)
+                       goto failed;
+               if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu,
+                               opts->mode, opts->master, opts->flushable,
+                               opts->priority, err))
+                       goto failed;
+               break;
        case BT_IO_RFCOMM:
                sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
                if (sock < 0) {
@@ -1337,10 +1377,13 @@ GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
 
        switch (type) {
        case BT_IO_L2RAW:
-               err = l2cap_connect(sock, &opts.dst, 0, opts.cid);
+               err = l2cap_connect(sock, &opts.dst, opts.dst_type, 0,
+                                                               opts.cid);
                break;
        case BT_IO_L2CAP:
-               err = l2cap_connect(sock, &opts.dst, opts.psm, opts.cid);
+       case BT_IO_L2ERTM:
+               err = l2cap_connect(sock, &opts.dst, opts.dst_type,
+                                                       opts.psm, opts.cid);
                break;
        case BT_IO_RFCOMM:
                err = rfcomm_connect(sock, &opts.dst, opts.channel);
index ae55b61..cf0e070 100644 (file)
@@ -40,6 +40,7 @@ GQuark bt_io_error_quark(void);
 typedef enum {
        BT_IO_L2RAW,
        BT_IO_L2CAP,
+       BT_IO_L2ERTM,
        BT_IO_RFCOMM,
        BT_IO_SCO,
 } BtIOType;
@@ -50,8 +51,10 @@ typedef enum {
        BT_IO_OPT_SOURCE_BDADDR,
        BT_IO_OPT_DEST,
        BT_IO_OPT_DEST_BDADDR,
+       BT_IO_OPT_DEST_TYPE,
        BT_IO_OPT_DEFER_TIMEOUT,
        BT_IO_OPT_SEC_LEVEL,
+       BT_IO_OPT_KEY_SIZE,
        BT_IO_OPT_CHANNEL,
        BT_IO_OPT_SOURCE_CHANNEL,
        BT_IO_OPT_DEST_CHANNEL,
@@ -75,6 +78,14 @@ typedef enum {
        BT_IO_SEC_HIGH,
 } BtIOSecLevel;
 
+typedef enum {
+       BT_IO_MODE_BASIC = 0,
+       BT_IO_MODE_RETRANS,
+       BT_IO_MODE_FLOWCTL,
+       BT_IO_MODE_ERTM,
+       BT_IO_MODE_STREAMING
+} BtIOMode;
+
 typedef void (*BtIOConfirm)(GIOChannel *io, gpointer user_data);
 
 typedef void (*BtIOConnect)(GIOChannel *io, GError *err, gpointer user_data);
index de98830..3f3a0d4 100644 (file)
@@ -191,8 +191,8 @@ static int dun_create_tty(int sk, char *tty, int size)
        int id, try = 30;
 
        struct rfcomm_dev_req req = {
-               flags:   (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP),
-               dev_id:  -1
+               .flags = (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP),
+               .dev_id = -1
        };
 
        alen = sizeof(sa);
index fd1b28c..f8a0dfd 100644 (file)
@@ -811,7 +811,7 @@ int main(int argc, char *argv[])
         if (detach) {
                if (daemon(0, 0)) {
                        perror("Can't start daemon");
-                       exit(1);
+                       exit(1);
                }
        } else
                log_option |= LOG_PERROR;
index f384844..9ad8333 100644 (file)
 static sdp_record_t *record = NULL;
 static sdp_session_t *session = NULL;
 
-static void add_lang_attr(sdp_record_t *r)
-{
-       sdp_lang_attr_t base_lang;
-       sdp_list_t *langs = 0;
-
-       /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */
-       base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
-       base_lang.encoding = 106;
-       base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
-       langs = sdp_list_append(0, &base_lang);
-       sdp_set_lang_attr(r, langs);
-       sdp_list_free(langs, 0);
-}
-
 static void epox_endian_quirk(unsigned char *data, int size)
 {
        /* USAGE_PAGE (Keyboard)        05 07
@@ -448,7 +434,7 @@ int bnep_sdp_register(bdaddr_t *device, uint16_t role)
        aproto = sdp_list_append(NULL, apseq);
        sdp_set_access_protos(record, aproto);
 
-       add_lang_attr(record);
+       sdp_add_lang_attr(record);
 
        sdp_list_free(proto[0], NULL);
        sdp_list_free(proto[1], NULL);
index 5b81f28..f2db920 100644 (file)
@@ -1,5 +1,5 @@
 AC_PREREQ(2.60)
-AC_INIT(bluez, 4.98)
+AC_INIT(bluez, 4.101)
 
 AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
 AM_CONFIG_HEADER(config.h)
@@ -52,16 +52,6 @@ AC_PATH_CHECK
 
 AC_ARG_BLUEZ
 
-AC_ARG_ENABLE(capng, AC_HELP_STRING([--enable-capng],
-               [enable capabilities support]), [enable_capng=${enableval}])
-if (test "${enable_capng}" = "yes"); then
-       PKG_CHECK_MODULES(CAPNG, libcap-ng, dummy=yes,
-                               AC_MSG_ERROR(Capabilities library is required))
-       AC_SUBST(CAPNG_CFLAGS)
-       AC_SUBST(CAPNG_LIBS)
-       AC_DEFINE(HAVE_CAPNG, 1, [Define to 1 if you have capabilities library.])
-fi
-
 AC_ARG_WITH([systemdunitdir], AC_HELP_STRING([--with-systemdunitdir=DIR],
        [path to systemd system service directory]), [path_systemdunit=${withval}],
                [path_systemdunit="`$PKG_CONFIG --variable=systemdsystemunitdir systemd`"])
@@ -71,5 +61,4 @@ if (test -n "${path_systemdunit}"); then
 fi
 AM_CONDITIONAL(SYSTEMD, test -n "${path_systemdunit}")
 
-AC_OUTPUT(Makefile scripts/bluetooth.rules doc/version.xml
-                       src/bluetoothd.8 src/bluetooth.service bluez.pc)
+AC_OUTPUT(Makefile doc/version.xml src/bluetoothd.8 src/bluetooth.service bluez.pc)
index 2d2b31e..d428fa9 100644 (file)
-bluez (4.98-slp2+1-3) unstable; urgency=low
+bluez (4.101-slp2+2) unstable; urgency=low
 
-  * Release Tizen 1.0
-  * Git: pkgs/b/bluez
-  * Tag: bluez_4.98-slp2+1-3
+  * Increase version for package upload
+  * Git: framework/connectivity/bluez
+  * Tag: bluez_4.101-slp2+2
 
- -- DoHyun Pyun <dh79.pyun@samsung.com>  Tue, 20 Mar 2012 17:32:01 +0900
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Mon, 20 Aug 2012 14:51:40 +0900
 
-bluez (4.98-slp2+1-2) unstable; urgency=low
+bluez (4.101-slp2+1) unstable; urgency=low
 
-  * Change "SAMSUNG_PATCH" -> "TIZEN_PATCH"
-  * Git: pkgs/b/bluez
-  * Tag: bluez_4.98-slp2+1-2
+  * Increase version for package upload
+  * Git: framework/connectivity/bluez
+  * Tag: bluez_4.101-slp2+1
 
- -- DoHyun Pyun <dh79.pyun@samsung.com>  Tue, 21 Feb 2012 18:03:00 +0900
+ -- Jaganath K <jaganath.k@samsung.com>  Mon, 13 Aug 2012 19:16:04 +0530
 
-bluez (4.98-slp2+1-1) unstable; urgency=low
+bluez (4.99-slp2+8) unstable; urgency=low
 
-  * Merge with lastest private git
-  * Git: pkgs/b/bluez
-  * Tag: bluez_4.98-slp2+1-1
+  * Increase version for package upload
+  * Git: slp/pkgs/b/bluez
+  * Tag: bluez_4.99-slp2+8
 
- -- DoHyun Pyun <dh79.pyun@samsung.com>  Thu, 09 Feb 2012 14:31:53 +0900
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Wed, 08 Aug 2012 12:25:20 +0900
 
-bluez (4.90-slp2+18-2) unstable; urgency=low
+bluez (4.99-slp2+7) unstable; urgency=low
 
-  * Change "SAMSUNG_PATCH" -> "TIZEN_PATCH"
-  * Git: pkgs/b/bluez
-  * Tag: bluez_4.90-slp2+18-2
+  * Increase version for package upload
+  * Git: slp/pkgs/b/bluez
+  * Tag: bluez_4.99-slp2+7
 
- -- Hocheol Seo <hocheol.seo@samsung.com>  Fri, 23 Dec 2011 11:26:09 +0900
+ -- Divya yadav <divya.yadav@samsung.com>  Mon, 06 Aug 2012 15:23:20 +0530
 
-bluez (4.90-slp2+18-1) unstable; urgency=low
+bluez (4.99-slp2+6) unstable; urgency=low
 
-  * Change "com.samsung" -> "org.tizen"
-  * Git: pkgs/b/bluez
-  * Tag: bluez_4.90-slp2+18-1
+  * Enable OOB profile
+  * Git: slp/pkgs/b/bluez
+  * Tag: bluez_4.99-slp2+6
 
- -- DoHyun Pyun <dh79.pyun@samsung.com>  Thu, 22 Dec 2011 18:03:02 +0900
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Thu, 26 Jul 2012 11:28:58 +0900
+
+bluez (4.99-slp2+5) unstable; urgency=low
+
+  * Increase version for package upload
+  * Git: slp/pkgs/b/bluez
+  * Tag: bluez_4.99-slp2+5
+
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Wed, 18 Jul 2012 12:55:39 +0900
+
+bluez (4.99-slp2+4) unstable; urgency=low
+
+  * Increase version for package upload
+  * Git: slp/pkgs/b/bluez
+  * Tag: bluez_4.99-slp2+4
+
+ -- Girish Ashok Joshi <girish.joshi@samsung.com>  Tue, 05 Jun 2012 12:37:12 +0530
+
+bluez (4.99-slp2+3) unstable; urgency=low
+
+  * Increase version for package upload
+  * Git: slp/pkgs/b/bluez
+  * Tag: bluez_4.99-slp2+3
+
+ -- Chethan T N <chethan.tn@samsung.com>  Tue, 22 May 2012 11:36:35 +0530
+
+bluez (4.99-slp2+2) unstable; urgency=low
+
+  * Increase version for package upload
+  * Git: slp/pkgs/b/bluez
+  * Tag: bluez_4.99-slp2+2
+
+ -- Divya yadav <divya.yadav@samsung.com>  Tue, 15 May 2012 15:51:58 +0530
+
+bluez (4.99-slp2+1) unstable; urgency=low
+
+  * Upgrade bluez and package upload.
+  * Git: slp/pkgs/b/bluez
+  * Tag: bluez_4.99-slp2+1
+
+ -- Chethan T N <chethan.tn@samsung.com>  Mon, 07 May 2012 14:01:34 +0530
+
+bluez (4.98-slp2+3) unstable; urgency=low
+
+  * Increase version for package upload.
+  * Git: slp/pkgs/b/bluez
+  * Tag: bluez_4.98-slp2+3
+
+ -- Syam Sidhardhan <s.syam@samsung.com>  Thu, 19 Apr 2012 11:30:40 +0530
+
+bluez (4.98-slp2+2) unstable; urgency=low
+
+  * Increase version for package upload.
+  * Git: slp/pkgs/b/bluez
+  * Tag: bluez_4.98-slp2+2
+
+ -- Sunil Kumar Behera <sunil.behera@samsung.com>  Mon, 16 Apr 2012 19:32:14 +0530
+
+bluez (4.98-slp2+1) unstable; urgency=low
+
+  * Upgrade the bluez and upload the package
+  * Git: slp/pkgs/b/bluez
+  * Tag: bluez_4.98-slp2+1
+
+ -- Syam Sidhardhan <s.syam@samsung.com>  Wed, 08 Feb 2012 15:38:55 +0530
 
 bluez (4.90-slp2+18) unstable; urgency=low
 
-  * Update Version for build
+  * Remove gstreamer dpkg from bluez dpkgs
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+18
+
+ -- Chanyeol Park <chanyeol.park@samsung.com>  Mon, 05 Dec 2011 15:17:40 +0900
+
+bluez (4.90-slp2+17) unstable; urgency=low
+
+  * Remove the samsung path about service list
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+17
+
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Thu, 17 Nov 2011 09:13:45 +0900
+
+bluez (4.90-slp2+16) unstable; urgency=low
+
+  * Remove samsung dbus avrcp
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+16
+
+ -- Chanyeol Park <chanyeol.park@samsung.com>  Sat, 15 Oct 2011 15:35:53 +0900
+
+bluez (4.90-slp2+15) unstable; urgency=low
+
+  * Upload the package
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+15
+
+ -- Chethan T N <chethan.tn@samsung.com>  Mon, 10 Oct 2011 14:30:36 +0530
+
+bluez (4.90-slp2+14) unstable; urgency=low
+
+  * Upload packages for the changes
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+14
+
+ -- Syam Sidhardhan <s.syam@samsung.com>  Tue, 27 Sep 2011 12:36:09 +0530
+
+bluez (4.90-slp2+13) unstable; urgency=low
+
+  * Fix the headset connection problem
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+13
+
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Tue, 20 Sep 2011 20:04:28 +0900
+
+bluez (4.90-slp2+12) unstable; urgency=low
+
+  * Reduce A2DP SBC bitpool from 53 to 32
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+12
+
+ -- Chanyeol Park <chanyeol.park@samsung.com>  Sat, 17 Sep 2011 16:59:58 +0900
+
+bluez (4.90-slp2+11) unstable; urgency=low
+
+  * Upload Package
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+11
+
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Fri, 09 Sep 2011 15:01:21 +0900
+
+bluez (4.90-slp2+10) unstable; urgency=low
+
+  * Enable bluez avrcp
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+10
+
+ -- Chanyeol Park <chanyeol.park@samsung.com>  Thu, 01 Sep 2011 17:35:11 +0900
+
+bluez (4.90-slp2+9) unstable; urgency=low
+
+  * Upload Package
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+9
+
+ -- Jaganath K <jaganath.k@samsung.com>  Tue, 23 Aug 2011 16:34:32 +0530
+
+bluez (4.90-slp2+8) unstable; urgency=low
+
+  * Upload Package
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+8
+
+ -- Jaganath K <jaganath.k@samsung.com>  Tue, 23 Aug 2011 11:16:42 +0530
+
+bluez (4.90-slp2+7) unstable; urgency=low
+
+  * Upgrade bluez audio from 4.90 to 4.96
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+7
+
+ -- Chanyeol Park <chanyeol.park@samsung.com>  Tue, 23 Aug 2011 09:24:03 +0900
+
+bluez (4.90-slp2+6) unstable; urgency=low
+
+  * Upload Package
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+6
+
+ -- Jaganath K <jaganath.k@samsung.com>  Tue, 02 Aug 2011 17:42:12 +0530
+
+bluez (4.90-slp2+5) unstable; urgency=low
+
+  * Print dbus method call message
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+5
+
+ -- Chanyeol Park <chanyeol.park@samsung.com>  Tue, 12 Jul 2011 20:21:10 +0900
+
+bluez (4.90-slp2+4) unstable; urgency=low
+
+  * Upload Package
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+4
+
+ -- Chethan T N <chethan.tn@samsung.com>  Fri, 08 Jul 2011 15:11:07 +0530
 
- -- Chanyeol Park <chanyeol.park@samsung.com>  Thu, 15 Dec 2011 12:56:21 +0900
+bluez (4.90-slp2+3) unstable; urgency=low
+
+  * Upload Package
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+3
+
+ -- Jaganath K <jaganath.k@samsung.com>  Thu, 07 Jul 2011 13:54:04 +0530
+
+bluez (4.90-slp2+2) unstable; urgency=low
+
+  * BlueZ Upgrade 4.90 Merged from 4.90 branch
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+2
+
+ -- Chanyeol Park <chanyeol.park@samsung.com>  Tue, 21 Jun 2011 21:44:48 +0900
 
 bluez (4.90-slp2+1) unstable; urgency=low
 
-  * Initial Release
+  * Migrated from Bluez 4.69 to Bluez 4.90
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.90-slp2+1
+
+ -- Syam Sidhardhan <s.syam@samsung.com>  Thu, 05 May 2011 13:46:04 +0900
+
+bluez (4.69-slp2+22) unstable; urgency=low
+
+  * Fix pairing B/S(root cause)                
+  * Git: 165.213.180.234:slp/pkgs/b/bluez              
+  * Tag: bluez_4.69-slp2+22            
+
+ -- Chanyeol Park <chanyeol.park@samsung.com>  Mon, 23 May 2011 15:03:34 +0900         
+
+bluez (4.69-slp2+21) unstable; urgency=low
+
+  * Fix pairing B/S            
+  * Git: 165.213.180.234:slp/pkgs/b/bluez              
+  * Tag: bluez_4.69-slp2+21            
+
+bluez (4.69-slp2+20) unstable; urgency=low
+
+  * Fix autogen bug by Mike
+  * Fix AVDTP crash
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.69-slp2+20
+
+ -- ChanYeol Park <chanyeol.park@samsung.com>  Mon, 11 Apr 2011 13:46:04 +0900
+
+bluez (4.69-slp2+19) unstable; urgency=low
+
+  * Modify the bluetooth.conf file caused by dbus security
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.69-slp2+19 
+
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Wed, 26 Jan 2011 16:21:29 +0900
+
+bluez (4.69-slp2+18) unstable; urgency=low
+
+  * Change localstatedir from /usr/var to /opt/var because /usr would be
+    RO(read only)
+  * Git: 165.213.180.234:slp/pkgs/b/bluez
+  * Tag: bluez_4.69-slp2+18
+
+ -- ChanYeol Park <chanyeol.park@samsung.com>  Thu, 13 Jan 2011 10:03:05 +0900
+
+bluez (4.69-slp2+17) unstable; urgency=low
+
+  * Fix the A2DP bug
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez
+  * Tag: bluez_4.69-slp2+17
+
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Thu, 25 Nov 2010 20:53:03 +0900
+
+bluez (4.69-slp2+16) unstable; urgency=low
+
+  * Remove the dependency of the ALSA
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez
+  * Tag: bluez_4.69-slp2+16
+
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Fri, 19 Nov 2010 11:10:28 +0900
+
+bluez (4.69-slp2+15) unstable; urgency=low
+
+  * Disable the test setting
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez
+  * Tag: bluez_4.69-slp2+15 
+
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Fri, 12 Nov 2010 11:16:27 +0900
+
+bluez (4.69-slp2+14) unstable; urgency=low
+
+  * Fix the bug about visibility
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez
+  * Tag: bluez_4.69-slp2+14
+
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Thu, 11 Nov 2010 11:31:05 +0900
+
+bluez (4.69-slp2+13) unstable; urgency=low
+
+  * Add the homepage filed in control file
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez
+  * Tag: bluez_4.69-slp2+13
+
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Fri, 29 Oct 2010 17:18:12 +0900
+
+bluez (4.69-slp2+12) unstable; urgency=low
+
+  * Fix the memory leak with the service watch
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez
+  * Tag: bluez_4.69-slp2+12 
+
+ -- Syam Sidhardhan <s.syam@samsung.com>  Mon, 18 Oct 2010 17:44:34 +0530
+
+bluez (4.69-slp2+11) unstable; urgency=low
+
+  * Fix the bug about custom visibility
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez
+  * Tag: bluez_4.69-slp2+11 
+
+ -- DoHyun Pyun <dh79.pyunamsung.com>  Fri, 15 Oct 2010 11:47:55 +0900
+
+bluez (4.69-slp2+10) unstable; urgency=low
+
+  * Since the bluetooth and bluetooth-frwk is directly accessing the linkkey file, Given the permission to the group.
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez
+  * Tag: bluez_4.69-slp2+10
+
+ -- Syam Sidhardhan <s.syam@samsung.com>  Mon, 11 Oct 2010 09:30:07 +0530
+
+bluez (4.69-slp2+9) unstable; urgency=low
+
+  * Fixed the bluetoothd crash due to undefined reference symbol
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez
+  * Tag: bluez_4.69-slp2+9 
+
+ -- Sunil Kumar Behera <sunil.behera@samsung.com>  Sat, 09 Oct 2010 16:04:55 +0530
+
+bluez (4.69-slp2+8) unstable; urgency=low
+
+  * Fixed the bluetoothd crash due to undefined reference symbol
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez
+  * Tag: bluez_4.69-slp2+8
+
+ -- Syam Sidhardhan <s.syam@samsung.com>  Sat, 09 Oct 2010 15:44:26 +0530
+
+bluez (4.69-slp2+7) unstable; urgency=low
+
+  * Apply the proyo patch
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez
+  * Tag: bluez_4.69-slp2+7
+
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Fri, 17 Sep 2010 10:41:15 +0900
+
+bluez (4.69-slp2+6) unstable; urgency=low
+
+  * Add the apt-x codes in A2DP
+  * Patch the android code (adapter, device)
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez
+  * Tag: bluez_4.69-slp2+6
+
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Fri, 10 Sep 2010 19:34:44 +0900
+
+bluez (4.69-slp2+5) unstable; urgency=low
+
+  * Code cleanup
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez
+  * Tag: bluez_4.69-slp2+5
+
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Mon, 30 Aug 2010 13:33:19 +0900
+
+bluez (4.69-slp2+4) unstable; urgency=low
+
+  * Implement the NAP service
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez
+  * Tag: bluez_4.69-slp2+4
+
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Wed, 04 Aug 2010 22:05:47 +0900
+
+bluez (4.69-slp2+3) unstable; urgency=low
+
+  * Add HS UART patch for BRCM chip 3M mode
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez
+  * Tag: bluez_4.69-slp2+3
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Tue, 03 Aug 2010 17:23:25 +0900
+
+bluez (4.69-slp2+2) unstable; urgency=low
+
+  * Fix dbus policy conf file for DAC to allow any user use dbus interface
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez
+  * Tag: bluez_4.69-slp2+2
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Fri, 30 Jul 2010 11:16:09 +0900
+
+bluez (4.69-slp2+1) unstable; urgency=low
+
+  * Migrated from Bluez4.58 to Bluez4.69. Also removed the depricated files
+    in the Bluez4.69 from Git
+  * Git: 165.213.180.234:/git/slp/pkgs/bluez/
+  * Tag: bluez_4.69-slp2+1
+
+ -- Syam Sidhardhan <s.syam@samsung.com>  Thu, 22 Jul 2010 17:35:55 +0530
+
+bluez (4.58-slp2+20) unstable; urgency=low
+
+  * Modify the maintainer list
+  * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/bluez-4/
+  * Tag: bluez_4.58-slp2+20
+
+ -- DoHyun Pyun <dh79.pyun@samsung.com>  Thu, 08 Jul 2010 10:25:32 +0900
+
+bluez (4.58-slp2+19) unstable; urgency=low
+
+  * Add doc option flag
+  * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/bluez-4/
+  * Tag: bluez_4.58-slp2+19
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Mon, 05 Jul 2010 19:04:32 +0900
+
+bluez (4.58-slp2+18) unstable; urgency=low
+
+  * FIx BlueZ SDP bug in the original src 
+  * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/bluez-4/
+  * Tag: bluez_4.58-slp2+18
+
+ -- chanyeol.park <chanyeol.park@samsung.com>  Mon, 14 Jun 2010 22:06:04 +0900
+
+bluez (4.58-slp2+17) unstable; urgency=low
+
+  * Enable serial build option
+  * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/bluez-4/
+  * Tag: bluez_4.58-slp2+17
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Fri, 28 May 2010 21:23:56 +0900
+
+bluez (4.58-slp2+16) unstable; urgency=low
+
+  * Fix done for resolving the service search issues 
+  * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/bluez-4/
+  * Tag: bluez_4.58-slp2+16
+
+ -- Syam Sidhardhan <s.syam@samsung.com>  Wed, 26 May 2010 16:51:27 +0530
+
+bluez (4.58-slp2+15) unstable; urgency=low
+
+  * Removed the unwanted #ifdef SISO_BLUETOOTHD_SOCKET_INTERFACE.
+  * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/bluez-4/
+  * Tag: bluez_4.58-slp2+15
+
+ -- Syam Sidhardhan <s.syam@samsung.com>  Tue, 18 May 2010 17:42:52 +0530
+
+bluez (4.58-slp2+14) unstable; urgency=low
+
+  * Add bonding error code for reject by agent useraction
+  * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/bluez-4/
+  * Tag: bluez_4.58-slp2+14
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Tue, 18 May 2010 09:38:06 +0900
+
+bluez (4.58-slp2+13) unstable; urgency=low
+
+  * Temporarly reverting back the automatic service search just after pairing
+   fix, because of the A2dp issue. 
+  * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/bluez-4/
+  * Tag: bluez_4.58-slp2+13
+
+ -- Syam Sidhardhan <s.syam@samsung.com>  Fri, 14 May 2010 16:59:24 +0530
+
+bluez (4.58-slp2+12) unstable; urgency=low
+
+  *Fix to come out of the sdp loop in the case of sdp error (JSR82). 
+  * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/bluez-4/
+  * Tag: bluez_4.58-slp2+12
+
+ -- Syam Sidhardhan <s.syam@samsung.com>  Thu, 06 May 2010 09:49:01 +0530
+
+bluez (4.58-slp2+11) unstable; urgency=low
+
+  * Fixed the issues related to automatic service search just after pairing.
+  * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/bluez-4/
+  * Tag: bluez_4.58-slp2+11
+
+ -- Syam Sidhardhan <s.syam@samsung.com>  Wed, 05 May 2010 12:14:52 +0530
+
+bluez (4.58-slp2+10) unstable; urgency=low
+
+  * Re-upload for installing verification
+  * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/bluez-4/
+  * Tag: bluez_4.58-slp2+10
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Fri, 23 Apr 2010 23:12:57 +0900
+
+bluez (4.58-slp2+9) unstable; urgency=low
+
+  * Fix gstbluetooth plugin bug while avdtp get capability
+  * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/bluez-4/
+  * Tag: bluez_4.58-slp2+9
+
+ -- chanyeol.park <chanyeol.park@samsung.com>  Fri, 23 Apr 2010 20:04:26 +0900
+
+bluez (4.58-slp2+8) unstable; urgency=low
+
+  * Fix org.bluez.Device.DiscoverServices dbus command reply bug
+  * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/bluez-4/
+  * Tag: bluez_4.58-slp2+8
+
+ -- chanyeol.park <chanyeol.park@samsung.com>  Tue, 13 Apr 2010 14:40:23 +0900
+
+bluez (4.58-slp2+7) unstable; urgency=low
+
+  * Fix get_property to remove GetBasicProperties and to add
+    GetVersionProperties
+  * Add NULL check for confirm cb with remote cancel case
+  * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/bluez-4/
+  * Tag: bluez_4.58-slp2+7
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Wed, 07 Apr 2010 15:08:10 +0900
+
+bluez (4.58-slp2+6) unstable; urgency=low
+
+  * reverted thread method and used open source method of service search
+  * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/bluez-4/
+  * Tag: bluez_4.58-slp2+6
+
+ -- Ankur Gandhi <a.gandhi@samsung.com>  Mon, 05 Apr 2010 13:47:42 +0530
+
+bluez (4.58-slp2+5) unstable; urgency=low
+
+  * changes for SSP between sdp connection 
+
+ -- Hathab Shajahan <hathab.s@samsung.com>  Mon, 29 Mar 2010 17:50:24 +0530
+
+bluez (4.58-slp2+4) unstable; urgency=low
+
+  * Upload for Toolchain upgrade
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Thu, 25 Mar 2010 13:43:00 +0900
+
+bluez (4.58-slp2+3) unstable; urgency=low
+
+  * Rollback to 4.58-slp2+1 because of Pairing fail issue
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Mon, 22 Mar 2010 09:16:48 +0900
+
+bluez (4.58-slp2+2) unstable; urgency=low
+
+  * ftc disconnect fix  
+
+ -- Hathab Shajahan <hathab.s@samsung.com>  Fri, 19 Mar 2010 16:42:57 +0530
+
+bluez (4.58-slp2+1) unstable; urgency=low
+
+  * Re-versioning as SCM policy
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Thu, 18 Mar 2010 22:18:37 +0900
+
+bluez (4.58-19) unstable; urgency=low
+
+  * Add all config files to install list
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Thu, 18 Mar 2010 11:21:01 +0900
+
+bluez (4.58-18) unstable; urgency=low
+
+  * New service Search Method is Added 
+
+ -- Hathab Shajahan <hathab.s@samsung.com>  Fri, 05 Mar 2010 17:54:01 +0530
+
+bluez (4.58-17) unstable; urgency=low
+
+  * Fix BS when pairing fail with weak signal device
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Tue, 02 Mar 2010 20:47:16 +0900
+
+bluez (4.58-16) unstable; urgency=low
+
+  *  unified authenticate interface for DM and JSR82 
+
+ -- Ankur Gandhi <a.gandhi@samsung.com>  Thu, 25 Feb 2010 10:26:24 +0530
+
+bluez (4.58-15) unstable; urgency=low
+
+  *  Changes for Jsr82 authorization fix in bluez   
+
+ -- Hathab Shajahan <hathab.s@samsung.com>  Wed, 24 Feb 2010 12:17:00 +0530
+
+bluez (4.58-14) unstable; urgency=low
+
+  * Modified auth interface for JSR82 and corrected delete device problem when
+    device is paired using SSP 
+
+ -- Ankur Gandhi <a.gandhi@samsung.com>  Mon, 22 Feb 2010 18:35:37 +0530
+
+bluez (4.58-13) unstable; urgency=low
+
+  *To Take N-project Changes 
+
+ -- Hathab Shajahan <hathab.s@samsung.com>  Thu, 11 Feb 2010 16:40:01 +0530
+
+bluez (4.58-12) unstable; urgency=low
+
+  * Fix A2DP gstreamer plugin for 3gp play (merge back from N code - sbc/mpeg
+    dynamic bin to sbc static)
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Fri, 05 Feb 2010 22:38:13 +0900
+
+bluez (4.58-11) unstable; urgency=low
+
+  * Bluez merged with N-project to absorb the fixes.
+
+ -- Hathab Shajahan <hathab.s@samsung.com>  Thu, 04 Feb 2010 17:14:02 +0530
+
+bluez (4.58-10) unstable; urgency=low
+
+  * Fix SDP record get after pairing crash
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Mon, 01 Feb 2010 19:53:19 +0900
+
+bluez (4.58-9) unstable; urgency=low
+
+  * Fix source file mod to 644
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Fri, 29 Jan 2010 02:02:25 +0900
+
+bluez (4.58-8) unstable; urgency=low
+
+  * Added JSR82 support 
+
+ -- Hathab Shajahan <hathab.s@samsung.com>  Thu, 28 Jan 2010 17:01:15 +0530
+
+bluez (4.58-7) unstable; urgency=low
+
+  * Added JSR82 support 
+
+ -- Ankur Gandhi <a.gandhi@samsung.com>  Thu, 28 Jan 2010 16:52:52 +0530
+
+bluez (4.58-6) unstable; urgency=low
+
+  * Add debug package having debugging symbols
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Thu, 21 Jan 2010 16:35:14 +0900
+
+bluez (4.58-5) unstable; urgency=low
+
+  * Fix cleaning rules, restore git original files
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Tue, 29 Dec 2009 19:09:13 +0900
+
+bluez (4.58-4) unstable; urgency=low
+
+  * Change Maintainer email address and Maintainers list format
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Tue, 22 Dec 2009 17:37:05 +0900
+
+bluez (4.58-3) unstable; urgency=low
+
+  * Fix install conf file and Add bluez-alsa package
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Tue, 08 Dec 2009 20:48:03 +0900
+
+bluez (4.58-2) unstable; urgency=low
+
+  * Add as-needed LDFLAGS
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Fri, 20 Nov 2009 16:31:44 +0900
+
+bluez (4.58-1) unstable; urgency=low
+
+  * Upgrade bluez-4.57 to bluez-4.58
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Thu, 19 Nov 2009 09:38:31 +0900
+
+bluez (4.57-4) unstable; urgency=low
+
+  * Fix bluez-gstreamer dependency
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Tue, 17 Nov 2009 15:35:30 +0900
+
+bluez (4.57-3) unstable; urgency=low
+
+  * Fix build break with wrong src dependency
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Tue, 17 Nov 2009 11:55:46 +0900
+
+bluez (4.57-2) unstable; urgency=low
+
+  * Delete install files
+
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Mon, 16 Nov 2009 15:10:46 +0900
+
+bluez (4.57-1) unstable; urgency=low
+
+  * Initial Release.
 
- -- Chanyeol Park <chanyeol.park@samsung.com>  Wed, 07 Dec 2011 12:53:10 +0900
+ -- Seung-Woo Kim <sw0312.kim@samsung.com>  Thu, 12 Nov 2009 09:50:16 +0900
old mode 100755 (executable)
new mode 100644 (file)
index 807407c..6c4e5f1
@@ -10,7 +10,7 @@ DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
 DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
 
 CFLAGS ?= -Wall -g
-LDFLAGS ?= 
+LDFLAGS ?=
 PREFIX ?= /usr
 DATADIR ?= /opt
 
@@ -24,7 +24,7 @@ endif
 
 MACHINE="aquila"
 BT_CHIP_CFLAGS=-D__BROADCOM_PATCH__
-CHIP_OPTIONS=--disable-bccmd 
+CHIP_OPTIONS=--disable-bccmd
 
 configure: configure.ac
        aclocal
@@ -37,9 +37,9 @@ config.status: configure
        dh_testdir
 
        # Add here commands to configure the package.
-       CFLAGS="$(CFLAGS) -D__TIZEN_PATCH__ $(BT_CHIP_CFLAGS)" \
+       CFLAGS="$(CFLAGS) -D__TIZEN_PATCH__ -D__BROADCOM_PATCH__ $(BT_CHIP_CFLAGS)" \
        LDFLAGS="$(LDFLAGS) -Wl,--warn-unresolved-symbols" \
-       ./configure     --prefix=$(PREFIX) \
+       ./configure     --prefix=$(PREFIX) \
                        --sysconfdir=$(PREFIX)/etc \
                        --localstatedir=$(DATADIR)/var \
                        --enable-pie \
@@ -57,7 +57,6 @@ config.status: configure
                        --disable-cups \
                        --disable-test \
                        --enable-health \
-                       --disable-udevrules \
                        --enable-dbusoob \
                        --with-telephony=tizen
 
@@ -95,7 +94,7 @@ clean:
 install: build
        dh_testdir
        dh_testroot
-       dh_clean -k 
+       dh_clean -k
        dh_installdirs
 
        # Add here commands to install the package into debian/tmp.
@@ -113,7 +112,7 @@ binary-indep: build install
 binary-arch: build install
        dh_testdir
        dh_testroot
-       dh_installchangelogs 
+       dh_installchangelogs
        dh_installdocs
        dh_installexamples
        dh_install --sourcedir=debian/tmp
@@ -131,4 +130,4 @@ binary-arch: build install
        dh_builddeb
 
 binary: binary-indep binary-arch
-.PHONY: build clean binary-indep binary-arch binary install 
+.PHONY: build clean binary-indep binary-arch binary install
diff --git a/deviceinfo/deviceinfo.c b/deviceinfo/deviceinfo.c
new file mode 100644 (file)
index 0000000..8c3af93
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "gattrib.h"
+#include "attio.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "log.h"
+#include "deviceinfo.h"
+
+struct deviceinfo {
+       struct btd_device       *dev;           /* Device reference */
+       GAttrib                 *attrib;        /* GATT connection */
+       guint                   attioid;        /* Att watcher id */
+       struct att_range        *svc_range;     /* DeviceInfo range */
+       GSList                  *chars;         /* Characteristics */
+};
+
+static GSList *servers = NULL;
+
+struct characteristic {
+       struct gatt_char        attr;   /* Characteristic */
+       struct deviceinfo       *d;     /* deviceinfo where the char belongs */
+};
+
+static void deviceinfo_free(gpointer user_data)
+{
+       struct deviceinfo *d = user_data;
+
+       if (d->attioid > 0)
+               btd_device_remove_attio_callback(d->dev, d->attioid);
+
+       if (d->attrib != NULL)
+               g_attrib_unref(d->attrib);
+
+       g_slist_free_full(d->chars, g_free);
+
+       btd_device_unref(d->dev);
+       g_free(d->svc_range);
+       g_free(d);
+}
+
+static gint cmp_device(gconstpointer a, gconstpointer b)
+{
+       const struct deviceinfo *d = a;
+       const struct btd_device *dev = b;
+
+       if (dev == d->dev)
+               return 0;
+
+       return -1;
+}
+
+static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len,
+                                                       gpointer user_data)
+{
+       struct characteristic *ch = user_data;
+       uint8_t value[ATT_MAX_MTU];
+       int vlen;
+
+       if (status != 0) {
+               error("Error reading PNP_ID value: %s", att_ecode2str(status));
+               return;
+       }
+
+       if (!dec_read_resp(pdu, len, value, &vlen)) {
+               error("Error reading PNP_ID: Protocol error");
+               return;
+       }
+
+       if (vlen < 7) {
+               error("Error reading PNP_ID: Invalid pdu length received");
+               return;
+       }
+
+       device_set_pnpid(ch->d->dev, value[0], att_get_u16(&value[1]),
+                               att_get_u16(&value[3]), att_get_u16(&value[5]));
+}
+
+static void process_deviceinfo_char(struct characteristic *ch)
+{
+       if (g_strcmp0(ch->attr.uuid, PNPID_UUID) == 0)
+               gatt_read_char(ch->d->attrib, ch->attr.value_handle, 0,
+                                                       read_pnpid_cb, ch);
+}
+
+static void configure_deviceinfo_cb(GSList *characteristics, guint8 status,
+                                                       gpointer user_data)
+{
+       struct deviceinfo *d = user_data;
+       GSList *l;
+
+       if (status != 0) {
+               error("Discover deviceinfo characteristics: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       for (l = characteristics; l; l = l->next) {
+               struct gatt_char *c = l->data;
+               struct characteristic *ch;
+
+               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->d = d;
+
+               d->chars = g_slist_append(d->chars, ch);
+
+               process_deviceinfo_char(ch);
+       }
+}
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+       struct deviceinfo *d = user_data;
+
+       d->attrib = g_attrib_ref(attrib);
+
+       gatt_discover_char(d->attrib, d->svc_range->start, d->svc_range->end,
+                                       NULL, configure_deviceinfo_cb, d);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+       struct deviceinfo *d = user_data;
+
+       g_attrib_unref(d->attrib);
+       d->attrib = NULL;
+}
+
+int deviceinfo_register(struct btd_device *device, struct gatt_primary *prim)
+{
+       struct deviceinfo *d;
+
+       d = g_new0(struct deviceinfo, 1);
+       d->dev = btd_device_ref(device);
+       d->svc_range = g_new0(struct att_range, 1);
+       d->svc_range->start = prim->range.start;
+       d->svc_range->end = prim->range.end;
+
+       servers = g_slist_prepend(servers, d);
+
+       d->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
+                                               attio_disconnected_cb, d);
+       return 0;
+}
+
+void deviceinfo_unregister(struct btd_device *device)
+{
+       struct deviceinfo *d;
+       GSList *l;
+
+       l = g_slist_find_custom(servers, device, cmp_device);
+       if (l == NULL)
+               return;
+
+       d = l->data;
+       servers = g_slist_remove(servers, d);
+
+       deviceinfo_free(d);
+}
diff --git a/deviceinfo/deviceinfo.h b/deviceinfo/deviceinfo.h
new file mode 100644 (file)
index 0000000..7a804a5
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int deviceinfo_register(struct btd_device *device, struct gatt_primary *prim);
+void deviceinfo_unregister(struct btd_device *device);
diff --git a/deviceinfo/main.c b/deviceinfo/main.c
new file mode 100644 (file)
index 0000000..82ecc82
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include "plugin.h"
+#include "manager.h"
+#include "hcid.h"
+#include "log.h"
+
+static int deviceinfo_init(void)
+{
+       if (!main_opts.gatt_enabled) {
+               error("DIS cannot start: GATT is disabled");
+               return -ENOTSUP;
+       }
+
+       return deviceinfo_manager_init();
+}
+
+static void deviceinfo_exit(void)
+{
+       deviceinfo_manager_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(deviceinfo, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                                       deviceinfo_init, deviceinfo_exit)
diff --git a/deviceinfo/manager.c b/deviceinfo/manager.c
new file mode 100644 (file)
index 0000000..1d59918
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <glib.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "deviceinfo.h"
+#include "manager.h"
+
+static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct gatt_primary *prim = a;
+       const char *uuid = b;
+
+       return g_strcmp0(prim->uuid, uuid);
+}
+
+static int deviceinfo_driver_probe(struct btd_device *device, GSList *uuids)
+{
+       struct gatt_primary *prim;
+       GSList *primaries, *l;
+
+       primaries = btd_device_get_primaries(device);
+
+       l = g_slist_find_custom(primaries, DEVICE_INFORMATION_UUID,
+                                                       primary_uuid_cmp);
+       if (l == NULL)
+               return -EINVAL;
+
+       prim = l->data;
+
+       return deviceinfo_register(device, prim);
+}
+
+static void deviceinfo_driver_remove(struct btd_device *device)
+{
+       deviceinfo_unregister(device);
+}
+
+static struct btd_device_driver deviceinfo_device_driver = {
+       .name   = "deviceinfo-driver",
+       .uuids  = BTD_UUIDS(DEVICE_INFORMATION_UUID),
+       .probe  = deviceinfo_driver_probe,
+       .remove = deviceinfo_driver_remove
+};
+
+int deviceinfo_manager_init(void)
+{
+       return btd_register_device_driver(&deviceinfo_device_driver);
+}
+
+void deviceinfo_manager_exit(void)
+{
+       btd_unregister_device_driver(&deviceinfo_device_driver);
+}
diff --git a/deviceinfo/manager.h b/deviceinfo/manager.h
new file mode 100644 (file)
index 0000000..0f742ca
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int deviceinfo_manager_init(void);
+void deviceinfo_manager_exit(void);
index 20cef03..dccb6bf 100644 (file)
@@ -165,10 +165,11 @@ Methods           dict GetProperties()
                        of its registered agents will be removed.
 
                        The capability parameter can have the values
-                       "DisplayOnly", "DisplayYesNo", "KeyboardOnly" and
-                       "NoInputNoOutput" which reflects the input and output
-                       capabilities of the agent. If an empty string is
-                       used it will fallback to "DisplayYesNo".
+                       "DisplayOnly", "DisplayYesNo", "KeyboardOnly",
+                       "NoInputNoOutput" and "KeyboardDisplay" which reflects
+                       the input and output capabilities of the agent. If an
+                       empty string is used it will fallback to
+                       "DisplayYesNo".
 
                        Possible errors: org.bluez.Error.InvalidArguments
                                         org.bluez.Error.AlreadyExists
@@ -261,7 +262,7 @@ Properties  string Address [readonly]
 
                        The pairable timeout in seconds. A value of zero
                        means that the timeout is disabled and it will stay in
-                       pareable mode forever.
+                       pairable mode forever.
 
                uint32 DiscoverableTimeout [readwrite]
 
index 9ab2063..5c8d4d2 100644 (file)
@@ -61,6 +61,30 @@ Methods              void Release()
                        so the display should be zero-padded at the start if
                        the value contains less than 6 digits.
 
+               void DisplayPinCode(object device, string pincode)
+
+                       This method gets called when the service daemon
+                       needs to display a pincode for an authentication.
+
+                       An empty reply should be returned. When the pincode
+                       needs no longer to be displayed, the Cancel method
+                       of the agent will be called.
+
+                       If this method is not implemented the RequestPinCode
+                       method will be used instead.
+
+                       This is used during the pairing process of keyboards
+                       that don't support Bluetooth 2.1 Secure Simple Pairing,
+                       in contrast to DisplayPasskey which is used for those
+                       that do.
+
+                       This method will only ever be called once since
+                       older keyboards do not support typing notification.
+
+                       Note that the PIN will always be a 6-digit number,
+                       zero-padded to 6 digits. This is for harmony with
+                       the later specification.
+
                void RequestConfirmation(object device, uint32 passkey)
 
                        This method gets called when the service daemon
index b85400b..ad58d55 100644 (file)
@@ -127,6 +127,11 @@ Methods            void Connect()
 
                        Possible Errors: org.bluez.Error.DoesNotExist
                                         org.bluez.Error.InvalidArguments
+__TIZEN_PATCH__
+               void SetVoiceDial(boolean)
+
+                       Sends enable/disable Voice Recognition to headset.
+__TIZEN_PATCH__
 
 Signals                void AnswerRequested()
 
@@ -428,7 +433,7 @@ properties  boolean Connected [readonly]
 
                uint16 RegistrationStatus [readonly]
 
-                       Service availability indicatior of AG, where:
+                       Service availability indicator of AG, where:
                        0 implies no service. No Home/Roam network available.
                        1 implies presence of service. Home/Roam network
                        available.
index e8fc314..4a170e4 100644 (file)
@@ -129,6 +129,10 @@ Properties string Address [readonly]
 
                        Vendor unique numeric identifier.
 
+               uint16 VendorSource [readonly]
+
+                       Vendor source numeric identifier.
+
                uint16 Product [readonly]
 
                        Product unique numeric identifier.
@@ -187,7 +191,7 @@ Properties  string Address [readonly]
                        device name. Setting an empty string as alias will
                        convert it back to the remote device name.
 
-                       When reseting the alias with an empty string, the
+                       When resetting the alias with an empty string, the
                        emitted PropertyChanged signal will show the remote
                        name again.
 
index 3d0a717..7a000cb 100644 (file)
@@ -82,8 +82,8 @@ Methods:
        void DestroyChannel(object channel)
 
                Destroys the data channel object. Only the creator of the
-               channel or the creator of the HealtApplication that received the
-               data channel will be able to destroy it
+               channel or the creator of the HealthApplication that received
+               the data channel will be able to destroy it.
 
                Possible errors: org.bluez.Error.InvalidArguments
                                org.bluez.Error.NotFound
@@ -131,7 +131,7 @@ Methods:
                Returns all properties for the interface. See the properties
                section for available properties.
 
-               Posible errors: org.bluez.Error.NotAllowed
+               Possible errors: org.bluez.Error.NotAllowed
 
        fd Acquire()
 
index cf2e730..fad89ae 100644 (file)
@@ -66,9 +66,7 @@ Methods               void NewConnection(filedescriptor fd, uint16 version)
 
                        This method gets called whenever a new handsfree
                        connection has been established.  The objectpath
-                       contains the object path of the remote device.  This
-                       method assumes that DBus daemon with file descriptor
-                       passing capability is being used.
+                       contains the object path of the remote device.
 
                        The agent should only return successfully once the
                        establishment of the service level connection (SLC)
index c53ab7b..4446439 100644 (file)
@@ -25,7 +25,7 @@ Methods               void RegisterEndpoint(object endpoint, dict properties)
 
                                byte Codec:
 
-                                       Assigned mumber of codec that the
+                                       Assigned number of codec that the
                                        endpoint implements. The values should
                                        match the profile specification which
                                        is indicated by the UUID.
@@ -308,7 +308,7 @@ Properties  object Device [readonly]
 
                byte Codec [readonly]
 
-                       Assigned mumber of codec that the transport support.
+                       Assigned number of codec that the transport support.
                        The values should match the profile specification which
                        is indicated by the UUID.
 
@@ -319,7 +319,7 @@ Properties  object Device [readonly]
 
                uint16 Delay [readwrite]
 
-                       Optional. Transport delay in 1/10 of milisecond, this
+                       Optional. Transport delay in 1/10 of millisecond, this
                        property is only writeable when the transport was
                        acquired by the sender.
 
@@ -341,3 +341,11 @@ Properties object Device [readonly]
                        Optional. Indicates where is the transport being routed
 
                        Possible Values: "HCI" or "PCM"
+
+               uint16 Volume [readwrite]
+
+                       Optional. Indicates volume level of the transport,
+                       this property is only writeable when the transport was
+                       acquired by the sender.
+
+                       Possible Values: 0-127
index c8305d9..51c9b46 100644 (file)
@@ -23,6 +23,8 @@ Packet Structures
        +-------------------+-------------------+-------------------+
        |                                                           |
 
+All fields are in little-endian byte order (least significant byte first).
+
 Controller Index can have a special value <non-controller> to indicate that
 command or event is not related to any controller. Possible values:
 
@@ -30,6 +32,30 @@ command or event is not related to any controller. Possible values:
        <non-controller>        0xFFFF
 
 
+Error Codes
+===========
+
+The following values have been defined for use with the Command Status
+and Command Complete events:
+
+0x00   Success
+0x01   Unknown Command
+0x02   Not Connected
+0x03   Failed
+0x04   Connect Failed
+0x05   Authentication Failed
+0x06   Not Paired
+0x07   No Resources
+0x08   Timeout
+0x09   Already Connected
+0x0A   Busy
+0x0B   Rejected
+0x0C   Not Supported
+0x0D   Invalid Parameters
+0x0E   Disconnected
+0x0F   Not Powered
+
+
 Read Management Version Information Command
 ===========================================
 
@@ -39,17 +65,34 @@ Read Management Version Information Command
        Return Parameters:      Version (1 Octets)
                                Revision (2 Octets)
 
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
 
-Read Management Supported Features Command
+
+Read Management Supported Commands Command
 ==========================================
 
        Command Code:           0x0002
        Controller Index:       <non-controller>
        Command Parameters:
-       Return Parameters:      Features (8 Octets)
+       Return Parameters:      Num_Of_Commands (2 Octets)
+                               Num_Of_Events (2 Octets)
+                               Command1 (2 Octets)
+                               Command2 (2 Octets)
+                               ...
+                               Event1 (2 Octets)
+                               Event2 (2 Octets)
+                               ...
+
+       The commands Read Management Version Information and Read
+       management Supported Commands are not included in this list.
+       Both commands are always supported and mandatory.
 
-               Feature Bit 0:  Controller Support
-               Feature Bit 1:  Tracing Support
+       The events Command Status and Command Complete are not included
+       in this list. Both are implicit and mandatory.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
 
 
 Read Controller Index List Command
@@ -61,6 +104,9 @@ Read Controller Index List Command
        Return Parameters:      Num_Controllers (2 Octets)
                                Controller_Index[i] (2 Octets)
 
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Read Controller Information Command
 ===================================
@@ -94,6 +140,9 @@ Read Controller Information Command
                9       High Speed
                10      Low Energy
 
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Set Powered Command
 ===================
@@ -103,6 +152,13 @@ Set Powered Command
        Command Parameters:     Powered (1 Octet)
        Return Parameters:      Current_Settings (4 Octets)
 
+       If discoverable setting is activated with a timeout, then
+       switching the controller off will expire this timeout and
+       disable discoverable.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Set Discoverable Command
 ========================
@@ -113,9 +169,21 @@ Set Discoverable Command
                                Timeout (2 Octets)
        Return Parameters:      Current_Settings (4 Octets)
 
-       Timeout is the time in seconds and is only meningful when
+       Timeout is the time in seconds and is only meaningful when
        Discoverable is set to 1.
 
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
+
+       However using a timeout when the controller is not powered will
+       return an error.
+
+       When switching discoverable on and the connectable setting is
+       off it will return an error.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Set Connectable Command
 =======================
@@ -125,6 +193,20 @@ Set Connectable Command
        Command Parameters:     Connectable (1 Octet)
        Return Parameters:      Current_Settings (4 Octets)
 
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
+
+       When switching connectable off, it will also switch off the
+       discoverable setting. Switching connectable back on will not
+       restore a previous discoverable. It will stay off and needs
+       to be manually switched back on.
+
+       When switching connectable off, it will expire a discoverable
+       setting with a timeout.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Set Fast Connectable Command
 ============================
@@ -134,6 +216,14 @@ Set Fast Connectable Command
        Command Parameters:     Enable (1 Octet)
        Return Parameters:      Current_Settings (4 Octets)
 
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
+
+       If connectable is not set, then this command will fail.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Set Pairable Command
 ====================
@@ -143,6 +233,17 @@ Set Pairable Command
        Command Parameters:     Pairable (1 Octet)
        Return Parameters:      Current_Settings (4 Octets)
 
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
+
+       Turning pairable on will not automatically switch the controller
+       into connectable mode. That needs to be done separately.
+
+       The setting will be remembered during power down/up toggles.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Set Link Security Command
 =========================
@@ -152,6 +253,12 @@ Set Link Security Command
        Command Parameters:     Link_Security (1 Octet)
        Return Parameters:      Current_Settings (4 Octets)
 
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Set Secure Simple Pairing Command
 =================================
@@ -161,6 +268,15 @@ Set Secure Simple Pairing Command
        Command Parameters:     Secure_Simple_Pairing (1 Octet)
        Return Parameters:      Current_Settings (4 Octets)
 
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
+
+       In case the controller does not support Secure Simple Pairing,
+       the command will fail regardless.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Set High Speed Command
 ======================
@@ -170,6 +286,15 @@ Set High Speed Command
        Command Parameters:     High_Speed (1 Octet)
        Return Parameters:      Current_Settings (4 Octets)
 
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
+
+       In case the kernel subsystem does not support High Speed, the
+       command will fail regardless.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Set Low Energy Command
 ======================
@@ -179,6 +304,15 @@ Set Low Energy Command
        Command Parameters:     Low_Energy (1 Octet)
        Return Parameters:      Current_Settings (4 Octets)
 
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
+
+       In case the kernel subsystem does not support Low Energy or the
+       controller does not either, the command will fail regardless.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Set Device Class
 ================
@@ -192,6 +326,16 @@ Set Device Class
        This command will also implicitly disable caching of pending CoD
        and EIR updates.
 
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
+
+       In case the controller is powered off, 0x000000 will be returned
+       for the class of device parameter. And after power on the new
+       value will be announced via class of device changed event.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Set Local Name Command
 ======================
@@ -203,9 +347,20 @@ Set Local Name Command
        Return Parameters:      Name (249 Octets)
                                Short_Name (11 Octets)
 
-       The name parameters need to always end with a nul byte (failure
+       The name parameters need to always end with a null byte (failure
        to do so will cause the command to fail).
 
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
+
+       The values of name and short name will be remembered when
+       switching the controller off and back on again. So the name
+       and short name only have to be set once when a new controller
+       is found and will stay until removed.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Add UUID Command
 ================
@@ -216,6 +371,16 @@ Add UUID Command
                                SVC_Hint (1 Octet)
        Return Parameters:      Class_Of_Device (3 Octets)
 
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
+
+       In case the controller is powered off, 0x000000 will be returned
+       for the class of device parameter. And after power on the new
+       value will be announced via class of device changed event.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Remove UUID Command
 ===================
@@ -225,6 +390,19 @@ Remove UUID Command
        Command Parameters:     UUID (16 Octets)
        Return Parameters:      Class_Of_Device (3 Octets)
 
+       When the UUID parameter is an empty UUID (16 x 0x00), then all
+       previously loaded UUIDs will be removed.
+
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
+
+       In case the controller is powered off, 0x000000 will be returned
+       for the class of device parameter. And after power on the new
+       value will be announced via class of device changed event.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Load Link Keys Command
 ======================
@@ -235,7 +413,8 @@ Load Link Keys Command
                                Key_Count (2 Octets)
                                Key1 {
                                        Address (6 Octets)
-                                       Type (1 Octet)
+                                       Address_Type (1 Octet)
+                                       Key_Type (1 Octet)
                                        Value (16 Octets)
                                        PIN_Length (1 Octet)
                                }
@@ -243,18 +422,35 @@ Load Link Keys Command
                                ...
        Return Parameters:
 
+       This command can be used when the controller is not powered.
 
-Remove Keys Command
-===================
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
+
+Load Long Term 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)
+       Command Parameters:     Key Count (2 Octets)
+                               Key1 {
+                                       Address (6 Octets)
+                                       Address_Type (1 Octet)
+                                       Authenticated (1 Octet)
+                                       Master (1 Octet)
+                                       Encryption Size (1 Octet)
+                                       Enc. Diversifier (2 Octets)
+                                       Random Number (8 Octets)
+                                       Value (16 Octets)
+                               }
+                               Key2 {  }
+                               ...
 
-       Removes all keys associated with the remote device.
+       This command can be used when the controller is not powered.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
 
 
 Disconnect Command
@@ -263,8 +459,14 @@ Disconnect Command
        Command Code:           0x0014
        Controller Index:       <controller id>
        Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
        Return Parameters:      Address (6 Octets)
-                               Status (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
 
 
 Get Connections Command
@@ -276,26 +478,38 @@ Get Connections Command
        Return Parameters:      Connection_Count (2 Octets)
                                Address1 {
                                        Address (6 Octets)
-                                       Type (1 Octet)
+                                       Address_Type (1 Octet)
                                }
                                Address2 { }
                                ...
 
-       Possible values for the Type parameter:
+       Possible values for the Address_Type parameter:
                0       BR/EDR
                1       LE Public
                2       LE Random
 
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 PIN Code Reply Command
 =======================
 
        Command Code:           0x0016
        Controller Index:       <controller id>
-       Command Parameters:
-       Return Parameters:      Address (6 Octets)
+       Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
                                PIN_Length (1 Octet)
                                PIN_Code (16 Octets)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
 
 
 PIN Code Negative Reply Command
@@ -303,8 +517,15 @@ PIN Code Negative Reply Command
 
        Command Code:           0x0017
        Controller Index:       <controller id>
-       Command Parameters:
+       Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
        Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
 
 
 Set IO Capability Command
@@ -315,6 +536,11 @@ Set IO Capability Command
        Command Parameters:     IO_Capability (1 Octet)
        Return Parameters:
 
+       This command can be used when the controller is not powered.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Pair Device Command
 ===================
@@ -326,95 +552,185 @@ Pair Device Command
                                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
 
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
+
+
+Cancel Pair Device
+==================
+
+       Command Code:           0x001A
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       The Address and Address_Type parameters should match what was
+       given to a preceding Pair Device command.
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
+
+
+Unpair Device Command
+=====================
+
+       Command Code:           0x001B
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
+                               Disconnect (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       Removes all keys associated with the remote device.
+
+       The Disconnect parameter tells the kernel whether to forcefully
+       disconnect any existing connections to the device. It should in
+       practice always be 1 except for some special GAP qualification
+       test-cases where a key removal without disconnecting is needed.
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
+
 
 User Confirmation Reply Command
 ===============================
 
-       Command Code:           0x001A
+       Command Code:           0x001C
        Controller Index:       <controller id>
        Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
        Return Parameters:      Address (6 Octets)
-                               Status (1 Octet)
+                               Address_Type (1 Octet)
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
 
 
 User Confirmation Negative Reply Command
 ========================================
 
-       Command Code:           0x001B
+       Command Code:           0x001D
        Controller Index:       <controller id>
        Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
        Return Parameters:      Address (6 Octets)
-                               Status (1 Octet)
+                               Address_Type (1 Octet)
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
 
 
 User Passkey Reply Command
 ==========================
 
-       Command Code:           0x001C
+       Command Code:           0x001E
        Controller Index:       <controller id>
        Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
                                Passkey (4 Octets)
        Return Parameters:      Address (6 Octets)
-                               Status (1 Octet)
+                               Address_Type (1 Octet)
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
 
 
 User Passkey Negative Reply Command
 ===================================
 
-       Command Code:           0x001D
+       Command Code:           0x001F
        Controller Index:       <controller id>
        Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
        Return Parameters:      Address (6 Octets)
-                               Status (1 Octet)
+                               Address_Type (1 Octet)
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
 
 
 Read Local Out Of Band Data Command
 ===================================
 
-       Command Code:           0x001E
+       Command Code:           0x0020
        Controller Index:       <controller id>
        Command Parameters:
        Return Parameters:      Hash (16 Octets)
                                Randomizer (16 Octets)
 
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
 
 Add Remote Out Of Band Data Command
 ===================================
 
-       Command Code:           0x001F
+       Command Code:           0x0021
        Controller Index:       <controller id>
        Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
                                Hash (16 Octets)
                                Randomizer (16 Octets)
-       Return Parameters:
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
 
 
 Remove Remote Out Of Band Data Command
-========================================
+======================================
 
-       Command Code:           0x0020
+       Command Code:           0x0022
        Controller Index:       <controller id>
        Command Parameters:     Address (6 Octets)
-       Return Parameters:
+                               Address_Type (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
 
 
 Start Discovery Command
 =======================
 
-       Command Code:           0x00021
+       Command Code:           0x0023
        Controller Index:       <controller id>
-       Command Parameters:     Type (1 Octet)
-       Return Parameters:
+       Command Parameters:     Address_Type (1 Octet)
+       Return Parameters:      Address_Type (1 Octet)
 
-       Possible values for the Type parameter are a bit-wise or of the
-       following bits:
+       Possible values for the Address_Type parameter are a bit-wise or
+       of the following bits:
 
                1       BR/EDR
                2       LE Public
@@ -426,118 +742,107 @@ Start Discovery Command
                6       LE (public & random)
                7       BR/EDR/LE (interleaved discovery)
 
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
+
 
 Stop Discovery Command
 ======================
 
-       Command Code:           0x00022
+       Command Code:           0x0024
        Controller Index:       <controller id>
-       Command Parameters:
-       Return Parameters:
+       Command Parameters:     Address_Type (1 Octet)
+       Return Parameters:      Address_Type (1 Octet)
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
 
 
 Confirm Name Command
 ====================
 
-       Command Code:           0x00023
+       Command Code:           0x0025
        Controller Index:       <controller id>
        Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
                                Name_Known (1 Octet)
        Return Parameters:      Address (6 Octets)
-                               Status (1 Octet)
+                               Address_Type (1 Octet)
 
        This command is only valid during device discovery and is
        expected for each Device Found event with the Confirm Name
        flag set.
 
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
+
 
 Block Device Command
 ====================
 
-       Command Code:           0x00024
+       Command Code:           0x0026
        Controller Index:       <controller id>
        Command Parameters:     Address (6 Octets)
-       Return Parameters:
+                               Address_Type (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command can be used when the controller is not powered.
+
+       This command generates a Command Complete event on success
+       or failure.
 
 
 Unblock Device Command
 ======================
 
-       Command Code:           0x00025
+       Command Code:           0x0027
        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
-=================================
+                               Address_Type (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
 
-       Command Code:           <not yet assigned>
-       Controller Index:       <non-controller>
-       Command Parameters:     Buffer_Size (2 Octets)
-       Return Parameters:      Status (1 Octet)
+       This command can be used when the controller is not powered.
 
-               Buffer Size in Kilobytes
+       This command generates a Command Complete event on success
+       or failure.
 
 
-Read Controller Tracing Filter Command
-=======================================
+Set Device ID Command
+=====================
 
-       Command Code:           <not yet assigned>
+       Command Code:           0x0028
        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)
+       Command Parameters:     Source (2 Octets)
+                               Vendor (2 Octets)
+                               Product (2 Octets)
+                               Version (2 Octets)
+       Return Parameters:
 
-               Tracing_Enable: 0x00 Tracing disabled
-                               0x01 Command and Event tracing
-                               0x02 Command, Event and ACL tracing
-                               0x03 Command, Event, ACL and SCO tracing
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
 
+       The Source parameter selects the organization that assigned the
+       Vendor parameter:
 
-Write Controller Tracing Filter Command
-=======================================
+               0x0000  Disable Device ID
+               0x0001  Bluetooth SIG
+               0x0002  USB Implementer’s Forum
 
-       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)
+       The information are put into the EIR data. If the controller does
+       not support EIR or if SSP is disabled, this command will still
+       succeed. The information are stored for later use and will survive
+       toggling SSP on and off.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
 
 
 Command Complete Event
@@ -546,6 +851,7 @@ Command Complete Event
 Event Code             0x0001
 Controller Index:      <controller id> or <non-controller>
 Event Parameters       Command_Opcode (2 Octets)
+                       Status (1 Octet)
                        Return_Parameters
 
 
@@ -554,8 +860,8 @@ Command Status Event
 
 Event Code             0x0002
 Controller Index:      <controller id> or <non-controller>
-Event Parameters       Status (1 Octet)
-                       Command_Opcode (2 Octets)
+Event Parameters       Command_Opcode (2 Octets)
+                       Status (1 Octet)
 
 
 Controller Error Event
@@ -614,36 +920,61 @@ Event Code                0x0009
 Controller Index:      <controller id>
 Event Parameters       Key {
                                Address (6 Octets)
-                               Type (1 Octet)
+                               Address_Type (1 Octet)
+                               Key_Type (1 Octet)
                                Value (16 Octets)
                                PIN_Length (1 Octet)
                        }
-                       Old_Key_Type (1 Octet)
+
+
+New Long Term Key Event
+=======================
+
+Event Code             0x000A
+Controller Index       <controller id>
+Event Parameters       Store Hint (1 Octet)
+                       Key {
+                               Address (6 Octets)
+                               Address_Type (1 Octet)
+                               Authenticated (1 Octet)
+                               Master (1 Octet)
+                               Encryption Size (1 Octet)
+                               Enc. Diversifier (2 Octets)
+                               Random Number (8 Octets)
+                               Value (16 Octets)
+                       }
 
 
 Device Connected Event
 ======================
 
-Event Code             0x000A
+Event Code             0x000B
 Controller Index:      <controller id>
 Event Parameters       Address (6 Octets)
-                       Type (1 Octet)
+                       Address_Type (1 Octet)
+                       Flags (4 Octets)
+                       EIR_Data_Length (2 Octets)
+                       EIR_Data (0-65535 Octets)
 
-       Possible values for the Type parameter:
+       Possible values for the Address_Type parameter:
                0       BR/EDR
                1       LE Public
                2       LE Random
 
+       The following bits are defined for the Flags parameter:
+               0       Reserved (not in use)
+               1       Legacy Pairing
+
 
 Device Disconnected Event
 =========================
 
-Event Code             0x000B
+Event Code             0x000C
 Controller Index:      <controller id>
 Event Parameters       Address (6 Octets)
-                       Type (1 Octet)
+                       Address_Type (1 Octet)
 
-       Possible values for the Type parameter:
+       Possible values for the Address_Type parameter:
                0       BR/EDR
                1       LE Public
                2       LE Random
@@ -652,13 +983,13 @@ Event Parameters  Address (6 Octets)
 Connect Failed Event
 ====================
 
-Event Code             0x000C
+Event Code             0x000D
 Controller Index:      <controller id>
 Event Parameters       Address (6 Octets)
-                       Type (1 Octet)
+                       Address_Type (1 Octet)
                        Status (1 Octet)
 
-       Possible values for the Type parameter:
+       Possible values for the Address_Type parameter:
                0       BR/EDR
                1       LE Public
                2       LE Random
@@ -667,9 +998,10 @@ Event Parameters   Address (6 Octets)
 PIN Code Request Event
 ======================
 
-Event Code             0x000D
+Event Code             0x000E
 Controller Index:      <controller id>
 Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
                        Secure (1 Octet)
 
        Secure: 0x01  secure PIN code required
@@ -679,91 +1011,86 @@ Event Parameters Address (6 Octets)
 User Confirmation Request Event
 ===============================
 
-Event Code             0x000E
+Event Code             0x000F
 Controller Index:      <controller id>
 Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
+                       Confirm_Hint (1 Octet)
                        Value (4 Octets)
 
 
 User Passkey Request Event
 ==========================
 
-Event Code             0x000F
+Event Code             0x0010
 Controller Index:      <controller id>
 Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
 
 
 Authentication Failed Event
 ===========================
 
-Event Code             0x0010
+Event Code             0x0011
 Controller Index:      <controller id>
 Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
                        Status (1 Octet)
 
 
 Device Found Event
 ==================
 
-Event Code             0x0011
+Event Code             0x0012
 Controller Index       <controller id>
 Event Parameters       Address (6 Octets)
-                       Type (1 Octet)
-                       Class_Of_Device (3 Octets)
+                       Address_Type (1 Octet)
                        RSSI (1 Octet)
-                       Confirm Name (1 Octet)
-                       EIR_Data (240 Octets)
+                       Flags (4 Octets)
+                       EIR_Data_Length (2 Octets)
+                       EIR_Data (0-65535 Octets)
 
-       Possible values for the Type parameter:
+       Possible values for the Address_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)
+       The following bits are defined for the Flags parameter:
+               0       Confirm name
+               1       Legacy Pairing
 
 
 Discovering Event
 =================
 
-Event Code             0x00013
+Event Code             0x0013
 Controller Index       <controller id>
-Event Parameters       Discovering (1 Octet)
+Event Parameters       Address_Type (1 Octet)
+                       Discovering (1 Octet)
 
 
 Device Blocked Event
 ====================
 
-Event Code             0x00014
+Event Code             0x0014
 Controller Index       <controller id>
 Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
 
 
 Device Unblocked Event
 ======================
 
-Event Code             0x00015
+Event Code             0x0015
 Controller Index       <controller id>
 Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
 
 
-New Long Term Key Event
-=======================
+Device Unpaired 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)
-                       }
+Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
index cf64bbf..0c60d47 100644 (file)
@@ -4,8 +4,8 @@ BlueZ D-Bus Proximity API description
 Copyright (C) 2011  Claudio Takahasi <claudio.takahasi@openbossa.org>
 
 
-Proximity hierarchy
-=================
+Proximity Monitor hierarchy
+===========================
 
 Service                org.bluez
 Interface      org.bluez.ProximityMonitor
@@ -52,3 +52,39 @@ Properties
                        "none" will be emitted after the configured timeout.
                        When changing the level, signal is the confirmation
                        that the value was written in the remote.
+
+Proximity Reporter hierarchy
+===========================
+
+Shared service used by Proximity Path Loss and Find Me. Allows per device
+alert level handling.
+
+Service                org.bluez
+Interface      org.bluez.ProximityReporter
+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.
+
+Signals                PropertyChanged(string name, variant value)
+
+                       This signal indicates a changed value of a given
+                       property.
+
+Properties
+
+               string ImmediateAlertLevel [readonly]
+
+                       This property indicates that Immediate Alert Level
+                       characteristic in the local Immediate Alert Service
+                       was changed by the remote device. Property shared
+                       between Path Loss and Find Me. Values: "none", "mild",
+                       "high".
+
+               string LinkLossAlertLevel [readonly]
+
+                       This property indicates that Alert Level characteristic
+                       in the local Link Loss Service was changed by the
+                       remote device. Values: "none", "mild", "high".
index ad496d2..0bdbdcd 100644 (file)
@@ -51,7 +51,7 @@ Methods               fd ConnectFD(string pattern) [experimental]
                        timeouts in the client it is fine to call this method.
 
                        In that case one of patterns of the Connect method should
-                       be suplied instead of the TTY device.
+                       be supplied instead of the TTY device.
 
                        Possible errors: org.bluez.Error.InvalidArguments
                                         org.bluez.Error.DoesNotExist
index 6392d39..2271270 100644 (file)
@@ -103,7 +103,8 @@ Methods             void MeasurementReceived(dict measure)
                        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.
+                       health devices. The Type entry is only present if the
+                       measurement type is known. Otherwise, it is undefined.
 
                        Dict is defined as below:
                        {
diff --git a/emulator/btdev.c b/emulator/btdev.c
new file mode 100644 (file)
index 0000000..7d4517a
--- /dev/null
@@ -0,0 +1,1076 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bt.h"
+#include "btdev.h"
+
+#define le16_to_cpu(val) (val)
+#define cpu_to_le16(val) (val)
+
+struct btdev {
+       struct btdev *conn;
+
+       btdev_send_func send_handler;
+       void *send_data;
+
+        uint16_t manufacturer;
+        uint8_t  version;
+       uint16_t revision;
+       uint8_t  commands[64];
+       uint8_t  features[8];
+       uint16_t acl_mtu;
+       uint16_t acl_max_pkt;
+       uint8_t  country_code;
+       uint8_t  bdaddr[6];
+       uint8_t  le_features[8];
+       uint8_t  le_states[8];
+
+       uint16_t default_link_policy;
+       uint8_t  event_mask[8];
+       uint8_t  event_filter;
+       uint8_t  name[248];
+       uint8_t  dev_class[3];
+       uint16_t voice_setting;
+       uint16_t conn_accept_timeout;
+       uint16_t page_timeout;
+       uint8_t  scan_enable;
+       uint8_t  auth_enable;
+       uint8_t  inquiry_mode;
+       uint8_t  afh_assess_mode;
+       uint8_t  ext_inquiry_fec;
+       uint8_t  ext_inquiry_rsp[240];
+       uint8_t  simple_pairing_mode;
+       uint8_t  le_supported;
+       uint8_t  le_simultaneous;
+       uint8_t  le_event_mask[8];
+};
+
+#define MAX_BTDEV_ENTRIES 16
+
+static struct btdev *btdev_list[MAX_BTDEV_ENTRIES] = { };
+
+static inline int add_btdev(struct btdev *btdev)
+{
+       int i, index = -1;
+
+       for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
+               if (btdev_list[i] == NULL) {
+                       index = i;
+                       btdev_list[index] = btdev;
+                       break;
+               }
+       }
+
+       return index;
+}
+
+static inline int del_btdev(struct btdev *btdev)
+{
+       int i, index = -1;
+
+       for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
+               if (btdev_list[i] == btdev) {
+                       index = i;
+                       btdev_list[index] = NULL;
+                       break;
+               }
+       }
+
+       return index;
+}
+
+static inline struct btdev *find_btdev_by_bdaddr(const uint8_t *bdaddr)
+{
+       int i;
+
+       for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
+               if (btdev_list[i] && !memcmp(btdev_list[i]->bdaddr, bdaddr, 6))
+                       return btdev_list[i];
+       }
+
+       return NULL;
+}
+
+static void hexdump(const unsigned char *buf, uint16_t len)
+{
+       static const char hexdigits[] = "0123456789abcdef";
+       char str[68];
+       uint16_t i;
+
+       if (!len)
+               return;
+
+       for (i = 0; i < len; i++) {
+               str[((i % 16) * 3) + 0] = hexdigits[buf[i] >> 4];
+               str[((i % 16) * 3) + 1] = hexdigits[buf[i] & 0xf];
+               str[((i % 16) * 3) + 2] = ' ';
+               str[(i % 16) + 49] = isprint(buf[i]) ? buf[i] : '.';
+
+               if ((i + 1) % 16 == 0) {
+                       str[47] = ' ';
+                       str[48] = ' ';
+                       str[65] = '\0';
+                       printf("%-12c%s\n", ' ', str);
+                       str[0] = ' ';
+               }
+       }
+
+       if (i % 16 > 0) {
+               uint16_t j;
+               for (j = (i % 16); j < 16; j++) {
+                       str[(j * 3) + 0] = ' ';
+                       str[(j * 3) + 1] = ' ';
+                       str[(j * 3) + 2] = ' ';
+                       str[j + 49] = ' ';
+               }
+               str[47] = ' ';
+               str[48] = ' ';
+               str[65] = '\0';
+               printf("%-12c%s\n", ' ', str);
+       }
+}
+
+static void get_bdaddr(uint16_t id, uint8_t *bdaddr)
+{
+       bdaddr[0] = id & 0xff;
+       bdaddr[1] = id >> 8;
+       bdaddr[2] = 0x00;
+       bdaddr[3] = 0x01;
+       bdaddr[4] = 0xaa;
+       bdaddr[5] = 0x00;
+}
+
+struct btdev *btdev_create(uint16_t id)
+{
+       struct btdev *btdev;
+
+       btdev = malloc(sizeof(*btdev));
+       if (!btdev)
+               return NULL;
+
+       memset(btdev, 0, sizeof(*btdev));
+
+       btdev->manufacturer = 63;
+       btdev->version = 0x06;
+       btdev->revision = 0x0000;
+
+       btdev->features[0] |= 0x04;     /* Encryption */
+       btdev->features[0] |= 0x20;     /* Role switch */
+       btdev->features[0] |= 0x80;     /* Sniff mode */
+       btdev->features[1] |= 0x08;     /* SCO link */
+       btdev->features[3] |= 0x40;     /* RSSI with inquiry results */
+       btdev->features[3] |= 0x80;     /* Extended SCO link */
+       btdev->features[4] |= 0x08;     /* AFH capable slave */
+       btdev->features[4] |= 0x10;     /* AFH classification slave */
+       btdev->features[4] |= 0x40;     /* LE Supported */
+       btdev->features[5] |= 0x02;     /* Sniff subrating */
+       btdev->features[5] |= 0x04;     /* Pause encryption */
+       btdev->features[5] |= 0x08;     /* AFH capable master */
+       btdev->features[5] |= 0x10;     /* AFH classification master */
+       btdev->features[6] |= 0x01;     /* Extended Inquiry Response */
+       btdev->features[6] |= 0x02;     /* Simultaneous LE and BR/EDR */
+       btdev->features[6] |= 0x08;     /* Secure Simple Pairing */
+       btdev->features[6] |= 0x10;     /* Encapsulated PDU */
+       btdev->features[6] |= 0x20;     /* Erroneous Data Reporting */
+       btdev->features[6] |= 0x40;     /* Non-flushable Packet Boundary Flag */
+       btdev->features[7] |= 0x01;     /* Link Supervision Timeout Event */
+       btdev->features[7] |= 0x02;     /* Inquiry TX Power Level */
+       btdev->features[7] |= 0x80;     /* Extended features */
+
+       btdev->acl_mtu = 192;
+       btdev->acl_max_pkt = 1;
+
+       btdev->country_code = 0x00;
+
+       get_bdaddr(id, btdev->bdaddr);
+
+       add_btdev(btdev);
+
+       return btdev;
+}
+
+void btdev_destroy(struct btdev *btdev)
+{
+       if (!btdev)
+               return;
+
+       del_btdev(btdev);
+
+       free(btdev);
+}
+
+void btdev_set_send_handler(struct btdev *btdev, btdev_send_func handler,
+                                                       void *user_data)
+{
+       if (!btdev)
+               return;
+
+       btdev->send_handler = handler;
+       btdev->send_data = user_data;
+}
+
+static void send_packet(struct btdev *btdev, const void *data, uint16_t len)
+{
+       if (!btdev->send_handler)
+               return;
+
+       btdev->send_handler(data, len, btdev->send_data);
+}
+
+static void send_event(struct btdev *btdev, uint8_t event,
+                                               const void *data, uint8_t len)
+{
+       struct bt_hci_evt_hdr *hdr;
+       uint16_t pkt_len;
+       void *pkt_data;
+
+       pkt_len = 1 + sizeof(*hdr) + len;
+
+       pkt_data = malloc(pkt_len);
+       if (!pkt_data)
+               return;
+
+       ((uint8_t *) pkt_data)[0] = BT_H4_EVT_PKT;
+
+       hdr = pkt_data + 1;
+       hdr->evt = event;
+       hdr->plen = len;
+
+       if (len > 0)
+               memcpy(pkt_data + 1 + sizeof(*hdr), data, len);
+
+       send_packet(btdev, pkt_data, pkt_len);
+
+       free(pkt_data);
+}
+
+static void cmd_complete(struct btdev *btdev, uint16_t opcode,
+                                               const void *data, uint8_t len)
+{
+       struct bt_hci_evt_hdr *hdr;
+       struct bt_hci_evt_cmd_complete *cc;
+       uint16_t pkt_len;
+       void *pkt_data;
+
+       pkt_len = 1 + sizeof(*hdr) + sizeof(*cc) + len;
+
+       pkt_data = malloc(pkt_len);
+       if (!pkt_data)
+               return;
+
+       ((uint8_t *) pkt_data)[0] = BT_H4_EVT_PKT;
+
+       hdr = pkt_data + 1;
+       hdr->evt = BT_HCI_EVT_CMD_COMPLETE;
+       hdr->plen = sizeof(*cc) + len;
+
+       cc = pkt_data + 1 + sizeof(*hdr);
+       cc->ncmd = 0x01;
+       cc->opcode = cpu_to_le16(opcode);
+
+       if (len > 0)
+               memcpy(pkt_data + 1 + sizeof(*hdr) + sizeof(*cc), data, len);
+
+       send_packet(btdev, pkt_data, pkt_len);
+
+       free(pkt_data);
+}
+
+static void cmd_status(struct btdev *btdev, uint8_t status, uint16_t opcode)
+{
+       struct bt_hci_evt_cmd_status cs;
+
+       cs.status = status;
+       cs.ncmd = 0x01;
+       cs.opcode = cpu_to_le16(opcode);
+
+       send_event(btdev, BT_HCI_EVT_CMD_STATUS, &cs, sizeof(cs));
+}
+
+static void num_completed_packets(struct btdev *btdev)
+{
+       if (btdev->conn) {
+               struct bt_hci_evt_num_completed_packets ncp;
+
+               ncp.num_handles = 1;
+               ncp.handle = cpu_to_le16(42);
+               ncp.count = cpu_to_le16(1);
+
+               send_event(btdev, BT_HCI_EVT_NUM_COMPLETED_PACKETS,
+                                                       &ncp, sizeof(ncp));
+       }
+}
+
+static void inquiry_complete(struct btdev *btdev, uint8_t status)
+{
+       struct bt_hci_evt_inquiry_complete ic;
+       int i;
+
+       for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
+               if (!btdev_list[i] || btdev_list[i] == btdev)
+                       continue;
+
+               if (!(btdev_list[i]->scan_enable & 0x02))
+                       continue;
+
+               if (btdev->inquiry_mode == 0x02 &&
+                                       btdev_list[i]->ext_inquiry_rsp[0]) {
+                       struct bt_hci_evt_ext_inquiry_result ir;
+
+                       ir.num_resp = 0x01;
+                       memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
+                       memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
+                       ir.rssi = -60;
+                       memcpy(ir.data, btdev_list[i]->ext_inquiry_rsp, 240);
+
+                       send_event(btdev, BT_HCI_EVT_EXT_INQUIRY_RESULT,
+                                                       &ir, sizeof(ir));
+                       continue;
+               }
+
+               if (btdev->inquiry_mode > 0x00) {
+                       struct bt_hci_evt_inquiry_result_with_rssi ir;
+
+                       ir.num_resp = 0x01;
+                       memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
+                       memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
+                       ir.rssi = -60;
+
+                       send_event(btdev, BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI,
+                                                       &ir, sizeof(ir));
+               } else {
+                       struct bt_hci_evt_inquiry_result ir;
+
+                       ir.num_resp = 0x01;
+                       memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
+                       memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
+
+                       send_event(btdev, BT_HCI_EVT_INQUIRY_RESULT,
+                                                       &ir, sizeof(ir));
+               }
+        }
+
+       ic.status = status;
+
+       send_event(btdev, BT_HCI_EVT_INQUIRY_COMPLETE, &ic, sizeof(ic));
+}
+
+static void conn_complete(struct btdev *btdev,
+                                       const uint8_t *bdaddr, uint8_t status)
+{
+       struct bt_hci_evt_conn_complete cc;
+
+       if (!status) {
+               struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
+
+               btdev->conn = remote;
+               remote->conn = btdev;
+
+               cc.status = status;
+               memcpy(cc.bdaddr, btdev->bdaddr, 6);
+               cc.encr_mode = 0x00;
+
+               cc.handle = cpu_to_le16(42);
+               cc.link_type = 0x01;
+
+               send_event(remote, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc));
+
+               cc.handle = cpu_to_le16(42);
+               cc.link_type = 0x01;
+       } else {
+               cc.handle = cpu_to_le16(0x0000);
+               cc.link_type = 0x01;
+       }
+
+       cc.status = status;
+       memcpy(cc.bdaddr, bdaddr, 6);
+       cc.encr_mode = 0x00;
+
+       send_event(btdev, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc));
+}
+
+static void conn_request(struct btdev *btdev, const uint8_t *bdaddr)
+{
+       struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
+
+       if (remote) {
+               if (remote->scan_enable & 0x01) {
+                       struct bt_hci_evt_conn_request cr;
+
+                       memcpy(cr.bdaddr, btdev->bdaddr, 6);
+                       memcpy(cr.dev_class, btdev->dev_class, 3);
+                       cr.link_type = 0x01;
+
+                       send_event(remote, BT_HCI_EVT_CONN_REQUEST,
+                                                       &cr, sizeof(cr));
+               } else
+                       conn_complete(btdev, bdaddr, BT_HCI_ERR_PAGE_TIMEOUT);
+       } else
+               conn_complete(btdev, bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
+}
+
+static void disconnect_complete(struct btdev *btdev, uint16_t handle,
+                                                       uint8_t reason)
+{
+       struct bt_hci_evt_disconnect_complete dc;
+       struct btdev *remote;
+
+       if (!btdev) {
+               dc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+               dc.handle = cpu_to_le16(handle);
+               dc.reason = 0x00;
+
+               send_event(btdev, BT_HCI_EVT_DISCONNECT_COMPLETE,
+                                                       &dc, sizeof(dc));
+               return;
+       }
+
+       dc.status = BT_HCI_ERR_SUCCESS;
+       dc.handle = cpu_to_le16(handle);
+       dc.reason = reason;
+
+       remote = btdev->conn;
+
+       btdev->conn = NULL;
+       remote->conn = NULL;
+
+       send_event(btdev, BT_HCI_EVT_DISCONNECT_COMPLETE, &dc, sizeof(dc));
+       send_event(remote, BT_HCI_EVT_DISCONNECT_COMPLETE, &dc, sizeof(dc));
+}
+
+static void name_request_complete(struct btdev *btdev,
+                                       const uint8_t *bdaddr, uint8_t status)
+{
+        struct bt_hci_evt_remote_name_req_complete nc;
+
+       nc.status = status;
+       memcpy(nc.bdaddr, bdaddr, 6);
+       memset(nc.name, 0, 248);
+
+       if (!status) {
+               struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
+
+               if (remote)
+                       memcpy(nc.name, remote->name, 248);
+               else
+                       nc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+       }
+
+       send_event(btdev, BT_HCI_EVT_REMOTE_NAME_REQUEST_COMPLETE,
+                                                       &nc, sizeof(nc));
+}
+
+static void remote_features_complete(struct btdev *btdev, uint16_t handle)
+{
+       struct bt_hci_evt_remote_features_complete rfc;
+
+       if (btdev->conn) {
+               rfc.status = BT_HCI_ERR_SUCCESS;
+               rfc.handle = cpu_to_le16(handle);
+               memcpy(rfc.features, btdev->conn->features, 8);
+       } else {
+               rfc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+               rfc.handle = cpu_to_le16(handle);
+               memset(rfc.features, 0, 8);
+       }
+
+       send_event(btdev, BT_HCI_EVT_REMOTE_FEATURES_COMPLETE,
+                                                       &rfc, sizeof(rfc));
+}
+
+static void remote_ext_features_complete(struct btdev *btdev, uint16_t handle,
+                                                               uint8_t page)
+{
+       struct bt_hci_evt_remote_ext_features_complete refc;
+
+       if (btdev->conn && page < 0x02) {
+               refc.handle = cpu_to_le16(handle);
+               refc.page = page;
+               refc.max_page = 0x01;
+
+               switch (page) {
+               case 0x00:
+                       refc.status = BT_HCI_ERR_SUCCESS;
+                       memcpy(refc.features, btdev->conn->features, 8);
+                       break;
+               case 0x01:
+                       refc.status = BT_HCI_ERR_SUCCESS;
+                       memset(refc.features, 0, 8);
+                       break;
+               default:
+                       refc.status = BT_HCI_ERR_INVALID_PARAMETERS;
+                       memset(refc.features, 0, 8);
+                       break;
+               }
+       } else {
+               refc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+               refc.handle = cpu_to_le16(handle);
+               refc.page = page;
+               refc.max_page = 0x01;
+               memset(refc.features, 0, 8);
+       }
+
+       send_event(btdev, BT_HCI_EVT_REMOTE_EXT_FEATURES_COMPLETE,
+                                                       &refc, sizeof(refc));
+}
+
+static void remote_version_complete(struct btdev *btdev, uint16_t handle)
+{
+       struct bt_hci_evt_remote_version_complete rvc;
+
+       if (btdev->conn) {
+               rvc.status = BT_HCI_ERR_SUCCESS;
+               rvc.handle = cpu_to_le16(handle);
+               rvc.lmp_ver = btdev->conn->version;
+               rvc.manufacturer = cpu_to_le16(btdev->conn->manufacturer);
+               rvc.lmp_subver = cpu_to_le16(btdev->conn->revision);
+       } else {
+               rvc.status = BT_HCI_ERR_UNKNOWN_CONN_ID;
+               rvc.handle = cpu_to_le16(handle);
+               rvc.lmp_ver = 0x00;
+               rvc.manufacturer = cpu_to_le16(0);
+               rvc.lmp_subver = cpu_to_le16(0);
+       }
+
+       send_event(btdev, BT_HCI_EVT_REMOTE_VERSION_COMPLETE,
+                                                       &rvc, sizeof(rvc));
+}
+
+static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
+{
+       const struct bt_hci_cmd_hdr *hdr = data;
+       const struct bt_hci_cmd_create_conn *cc;
+       const struct bt_hci_cmd_disconnect *dc;
+       const struct bt_hci_cmd_create_conn_cancel *ccc;
+       const struct bt_hci_cmd_accept_conn_request *acr;
+       const struct bt_hci_cmd_reject_conn_request *rcr;
+       const struct bt_hci_cmd_remote_name_request *rnr;
+       const struct bt_hci_cmd_remote_name_request_cancel *rnrc;
+       const struct bt_hci_cmd_read_remote_features *rrf;
+       const struct bt_hci_cmd_read_remote_ext_features *rref;
+       const struct bt_hci_cmd_read_remote_version *rrv;
+       const struct bt_hci_cmd_write_default_link_policy *wdlp;
+       const struct bt_hci_cmd_set_event_mask *sem;
+       const struct bt_hci_cmd_set_event_filter *sef;
+       const struct bt_hci_cmd_write_local_name *wln;
+       const struct bt_hci_cmd_write_conn_accept_timeout *wcat;
+       const struct bt_hci_cmd_write_page_timeout *wpt;
+       const struct bt_hci_cmd_write_scan_enable *wse;
+       const struct bt_hci_cmd_write_auth_enable *wae;
+       const struct bt_hci_cmd_write_class_of_dev *wcod;
+       const struct bt_hci_cmd_write_voice_setting *wvs;
+       const struct bt_hci_cmd_write_inquiry_mode *wim;
+       const struct bt_hci_cmd_write_afh_assess_mode *waam;
+       const struct bt_hci_cmd_write_ext_inquiry_rsp *weir;
+       const struct bt_hci_cmd_write_simple_pairing_mode *wspm;
+       const struct bt_hci_cmd_write_le_host_supported *wlhs;
+       const struct bt_hci_cmd_le_set_event_mask *lsem;
+       struct bt_hci_rsp_read_default_link_policy rdlp;
+       struct bt_hci_rsp_read_stored_link_key rslk;
+       struct bt_hci_rsp_write_stored_link_key wslk;
+       struct bt_hci_rsp_delete_stored_link_key dslk;
+       struct bt_hci_rsp_read_local_name rln;
+       struct bt_hci_rsp_read_conn_accept_timeout rcat;
+       struct bt_hci_rsp_read_page_timeout rpt;
+       struct bt_hci_rsp_read_scan_enable rse;
+       struct bt_hci_rsp_read_auth_enable rae;
+       struct bt_hci_rsp_read_class_of_dev rcod;
+       struct bt_hci_rsp_read_voice_setting rvs;
+       struct bt_hci_rsp_read_inquiry_mode rim;
+       struct bt_hci_rsp_read_afh_assess_mode raam;
+       struct bt_hci_rsp_read_ext_inquiry_rsp reir;
+       struct bt_hci_rsp_read_simple_pairing_mode rspm;
+       struct bt_hci_rsp_read_inquiry_rsp_tx_power rirtp;
+       struct bt_hci_rsp_read_le_host_supported rlhs;
+       struct bt_hci_rsp_read_local_version rlv;
+       struct bt_hci_rsp_read_local_commands rlc;
+       struct bt_hci_rsp_read_local_features rlf;
+       struct bt_hci_rsp_read_local_ext_features rlef;
+       struct bt_hci_rsp_read_buffer_size rbs;
+       struct bt_hci_rsp_read_country_code rcc;
+       struct bt_hci_rsp_read_bd_addr rba;
+       struct bt_hci_rsp_read_data_block_size rdbs;
+       struct bt_hci_rsp_le_read_buffer_size lrbs;
+       struct bt_hci_rsp_le_read_local_features lrlf;
+       struct bt_hci_rsp_le_read_supported_states lrss;
+       uint16_t opcode;
+       uint8_t status, page;
+
+       if (len < sizeof(*hdr))
+               return;
+
+       opcode = le16_to_cpu(hdr->opcode);
+
+       switch (opcode) {
+       case BT_HCI_CMD_INQUIRY:
+               cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+               inquiry_complete(btdev, BT_HCI_ERR_SUCCESS);
+               break;
+
+       case BT_HCI_CMD_INQUIRY_CANCEL:
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_CREATE_CONN:
+               cc = data + sizeof(*hdr);
+               cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+               conn_request(btdev, cc->bdaddr);
+               break;
+
+       case BT_HCI_CMD_DISCONNECT:
+               dc = data + sizeof(*hdr);
+               cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+               disconnect_complete(btdev, le16_to_cpu(dc->handle), dc->reason);
+               break;
+
+       case BT_HCI_CMD_CREATE_CONN_CANCEL:
+               ccc = data + sizeof(*hdr);
+               cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+               conn_complete(btdev, ccc->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
+               break;
+
+       case BT_HCI_CMD_ACCEPT_CONN_REQUEST:
+               acr = data + sizeof(*hdr);
+               cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+               conn_complete(btdev, acr->bdaddr, BT_HCI_ERR_SUCCESS);
+               break;
+
+       case BT_HCI_CMD_REJECT_CONN_REQUEST:
+               rcr = data + sizeof(*hdr);
+               cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+               conn_complete(btdev, rcr->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
+               break;
+
+       case BT_HCI_CMD_REMOTE_NAME_REQUEST:
+               rnr = data + sizeof(*hdr);
+               cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+               name_request_complete(btdev, rnr->bdaddr, BT_HCI_ERR_SUCCESS);
+               break;
+
+       case BT_HCI_CMD_REMOTE_NAME_REQUEST_CANCEL:
+               rnrc = data + sizeof(*hdr);
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               name_request_complete(btdev, rnrc->bdaddr,
+                                               BT_HCI_ERR_UNKNOWN_CONN_ID);
+               break;
+
+       case BT_HCI_CMD_READ_REMOTE_FEATURES:
+               rrf = data + sizeof(*hdr);
+               cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+               remote_features_complete(btdev, le16_to_cpu(rrf->handle));
+               break;
+
+       case BT_HCI_CMD_READ_REMOTE_EXT_FEATURES:
+               rref = data + sizeof(*hdr);
+               cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+               remote_ext_features_complete(btdev, le16_to_cpu(rref->handle),
+                                                               rref->page);
+               break;
+
+       case BT_HCI_CMD_READ_REMOTE_VERSION:
+               rrv = data + sizeof(*hdr);
+               cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+               remote_version_complete(btdev, le16_to_cpu(rrv->handle));
+               break;
+
+       case BT_HCI_CMD_READ_DEFAULT_LINK_POLICY:
+               rdlp.status = BT_HCI_ERR_SUCCESS;
+               rdlp.policy = cpu_to_le16(btdev->default_link_policy);
+               cmd_complete(btdev, opcode, &rdlp, sizeof(rdlp));
+               break;
+
+       case BT_HCI_CMD_WRITE_DEFAULT_LINK_POLICY:
+               wdlp = data + sizeof(*hdr);
+               btdev->default_link_policy = le16_to_cpu(wdlp->policy);
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_SET_EVENT_MASK:
+               sem = data + sizeof(*hdr);
+               memcpy(btdev->event_mask, sem->mask, 8);
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_RESET:
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_SET_EVENT_FILTER:
+               sef = data + sizeof(*hdr);
+               btdev->event_filter = sef->type;
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_READ_STORED_LINK_KEY:
+               rslk.status = BT_HCI_ERR_SUCCESS;
+               rslk.max_num_keys = cpu_to_le16(0);
+               rslk.num_keys = cpu_to_le16(0);
+               cmd_complete(btdev, opcode, &rslk, sizeof(rslk));
+               break;
+
+       case BT_HCI_CMD_WRITE_STORED_LINK_KEY:
+               wslk.status = BT_HCI_ERR_SUCCESS;
+               wslk.num_keys = 0;
+               cmd_complete(btdev, opcode, &wslk, sizeof(wslk));
+               break;
+
+       case BT_HCI_CMD_DELETE_STORED_LINK_KEY:
+               dslk.status = BT_HCI_ERR_SUCCESS;
+               dslk.num_keys = cpu_to_le16(0);
+               cmd_complete(btdev, opcode, &dslk, sizeof(dslk));
+               break;
+
+       case BT_HCI_CMD_WRITE_LOCAL_NAME:
+               wln = data + sizeof(*hdr);
+               memcpy(btdev->name, wln->name, 248);
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_READ_LOCAL_NAME:
+               rln.status = BT_HCI_ERR_SUCCESS;
+               memcpy(rln.name, btdev->name, 248);
+               cmd_complete(btdev, opcode, &rln, sizeof(rln));
+               break;
+
+       case BT_HCI_CMD_READ_CONN_ACCEPT_TIMEOUT:
+               rcat.status = BT_HCI_ERR_SUCCESS;
+               rcat.timeout = cpu_to_le16(btdev->conn_accept_timeout);
+               cmd_complete(btdev, opcode, &rcat, sizeof(rcat));
+               break;
+
+       case BT_HCI_CMD_WRITE_CONN_ACCEPT_TIMEOUT:
+               wcat = data + sizeof(*hdr);
+               btdev->conn_accept_timeout = le16_to_cpu(wcat->timeout);
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_READ_PAGE_TIMEOUT:
+               rpt.status = BT_HCI_ERR_SUCCESS;
+               rpt.timeout = cpu_to_le16(btdev->page_timeout);
+               cmd_complete(btdev, opcode, &rpt, sizeof(rpt));
+               break;
+
+       case BT_HCI_CMD_WRITE_PAGE_TIMEOUT:
+               wpt = data + sizeof(*hdr);
+               btdev->page_timeout = le16_to_cpu(wpt->timeout);
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_READ_SCAN_ENABLE:
+               rse.status = BT_HCI_ERR_SUCCESS;
+               rse.enable = btdev->scan_enable;
+               cmd_complete(btdev, opcode, &rse, sizeof(rse));
+               break;
+
+       case BT_HCI_CMD_WRITE_SCAN_ENABLE:
+               wse = data + sizeof(*hdr);
+               btdev->scan_enable = wse->enable;
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_READ_AUTH_ENABLE:
+               rae.status = BT_HCI_ERR_SUCCESS;
+               rae.enable = btdev->auth_enable;
+               cmd_complete(btdev, opcode, &rae, sizeof(rae));
+               break;
+
+       case BT_HCI_CMD_WRITE_AUTH_ENABLE:
+               wae = data + sizeof(*hdr);
+               btdev->auth_enable = wae->enable;
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_READ_CLASS_OF_DEV:
+               rcod.status = BT_HCI_ERR_SUCCESS;
+               memcpy(rcod.dev_class, btdev->dev_class, 3);
+               cmd_complete(btdev, opcode, &rcod, sizeof(rcod));
+               break;
+
+       case BT_HCI_CMD_WRITE_CLASS_OF_DEV:
+               wcod = data + sizeof(*hdr);
+               memcpy(btdev->dev_class, wcod->dev_class, 3);
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_READ_VOICE_SETTING:
+               rvs.status = BT_HCI_ERR_SUCCESS;
+               rvs.setting = cpu_to_le16(btdev->voice_setting);
+               cmd_complete(btdev, opcode, &rvs, sizeof(rvs));
+               break;
+
+       case BT_HCI_CMD_WRITE_VOICE_SETTING:
+               wvs = data + sizeof(*hdr);
+               btdev->voice_setting = le16_to_cpu(wvs->setting);
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_READ_INQUIRY_MODE:
+               rim.status = BT_HCI_ERR_SUCCESS;
+               rim.mode = btdev->inquiry_mode;
+               cmd_complete(btdev, opcode, &rim, sizeof(rim));
+               break;
+
+       case BT_HCI_CMD_WRITE_INQUIRY_MODE:
+               wim = data + sizeof(*hdr);
+               btdev->inquiry_mode = wim->mode;
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_READ_AFH_ASSESS_MODE:
+               raam.status = BT_HCI_ERR_SUCCESS;
+               raam.mode = btdev->afh_assess_mode;
+               cmd_complete(btdev, opcode, &raam, sizeof(raam));
+               break;
+
+       case BT_HCI_CMD_WRITE_AFH_ASSESS_MODE:
+               waam = data + sizeof(*hdr);
+               btdev->afh_assess_mode = waam->mode;
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_READ_EXT_INQUIRY_RSP:
+               reir.status = BT_HCI_ERR_SUCCESS;
+               reir.fec = btdev->ext_inquiry_fec;
+               memcpy(reir.data, btdev->ext_inquiry_rsp, 240);
+               cmd_complete(btdev, opcode, &reir, sizeof(reir));
+               break;
+
+       case BT_HCI_CMD_WRITE_EXT_INQUIRY_RSP:
+               weir = data + sizeof(*hdr);
+               btdev->ext_inquiry_fec = weir->fec;
+               memcpy(btdev->ext_inquiry_rsp, weir->data, 240);
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_READ_SIMPLE_PAIRING_MODE:
+               rspm.status = BT_HCI_ERR_SUCCESS;
+               rspm.mode = btdev->simple_pairing_mode;
+               cmd_complete(btdev, opcode, &rspm, sizeof(rspm));
+               break;
+
+       case BT_HCI_CMD_WRITE_SIMPLE_PAIRING_MODE:
+               wspm = data + sizeof(*hdr);
+               btdev->simple_pairing_mode = wspm->mode;
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_READ_INQUIRY_RSP_TX_POWER:
+               rirtp.status = BT_HCI_ERR_SUCCESS;
+               rirtp.level = 0;
+               cmd_complete(btdev, opcode, &rirtp, sizeof(rirtp));
+               break;
+
+       case BT_HCI_CMD_READ_LE_HOST_SUPPORTED:
+               rlhs.status = BT_HCI_ERR_SUCCESS;
+               rlhs.supported = btdev->le_supported;
+               rlhs.simultaneous = btdev->le_simultaneous;
+               cmd_complete(btdev, opcode, &rlhs, sizeof(rlhs));
+               break;
+
+       case BT_HCI_CMD_WRITE_LE_HOST_SUPPORTED:
+               wlhs = data + sizeof(*hdr);
+               btdev->le_supported = wlhs->supported;
+               btdev->le_simultaneous = wlhs->simultaneous;
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_READ_LOCAL_VERSION:
+               rlv.status = BT_HCI_ERR_SUCCESS;
+               rlv.hci_ver = btdev->version;
+               rlv.hci_rev = cpu_to_le16(btdev->revision);
+               rlv.lmp_ver = btdev->version;
+               rlv.manufacturer = cpu_to_le16(btdev->manufacturer);
+               rlv.lmp_subver = cpu_to_le16(btdev->revision);
+               cmd_complete(btdev, opcode, &rlv, sizeof(rlv));
+               break;
+
+       case BT_HCI_CMD_READ_LOCAL_COMMANDS:
+               rlc.status = BT_HCI_ERR_SUCCESS;
+               memcpy(rlc.commands, btdev->commands, 64);
+               cmd_complete(btdev, opcode, &rlc, sizeof(rlc));
+               break;
+
+       case BT_HCI_CMD_READ_LOCAL_FEATURES:
+               rlf.status = BT_HCI_ERR_SUCCESS;
+               memcpy(rlf.features, btdev->features, 8);
+               cmd_complete(btdev, opcode, &rlf, sizeof(rlf));
+               break;
+
+       case BT_HCI_CMD_READ_LOCAL_EXT_FEATURES:
+               page = ((const uint8_t *) data)[sizeof(*hdr)];
+               switch (page) {
+               case 0x00:
+                       rlef.status = BT_HCI_ERR_SUCCESS;
+                       rlef.page = 0x00;
+                       rlef.max_page = 0x01;
+                       memcpy(rlef.features, btdev->features, 8);
+                       break;
+               case 0x01:
+                       rlef.status = BT_HCI_ERR_SUCCESS;
+                       rlef.page = 0x01;
+                       rlef.max_page = 0x01;
+                       memset(rlef.features, 0, 8);
+                       if (btdev->simple_pairing_mode)
+                               rlef.features[0] |= 0x01;
+                       if (btdev->le_supported)
+                               rlef.features[0] |= 0x02;
+                       if (btdev->le_simultaneous)
+                               rlef.features[0] |= 0x04;
+                       break;
+               default:
+                       rlef.status = BT_HCI_ERR_INVALID_PARAMETERS;
+                       rlef.page = page;
+                       rlef.max_page = 0x01;
+                       memset(rlef.features, 0, 8);
+                       break;
+               }
+               cmd_complete(btdev, opcode, &rlef, sizeof(rlef));
+               break;
+
+       case BT_HCI_CMD_READ_BUFFER_SIZE:
+               rbs.status = BT_HCI_ERR_SUCCESS;
+               rbs.acl_mtu = cpu_to_le16(btdev->acl_mtu);
+               rbs.sco_mtu = 0;
+               rbs.acl_max_pkt = cpu_to_le16(btdev->acl_max_pkt);
+               rbs.sco_max_pkt = cpu_to_le16(0);
+               cmd_complete(btdev, opcode, &rbs, sizeof(rbs));
+               break;
+
+       case BT_HCI_CMD_READ_COUNTRY_CODE:
+               rcc.status = BT_HCI_ERR_SUCCESS;
+               rcc.code = btdev->country_code;
+               cmd_complete(btdev, opcode, &rcc, sizeof(rcc));
+               break;
+
+       case BT_HCI_CMD_READ_BD_ADDR:
+               rba.status = BT_HCI_ERR_SUCCESS;
+               memcpy(rba.bdaddr, btdev->bdaddr, 6);
+               cmd_complete(btdev, opcode, &rba, sizeof(rba));
+               break;
+
+       case BT_HCI_CMD_READ_DATA_BLOCK_SIZE:
+               rdbs.status = BT_HCI_ERR_SUCCESS;
+               rdbs.max_acl_len = cpu_to_le16(btdev->acl_mtu);
+               rdbs.block_len = cpu_to_le16(btdev->acl_mtu);
+               rdbs.num_blocks = cpu_to_le16(btdev->acl_max_pkt);
+               cmd_complete(btdev, opcode, &rdbs, sizeof(rdbs));
+               break;
+
+       case BT_HCI_CMD_LE_SET_EVENT_MASK:
+               lsem = data + sizeof(*hdr);
+               memcpy(btdev->le_event_mask, lsem->mask, 8);
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_LE_READ_BUFFER_SIZE:
+               lrbs.status = BT_HCI_ERR_SUCCESS;
+               lrbs.le_mtu = cpu_to_le16(btdev->acl_mtu);
+               lrbs.le_max_pkt = btdev->acl_max_pkt;
+               cmd_complete(btdev, opcode, &lrbs, sizeof(lrbs));
+               break;
+
+       case BT_HCI_CMD_LE_READ_LOCAL_FEATURES:
+               lrlf.status = BT_HCI_ERR_SUCCESS;
+               memcpy(lrlf.features, btdev->le_features, 8);
+               cmd_complete(btdev, opcode, &lrlf, sizeof(lrlf));
+               break;
+
+       case BT_HCI_CMD_LE_SET_SCAN_PARAMETERS:
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_LE_SET_SCAN_ENABLE:
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_LE_READ_SUPPORTED_STATES:
+               lrss.status = BT_HCI_ERR_SUCCESS;
+               memcpy(lrss.states, btdev->le_states, 8);
+               cmd_complete(btdev, opcode, &lrss, sizeof(lrss));
+               break;
+
+       default:
+               printf("Unsupported command 0x%4.4x\n", opcode);
+               hexdump(data, len);
+               cmd_status(btdev, BT_HCI_ERR_UNKNOWN_COMMAND, opcode);
+               break;
+       }
+}
+
+void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len)
+{
+       uint8_t pkt_type;
+
+       if (!btdev)
+               return;
+
+       if (len < 1)
+               return;
+
+       pkt_type = ((const uint8_t *) data)[0];
+
+       switch (pkt_type) {
+       case BT_H4_CMD_PKT:
+               process_cmd(btdev, data + 1, len - 1);
+               break;
+       case BT_H4_ACL_PKT:
+               if (btdev->conn)
+                       send_packet(btdev->conn, data, len);
+               num_completed_packets(btdev);
+               break;
+       default:
+               printf("Unsupported packet 0x%2.2x\n", pkt_type);
+               break;
+       }
+}
diff --git a/emulator/btdev.h b/emulator/btdev.h
new file mode 100644 (file)
index 0000000..7b211a2
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+
+typedef void (*btdev_send_func) (const void *data, uint16_t len,
+                                                       void *user_data);
+
+struct btdev;
+
+struct btdev *btdev_create(uint16_t id);
+void btdev_destroy(struct btdev *btdev);
+
+void btdev_set_send_handler(struct btdev *btdev, btdev_send_func handler,
+                                                       void *user_data);
+
+void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len);
diff --git a/emulator/main.c b/emulator/main.c
new file mode 100644 (file)
index 0000000..125460d
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include "mainloop.h"
+#include "server.h"
+#include "vhci.h"
+
+static void signal_callback(int signum, void *user_data)
+{
+       switch (signum) {
+       case SIGINT:
+       case SIGTERM:
+               mainloop_quit();
+               break;
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       struct vhci *vhci;
+       struct server *server;
+       sigset_t mask;
+
+       mainloop_init();
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+       sigaddset(&mask, SIGTERM);
+
+       mainloop_set_signal(&mask, signal_callback, NULL, NULL);
+
+       vhci = vhci_open(VHCI_TYPE_BREDR, 0x23);
+       if (!vhci) {
+               fprintf(stderr, "Failed to open Virtual HCI device\n");
+               return 1;
+       }
+
+       server = server_open_unix("/tmp/bt-server-bredr", 0x42);
+       if (!server) {
+               fprintf(stderr, "Failed to open server channel\n");
+               vhci_close(vhci);
+               return 1;
+       }
+
+       return mainloop_run();
+}
diff --git a/emulator/server.c b/emulator/server.c
new file mode 100644 (file)
index 0000000..1ff9904
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+
+#include "mainloop.h"
+#include "btdev.h"
+#include "server.h"
+
+struct server {
+       uint16_t id;
+       int fd;
+};
+
+struct client {
+       int fd;
+       struct btdev *btdev;
+       uint8_t *pkt_data;
+       uint8_t pkt_type;
+       uint16_t pkt_expect;
+       uint16_t pkt_len;
+       uint16_t pkt_offset;
+};
+
+static void server_destroy(void *user_data)
+{
+       struct server *server = user_data;
+
+       close(server->fd);
+
+       free(server);
+}
+
+static void client_destroy(void *user_data)
+{
+       struct client *client = user_data;
+
+       btdev_destroy(client->btdev);
+
+       close(client->fd);
+
+       free(client);
+}
+
+static void client_write_callback(const void *data, uint16_t len,
+                                                       void *user_data)
+{
+       struct client *client = user_data;
+       ssize_t written;
+
+       written = send(client->fd, data, len, MSG_DONTWAIT);
+       if (written < 0)
+               return;
+}
+
+static void client_read_callback(int fd, uint32_t events, void *user_data)
+{
+       struct client *client = user_data;
+       static uint8_t buf[4096];
+       uint8_t *ptr = buf;
+       ssize_t len;
+       uint16_t count;
+
+       if (events & (EPOLLERR | EPOLLHUP))
+               return;
+
+again:
+       len = recv(fd, buf + client->pkt_offset,
+                       sizeof(buf) - client->pkt_offset, MSG_DONTWAIT);
+       if (len < 0) {
+               if (errno == EAGAIN)
+                       goto again;
+               return;
+       }
+
+       count = client->pkt_offset + len;
+
+       while (count > 0) {
+               hci_command_hdr *cmd_hdr;
+
+               if (!client->pkt_data) {
+                       client->pkt_type = ptr[0];
+
+                       switch (client->pkt_type) {
+                       case HCI_COMMAND_PKT:
+                               if (count < HCI_COMMAND_HDR_SIZE + 1) {
+                                       client->pkt_offset += len;
+                                       return;
+                               }
+                               cmd_hdr = (hci_command_hdr *) (ptr + 1);
+                               client->pkt_expect = HCI_COMMAND_HDR_SIZE +
+                                                       cmd_hdr->plen + 1;
+                               client->pkt_data = malloc(client->pkt_expect);
+                               client->pkt_len = 0;
+                               break;
+                       default:
+                               printf("packet error\n");
+                               return;
+                       }
+
+                       client->pkt_offset = 0;
+               }
+
+               if (count >= client->pkt_expect) {
+                       memcpy(client->pkt_data + client->pkt_len,
+                                               ptr, client->pkt_expect);
+                       ptr += client->pkt_expect;
+                       count -= client->pkt_expect;
+
+                       btdev_receive_h4(client->btdev, client->pkt_data,
+                                       client->pkt_len + client->pkt_expect);
+
+                       free(client->pkt_data);
+                       client->pkt_data = NULL;
+               } else {
+                       memcpy(client->pkt_data + client->pkt_len, ptr, count);
+                       client->pkt_len += count;
+                       client->pkt_expect -= count;
+                       count = 0;
+               }
+       }
+}
+
+static int accept_client(int fd)
+{
+       struct sockaddr_un addr;
+       socklen_t len;
+       int nfd;
+
+       memset(&addr, 0, sizeof(addr));
+       len = sizeof(addr);
+
+       if (getsockname(fd, (struct sockaddr *) &addr, &len) < 0) {
+               perror("Failed to get socket name");
+               return -1;
+       }
+
+       printf("Request for %s\n", addr.sun_path);
+
+       nfd = accept(fd, (struct sockaddr *) &addr, &len);
+       if (nfd < 0) {
+               perror("Failed to accept client socket");
+               return -1;
+       }
+
+       return nfd;
+}
+
+static void server_accept_callback(int fd, uint32_t events, void *user_data)
+{
+       struct server *server = user_data;
+       struct client *client;
+
+       if (events & (EPOLLERR | EPOLLHUP))
+               return;
+
+       client = malloc(sizeof(*client));
+       if (!client)
+               return;
+
+       memset(client, 0, sizeof(*client));
+
+       client->fd = accept_client(server->fd);
+       if (client->fd < 0) {
+               free(client);
+               return;
+       }
+
+       client->btdev = btdev_create(server->id);
+       if (!client->btdev) {
+               close(client->fd);
+               free(client);
+               return;
+       }
+
+       btdev_set_send_handler(client->btdev, client_write_callback, client);
+
+       if (mainloop_add_fd(client->fd, EPOLLIN, client_read_callback,
+                                               client, client_destroy) < 0) {
+               btdev_destroy(client->btdev);
+               close(client->fd);
+               free(client);
+       }
+}
+
+static int open_server(const char *path)
+{
+       struct sockaddr_un addr;
+       int fd;
+
+       unlink(path);
+
+       fd = socket(PF_UNIX, SOCK_STREAM, 0);
+       if (fd < 0) {
+               perror("Failed to open server socket");
+               return -1;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       strcpy(addr.sun_path, path);
+
+       if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               perror("Failed to bind server socket");
+               close(fd);
+               return -1;
+       }
+
+       if (listen(fd, 5) < 0) {
+               perror("Failed to listen server socket");
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+struct server *server_open_unix(const char *path, uint16_t id)
+{
+       struct server *server;
+
+       server = malloc(sizeof(*server));
+       if (!server)
+               return NULL;
+
+       memset(server, 0, sizeof(*server));
+       server->id = id;
+
+       server->fd = open_server(path);
+       if (server->fd < 0) {
+               free(server);
+               return NULL;
+       }
+
+       if (mainloop_add_fd(server->fd, EPOLLIN, server_accept_callback,
+                                               server, server_destroy) < 0) {
+               close(server->fd);
+               free(server);
+               return NULL;
+       }
+
+       return server;
+}
+
+void server_close(struct server *server)
+{
+       if (!server)
+               return;
+
+       mainloop_remove_fd(server->fd);
+}
diff --git a/emulator/server.h b/emulator/server.h
new file mode 100644 (file)
index 0000000..836db5f
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+
+struct server;
+
+struct server *server_open_unix(const char *path, uint16_t id);
+void server_close(struct server *server);
diff --git a/emulator/vhci.c b/emulator/vhci.c
new file mode 100644 (file)
index 0000000..940e562
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mainloop.h"
+#include "btdev.h"
+#include "vhci.h"
+
+struct vhci {
+       enum vhci_type type;
+       int fd;
+       struct btdev *btdev;
+};
+
+static void vhci_destroy(void *user_data)
+{
+       struct vhci *vhci = user_data;
+
+       btdev_destroy(vhci->btdev);
+
+       close(vhci->fd);
+
+       free(vhci);
+}
+
+static void vhci_write_callback(const void *data, uint16_t len, void *user_data)
+{
+       struct vhci *vhci = user_data;
+       ssize_t written;
+
+       written = write(vhci->fd, data, len);
+       if (written < 0)
+               return;
+}
+
+static void vhci_read_callback(int fd, uint32_t events, void *user_data)
+{
+       struct vhci *vhci = user_data;
+       unsigned char buf[4096];
+       ssize_t len;
+
+       if (events & (EPOLLERR | EPOLLHUP))
+               return;
+
+       len = read(vhci->fd, buf, sizeof(buf));
+       if (len < 0)
+               return;
+
+       btdev_receive_h4(vhci->btdev, buf, len);
+}
+
+struct vhci *vhci_open(enum vhci_type type, uint16_t id)
+{
+       struct vhci *vhci;
+
+       switch (type) {
+       case VHCI_TYPE_BREDR:
+               break;
+       case VHCI_TYPE_AMP:
+               return NULL;
+       }
+
+       vhci = malloc(sizeof(*vhci));
+       if (!vhci)
+               return NULL;
+
+       memset(vhci, 0, sizeof(*vhci));
+       vhci->type = type;
+
+       vhci->fd = open("/dev/vhci", O_RDWR | O_NONBLOCK);
+       if (vhci->fd < 0) {
+               free(vhci);
+               return NULL;
+       }
+
+       vhci->btdev = btdev_create(id);
+       if (!vhci->btdev) {
+               close(vhci->fd);
+               free(vhci);
+               return NULL;
+       }
+
+       btdev_set_send_handler(vhci->btdev, vhci_write_callback, vhci);
+
+       if (mainloop_add_fd(vhci->fd, EPOLLIN, vhci_read_callback,
+                                               vhci, vhci_destroy) < 0) {
+               btdev_destroy(vhci->btdev);
+               close(vhci->fd);
+               free(vhci);
+               return NULL;
+       }
+
+       return vhci;
+}
+
+void vhci_close(struct vhci *vhci)
+{
+       if (!vhci)
+               return;
+
+       mainloop_remove_fd(vhci->fd);
+}
diff --git a/emulator/vhci.h b/emulator/vhci.h
new file mode 100644 (file)
index 0000000..4abb183
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+
+enum vhci_type {
+       VHCI_TYPE_BREDR = 0,
+       VHCI_TYPE_AMP   = 1,
+};
+
+struct vhci;
+
+struct vhci *vhci_open(enum vhci_type type, uint16_t id);
+void vhci_close(struct vhci *vhci);
index a0583e6..0a8a27c 100644 (file)
@@ -85,16 +85,21 @@ typedef enum {
 typedef struct {
        const char *name;
        const char *signature;
-       const char *reply;
+} GDBusArgInfo;
+
+typedef struct {
+       const char *name;
        GDBusMethodFunction function;
        GDBusMethodFlags flags;
        unsigned int privilege;
+       const GDBusArgInfo *in_args;
+       const GDBusArgInfo *out_args;
 } GDBusMethodTable;
 
 typedef struct {
        const char *name;
-       const char *signature;
        GDBusSignalFlags flags;
+       const GDBusArgInfo *args;
 } GDBusSignalTable;
 
 typedef struct {
@@ -110,6 +115,51 @@ typedef struct {
        GDBusSecurityFunction function;
 } GDBusSecurityTable;
 
+#define GDBUS_ARGS(args...) (const GDBusArgInfo[]) { args, { } }
+
+#define GDBUS_METHOD(_name, _in_args, _out_args, _function) \
+       .name = _name, \
+       .in_args = _in_args, \
+       .out_args = _out_args, \
+       .function = _function
+
+#define GDBUS_ASYNC_METHOD(_name, _in_args, _out_args, _function) \
+       .name = _name, \
+       .in_args = _in_args, \
+       .out_args = _out_args, \
+       .function = _function, \
+       .flags = G_DBUS_METHOD_FLAG_ASYNC
+
+#define GDBUS_DEPRECATED_METHOD(_name, _in_args, _out_args, _function) \
+       .name = _name, \
+       .in_args = _in_args, \
+       .out_args = _out_args, \
+       .function = _function, \
+       .flags = G_DBUS_METHOD_FLAG_DEPRECATED
+
+#define GDBUS_DEPRECATED_ASYNC_METHOD(_name, _in_args, _out_args, _function) \
+       .name = _name, \
+       .in_args = _in_args, \
+       .out_args = _out_args, \
+       .function = _function, \
+       .flags = G_DBUS_METHOD_FLAG_ASYNC | G_DBUS_METHOD_FLAG_DEPRECATED
+
+#define GDBUS_NOREPLY_METHOD(_name, _in_args, _out_args, _function) \
+       .name = _name, \
+       .in_args = _in_args, \
+       .out_args = _out_args, \
+       .function = _function, \
+       .flags = G_DBUS_METHOD_FLAG_NOREPLY
+
+#define GDBUS_SIGNAL(_name, _args) \
+       .name = _name, \
+       .args = _args
+
+#define GDBUS_DEPRECATED_SIGNAL(_name, _args) \
+       .name = _name, \
+       .args = _args, \
+       .flags = G_DBUS_SIGNAL_FLAG_DEPRECATED
+
 gboolean g_dbus_register_interface(DBusConnection *connection,
                                        const char *path, const char *name,
                                        const GDBusMethodTable *methods,
index 8718da0..cff326f 100644 (file)
 #include <glib.h>
 #include <dbus/dbus.h>
 
-#ifdef NEED_DBUS_WATCH_GET_UNIX_FD
-#define dbus_watch_get_unix_fd dbus_watch_get_fd
-#endif
-
 #include "gdbus.h"
 
 #define DISPATCH_TIMEOUT  0
index bb57ce5..b517c4f 100644 (file)
@@ -63,63 +63,20 @@ struct security_data {
        void *iface_user_data;
 };
 
-static void print_arguments(GString *gstr, const char *sig,
+static void print_arguments(GString *gstr, const GDBusArgInfo *args,
                                                const char *direction)
 {
-       int i;
-
-       for (i = 0; sig[i]; i++) {
-               char type[32];
-               int struct_level, dict_level;
-               unsigned int len;
-               gboolean complete;
-
-               complete = FALSE;
-               struct_level = dict_level = 0;
-               memset(type, 0, sizeof(type));
-
-               /* Gather enough data to have a single complete type */
-               for (len = 0; len < (sizeof(type) - 1) && sig[i]; len++, i++) {
-                       switch (sig[i]) {
-                       case '(':
-                               struct_level++;
-                               break;
-                       case ')':
-                               struct_level--;
-                               if (struct_level <= 0 && dict_level <= 0)
-                                       complete = TRUE;
-                               break;
-                       case '{':
-                               dict_level++;
-                               break;
-                       case '}':
-                               dict_level--;
-                               if (struct_level <= 0 && dict_level <= 0)
-                                       complete = TRUE;
-                               break;
-                       case 'a':
-                               break;
-                       default:
-                               if (struct_level <= 0 && dict_level <= 0)
-                                       complete = TRUE;
-                               break;
-                       }
-
-                       type[len] = sig[i];
-
-                       if (complete)
-                               break;
-               }
-
+       for (; args && args->name; args++) {
+               g_string_append_printf(gstr,
+                                       "\t\t\t<arg name=\"%s\" type=\"%s\"",
+                                       args->name, args->signature);
 
                if (direction)
                        g_string_append_printf(gstr,
-                                       "\t\t\t<arg type=\"%s\" direction=\"%s\"/>\n",
-                                       type, direction);
+                                       " direction=\"%s\"/>\n", direction);
                else
-                       g_string_append_printf(gstr,
-                                       "\t\t\t<arg type=\"%s\"/>\n",
-                                       type);
+                       g_string_append_printf(gstr, "/>\n");
+
        }
 }
 
@@ -129,26 +86,47 @@ static void generate_interface_xml(GString *gstr, struct interface_data *iface)
        const GDBusSignalTable *signal;
 
        for (method = iface->methods; method && method->name; method++) {
-               if (!strlen(method->signature) && !strlen(method->reply))
+               gboolean deprecated = method->flags &
+                                               G_DBUS_METHOD_FLAG_DEPRECATED;
+               gboolean noreply = method->flags &
+                                               G_DBUS_METHOD_FLAG_NOREPLY;
+
+               if (!deprecated && !noreply &&
+                               !(method->in_args && method->in_args->name) &&
+                               !(method->out_args && method->out_args->name))
                        g_string_append_printf(gstr, "\t\t<method name=\"%s\"/>\n",
                                                                method->name);
                else {
                        g_string_append_printf(gstr, "\t\t<method name=\"%s\">\n",
                                                                method->name);
-                       print_arguments(gstr, method->signature, "in");
-                       print_arguments(gstr, method->reply, "out");
+                       print_arguments(gstr, method->in_args, "in");
+                       print_arguments(gstr, method->out_args, "out");
+
+                       if (deprecated)
+                               g_string_append_printf(gstr, "\t\t\t<annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n");
+
+                       if (noreply)
+                               g_string_append_printf(gstr, "\t\t\t<annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n");
+
                        g_string_append_printf(gstr, "\t\t</method>\n");
                }
        }
 
        for (signal = iface->signals; signal && signal->name; signal++) {
-               if (!strlen(signal->signature))
+               gboolean deprecated = signal->flags &
+                                               G_DBUS_SIGNAL_FLAG_DEPRECATED;
+
+               if (!deprecated && !(signal->args && signal->args->name))
                        g_string_append_printf(gstr, "\t\t<signal name=\"%s\"/>\n",
                                                                signal->name);
                else {
                        g_string_append_printf(gstr, "\t\t<signal name=\"%s\">\n",
                                                                signal->name);
-                       print_arguments(gstr, signal->signature, NULL);
+                       print_arguments(gstr, signal->args, NULL);
+
+                       if (deprecated)
+                               g_string_append_printf(gstr, "\t\t\t<annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n");
+
                        g_string_append_printf(gstr, "\t\t</signal>\n");
                }
        }
@@ -200,11 +178,6 @@ static DBusMessage *introspect(DBusConnection *connection,
        struct generic_data *data = user_data;
        DBusMessage *reply;
 
-       if (!dbus_message_has_signature(message, DBUS_TYPE_INVALID_AS_STRING)) {
-               error("Unexpected signature to introspect call");
-               return NULL;
-       }
-
        if (data->introspect == NULL)
                generate_introspection_xml(connection, data,
                                                dbus_message_get_path(message));
@@ -420,6 +393,27 @@ static struct interface_data *find_interface(GSList *interfaces,
        return NULL;
 }
 
+static gboolean g_dbus_args_have_signature(const GDBusArgInfo *args,
+                                                       DBusMessage *message)
+{
+       const char *sig = dbus_message_get_signature(message);
+       const char *p = NULL;
+
+       for (; args && args->signature && *sig; args++) {
+               p = args->signature;
+
+               for (; *sig && *p; sig++, p++) {
+                       if (*p != *sig)
+                               return FALSE;
+               }
+       }
+
+       if (*sig || (p && *p) || (args && args->signature))
+               return FALSE;
+
+       return TRUE;
+}
+
 static DBusHandlerResult generic_message(DBusConnection *connection,
                                        DBusMessage *message, void *user_data)
 {
@@ -440,8 +434,8 @@ static DBusHandlerResult generic_message(DBusConnection *connection,
                                                        method->name) == FALSE)
                        continue;
 
-               if (dbus_message_has_signature(message,
-                                               method->signature) == FALSE)
+               if (g_dbus_args_have_signature(method->in_args,
+                                                       message) == FALSE)
                        continue;
 
                if (check_privilege(connection, message, method,
@@ -449,8 +443,8 @@ static DBusHandlerResult generic_message(DBusConnection *connection,
                        return DBUS_HANDLER_RESULT_HANDLED;
 
 #ifdef __TIZEN_PATCH__
-               DBG("%s: %s.%s()",dbus_message_get_path(message),
-                                                                       iface->name,method->name);
+               DBG("%s: %s.%s()", dbus_message_get_path(message),
+                                                                       iface->name, method->name);
 #endif
                return process_message(connection, message, method,
                                                        iface->user_data);
@@ -499,8 +493,9 @@ done:
        g_free(parent_path);
 }
 
-static GDBusMethodTable introspect_methods[] = {
-       { "Introspect", "",     "s", introspect },
+static const GDBusMethodTable introspect_methods[] = {
+       { GDBUS_METHOD("Introspect", NULL,
+                       GDBUS_ARGS({ "xml", "s" }), introspect) },
        { }
 };
 
@@ -601,7 +596,7 @@ static void object_path_unref(DBusConnection *connection, const char *path)
 
 static gboolean check_signal(DBusConnection *conn, const char *path,
                                const char *interface, const char *name,
-                               const char **args)
+                               const GDBusArgInfo **args)
 {
        struct generic_data *data = NULL;
        struct interface_data *iface;
@@ -624,17 +619,13 @@ static gboolean check_signal(DBusConnection *conn, const char *path,
 
        for (signal = iface->signals; signal && signal->name; signal++) {
                if (!strcmp(signal->name, name)) {
-                       *args = signal->signature;
-                       break;
+                       *args = signal->args;
+                       return TRUE;
                }
        }
 
-       if (*args == NULL) {
-               error("No signal named %s on interface %s", name, interface);
-               return FALSE;
-       }
-
-       return TRUE;
+       error("No signal named %s on interface %s", name, interface);
+       return FALSE;
 }
 
 static dbus_bool_t emit_signal_valist(DBusConnection *conn,
@@ -646,7 +637,7 @@ static dbus_bool_t emit_signal_valist(DBusConnection *conn,
 {
        DBusMessage *signal;
        dbus_bool_t ret;
-       const char *signature, *args;
+       const GDBusArgInfo *args;
 
        if (!check_signal(conn, path, interface, name, &args))
                return FALSE;
@@ -661,10 +652,14 @@ static dbus_bool_t emit_signal_valist(DBusConnection *conn,
        if (!ret)
                goto fail;
 
-       signature = dbus_message_get_signature(signal);
-       if (strcmp(args, signature) != 0) {
-               error("%s.%s: expected signature'%s' but got '%s'",
+       if (g_dbus_args_have_signature(args, signal) == FALSE) {
+#ifdef __TIZEN_PATCH__
+               error("%s.%s: got unexpected signature '%s'", interface, name,
+                                       dbus_message_get_signature(signal));
+#else
+               error("%s.%s: expected signature'%s' but got %s'",
                                interface, name, args, signature);
+#endif
                ret = FALSE;
                goto fail;
        }
index fba58c3..9a716b0 100644 (file)
@@ -666,7 +666,7 @@ guint g_dbus_add_service_watch(DBusConnection *connection, const char *name,
        if (data == NULL)
                return 0;
 
-       cb = filter_data_add_callback(data, connect, disconnect, NULL, NULL,
+       cb = filter_data_add_callback(data, connect, disconnect, NULL, destroy,
                                        user_data);
        if (cb == NULL)
                return 0;
index 812352f..2316204 100644 (file)
 #include "hdp.h"
 #include "mcap.h"
 
-#ifndef DBUS_TYPE_UNIX_FD
-       #define DBUS_TYPE_UNIX_FD -1
-#endif
-
 #define ECHO_TIMEOUT   1 /* second */
 #define HDP_ECHO_LEN   15
 
@@ -424,10 +420,15 @@ static void manager_path_unregister(gpointer data)
        g_slist_foreach(adapters, (GFunc) update_adapter, NULL);
 }
 
-static GDBusMethodTable health_manager_methods[] = {
-       {"CreateApplication", "a{sv}", "o", manager_create_application},
-       {"DestroyApplication", "o", "", manager_destroy_application},
-       { NULL }
+static const GDBusMethodTable health_manager_methods[] = {
+       { GDBUS_METHOD("CreateApplication",
+                       GDBUS_ARGS({ "config", "a{sv}" }),
+                       GDBUS_ARGS({ "application", "o" }),
+                       manager_create_application) },
+       { GDBUS_METHOD("DestroyApplication",
+                       GDBUS_ARGS({ "application", "o" }), NULL,
+                       manager_destroy_application) },
+       { }
 };
 
 static DBusMessage *channel_get_properties(DBusConnection *conn,
@@ -723,26 +724,23 @@ static void health_channel_destroy(void *data)
                                        DBUS_TYPE_INVALID);
 
        if (hdp_chan == dev->fr) {
-               char *empty_path;
-
                hdp_channel_unref(dev->fr);
                dev->fr = NULL;
-               empty_path = "/";
-               emit_property_changed(dev->conn, device_get_path(dev->dev),
-                                       HEALTH_DEVICE, "MainChannel",
-                                       DBUS_TYPE_OBJECT_PATH, &empty_path);
        }
 
 end:
        hdp_channel_unref(hdp_chan);
 }
 
-static GDBusMethodTable health_channels_methods[] = {
-       {"GetProperties","",    "a{sv}",        channel_get_properties },
-       {"Acquire",     "",     "h",            channel_acquire,
-                                               G_DBUS_METHOD_FLAG_ASYNC },
-       {"Release",     "",     "",             channel_release },
-       { NULL }
+static const GDBusMethodTable health_channels_methods[] = {
+       { GDBUS_METHOD("GetProperties",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       channel_get_properties) },
+       { GDBUS_ASYNC_METHOD("Acquire",
+                       NULL, GDBUS_ARGS({ "fd", "h" }),
+                       channel_acquire) },
+       { GDBUS_METHOD("Release", NULL, NULL, channel_release) },
+       { }
 };
 
 static struct hdp_channel *create_channel(struct hdp_device *dev,
@@ -2061,7 +2059,6 @@ static DBusMessage *device_get_properties(DBusConnection *conn,
        struct hdp_device *device = user_data;
        DBusMessageIter iter, dict;
        DBusMessage *reply;
-       char *path;
 
        reply = dbus_message_new_method_return(msg);
        if (reply == NULL)
@@ -2075,11 +2072,9 @@ static DBusMessage *device_get_properties(DBusConnection *conn,
                        DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
 
        if (device->fr != NULL)
-               path = g_strdup(device->fr->path);
-       else
-               path = g_strdup("");
-       dict_append_entry(&dict, "MainChannel", DBUS_TYPE_OBJECT_PATH, &path);
-       g_free(path);
+               dict_append_entry(&dict, "MainChannel", DBUS_TYPE_OBJECT_PATH,
+                                                       &device->fr->path);
+
        dbus_message_iter_close_container(&iter, &dict);
 
        return reply;
@@ -2102,22 +2097,31 @@ static void health_device_destroy(void *data)
        health_device_unref(device);
 }
 
-static GDBusMethodTable health_device_methods[] = {
-       {"Echo",                "",     "b",    device_echo,
-                                               G_DBUS_METHOD_FLAG_ASYNC },
-       {"CreateChannel",       "os",   "o",    device_create_channel,
-                                               G_DBUS_METHOD_FLAG_ASYNC },
-       {"DestroyChannel",      "o",    "",     device_destroy_channel,
-                                               G_DBUS_METHOD_FLAG_ASYNC },
-       {"GetProperties",       "",     "a{sv}", device_get_properties},
-       { NULL }
+static const GDBusMethodTable health_device_methods[] = {
+       { GDBUS_ASYNC_METHOD("Echo",
+                       NULL, GDBUS_ARGS({ "value", "b" }), device_echo) },
+       { GDBUS_ASYNC_METHOD("CreateChannel",
+                       GDBUS_ARGS({ "application", "o" },
+                                       { "configuration", "s" }),
+                       GDBUS_ARGS({ "channel", "o" }),
+                       device_create_channel) },
+       { GDBUS_ASYNC_METHOD("DestroyChannel",
+                       GDBUS_ARGS({ "channel", "o" }), NULL,
+                       device_destroy_channel) },
+       { GDBUS_METHOD("GetProperties",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       device_get_properties) },
+       { }
 };
 
-static GDBusSignalTable health_device_signals[] = {
-       {"ChannelConnected",            "o"             },
-       {"ChannelDeleted",              "o"             },
-       {"PropertyChanged",             "sv"            },
-       { NULL }
+static const GDBusSignalTable health_device_signals[] = {
+       { GDBUS_SIGNAL("ChannelConnected",
+                       GDBUS_ARGS({ "channel", "o" })) },
+       { GDBUS_SIGNAL("ChannelDeleted",
+                       GDBUS_ARGS({ "channel", "o" })) },
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+       { }
 };
 
 static struct hdp_device *create_health_device(DBusConnection *conn,
index cccb1a6..ffaed5d 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
 
 #include <btio.h>
 #include <adapter.h>
index 9a6776f..7f8b015 100644 (file)
 #ifndef __HDP_TYPES_H__
 #define __HDP_TYPES_H__
 
-#define HDP_UUID               "00001400-0000-1000-8000-00805F9B34FB"
-#define HDP_SOURCE_UUID                "00001401-0000-1000-8000-00805F9B34FB"
-#define HDP_SINK_UUID          "00001402-0000-1000-8000-00805F9B34FB"
-
 #define MANAGER_PATH           "/org/bluez"
 
 #define HEALTH_MANAGER         "org.bluez.HealthManager"
index 3b48e44..744e390 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <sdpd.h>
 #include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
 #include <sdp-client.h>
 #include <glib-helper.h>
 
index 4c726b6..b76d88a 100644 (file)
@@ -901,6 +901,7 @@ static gboolean parse_set_opts(struct mcap_mdl_cb *mdl_cb, GError **err,
                default:
                        g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS,
                                                "Unknown option %d", cb);
+                       g_free(c);
                        return FALSE;
                }
                cb = va_arg(args, int);
index a1ecdd7..0e3f4a9 100644 (file)
@@ -37,6 +37,7 @@
 #include <bluetooth/hidp.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
@@ -56,6 +57,8 @@
 #include "fakehid.h"
 #include "btio.h"
 
+#include "sdp-client.h"
+
 #define INPUT_DEVICE_INTERFACE "org.bluez.Input"
 
 #define BUF_SIZE               16
@@ -68,12 +71,13 @@ struct input_conn {
        struct fake_input       *fake;
        DBusMessage             *pending_connect;
        char                    *uuid;
-       char                    *alias;
        GIOChannel              *ctrl_io;
        GIOChannel              *intr_io;
        guint                   ctrl_watch;
        guint                   intr_watch;
+       guint                   sec_watch;
        int                     timeout;
+       struct hidp_connadd_req *req;
        struct input_device     *idev;
 };
 
@@ -84,6 +88,7 @@ struct input_device {
        bdaddr_t                dst;
        uint32_t                handle;
        guint                   dc_id;
+       gboolean                disable_sdp;
        char                    *name;
        struct btd_device       *device;
        GSList                  *connections;
@@ -110,9 +115,6 @@ static struct input_conn *find_connection(GSList *list, const char *pattern)
 
                if (!strcasecmp(iconn->uuid, pattern))
                        return iconn;
-
-               if (!strcasecmp(iconn->alias, pattern))
-                       return iconn;
        }
 
        return NULL;
@@ -129,6 +131,9 @@ static void input_conn_free(struct input_conn *iconn)
        if (iconn->intr_watch)
                g_source_remove(iconn->intr_watch);
 
+       if (iconn->sec_watch)
+               g_source_remove(iconn->sec_watch);
+
        if (iconn->intr_io)
                g_io_channel_unref(iconn->intr_io);
 
@@ -136,7 +141,6 @@ static void input_conn_free(struct input_conn *iconn)
                g_io_channel_unref(iconn->ctrl_io);
 
        g_free(iconn->uuid);
-       g_free(iconn->alias);
        g_free(iconn->fake);
        g_free(iconn);
 }
@@ -368,6 +372,7 @@ static gboolean rfcomm_connect(struct input_conn *iconn, GError **err)
                                NULL, err,
                                BT_IO_OPT_SOURCE_BDADDR, &idev->src,
                                BT_IO_OPT_DEST_BDADDR, &idev->dst,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
                                BT_IO_OPT_INVALID);
        if (!io)
                return FALSE;
@@ -567,14 +572,31 @@ cleanup:
        g_free(req);
 }
 
+static gboolean encrypt_notify(GIOChannel *io, GIOCondition condition,
+                                                               gpointer data)
+{
+       struct input_conn *iconn = data;
+       struct hidp_connadd_req *req = iconn->req;
+
+       DBG(" ");
+
+       encrypt_completed(0, req);
+
+       iconn->sec_watch = 0;
+       iconn->req = NULL;
+
+       return FALSE;
+}
+
 static int hidp_add_connection(const struct input_device *idev,
-                               const struct input_conn *iconn)
+                                       struct input_conn *iconn)
 {
        struct hidp_connadd_req *req;
        struct fake_hid *fake_hid;
        struct fake_input *fake;
        sdp_record_t *rec;
        char src_addr[18], dst_addr[18];
+       GError *gerr = NULL;
        int err;
 
        req = g_new0(struct hidp_connadd_req, 1);
@@ -628,7 +650,12 @@ static int hidp_add_connection(const struct input_device *idev,
                if (err == 0) {
                        /* Waiting async encryption */
                        return 0;
-               } else if (err != -EALREADY) {
+               }
+
+               if (err == -ENOSYS)
+                       goto nosys;
+
+               if (err != -EALREADY) {
                        error("encrypt_link: %s (%d)", strerror(-err), -err);
                        goto cleanup;
                }
@@ -641,6 +668,20 @@ cleanup:
        g_free(req);
 
        return err;
+
+nosys:
+       if (!bt_io_set(iconn->intr_io, BT_IO_L2CAP, &gerr,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+                               BT_IO_OPT_INVALID)) {
+               error("btio: %s", gerr->message);
+               g_error_free(gerr);
+               goto cleanup;
+       }
+
+       iconn->req = req;
+       iconn->sec_watch = g_io_add_watch(iconn->intr_io, G_IO_OUT,
+                                                       encrypt_notify, iconn);
+       return 0;
 }
 
 static int is_connected(struct input_conn *iconn)
@@ -914,7 +955,7 @@ static DBusMessage *input_device_connect(DBusConnection *conn,
        DBusMessage *reply;
        GError *err = NULL;
 
-       iconn = find_connection(idev->connections, "HID");
+       iconn = find_connection(idev->connections, HID_UUID);
        if (!iconn)
                return btd_error_not_supported(msg);
 
@@ -935,6 +976,9 @@ static DBusMessage *input_device_connect(DBusConnection *conn,
                /* HID devices */
                GIOChannel *io;
 
+               if (idev->disable_sdp)
+                       bt_clear_cached_session(&idev->src, &idev->dst);
+
                io = bt_io_connect(BT_IO_L2CAP, control_connect_cb, iconn,
                                        NULL, &err,
                                        BT_IO_OPT_SOURCE_BDADDR, &idev->src,
@@ -1017,37 +1061,42 @@ static DBusMessage *input_device_get_properties(DBusConnection *conn,
        return reply;
 }
 
-static GDBusMethodTable device_methods[] = {
-       { "Connect",            "",     "",     input_device_connect,
-                                               G_DBUS_METHOD_FLAG_ASYNC },
-       { "Disconnect",         "",     "",     input_device_disconnect },
-       { "GetProperties",      "",     "a{sv}",input_device_get_properties },
+static const GDBusMethodTable device_methods[] = {
+       { GDBUS_ASYNC_METHOD("Connect",
+                               NULL, NULL, input_device_connect) },
+       { GDBUS_METHOD("Disconnect",
+                               NULL, NULL, input_device_disconnect) },
+       { GDBUS_METHOD("GetProperties",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       input_device_get_properties) },
        { }
 };
 
-static GDBusSignalTable device_signals[] = {
-       { "PropertyChanged",    "sv"    },
+static const GDBusSignalTable device_signals[] = {
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
        { }
 };
 
 static struct input_device *input_device_new(DBusConnection *conn,
-                                       struct btd_device *device, const char *path,
-                                       const bdaddr_t *src, const bdaddr_t *dst,
-                                       const uint32_t handle)
+                               struct btd_device *device, const char *path,
+                               const uint32_t handle, gboolean disable_sdp)
 {
+       struct btd_adapter *adapter = device_get_adapter(device);
        struct input_device *idev;
        char name[249], src_addr[18], dst_addr[18];
 
        idev = g_new0(struct input_device, 1);
-       bacpy(&idev->src, src);
-       bacpy(&idev->dst, dst);
+       adapter_get_address(adapter, &idev->src);
+       device_get_address(device, &idev->dst, NULL);
        idev->device = btd_device_ref(device);
        idev->path = g_strdup(path);
        idev->conn = dbus_connection_ref(conn);
        idev->handle = handle;
+       idev->disable_sdp = disable_sdp;
 
-       ba2str(src, src_addr);
-       ba2str(dst, dst_addr);
+       ba2str(&idev->src, src_addr);
+       ba2str(&idev->dst, dst_addr);
        if (read_device_name(src_addr, dst_addr, name) == 0)
                idev->name = g_strdup(name);
 
@@ -1067,39 +1116,44 @@ static struct input_device *input_device_new(DBusConnection *conn,
 }
 
 static struct input_conn *input_conn_new(struct input_device *idev,
-                                       const char *uuid, const char *alias,
-                                       int timeout)
+                                       const char *uuid, int timeout)
 {
        struct input_conn *iconn;
 
        iconn = g_new0(struct input_conn, 1);
        iconn->timeout = timeout;
        iconn->uuid = g_strdup(uuid);
-       iconn->alias = g_strdup(alias);
        iconn->idev = idev;
 
        return iconn;
 }
 
+static gboolean is_device_sdp_disable(const sdp_record_t *rec)
+{
+       sdp_data_t *data;
+
+       data = sdp_data_get(rec, SDP_ATTR_HID_SDP_DISABLE);
+
+       return data && data->val.uint8;
+}
+
 int input_device_register(DBusConnection *conn, struct btd_device *device,
-                       const char *path, const bdaddr_t *src,
-                       const bdaddr_t *dst, const char *uuid,
-                       uint32_t handle, int timeout)
+                                       const char *path, const char *uuid,
+                                       const sdp_record_t *rec, int timeout)
 {
        struct input_device *idev;
        struct input_conn *iconn;
 
        idev = find_device_by_path(devices, path);
        if (!idev) {
-               idev = input_device_new(conn, device, path, src, dst, handle);
+               idev = input_device_new(conn, device, path, rec->handle,
+                                       is_device_sdp_disable(rec));
                if (!idev)
                        return -EINVAL;
                devices = g_slist_append(devices, idev);
        }
 
-       iconn = input_conn_new(idev, uuid, "hid", timeout);
-       if (!iconn)
-               return -EINVAL;
+       iconn = input_conn_new(idev, uuid, timeout);
 
        idev->connections = g_slist_append(idev->connections, iconn);
 
@@ -1107,24 +1161,20 @@ int input_device_register(DBusConnection *conn, struct btd_device *device,
 }
 
 int fake_input_register(DBusConnection *conn, struct btd_device *device,
-                       const char *path, bdaddr_t *src, bdaddr_t *dst,
-                       const char *uuid, uint8_t channel)
+                       const char *path, const char *uuid, uint8_t channel)
 {
        struct input_device *idev;
        struct input_conn *iconn;
 
        idev = find_device_by_path(devices, path);
        if (!idev) {
-               idev = input_device_new(conn, device, path, src, dst, 0);
+               idev = input_device_new(conn, device, path, 0, FALSE);
                if (!idev)
                        return -EINVAL;
                devices = g_slist_append(devices, idev);
        }
 
-       iconn = input_conn_new(idev, uuid, "hsp", 0);
-       if (!iconn)
-               return -EINVAL;
-
+       iconn = input_conn_new(idev, uuid, 0);
        iconn->fake = g_new0(struct fake_input, 1);
        iconn->fake->ch = channel;
        iconn->fake->connect = rfcomm_connect;
@@ -1213,7 +1263,7 @@ int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm,
        if (!idev)
                return -ENOENT;
 
-       iconn = find_connection(idev->connections, "hid");
+       iconn = find_connection(idev->connections, HID_UUID);
        if (!iconn)
                return -ENOENT;
 
@@ -1244,7 +1294,7 @@ int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst)
        if (!idev)
                return -ENOENT;
 
-       iconn = find_connection(idev->connections, "hid");
+       iconn = find_connection(idev->connections, HID_UUID);
        if (!iconn)
                return -ENOENT;
 
index 14c0f97..509a353 100644 (file)
@@ -21,9 +21,6 @@
  *
  */
 
-#define HSP_HS_UUID            "00001108-0000-1000-8000-00805F9B34FB"
-#define HID_UUID               "00001124-0000-1000-8000-00805f9b34fb"
-
 #define L2CAP_PSM_HIDP_CTRL    0x11
 #define L2CAP_PSM_HIDP_INTR    0x13
 
@@ -43,12 +40,10 @@ struct fake_input {
 };
 
 int fake_input_register(DBusConnection *conn, struct btd_device *device,
-                       const char *path, bdaddr_t *src, bdaddr_t *dst,
-                       const char *uuid, uint8_t channel);
+                       const char *path, const char *uuid, uint8_t channel);
 int input_device_register(DBusConnection *conn, struct btd_device *device,
-                       const char *path, const bdaddr_t *src,
-                       const bdaddr_t *dst, const char *uuid,
-                       uint32_t handle, int timeout);
+                                       const char *path, const char *uuid,
+                                       const sdp_record_t *rec, int timeout);
 int input_device_unregister(const char *path, const char *uuid);
 
 int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm,
index eebca05..3181538 100644 (file)
 #include <sys/types.h>
 
 #include <bluetooth/bluetooth.h>
-#include <bluetooth/hidp.h>
-#include <bluetooth/sdp.h>
 
 #include <glib.h>
-#include <dbus/dbus.h>
 
 #include "../src/adapter.h"
 #include "../src/device.h"
@@ -47,8 +44,6 @@
 #include "fakehid.h"
 #include "uinput.h"
 
-#define PS3_FLAGS_MASK 0xFFFFFF00
-
 enum ps3remote_special_keys {
        PS3R_BIT_PS = 0,
        PS3R_BIT_ENTER = 3,
@@ -393,15 +388,17 @@ struct fake_input *fake_hid_connadd(struct fake_input *fake,
 
        /* New device? Add it to the list of known devices,
         * and create the uinput necessary */
-       if (old == NULL) {
+       if (old == NULL || old->uinput < 0) {
                if (fake_hid->setup_uinput(fake, fake_hid)) {
                        error("Error setting up uinput");
                        g_free(fake);
                        return NULL;
                }
-               fake_hid->devices = g_list_append(fake_hid->devices, fake);
        }
 
+       if (old == NULL)
+               fake_hid->devices = g_list_append(fake_hid->devices, fake);
+
        fake->io = g_io_channel_ref(intr_io);
        g_io_channel_set_close_on_unref(fake->io, TRUE);
        g_io_add_watch(fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
index e165ab4..da09b86 100644 (file)
@@ -82,5 +82,5 @@ static void input_exit(void)
        dbus_connection_unref(connection);
 }
 
-BLUETOOTH_PLUGIN_DEFINE(input, VERSION,
-                       BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, input_init, input_exit)
+BLUETOOTH_PLUGIN_DEFINE(input, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                                                       input_init, input_exit)
index ede06be..5cc552b 100644 (file)
@@ -31,6 +31,7 @@
 #include <bluetooth/hci.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
 
 #include <gdbus.h>
 
@@ -58,21 +59,16 @@ static void input_remove(struct btd_device *device, const char *uuid)
 
 static int hid_device_probe(struct btd_device *device, GSList *uuids)
 {
-       struct btd_adapter *adapter = device_get_adapter(device);
        const gchar *path = device_get_path(device);
        const sdp_record_t *rec = btd_device_get_record(device, uuids->data);
-       bdaddr_t src, dst;
 
        DBG("path %s", path);
 
        if (!rec)
                return -1;
 
-       adapter_get_address(adapter, &src);
-       device_get_address(device, &dst, NULL);
-
-       return input_device_register(connection, device, path, &src, &dst,
-                               HID_UUID, rec->handle, idle_timeout * 60);
+       return input_device_register(connection, device, path, HID_UUID, rec,
+                                                       idle_timeout * 60);
 }
 
 static void hid_device_remove(struct btd_device *device)
@@ -82,12 +78,10 @@ static void hid_device_remove(struct btd_device *device)
 
 static int headset_probe(struct btd_device *device, GSList *uuids)
 {
-       struct btd_adapter *adapter = device_get_adapter(device);
        const gchar *path = device_get_path(device);
        const sdp_record_t *record;
        sdp_list_t *protos;
        int ch;
-       bdaddr_t src, dst;
 
        DBG("path %s", path);
 
@@ -111,11 +105,7 @@ static int headset_probe(struct btd_device *device, GSList *uuids)
                return -EINVAL;
        }
 
-       adapter_get_address(adapter, &src);
-       device_get_address(device, &dst, NULL);
-
-       return fake_input_register(connection, device, path, &src, &dst,
-                               HSP_HS_UUID, ch);
+       return fake_input_register(connection, device, path, HSP_HS_UUID, ch);
 }
 
 static void headset_remove(struct btd_device *device)
index cea08d1..86e2ac8 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
+#include <bluetooth/uuid.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
@@ -148,6 +149,7 @@ static void confirm_event_cb(GIOChannel *chan, gpointer user_data)
        struct input_server *server = user_data;
        bdaddr_t src, dst;
        GError *err = NULL;
+       char addr[18];
        int ret;
 
        bt_io_get(chan, BT_IO_L2CAP, &err,
@@ -176,6 +178,10 @@ static void confirm_event_cb(GIOChannel *chan, gpointer user_data)
        if (ret == 0)
                return;
 
+       ba2str(&src, addr);
+       error("input: authorization for %s failed: %s (%d)",
+                                               addr, strerror(-ret), ret);
+
        g_io_channel_unref(server->confirm);
        server->confirm = NULL;
 
index 5c58b9b..5c50a58 100644 (file)
@@ -296,4 +296,3 @@ int main (int argc, char **argv)
 
        return 0;
 }
-
diff --git a/lib/a2mp.h b/lib/a2mp.h
new file mode 100644 (file)
index 0000000..61f1c1e
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
+ *  Copyright (c) 2012  Code Aurora Forum. 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
+ *
+ */
+
+#ifndef __A2MP_H
+#define __A2MP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* A2MP Protocol */
+
+/* A2MP command codes */
+
+#define A2MP_COMMAND_REJ       0x01
+#define A2MP_DISCOVER_REQ      0x02
+#define A2MP_DISCOVER_RSP      0x03
+#define A2MP_CHANGE_NOTIFY     0x04
+#define A2MP_CHANGE_RSP                0x05
+#define A2MP_INFO_REQ          0x06
+#define A2MP_INFO_RSP          0x07
+#define A2MP_ASSOC_REQ         0x08
+#define A2MP_ASSOC_RSP         0x09
+#define A2MP_CREATE_REQ                0x0a
+#define A2MP_CREATE_RSP                0x0b
+#define A2MP_DISCONN_REQ       0x0c
+#define A2MP_DISCONN_RSP       0x0d
+
+struct a2mp_hdr {
+       uint8_t         code;
+       uint8_t         ident;
+       uint16_t        len;
+} __attribute__ ((packed));
+#define A2MP_HDR_SIZE 4
+
+struct a2mp_command_rej {
+       uint16_t        reason;
+} __attribute__ ((packed));
+
+struct a2mp_discover_req {
+       uint16_t        mtu;
+       uint16_t        mask;
+} __attribute__ ((packed));
+
+struct a2mp_ctrl {
+       uint8_t         id;
+       uint8_t         type;
+       uint8_t         status;
+} __attribute__ ((packed));
+
+struct a2mp_discover_rsp {
+       uint16_t        mtu;
+       uint16_t        mask;
+       struct a2mp_ctrl ctrl_list[0];
+} __attribute__ ((packed));
+
+struct a2mp_info_req {
+       uint8_t         id;
+} __attribute__ ((packed));
+
+struct a2mp_info_rsp {
+       uint8_t         id;
+       uint8_t         status;
+       uint32_t        total_bw;
+       uint32_t        max_bw;
+       uint32_t        min_latency;
+       uint16_t        pal_caps;
+       uint16_t        assoc_size;
+} __attribute__ ((packed));
+
+struct a2mp_assoc_req {
+       uint8_t         id;
+} __attribute__ ((packed));
+
+struct a2mp_assoc_rsp {
+       uint8_t         id;
+       uint8_t         status;
+       uint8_t         assoc_data[0];
+} __attribute__ ((packed));
+
+struct a2mp_create_req {
+       uint8_t         local_id;
+       uint8_t         remote_id;
+       uint8_t         assoc_data[0];
+} __attribute__ ((packed));
+
+struct a2mp_create_rsp {
+       uint8_t         local_id;
+       uint8_t         remote_id;
+       uint8_t         status;
+} __attribute__ ((packed));
+
+struct a2mp_disconn_req {
+       uint8_t         local_id;
+       uint8_t         remote_id;
+} __attribute__ ((packed));
+
+struct a2mp_disconn_rsp {
+       uint8_t         local_id;
+       uint8_t         remote_id;
+       uint8_t         status;
+} __attribute__ ((packed));
+
+#define A2MP_COMMAND_NOT_RECOGNIZED 0x0000
+
+/* AMP controller status */
+#define AMP_CTRL_POWERED_DOWN          0x00
+#define AMP_CTRL_BLUETOOTH_ONLY                0x01
+#define AMP_CTRL_NO_CAPACITY           0x02
+#define AMP_CTRL_LOW_CAPACITY          0x03
+#define AMP_CTRL_MEDIUM_CAPACITY       0x04
+#define AMP_CTRL_HIGH_CAPACITY         0x05
+#define AMP_CTRL_FULL_CAPACITY         0x06
+
+/* A2MP response status */
+#define A2MP_STATUS_SUCCESS                            0x00
+#define A2MP_STATUS_INVALID_CTRL_ID                    0x01
+#define A2MP_STATUS_UNABLE_START_LINK_CREATION         0x02
+#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS            0x02
+#define A2MP_STATUS_COLLISION_OCCURED                  0x03
+#define A2MP_STATUS_DISCONN_REQ_RECVD                  0x04
+#define A2MP_STATUS_PHYS_LINK_EXISTS                   0x05
+#define A2MP_STATUS_SECURITY_VIOLATION                 0x06
+
+#define A2MP_MAC_ADDR_TYPE             1
+#define A2MP_PREF_CHANLIST_TYPE                2
+#define A2MP_CONNECTED_CHAN            3
+#define A2MP_PAL_CAP_TYPE              4
+#define A2MP_PAL_VER_INFO              5
+
+struct a2mp_tlv {
+       uint8_t type;
+       uint16_t len;
+       uint8_t val[0];
+} __attribute__ ((packed));
+
+struct a2mp_pal_ver {
+       uint8_t ver;
+       uint16_t company_id;
+       uint16_t sub_ver;
+} __attribute__ ((packed));
+
+struct a2mp_country_triplet {
+       union {
+               struct {
+                       uint8_t first_channel;
+                       uint8_t num_channels;
+                       int8_t max_power;
+               } __attribute__ ((packed)) chans;
+               struct {
+                       uint8_t reg_extension_id;
+                       uint8_t reg_class;
+                       uint8_t coverage_class;
+               } __attribute__ ((packed)) ext;
+       };
+} __attribute__ ((packed));
+
+struct a2mp_chan_list {
+       uint8_t country_code[3];
+       struct a2mp_country_triplet triplets[0];
+} __attribute__ ((packed));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __A2MP_H */
index cb2e6c1..a0be884 100644 (file)
@@ -498,6 +498,30 @@ char *bt_compidtostr(int compid)
                return "Group Sense Ltd.";
        case 116:
                return "Zomm, LLC";
+       case 117:
+               return "Samsung Electronics Co. Ltd.";
+       case 118:
+               return "Creative Technology Ltd.";
+       case 119:
+               return "Laird Technologies";
+       case 120:
+               return "Nike, Inc.";
+       case 121:
+               return "lesswire AG";
+       case 122:
+               return "MStar Semiconductor, Inc.";
+       case 123:
+               return "Hanlynn Technologies";
+       case 124:
+               return "A & R Cambridge";
+       case 125:
+               return "Seers Technology Co. Ltd.";
+       case 126:
+               return "Sports Tracking Technologies Ltd.";
+       case 127:
+               return "Autonet Mobile";
+       case 128:
+               return "DeLorme Publishing Company, Inc.";
        case 65535:
                return "internal use";
        default:
index 5bd4f03..0fc4508 100644 (file)
@@ -63,6 +63,7 @@ extern "C" {
 #define BT_SECURITY    4
 struct bt_security {
        uint8_t level;
+       uint8_t key_size;
 };
 #define BT_SECURITY_SDP                0
 #define BT_SECURITY_LOW                1
@@ -76,6 +77,33 @@ struct bt_security {
 #define BT_FLUSHABLE_OFF       0
 #define BT_FLUSHABLE_ON                1
 
+#define BT_CHANNEL_POLICY      10
+
+/* BR/EDR only (default policy)
+ *   AMP controllers cannot be used.
+ *   Channel move requests from the remote device are denied.
+ *   If the L2CAP channel is currently using AMP, move the channel to BR/EDR.
+ */
+#define BT_CHANNEL_POLICY_BREDR_ONLY           0
+
+/* BR/EDR Preferred
+ *   Allow use of AMP controllers.
+ *   If the L2CAP channel is currently on AMP, move it to BR/EDR.
+ *   Channel move requests from the remote device are allowed.
+ */
+#define BT_CHANNEL_POLICY_BREDR_PREFERRED      1
+
+/* AMP Preferred
+ *   Allow use of AMP controllers
+ *   If the L2CAP channel is currently on BR/EDR and AMP controller
+ *     resources are available, initiate a channel move to AMP.
+ *   Channel move requests from the remote device are allowed.
+ *   If the L2CAP socket has not been connected yet, try to create
+ *     and configure the channel directly on an AMP controller rather
+ *     than BR/EDR.
+ */
+#define BT_CHANNEL_POLICY_AMP_PREFERRED                2
+
 /* Connection and socket states */
 enum {
        BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
@@ -113,7 +141,7 @@ enum {
 ({                                             \
        struct __attribute__((packed)) {        \
                typeof(*(ptr)) __v;             \
-       } *__p = (void *) (ptr);                \
+       } *__p = (typeof(__p)) (ptr);           \
        __p->__v;                               \
 })
 
@@ -121,69 +149,69 @@ enum {
 do {                                           \
        struct __attribute__((packed)) {        \
                typeof(*(ptr)) __v;             \
-       } *__p = (void *) (ptr);                \
+       } *__p = (typeof(__p)) (ptr);           \
        __p->__v = (val);                       \
 } while(0)
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-static inline uint64_t bt_get_le64(void *ptr)
+static inline uint64_t bt_get_le64(const void *ptr)
 {
-       return bt_get_unaligned((uint64_t *) ptr);
+       return bt_get_unaligned((const uint64_t *) ptr);
 }
 
-static inline uint64_t bt_get_be64(void *ptr)
+static inline uint64_t bt_get_be64(const void *ptr)
 {
-       return bswap_64(bt_get_unaligned((uint64_t *) ptr));
+       return bswap_64(bt_get_unaligned((const uint64_t *) ptr));
 }
 
-static inline uint32_t bt_get_le32(void *ptr)
+static inline uint32_t bt_get_le32(const void *ptr)
 {
-       return bt_get_unaligned((uint32_t *) ptr);
+       return bt_get_unaligned((const uint32_t *) ptr);
 }
 
-static inline uint32_t bt_get_be32(void *ptr)
+static inline uint32_t bt_get_be32(const void *ptr)
 {
-       return bswap_32(bt_get_unaligned((uint32_t *) ptr));
+       return bswap_32(bt_get_unaligned((const uint32_t *) ptr));
 }
 
-static inline uint16_t bt_get_le16(void *ptr)
+static inline uint16_t bt_get_le16(const void *ptr)
 {
-       return bt_get_unaligned((uint16_t *) ptr);
+       return bt_get_unaligned((const uint16_t *) ptr);
 }
 
-static inline uint16_t bt_get_be16(void *ptr)
+static inline uint16_t bt_get_be16(const void *ptr)
 {
-       return bswap_16(bt_get_unaligned((uint16_t *) ptr));
+       return bswap_16(bt_get_unaligned((const uint16_t *) ptr));
 }
 #elif __BYTE_ORDER == __BIG_ENDIAN
-static inline uint64_t bt_get_le64(void *ptr)
+static inline uint64_t bt_get_le64(const void *ptr)
 {
-       return bswap_64(bt_get_unaligned((uint64_t *) ptr));
+       return bswap_64(bt_get_unaligned((const uint64_t *) ptr));
 }
 
-static inline uint64_t bt_get_be64(void *ptr)
+static inline uint64_t bt_get_be64(const void *ptr)
 {
-       return bt_get_unaligned((uint64_t *) ptr);
+       return bt_get_unaligned((const uint64_t *) ptr);
 }
 
-static inline uint32_t bt_get_le32(void *ptr)
+static inline uint32_t bt_get_le32(const void *ptr)
 {
-       return bswap_32(bt_get_unaligned((uint32_t *) ptr));
+       return bswap_32(bt_get_unaligned((const uint32_t *) ptr));
 }
 
-static inline uint32_t bt_get_be32(void *ptr)
+static inline uint32_t bt_get_be32(const void *ptr)
 {
-       return bt_get_unaligned((uint32_t *) ptr);
+       return bt_get_unaligned((const uint32_t *) ptr);
 }
 
-static inline uint16_t bt_get_le16(void *ptr)
+static inline uint16_t bt_get_le16(const void *ptr)
 {
-       return bswap_16(bt_get_unaligned((uint16_t *) ptr));
+       return bswap_16(bt_get_unaligned((const uint16_t *) ptr));
 }
 
-static inline uint16_t bt_get_be16(void *ptr)
+static inline uint16_t bt_get_be16(const void *ptr)
 {
-       return bt_get_unaligned((uint16_t *) ptr);
+       return bt_get_unaligned((const uint16_t *) ptr);
 }
 #else
 #error "Unknown byte order"
@@ -194,6 +222,11 @@ typedef struct {
        uint8_t b[6];
 } __attribute__((packed)) bdaddr_t;
 
+/* BD Address type */
+#define BDADDR_BREDR           0x00
+#define BDADDR_LE_PUBLIC       0x01
+#define BDADDR_LE_RANDOM       0x02
+
 #define BDADDR_ANY   (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
 #define BDADDR_ALL   (&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}})
 #define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
index b122313..a08031b 100644 (file)
--- a/lib/hci.c
+++ b/lib/hci.c
@@ -860,7 +860,7 @@ done:
 
 static int __other_bdaddr(int dd, int dev_id, long arg)
 {
-       struct hci_dev_info di = { dev_id: dev_id };
+       struct hci_dev_info di = { .dev_id = dev_id };
 
        if (ioctl(dd, HCIGETDEVINFO, (void *) &di))
                return 0;
@@ -873,7 +873,7 @@ static int __other_bdaddr(int dd, int dev_id, long arg)
 
 static int __same_bdaddr(int dd, int dev_id, long arg)
 {
-       struct hci_dev_info di = { dev_id: dev_id };
+       struct hci_dev_info di = { .dev_id = dev_id };
 
        if (ioctl(dd, HCIGETDEVINFO, (void *) &di))
                return 0;
@@ -1417,8 +1417,13 @@ int hci_read_local_name(int dd, int len, char *name, int to)
                return -1;
        }
 
+#ifdef __TIZEN_PATCH__
+       strncpy(name, (char *) rp.name, len - 1);
+       name[len - 1] = '\0';
+#else
        rp.name[247] = '\0';
        strncpy(name, (char *) rp.name, len);
+#endif
        return 0;
 }
 
@@ -2829,7 +2834,7 @@ int hci_le_set_advertise_enable(int dd, uint8_t enable, int to)
 int hci_le_create_conn(int dd, uint16_t interval, uint16_t window,
                uint8_t initiator_filter, uint8_t peer_bdaddr_type,
                bdaddr_t peer_bdaddr, uint8_t own_bdaddr_type,
-               uint16_t min_interval,  uint16_t max_interval,
+               uint16_t min_interval, uint16_t max_interval,
                uint16_t latency, uint16_t supervision_timeout,
                uint16_t min_ce_length, uint16_t max_ce_length,
                uint16_t *handle, int to)
index 48692fa..a4b63cc 100644 (file)
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -276,7 +276,9 @@ enum {
 #define LMP_EXT_FEAT   0x80
 
 /* Extended LMP features */
-#define LMP_HOST_LE    0x02
+#define LMP_HOST_SSP           0x01
+#define LMP_HOST_LE            0x02
+#define LMP_HOST_LE_BREDR      0x04
 
 /* Link policies */
 #define HCI_LP_RSWITCH 0x0001
@@ -293,6 +295,16 @@ enum {
 #define HCI_LM_RELIABLE        0x0010
 #define HCI_LM_SECURE  0x0020
 
+/* Link Key types */
+#define HCI_LK_COMBINATION             0x00
+#define HCI_LK_LOCAL_UNIT              0x01
+#define HCI_LK_REMOTE_UNIT             0x02
+#define HCI_LK_DEBUG_COMBINATION       0x03
+#define HCI_LK_UNAUTH_COMBINATION      0x04
+#define HCI_LK_AUTH_COMBINATION                0x05
+#define HCI_LK_CHANGED_COMBINATION     0x06
+#define HCI_LK_INVALID                 0xFF
+
 /* -----  HCI Commands ----- */
 
 /* Link Control */
@@ -1239,6 +1251,14 @@ typedef struct {
 } __attribute__ ((packed)) write_best_effort_flush_timeout_rp;
 #define WRITE_BEST_EFFORT_FLUSH_TIMEOUT_RP_SIZE 1
 
+#define OCF_READ_LE_HOST_SUPPORTED     0x006C
+typedef struct {
+       uint8_t         status;
+       uint8_t         le;
+       uint8_t         simul;
+} __attribute__ ((packed)) read_le_host_supported_rp;
+#define READ_LE_HOST_SUPPORTED_RP_SIZE 3
+
 #define OCF_WRITE_LE_HOST_SUPPORTED    0x006D
 typedef struct {
        uint8_t         le;
@@ -2268,7 +2288,8 @@ struct sockaddr_hci {
 #define HCI_DEV_NONE   0xffff
 
 #define HCI_CHANNEL_RAW                0
-#define HCI_CHANNEL_CONTROL    1
+#define HCI_CHANNEL_MONITOR    2
+#define HCI_CHANNEL_CONTROL    3
 
 struct hci_filter {
        uint32_t type_mask;
@@ -2325,6 +2346,14 @@ struct hci_conn_info {
        uint8_t  out;
        uint16_t state;
        uint32_t link_mode;
+#ifdef __TIZEN_PATCH__
+/* Workaround to avoid HID crash during connection n PQ because of the
+ * data structure mismatch. This will work for U1 kernel aswell.
+ */
+       uint32_t mtu;
+       uint32_t cnt;
+       uint32_t pkts;
+#endif
 };
 
 struct hci_dev_req {
index 725eb05..cf4a0ff 100644 (file)
@@ -123,7 +123,7 @@ int hci_le_set_advertise_enable(int dev_id, uint8_t enable, int to);
 int hci_le_create_conn(int dd, uint16_t interval, uint16_t window,
                uint8_t initiator_filter, uint8_t peer_bdaddr_type,
                bdaddr_t peer_bdaddr, uint8_t own_bdaddr_type,
-               uint16_t min_interval,  uint16_t max_interval,
+               uint16_t min_interval, uint16_t max_interval,
                uint16_t latency, uint16_t supervision_timeout,
                uint16_t min_ce_length, uint16_t max_ce_length,
                uint16_t *handle, int to);
index 68593d3..5ce94c4 100644 (file)
@@ -5,6 +5,7 @@
  *  Copyright (C) 2000-2001  Qualcomm Incorporated
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (c) 2012       Code Aurora Forum. All rights reserved.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -42,6 +43,7 @@ struct sockaddr_l2 {
        unsigned short  l2_psm;
        bdaddr_t        l2_bdaddr;
        unsigned short  l2_cid;
+       uint8_t         l2_bdaddr_type;
 };
 
 /* L2CAP socket options */
@@ -82,6 +84,12 @@ struct l2cap_conninfo {
 #define L2CAP_ECHO_RSP         0x09
 #define L2CAP_INFO_REQ         0x0a
 #define L2CAP_INFO_RSP         0x0b
+#define L2CAP_CREATE_REQ       0x0c
+#define L2CAP_CREATE_RSP       0x0d
+#define L2CAP_MOVE_REQ         0x0e
+#define L2CAP_MOVE_RSP         0x0f
+#define L2CAP_MOVE_CFM         0x10
+#define L2CAP_MOVE_CFM_RSP     0x11
 
 /* L2CAP extended feature mask */
 #define L2CAP_FEAT_FLOWCTL     0x00000001
@@ -226,6 +234,44 @@ typedef struct {
 #define L2CAP_IR_SUCCESS       0x0000
 #define L2CAP_IR_NOTSUPP       0x0001
 
+typedef struct {
+       uint16_t        psm;
+       uint16_t        scid;
+       uint8_t         id;
+} __attribute__ ((packed)) l2cap_create_req;
+#define L2CAP_CREATE_REQ_SIZE 5
+
+typedef struct {
+       uint16_t        dcid;
+       uint16_t        scid;
+       uint16_t        result;
+       uint16_t        status;
+} __attribute__ ((packed)) l2cap_create_rsp;
+#define L2CAP_CREATE_RSP_SIZE 8
+
+typedef struct {
+       uint16_t        icid;
+       uint8_t         id;
+} __attribute__ ((packed)) l2cap_move_req;
+#define L2CAP_MOVE_REQ_SIZE 3
+
+typedef struct {
+       uint16_t        icid;
+       uint16_t        result;
+} __attribute__ ((packed)) l2cap_move_rsp;
+#define L2CAP_MOVE_RSP_SIZE 4
+
+typedef struct {
+       uint16_t        icid;
+       uint16_t        result;
+} __attribute__ ((packed)) l2cap_move_cfm;
+#define L2CAP_MOVE_CFM_SIZE 4
+
+typedef struct {
+       uint16_t        icid;
+} __attribute__ ((packed)) l2cap_move_cfm_rsp;
+#define L2CAP_MOVE_CFM_RSP_SIZE 2
+
 #ifdef __cplusplus
 }
 #endif
index f121b12..a58915b 100644 (file)
 
 #define MGMT_INDEX_NONE                        0xFFFF
 
+#define MGMT_STATUS_SUCCESS            0x00
+#define MGMT_STATUS_UNKNOWN_COMMAND    0x01
+#define MGMT_STATUS_NOT_CONNECTED      0x02
+#define MGMT_STATUS_FAILED             0x03
+#define MGMT_STATUS_CONNECT_FAILED     0x04
+#define MGMT_STATUS_AUTH_FAILED                0x05
+#define MGMT_STATUS_NOT_PAIRED         0x06
+#define MGMT_STATUS_NO_RESOURCES       0x07
+#define MGMT_STATUS_TIMEOUT            0x08
+#define MGMT_STATUS_ALREADY_CONNECTED  0x09
+#define MGMT_STATUS_BUSY               0x0a
+#define MGMT_STATUS_REJECTED           0x0b
+#define MGMT_STATUS_NOT_SUPPORTED      0x0c
+#define MGMT_STATUS_INVALID_PARAMS     0x0d
+#define MGMT_STATUS_DISCONNECTED       0x0e
+#define MGMT_STATUS_NOT_POWERED                0x0f
+#define MGMT_STATUS_CANCELLED          0x10
+#define MGMT_STATUS_INVALID_INDEX      0x11
+
 struct mgmt_hdr {
        uint16_t opcode;
        uint16_t index;
@@ -34,15 +53,22 @@ struct mgmt_hdr {
 } __packed;
 #define MGMT_HDR_SIZE  6
 
+struct mgmt_addr_info {
+       bdaddr_t bdaddr;
+       uint8_t type;
+} __packed;
+
 #define MGMT_OP_READ_VERSION           0x0001
 struct mgmt_rp_read_version {
        uint8_t version;
        uint16_t revision;
 } __packed;
 
-#define MGMT_OP_READ_FEATURES          0x0002
-struct mgmt_rp_read_features {
-       uint8_t features[8];
+#define MGMT_OP_READ_COMMANDS          0x0002
+struct mgmt_rp_read_commands {
+       uint16_t num_commands;
+       uint16_t num_events;
+       uint16_t opcodes[0];
 } __packed;
 
 #define MGMT_OP_READ_INDEX_LIST                0x0003
@@ -129,7 +155,7 @@ struct mgmt_cp_remove_uuid {
 } __packed;
 
 struct mgmt_link_key_info {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        uint8_t type;
        uint8_t val[16];
        uint8_t pin_len;
@@ -142,33 +168,28 @@ struct mgmt_cp_load_link_keys {
        struct mgmt_link_key_info keys[0];
 } __packed;
 
-#define MGMT_OP_REMOVE_KEYS            0x0013
-struct mgmt_cp_remove_keys {
-       bdaddr_t bdaddr;
-       uint8_t disconnect;
+struct mgmt_ltk_info {
+       struct mgmt_addr_info addr;
+       uint8_t authenticated;
+       uint8_t master;
+       uint8_t enc_size;
+       uint16_t ediv;
+       uint8_t rand[8];
+       uint8_t val[16];
 } __packed;
-struct mgmt_rp_remove_keys {
-       bdaddr_t bdaddr;
-       uint8_t status;
+
+#define MGMT_OP_LOAD_LONG_TERM_KEYS    0x0013
+struct mgmt_cp_load_long_term_keys {
+       uint16_t key_count;
+       struct mgmt_ltk_info keys[0];
 } __packed;
 
 #define MGMT_OP_DISCONNECT             0x0014
 struct mgmt_cp_disconnect {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __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;
+       struct mgmt_addr_info addr;
 } __packed;
 
 #define MGMT_OP_GET_CONNECTIONS                0x0015
@@ -179,14 +200,14 @@ struct mgmt_rp_get_connections {
 
 #define MGMT_OP_PIN_CODE_REPLY         0x0016
 struct mgmt_cp_pin_code_reply {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        uint8_t pin_len;
        uint8_t pin_code[16];
 } __packed;
 
 #define MGMT_OP_PIN_CODE_NEG_REPLY     0x0017
 struct mgmt_cp_pin_code_neg_reply {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
 
 #define MGMT_OP_SET_IO_CAPABILITY      0x0018
@@ -201,90 +222,109 @@ struct mgmt_cp_pair_device {
 } __packed;
 struct mgmt_rp_pair_device {
        struct mgmt_addr_info addr;
-       uint8_t status;
 } __packed;
 
-#define MGMT_OP_USER_CONFIRM_REPLY     0x001A
+#define MGMT_OP_CANCEL_PAIR_DEVICE     0x001A
+
+#define MGMT_OP_UNPAIR_DEVICE          0x001B
+struct mgmt_cp_unpair_device {
+       struct mgmt_addr_info addr;
+       uint8_t disconnect;
+} __packed;
+struct mgmt_rp_unpair_device {
+       struct mgmt_addr_info addr;
+} __packed;
+
+#define MGMT_OP_USER_CONFIRM_REPLY     0x001C
 struct mgmt_cp_user_confirm_reply {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
 struct mgmt_rp_user_confirm_reply {
-       bdaddr_t bdaddr;
-       uint8_t status;
+       struct mgmt_addr_info addr;
 } __packed;
 
-#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x001B
+#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x001D
 
-#define MGMT_OP_USER_PASSKEY_REPLY     0x001C
+#define MGMT_OP_USER_PASSKEY_REPLY     0x001E
 struct mgmt_cp_user_passkey_reply {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        uint32_t passkey;
 } __packed;
 struct mgmt_rp_user_passkey_reply {
-       bdaddr_t bdaddr;
-       uint8_t status;
+       struct mgmt_addr_info addr;
 } __packed;
 
-#define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x001D
+#define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x001F
 struct mgmt_cp_user_passkey_neg_reply {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
 
-#define MGMT_OP_READ_LOCAL_OOB_DATA    0x001E
+#define MGMT_OP_READ_LOCAL_OOB_DATA    0x0020
 struct mgmt_rp_read_local_oob_data {
        uint8_t hash[16];
        uint8_t randomizer[16];
 } __packed;
 
-#define MGMT_OP_ADD_REMOTE_OOB_DATA    0x001F
+#define MGMT_OP_ADD_REMOTE_OOB_DATA    0x0021
 struct mgmt_cp_add_remote_oob_data {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        uint8_t hash[16];
        uint8_t randomizer[16];
 } __packed;
 
-#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0020
+#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0022
 struct mgmt_cp_remove_remote_oob_data {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
 
-#define MGMT_OP_START_DISCOVERY                0x0021
+#define MGMT_OP_START_DISCOVERY                0x0023
 struct mgmt_cp_start_discovery {
        uint8_t type;
 } __packed;
 
-#define MGMT_OP_STOP_DISCOVERY         0x0022
+#define MGMT_OP_STOP_DISCOVERY         0x0024
+struct mgmt_cp_stop_discovery {
+       uint8_t type;
+} __packed;
 
-#define MGMT_OP_CONFIRM_NAME           0x0023
+#define MGMT_OP_CONFIRM_NAME           0x0025
 struct mgmt_cp_confirm_name {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        uint8_t name_known;
 } __packed;
 struct mgmt_rp_confirm_name {
-       bdaddr_t bdaddr;
-       uint8_t status;
+       struct mgmt_addr_info addr;
 } __packed;
 
-#define MGMT_OP_BLOCK_DEVICE           0x0024
+#define MGMT_OP_BLOCK_DEVICE           0x0026
 struct mgmt_cp_block_device {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
 
-#define MGMT_OP_UNBLOCK_DEVICE         0x0025
+#define MGMT_OP_UNBLOCK_DEVICE         0x0027
 struct mgmt_cp_unblock_device {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
+} __packed;
+
+#define MGMT_OP_SET_DEVICE_ID          0x0028
+struct mgmt_cp_set_device_id {
+       uint16_t source;
+       uint16_t vendor;
+       uint16_t product;
+       uint16_t version;
 } __packed;
 
 #define MGMT_EV_CMD_COMPLETE           0x0001
 struct mgmt_ev_cmd_complete {
        uint16_t opcode;
+       uint8_t status;
        uint8_t data[0];
 } __packed;
 
 #define MGMT_EV_CMD_STATUS             0x0002
 struct mgmt_ev_cmd_status {
-       uint8_t status;
        uint16_t opcode;
+       uint8_t status;
 } __packed;
 
 #define MGMT_EV_CONTROLLER_ERROR       0x0003
@@ -315,63 +355,200 @@ struct mgmt_ev_new_link_key {
        struct mgmt_link_key_info key;
 } __packed;
 
-#define MGMT_EV_DEVICE_CONNECTED       0x000A
+#define MGMT_EV_NEW_LONG_TERM_KEY      0x000A
+struct mgmt_ev_new_long_term_key {
+       uint8_t store_hint;
+       struct mgmt_ltk_info key;
+} __packed;
+
+#define MGMT_EV_DEVICE_CONNECTED       0x000B
+struct mgmt_ev_device_connected {
+       struct mgmt_addr_info addr;
+       uint32_t flags;
+       uint16_t eir_len;
+       uint8_t eir[0];
+} __packed;
 
-#define MGMT_EV_DEVICE_DISCONNECTED    0x000B
+#define MGMT_EV_DEVICE_DISCONNECTED    0x000C
+struct mgmt_ev_device_disconnected {
+       struct mgmt_addr_info addr;
+} __packed;
 
-#define MGMT_EV_CONNECT_FAILED         0x000C
+#define MGMT_EV_CONNECT_FAILED         0x000D
 struct mgmt_ev_connect_failed {
        struct mgmt_addr_info addr;
        uint8_t status;
 } __packed;
 
-#define MGMT_EV_PIN_CODE_REQUEST       0x000D
+#define MGMT_EV_PIN_CODE_REQUEST       0x000E
 struct mgmt_ev_pin_code_request {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        uint8_t secure;
 } __packed;
 
-#define MGMT_EV_USER_CONFIRM_REQUEST   0x000E
+#define MGMT_EV_USER_CONFIRM_REQUEST   0x000F
 struct mgmt_ev_user_confirm_request {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        uint8_t confirm_hint;
        uint32_t value;
 } __packed;
 
-#define MGMT_EV_USER_PASSKEY_REQUEST   0x000F
+#define MGMT_EV_USER_PASSKEY_REQUEST   0x0010
 struct mgmt_ev_user_passkey_request {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
 
-#define MGMT_EV_AUTH_FAILED            0x0010
+#define MGMT_EV_AUTH_FAILED            0x0011
 struct mgmt_ev_auth_failed {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        uint8_t status;
 } __packed;
 
-#define MGMT_EV_DEVICE_FOUND           0x0011
+#define MGMT_DEV_FOUND_CONFIRM_NAME    0x01
+#define MGMT_DEV_FOUND_LEGACY_PAIRING  0x02
+
+#define MGMT_EV_DEVICE_FOUND           0x0012
 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];
+       uint32_t flags;
+       uint16_t eir_len;
+       uint8_t eir[0];
 } __packed;
 
 #define MGMT_EV_DISCOVERING            0x0013
+struct mgmt_ev_discovering {
+       uint8_t type;
+       uint8_t discovering;
+} __packed;
 
 #define MGMT_EV_DEVICE_BLOCKED         0x0014
 struct mgmt_ev_device_blocked {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
 
 #define MGMT_EV_DEVICE_UNBLOCKED       0x0015
 struct mgmt_ev_device_unblocked {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
 } __packed;
+
+#define MGMT_EV_DEVICE_UNPAIRED                0x0016
+struct mgmt_ev_device_unpaired {
+       struct mgmt_addr_info addr;
+} __packed;
+
+static const char *mgmt_op[] = {
+       "<0x0000>",
+       "Read Version",
+       "Read Commands",
+       "Read Index List",
+       "Read Controller Info",
+       "Set Powered",
+       "Set Discoverable",
+       "Set Connectable",
+       "Set Fast Connectable",         /* 0x0008 */
+       "Set Pairable",
+       "Set Link Security",
+       "Set Secure Simple Pairing",
+       "Set High Speed",
+       "Set Low Energy",
+       "Set Dev Class",
+       "Set Local Name",
+       "Add UUID",                     /* 0x0010 */
+       "Remove UUID",
+       "Load Link Keys",
+       "Load Long Term Keys",
+       "Disconnect",
+       "Get Connections",
+       "PIN Code Reply",
+       "PIN Code Neg Reply",
+       "Set IO Capability",            /* 0x0018 */
+       "Pair Device",
+       "Cancel Pair Device",
+       "Unpair Device",
+       "User Confirm Reply",
+       "User Confirm Neg Reply",
+       "User Passkey Reply",
+       "User Passkey Neg Reply",
+       "Read Local OOB Data",          /* 0x0020 */
+       "Add Remote OOB Data",
+       "Remove Remove OOB Data",
+       "Start Discovery",
+       "Stop Discovery",
+       "Confirm Name",
+       "Block Device",
+       "Unblock Device",
+       "Set Device ID",
+};
+
+static const char *mgmt_ev[] = {
+       "<0x0000>",
+       "Command Complete",
+       "Command Status",
+       "Controller Error",
+       "Index Added",
+       "Index Removed",
+       "New Settings",
+       "Class of Device Changed",
+       "Local Name Changed",           /* 0x0008 */
+       "New Link Key",
+       "New Long Term Key",
+       "Device Connected",
+       "Device Disconnected",
+       "Connect Failed",
+       "PIN Code Request",
+       "User Confirm Request",
+       "User Passkey Request",         /* 0x0010 */
+       "Authentication Failed",
+       "Device Found",
+       "Discovering",
+       "Device Blocked",
+       "Device Unblocked",
+       "Device Unpaired",
+};
+
+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",
+       "Cancelled",
+       "Invalid Index",
+};
+
+#ifndef NELEM
+#define NELEM(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+static inline const char *mgmt_opstr(uint16_t op)
+{
+       if (op >= NELEM(mgmt_op))
+               return "<unknown opcode>";
+       return mgmt_op[op];
+}
+
+static inline const char *mgmt_evstr(uint16_t ev)
+{
+       if (ev >= NELEM(mgmt_ev))
+               return "<unknown event>";
+       return mgmt_ev[ev];
+}
+
+static inline const char *mgmt_errstr(uint8_t status)
+{
+       if (status >= NELEM(mgmt_status))
+               return "<unknown status>";
+       return mgmt_status[status];
+}
index a48ee14..7cb930f 100644 (file)
--- a/lib/sdp.c
+++ b/lib/sdp.c
@@ -60,8 +60,6 @@
 #define SDPDBG(fmt...)
 #endif
 
-#define BASE_UUID "00000000-0000-1000-8000-00805F9B34FB"
-
 static uint128_t bluetooth_base_uuid = {
        .data = {       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
                        0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB }
@@ -1387,7 +1385,7 @@ static void attr_print_func(void *value, void *userData)
 
        SDPDBG("=====================================\n");
        SDPDBG("ATTRIBUTE IDENTIFIER : 0x%x\n",  d->attrId);
-       SDPDBG("ATTRIBUTE VALUE PTR : 0x%x\n", (uint32_t)value);
+       SDPDBG("ATTRIBUTE VALUE PTR : %p\n", value);
        if (d)
                sdp_data_print(d);
        else
@@ -1934,7 +1932,6 @@ int sdp_get_uuidseq_attr(const sdp_record_t *rec, uint16_t attr,
                        if (!u)
                                goto fail;
 
-                       memset(u, 0, sizeof(uuid_t));
                        *u = d->val.uuid;
                        *seqp = sdp_list_append(*seqp, u);
                }
@@ -2064,8 +2061,13 @@ int sdp_get_profile_descs(const sdp_record_t *rec, sdp_list_t **profDescSeq)
                uint16_t version = 0x100;
 
                if (SDP_IS_UUID(seq->dtd)) {
+                       sdp_data_t *next = seq->next;
                        uuid = &seq->val.uuid;
-               } else {
+                       if (next && next->dtd == SDP_UINT16) {
+                               version = next->val.uint16;
+                               seq = next;
+                       }
+               } else if (SDP_IS_SEQ(seq->dtd)) {
                        sdp_data_t *puuid = seq->val.dataseq;
                        sdp_data_t *pVnum = seq->val.dataseq->next;
                        if (puuid && pVnum) {
@@ -3406,7 +3408,6 @@ int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search,
                scanned += sizeof(uint16_t);
                pdata_len -= sizeof(uint16_t);
 
-               SDPDBG("Total svc count: %d\n", total_rec_count);
                SDPDBG("Current svc count: %d\n", rec_count);
                SDPDBG("ResponseLength: %d\n", rsplen);
 
@@ -3703,8 +3704,8 @@ int sdp_set_notify(sdp_session_t *session, sdp_callback_t *func, void *udata)
 
 /*
  * This function starts an asynchronous service search request.
- * The incomming and outgoing data are stored in the transaction structure
- * buffers. When there is incomming data the sdp_process function must be
+ * The incoming and outgoing data are stored in the transaction structure
+ * buffers. When there is incoming data the sdp_process function must be
  * called to get the data and handle the continuation state.
  *
  * INPUT :
@@ -3795,8 +3796,8 @@ end:
 
 /*
  * This function starts an asynchronous service attribute request.
- * The incomming and outgoing data are stored in the transaction structure
- * buffers. When there is incomming data the sdp_process function must be
+ * The incoming and outgoing data are stored in the transaction structure
+ * buffers. When there is incoming data the sdp_process function must be
  * called to get the data and handle the continuation state.
  *
  * INPUT :
@@ -3906,9 +3907,9 @@ end:
 
 /*
  * This function starts an asynchronous service search attributes.
- * It is a service search request combined with attribute request. The incomming
+ * It is a service search request combined with attribute request. The incoming
  * and outgoing data are stored in the transaction structure buffers. When there
- * is incomming data the sdp_process function must be called to get the data
+ * is incoming data the sdp_process function must be called to get the data
  * and handle the continuation state.
  *
  * INPUT:
@@ -4051,7 +4052,7 @@ int sdp_get_error(sdp_session_t *session)
 }
 
 /*
- * Receive the incomming SDP PDU. This function must be called when there is data
+ * Receive the incoming SDP PDU. This function must be called when there is data
  * available to be read. On continuation state, the original request (with a new
  * transaction ID) and the continuation state data will be appended in the initial PDU.
  * If an error happens or the transaction finishes the callback function will be called.
@@ -4103,7 +4104,7 @@ int sdp_process(sdp_session_t *session)
        }
 
        if (n == 0 || reqhdr->tid != rsphdr->tid ||
-               (n != (ntohs(rsphdr->plen) + (int) sizeof(sdp_pdu_hdr_t)))) {
+               (n != (int) (ntohs(rsphdr->plen) + sizeof(sdp_pdu_hdr_t)))) {
                t->err = EPROTO;
                SDPERR("Protocol error.");
                goto end;
@@ -4789,3 +4790,16 @@ fail:
        return -1;
 }
 
+void sdp_add_lang_attr(sdp_record_t *rec)
+{
+       sdp_lang_attr_t base_lang;
+       sdp_list_t *langs;
+
+       base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
+       base_lang.encoding = 106;
+       base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
+
+       langs = sdp_list_append(0, &base_lang);
+       sdp_set_lang_attr(rec, langs);
+       sdp_list_free(langs, NULL);
+}
index 5f7d271..2fe74d5 100644 (file)
--- a/lib/sdp.h
+++ b/lib/sdp.h
@@ -432,6 +432,7 @@ typedef struct {
 } uuid_t;
 
 #define SDP_IS_UUID(x) ((x) == SDP_UUID16 || (x) == SDP_UUID32 || (x) ==SDP_UUID128)
+#define SDP_IS_SEQ(x)  ((x) == SDP_SEQ8 || (x) == SDP_SEQ16 || (x) == SDP_SEQ32)
 
 typedef struct _sdp_list sdp_list_t;
 struct _sdp_list {
index 433e9ef..6e1eb91 100644 (file)
@@ -624,6 +624,8 @@ void sdp_pattern_add_uuidseq(sdp_record_t *rec, sdp_list_t *seq);
 
 int sdp_send_req_w4_rsp(sdp_session_t *session, uint8_t *req, uint8_t *rsp, uint32_t reqsize, uint32_t *rspsize);
 
+void sdp_add_lang_attr(sdp_record_t *rec);
+
 #ifdef __cplusplus
 }
 #endif
index 9c082d3..2c2b351 100644 (file)
@@ -32,6 +32,57 @@ extern "C" {
 #include <stdint.h>
 #include <bluetooth/bluetooth.h>
 
+#define GENERIC_AUDIO_UUID     "00001203-0000-1000-8000-00805f9b34fb"
+
+#define HSP_HS_UUID            "00001108-0000-1000-8000-00805f9b34fb"
+#define HSP_AG_UUID            "00001112-0000-1000-8000-00805f9b34fb"
+
+#define HFP_HS_UUID            "0000111e-0000-1000-8000-00805f9b34fb"
+#define HFP_AG_UUID            "0000111f-0000-1000-8000-00805f9b34fb"
+
+#define ADVANCED_AUDIO_UUID    "0000110d-0000-1000-8000-00805f9b34fb"
+
+#define A2DP_SOURCE_UUID       "0000110a-0000-1000-8000-00805f9b34fb"
+#define A2DP_SINK_UUID         "0000110b-0000-1000-8000-00805f9b34fb"
+
+#define AVRCP_REMOTE_UUID      "0000110e-0000-1000-8000-00805f9b34fb"
+#define AVRCP_TARGET_UUID      "0000110c-0000-1000-8000-00805f9b34fb"
+
+#define PANU_UUID              "00001115-0000-1000-8000-00805f9b34fb"
+#define NAP_UUID               "00001116-0000-1000-8000-00805f9b34fb"
+#define GN_UUID                        "00001117-0000-1000-8000-00805f9b34fb"
+#define BNEP_SVC_UUID          "0000000f-0000-1000-8000-00805f9b34fb"
+
+#define PNPID_UUID             "00002a50-0000-1000-8000-00805f9b34fb"
+#define DEVICE_INFORMATION_UUID        "0000180a-0000-1000-8000-00805f9b34fb"
+
+#define GATT_UUID              "00001801-0000-1000-8000-00805f9b34fb"
+#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"
+
+#define SAP_UUID               "0000112D-0000-1000-8000-00805f9b34fb"
+
+#define HEALTH_THERMOMETER_UUID                "00001809-0000-1000-8000-00805f9b34fb"
+#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"
+
+#define RFCOMM_UUID_STR                "00000003-0000-1000-8000-00805f9b34fb"
+
+#define HDP_UUID               "00001400-0000-1000-8000-00805f9b34fb"
+#define HDP_SOURCE_UUID                "00001401-0000-1000-8000-00805f9b34fb"
+#define HDP_SINK_UUID          "00001402-0000-1000-8000-00805f9b34fb"
+
+#define HSP_HS_UUID            "00001108-0000-1000-8000-00805f9b34fb"
+#define HID_UUID               "00001124-0000-1000-8000-00805f9b34fb"
+
+#define DUN_GW_UUID            "00001103-0000-1000-8000-00805f9b34fb"
+
+#define GAP_SVC_UUID           "00001800-0000-1000-8000-00805f9b34fb"
+#define PNP_UUID               "00001200-0000-1000-8000-00805f9b34fb"
+
 typedef struct {
        enum {
                BT_UUID_UNSPEC = 0,
index 20d7bf8..b2d6c3c 100644 (file)
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
 #include <bluetooth/hci_lib.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_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",
-};
+#include <glib.h>
+#include "glib-helper.h"
 
 static bool monitor = false;
 static bool discovery = false;
@@ -137,27 +59,6 @@ static struct pending_cmd {
        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)
 {
@@ -240,6 +141,7 @@ static void mgmt_check_pending(int mgmt_sk, uint16_t op, uint16_t index,
                c->cb(mgmt_sk, op, index, status, data, len, c->user_data);
 
                free(c);
+               break;
        }
 }
 
@@ -262,7 +164,7 @@ static int mgmt_cmd_complete(int mgmt_sk, uint16_t index,
                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);
+       mgmt_check_pending(mgmt_sk, op, index, ev->status, ev->data, len);
 
        return 0;
 }
@@ -362,7 +264,7 @@ static int mgmt_new_settings(int mgmt_sk, uint16_t index,
 }
 
 static int mgmt_discovering(int mgmt_sk, uint16_t index,
-                                       struct mgmt_mode *ev, uint16_t len)
+                               struct mgmt_ev_discovering *ev, uint16_t len)
 {
        if (len < sizeof(*ev)) {
                fprintf(stderr, "Too short (%u bytes) discovering event\n",
@@ -370,12 +272,12 @@ static int mgmt_discovering(int mgmt_sk, uint16_t index,
                return -EINVAL;
        }
 
-       if (ev->val == 0 && discovery)
+       if (ev->discovering == 0 && discovery)
                exit(EXIT_SUCCESS);
 
        if (monitor)
-               printf("hci%u discovering %s\n", index,
-                                               ev->val ? "on" : "off");
+               printf("hci%u type %u discovering %s\n", index,
+                               ev->type, ev->discovering ? "on" : "off");
 
        return 0;
 }
@@ -392,7 +294,7 @@ static int mgmt_new_link_key(int mgmt_sk, uint16_t index,
 
        if (monitor) {
                char addr[18];
-               ba2str(&ev->key.bdaddr, addr);
+               ba2str(&ev->key.addr.bdaddr, addr);
                printf("hci%u new_link_key %s type 0x%02x pin_len %d "
                                "store_hint %u\n", index, addr, ev->key.type,
                                ev->key.pin_len, ev->store_hint);
@@ -405,28 +307,55 @@ static const char *typestr(uint8_t type)
 {
        const char *str[] = { "BR/EDR", "LE Public", "LE Random" };
 
-       if (type <= MGMT_ADDR_LE_RANDOM)
+       if (type <= BDADDR_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)
+static int mgmt_connected(int mgmt_sk, uint16_t index,
+                                       struct mgmt_ev_device_connected *ev,
+                                       uint16_t len)
 {
-       const char *ev_name = connected ? "connected" : "disconnected";
+       uint16_t eir_len;
+
+       if (len < sizeof(*ev)) {
+               fprintf(stderr,
+                       "Invalid connected event length (%u bytes)\n", len);
+               return -EINVAL;
+       }
+
+       eir_len = bt_get_le16(&ev->eir_len);
+       if (len != sizeof(*ev) + eir_len) {
+               fprintf(stderr, "Invalid connected event length "
+                       "(%u bytes, eir_len %u bytes)\n", len, eir_len);
+               return -EINVAL;
+       }
+
+       if (monitor) {
+               char addr[18];
+               ba2str(&ev->addr.bdaddr, addr);
+               printf("hci%u %s type %s connected eir_len %u\n", index, addr,
+                                       typestr(ev->addr.type), eir_len);
+       }
+
+       return 0;
+}
 
+static int mgmt_disconnected(int mgmt_sk, uint16_t index,
+                               struct mgmt_addr_info *ev, uint16_t len)
+{
        if (len != sizeof(*ev)) {
                fprintf(stderr,
-                       "Invalid %s event length (%u bytes)\n", ev_name, len);
+                       "Invalid disconnected event length (%u bytes)\n", 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);
+               printf("hci%u %s type %s disconnected\n", index, addr,
+                                                       typestr(ev->type));
        }
 
        return 0;
@@ -465,7 +394,7 @@ static int mgmt_auth_failed(int mgmt_sk, uint16_t index,
 
        if (monitor) {
                char addr[18];
-               ba2str(&ev->bdaddr, addr);
+               ba2str(&ev->addr.bdaddr, addr);
                printf("hci%u %s auth failed with status 0x%02x (%s)\n",
                        index, addr, ev->status, mgmt_errstr(ev->status));
        }
@@ -496,7 +425,7 @@ static void confirm_name_rsp(int mgmt_sk, uint16_t op, uint16_t id,
        struct mgmt_rp_confirm_name *rp = rsp;
        char addr[18];
 
-       if (status != 0) {
+       if (len == 0 && status != 0) {
                fprintf(stderr,
                        "hci%u confirm_name failed with status 0x%02x (%s)\n",
                                        id, status, mgmt_errstr(status));
@@ -510,12 +439,12 @@ static void confirm_name_rsp(int mgmt_sk, uint16_t op, uint16_t id,
                return;
        }
 
-       ba2str(&rp->bdaddr, addr);
+       ba2str(&rp->addr.bdaddr, addr);
 
-       if (rp->status != 0)
+       if (status != 0)
                fprintf(stderr,
                        "hci%u confirm_name for %s failed: 0x%02x (%s)\n",
-                       id, addr, rp->status, mgmt_errstr(status));
+                       id, addr, status, mgmt_errstr(status));
        else
                printf("hci%u confirm_name succeeded for %s\n", id, addr);
 }
@@ -523,28 +452,37 @@ static void confirm_name_rsp(int mgmt_sk, uint16_t op, uint16_t id,
 static int mgmt_device_found(int mgmt_sk, uint16_t index,
                                struct mgmt_ev_device_found *ev, uint16_t len)
 {
-       if (len != sizeof(*ev)) {
+       uint32_t flags;
+       uint16_t eir_len;
+
+       if (len < sizeof(*ev)) {
                fprintf(stderr,
-                       "Invalid device_found event length (%u bytes)\n", len);
+                       "Too short device_found length (%u bytes)\n", len);
+               return -EINVAL;
+       }
+
+       flags = btohs(ev->flags);
+
+       eir_len = bt_get_le16(&ev->eir_len);
+       if (len != sizeof(*ev) + eir_len) {
+               fprintf(stderr, "dev_found: expected %zu bytes, got %u bytes",
+                                               sizeof(*ev) + eir_len, 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");
+               printf("hci%u dev_found: %s type %s rssi %d "
+                       "flags 0x%04x eir_len %u\n", index, addr,
+                       typestr(ev->addr.type), ev->rssi, flags, eir_len);
        }
 
-       if (discovery && ev->confirm_name) {
+       if (discovery && (flags & MGMT_DEV_FOUND_CONFIRM_NAME)) {
                struct mgmt_cp_confirm_name cp;
 
                memset(&cp, 0, sizeof(cp));
-               bacpy(&cp.bdaddr, &ev->addr.bdaddr);
+               memcpy(&cp.addr, &ev->addr, sizeof(cp.addr));
                if (resolve_names)
                        cp.name_known = 0;
                else
@@ -558,24 +496,6 @@ static int mgmt_device_found(int mgmt_sk, uint16_t index,
        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)
 {
@@ -589,13 +509,14 @@ static void pin_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
        printf("hci%u PIN Reply successful\n", id);
 }
 
-static int mgmt_pin_reply(int mgmt_sk, uint16_t index, bdaddr_t *bdaddr,
+static int mgmt_pin_reply(int mgmt_sk, uint16_t index,
+                                               struct mgmt_addr_info *addr,
                                                const char *pin, size_t len)
 {
        struct mgmt_cp_pin_code_reply cp;
 
        memset(&cp, 0, sizeof(cp));
-       bacpy(&cp.bdaddr, bdaddr);
+       memcpy(&cp.addr, addr, sizeof(cp.addr));
        cp.pin_len = len;
        memcpy(cp.pin_code, pin, len);
 
@@ -616,12 +537,13 @@ static void pin_neg_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
        printf("hci%u PIN Negative Reply successful\n", id);
 }
 
-static int mgmt_pin_neg_reply(int mgmt_sk, uint16_t index, bdaddr_t *bdaddr)
+static int mgmt_pin_neg_reply(int mgmt_sk, uint16_t index,
+                                               struct mgmt_addr_info *addr)
 {
        struct mgmt_cp_pin_code_neg_reply cp;
 
        memset(&cp, 0, sizeof(cp));
-       bacpy(&cp.bdaddr, bdaddr);
+       memcpy(&cp.addr, addr, sizeof(cp.addr));
 
        return mgmt_send_cmd(mgmt_sk, MGMT_OP_PIN_CODE_NEG_REPLY, index,
                                        &cp, sizeof(cp), pin_neg_rsp, NULL);
@@ -642,7 +564,7 @@ static int mgmt_request_pin(int mgmt_sk, uint16_t index,
 
        if (monitor) {
                char addr[18];
-               ba2str(&ev->bdaddr, addr);
+               ba2str(&ev->addr.bdaddr, addr);
                printf("hci%u %s request PIN\n", index, addr);
        }
 
@@ -652,7 +574,7 @@ static int mgmt_request_pin(int mgmt_sk, uint16_t index,
        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);
+               return mgmt_pin_neg_reply(mgmt_sk, index, &ev->addr);
 
        pin_len = strlen(pin);
        if (pin[pin_len - 1] == '\n') {
@@ -660,7 +582,7 @@ static int mgmt_request_pin(int mgmt_sk, uint16_t index,
                pin_len--;
        }
 
-       return mgmt_pin_reply(mgmt_sk, index, &ev->bdaddr, pin, pin_len);
+       return mgmt_pin_reply(mgmt_sk, index, &ev->addr, pin, pin_len);
 }
 
 static void confirm_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
@@ -681,7 +603,7 @@ 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);
+       bacpy(&cp.addr.bdaddr, bdaddr);
 
        return mgmt_send_cmd(mgmt_sk, MGMT_OP_USER_CONFIRM_REPLY, index,
                                        &cp, sizeof(cp), confirm_rsp, NULL);
@@ -707,7 +629,7 @@ static int mgmt_confirm_neg_reply(int mgmt_sk, uint16_t index,
        struct mgmt_cp_user_confirm_reply cp;
 
        memset(&cp, 0, sizeof(cp));
-       bacpy(&cp.bdaddr, bdaddr);
+       bacpy(&cp.addr.bdaddr, bdaddr);
 
        return mgmt_send_cmd(mgmt_sk, MGMT_OP_USER_CONFIRM_NEG_REPLY, index,
                                &cp, sizeof(cp), confirm_neg_rsp, NULL);
@@ -729,7 +651,7 @@ static int mgmt_user_confirm(int mgmt_sk, uint16_t index,
                return -EINVAL;
        }
 
-       ba2str(&ev->bdaddr, addr);
+       ba2str(&ev->addr.bdaddr, addr);
        val = bt_get_le32(&ev->value);
 
        if (monitor)
@@ -746,7 +668,7 @@ static int mgmt_user_confirm(int mgmt_sk, uint16_t index,
        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);
+               return mgmt_confirm_neg_reply(mgmt_sk, index, &ev->addr.bdaddr);
 
        rsp_len = strlen(rsp);
        if (rsp[rsp_len - 1] == '\n') {
@@ -755,9 +677,9 @@ static int mgmt_user_confirm(int mgmt_sk, uint16_t index,
        }
 
        if (rsp[0] == 'y' || rsp[0] == 'Y')
-               return mgmt_confirm_reply(mgmt_sk, index, &ev->bdaddr);
+               return mgmt_confirm_reply(mgmt_sk, index, &ev->addr.bdaddr);
        else
-               return mgmt_confirm_neg_reply(mgmt_sk, index, &ev->bdaddr);
+               return mgmt_confirm_neg_reply(mgmt_sk, index, &ev->addr.bdaddr);
 }
 
 static int mgmt_handle_event(int mgmt_sk, uint16_t ev, uint16_t index,
@@ -784,9 +706,9 @@ static int mgmt_handle_event(int mgmt_sk, uint16_t ev, uint16_t index,
        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);
+               return mgmt_connected(mgmt_sk, index, data, len);
        case MGMT_EV_DEVICE_DISCONNECTED:
-               return mgmt_connected(mgmt_sk, index, false, data, len);
+               return mgmt_disconnected(mgmt_sk, index, data, len);
        case MGMT_EV_CONNECT_FAILED:
                return mgmt_conn_failed(mgmt_sk, index, data, len);
        case MGMT_EV_AUTH_FAILED:
@@ -795,8 +717,6 @@ static int mgmt_handle_event(int mgmt_sk, uint16_t ev, uint16_t index,
                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:
@@ -850,6 +770,94 @@ static void cmd_monitor(int mgmt_sk, uint16_t index, int argc, char **argv)
        monitor = true;
 }
 
+static void version_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_version *rp = rsp;
+
+       if (status != 0) {
+               fprintf(stderr, "Reading mgmt version failed with status"
+                       " 0x%02x (%s)\n", status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       if (len < sizeof(*rp)) {
+               fprintf(stderr, "Too small version reply (%u bytes)\n", len);
+               exit(EXIT_FAILURE);
+       }
+
+       printf("MGMT Version %u, revision %u\n", rp->version,
+                                               bt_get_le16(&rp->revision));
+
+       exit(EXIT_SUCCESS);
+}
+
+static void cmd_version(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE,
+                                       NULL, 0, version_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send read_version cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void commands_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_commands *rp = rsp;
+       uint16_t num_commands, num_events, *opcode;
+       size_t expected_len;
+       int i;
+
+       if (status != 0) {
+               fprintf(stderr, "Reading supported commands failed with status"
+                       " 0x%02x (%s)\n", status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       if (len < sizeof(*rp)) {
+               fprintf(stderr, "Too small commands reply (%u bytes)\n", len);
+               exit(EXIT_FAILURE);
+       }
+
+       num_commands = bt_get_le16(&rp->num_commands);
+       num_events = bt_get_le16(&rp->num_events);
+
+       expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) +
+                                               num_events * sizeof(uint16_t);
+
+       if (len < expected_len) {
+               fprintf(stderr, "Too small commands reply (%u != %zu)\n",
+                                                       len, expected_len);
+               exit(EXIT_FAILURE);
+       }
+
+       opcode = rp->opcodes;
+
+       printf("%u commands:\n", num_commands);
+       for (i = 0; i < num_commands; i++) {
+               uint16_t op = bt_get_le16(opcode++);
+               printf("\t%s (0x%04x)\n", mgmt_opstr(op), op);
+       }
+
+       printf("%u events:\n", num_events);
+       for (i = 0; i < num_events; i++) {
+               uint16_t ev = bt_get_le16(opcode++);
+               printf("\t%s (0x%04x)\n", mgmt_evstr(ev), ev);
+       }
+
+       exit(EXIT_SUCCESS);
+}
+
+static void cmd_commands(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE,
+                                       NULL, 0, commands_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send read_commands cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
 static void info_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
                                void *rsp, uint16_t len, void *user_data)
 {
@@ -1063,17 +1071,45 @@ 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 cmd_linksec(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       cmd_setting(mgmt_sk, index, MGMT_OP_SET_LINK_SECURITY, argc, argv);
+}
+
+static void cmd_ssp(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       cmd_setting(mgmt_sk, index, MGMT_OP_SET_SSP, argc, argv);
+}
+
+static void cmd_hs(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       cmd_setting(mgmt_sk, index, MGMT_OP_SET_HS, argc, argv);
+}
+
+static void cmd_le(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       cmd_setting(mgmt_sk, index, MGMT_OP_SET_LE, 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));
+       struct mgmt_ev_class_of_dev_changed *rp = rsp;
+
+       if (len == 0 && status != 0) {
+               fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
+                               mgmt_opstr(op), status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       if (len != sizeof(*rp)) {
+               fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len);
                exit(EXIT_FAILURE);
        }
 
-       printf("hci%u class changed\n", id);
+       printf("%s succeeded. Class 0x%02x%02x%02x\n", mgmt_opstr(op),
+               rp->class_of_dev[2], rp->class_of_dev[1], rp->class_of_dev[0]);
+
        exit(EXIT_SUCCESS);
 }
 
@@ -1106,7 +1142,7 @@ static void disconnect_rsp(int mgmt_sk, uint16_t op, uint16_t id,
        struct mgmt_rp_disconnect *rp = rsp;
        char addr[18];
 
-       if (status != 0) {
+       if (len == 0 && status != 0) {
                fprintf(stderr, "Disconnect failed with status 0x%02x (%s)\n",
                                                status, mgmt_errstr(status));
                exit(EXIT_FAILURE);
@@ -1118,15 +1154,15 @@ static void disconnect_rsp(int mgmt_sk, uint16_t op, uint16_t id,
                exit(EXIT_FAILURE);
        }
 
-       ba2str(&rp->bdaddr, addr);
+       ba2str(&rp->addr.bdaddr, addr);
 
-       if (rp->status == 0) {
+       if (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));
+                               addr, status, mgmt_errstr(status));
                exit(EXIT_FAILURE);
        }
 }
@@ -1140,7 +1176,7 @@ static void cmd_disconnect(int mgmt_sk, uint16_t index, int argc, char **argv)
                exit(EXIT_FAILURE);
        }
 
-       str2ba(argv[1], &cp.bdaddr);
+       str2ba(argv[1], &cp.addr.bdaddr);
 
        if (index == MGMT_INDEX_NONE)
                index = 0;
@@ -1208,18 +1244,55 @@ static void find_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
        discovery = true;
 }
 
+static void find_usage(void)
+{
+       printf("Usage: btmgmt find [-l|-b]>\n");
+}
+
+static struct option find_options[] = {
+       { "help",       0, 0, 'h' },
+       { "le-only",    1, 0, 'l' },
+       { "bredr-only", 1, 0, 'b' },
+       { 0, 0, 0, 0 }
+};
+
 static void cmd_find(int mgmt_sk, uint16_t index, int argc, char **argv)
 {
        struct mgmt_cp_start_discovery cp;
        uint8_t type;
+       int opt;
 
        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);
+       hci_set_bit(BDADDR_BREDR, &type);
+       hci_set_bit(BDADDR_LE_PUBLIC, &type);
+       hci_set_bit(BDADDR_LE_RANDOM, &type);
+
+       while ((opt = getopt_long(argc, argv, "+lbh", find_options,
+                                                               NULL)) != -1) {
+               switch (opt) {
+               case 'l':
+                       hci_clear_bit(BDADDR_BREDR, &type);
+                       hci_set_bit(BDADDR_LE_PUBLIC, &type);
+                       hci_set_bit(BDADDR_LE_RANDOM, &type);
+                       break;
+               case 'b':
+                       hci_set_bit(BDADDR_BREDR, &type);
+                       hci_clear_bit(BDADDR_LE_PUBLIC, &type);
+                       hci_clear_bit(BDADDR_LE_RANDOM, &type);
+                       break;
+               case 'h':
+               default:
+                       find_usage();
+                       exit(EXIT_SUCCESS);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+       optind = 0;
 
        memset(&cp, 0, sizeof(cp));
        cp.type = type;
@@ -1248,7 +1321,7 @@ 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]);
+               printf("Usage: btmgmt %s <name> [shortname]\n", argv[0]);
                exit(EXIT_FAILURE);
        }
 
@@ -1257,6 +1330,9 @@ static void cmd_name(int mgmt_sk, uint16_t index, int argc, char **argv)
 
        memset(&cp, 0, sizeof(cp));
        strncpy((char *) cp.name, argv[1], HCI_MAX_NAME_LENGTH);
+       if (argc > 2)
+               strncpy((char *) cp.short_name, argv[2],
+                                       MGMT_MAX_SHORT_NAME_LENGTH);
 
        if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_LOCAL_NAME, index,
                                        &cp, sizeof(cp), name_rsp, NULL) < 0) {
@@ -1271,7 +1347,7 @@ static void pair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
        struct mgmt_rp_pair_device *rp = rsp;
        char addr[18];
 
-       if (status != 0) {
+       if (len == 0 && status != 0) {
                fprintf(stderr, "Pairing failed with status 0x%02x (%s)\n",
                                                status, mgmt_errstr(status));
                exit(EXIT_FAILURE);
@@ -1284,11 +1360,11 @@ static void pair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
 
        ba2str(&rp->addr.bdaddr, addr);
 
-       if (rp->status != 0) {
+       if (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));
+                       addr, typestr(rp->addr.type), status,
+                       mgmt_errstr(status));
                exit(EXIT_FAILURE);
        }
 
@@ -1313,7 +1389,7 @@ 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;
+       uint8_t type = BDADDR_BREDR;
        int opt;
 
        while ((opt = getopt_long(argc, argv, "+c:t:h", pair_options,
@@ -1356,40 +1432,40 @@ static void cmd_pair(int mgmt_sk, uint16_t index, int argc, char **argv)
        }
 }
 
-static void remove_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+static void unpair_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;
+       struct mgmt_rp_unpair_device *rp = rsp;
        char addr[18];
 
-       if (status != 0) {
-               fprintf(stderr, "Remove keys failed with status 0x%02x (%s)\n",
+       if (len == 0 && status != 0) {
+               fprintf(stderr, "Unpair device failed. 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);
+               fprintf(stderr, "Unexpected unpair_device_rsp len %u\n", len);
                exit(EXIT_FAILURE);
        }
 
-       ba2str(&rp->bdaddr, addr);
+       ba2str(&rp->addr.bdaddr, addr);
 
-       if (rp->status != 0) {
+       if (status != 0) {
                fprintf(stderr,
-                       "Removing keys for %s failed. status 0x%02x (%s)\n",
-                               addr, rp->status, mgmt_errstr(rp->status));
+                       "Unpairing %s failed. status 0x%02x (%s)\n",
+                               addr, status, mgmt_errstr(status));
                exit(EXIT_FAILURE);
        }
 
-       printf("Removed keys for %s\n", addr);
+       printf("%s unpaired\n", addr);
 
        exit(EXIT_SUCCESS);
 }
 
-static void cmd_remove(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_unpair(int mgmt_sk, uint16_t index, int argc, char **argv)
 {
-       struct mgmt_cp_remove_keys cp;
+       struct mgmt_cp_unpair_device cp;
 
        if (argc < 2) {
                printf("Usage: btmgmt %s <remote address>\n", argv[0]);
@@ -1400,12 +1476,12 @@ static void cmd_remove(int mgmt_sk, uint16_t index, int argc, char **argv)
                index = 0;
 
        memset(&cp, 0, sizeof(cp));
-       str2ba(argv[1], &cp.bdaddr);
+       str2ba(argv[1], &cp.addr.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");
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_UNPAIR_DEVICE, index, &cp,
+                                       sizeof(cp), unpair_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send unpair_device cmd\n");
                exit(EXIT_FAILURE);
        }
 }
@@ -1440,25 +1516,316 @@ static void cmd_keys(int mgmt_sk, uint16_t index, int argc, char **argv)
        }
 }
 
+static void block_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
+                               void *rsp, uint16_t len, void *user_data)
+{
+       struct mgmt_addr_info *rp = rsp;
+       char addr[18];
+
+       if (len == 0 && status != 0) {
+               fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
+                               mgmt_opstr(op), status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       if (len != sizeof(*rp)) {
+               fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len);
+               exit(EXIT_FAILURE);
+       }
+
+       ba2str(&rp->bdaddr, addr);
+
+       if (status != 0) {
+               fprintf(stderr, "%s %s (%s) failed. status 0x%02x (%s)\n",
+                               mgmt_opstr(op), addr, typestr(rp->type),
+                               status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       printf("%s %s succeeded\n", mgmt_opstr(op), addr);
+
+       exit(EXIT_SUCCESS);
+}
+
+static void block_usage(void)
+{
+       printf("Usage: btmgmt block [-t type] <remote address>\n");
+}
+
+static struct option block_options[] = {
+       { "help",       0, 0, 'h' },
+       { "type",       1, 0, 't' },
+       { 0, 0, 0, 0 }
+};
+
+static void cmd_block(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       struct mgmt_cp_block_device cp;
+       uint8_t type = BDADDR_BREDR;
+       int opt;
+
+       while ((opt = getopt_long(argc, argv, "+t:h", block_options,
+                                                       NULL)) != -1) {
+               switch (opt) {
+               case 't':
+                       type = strtol(optarg, NULL, 0);
+                       break;
+               case 'h':
+               default:
+                       block_usage();
+                       exit(EXIT_SUCCESS);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+       optind = 0;
+
+       if (argc < 1) {
+               block_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;
+
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_BLOCK_DEVICE, index,
+                               &cp, sizeof(cp), block_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send block_device cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void unblock_usage(void)
+{
+       printf("Usage: btmgmt unblock [-t type] <remote address>\n");
+}
+
+static void cmd_unblock(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       struct mgmt_cp_unblock_device cp;
+       uint8_t type = BDADDR_BREDR;
+       int opt;
+
+       while ((opt = getopt_long(argc, argv, "+t:h", block_options,
+                                                       NULL)) != -1) {
+               switch (opt) {
+               case 't':
+                       type = strtol(optarg, NULL, 0);
+                       break;
+               case 'h':
+               default:
+                       unblock_usage();
+                       exit(EXIT_SUCCESS);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+       optind = 0;
+
+       if (argc < 1) {
+               unblock_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;
+
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_UNBLOCK_DEVICE, index,
+                               &cp, sizeof(cp), block_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send unblock_device cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid)
+{
+       if (uuid->type == SDP_UUID16)
+               sdp_uuid16_to_uuid128(uuid128, uuid);
+       else if (uuid->type == SDP_UUID32)
+               sdp_uuid32_to_uuid128(uuid128, uuid);
+       else
+               memcpy(uuid128, uuid, sizeof(*uuid));
+}
+
+static void cmd_add_uuid(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       struct mgmt_cp_add_uuid cp;
+       uint128_t uint128;
+       uuid_t uuid, uuid128;
+
+       if (argc < 3) {
+               printf("UUID and service hint needed\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       if (bt_string2uuid(&uuid, argv[1]) < 0) {
+               printf("Invalid UUID: %s\n", argv[1]);
+               exit(EXIT_FAILURE);
+       }
+
+       memset(&cp, 0, sizeof(cp));
+
+       uuid_to_uuid128(&uuid128, &uuid);
+       ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
+       htob128(&uint128, (uint128_t *) cp.uuid);
+
+       cp.svc_hint = atoi(argv[2]);
+
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_ADD_UUID, index,
+                               &cp, sizeof(cp), class_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send add_uuid cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void cmd_remove_uuid(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       struct mgmt_cp_remove_uuid cp;
+       uint128_t uint128;
+       uuid_t uuid, uuid128;
+
+       if (argc < 2) {
+               printf("UUID needed\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       if (bt_string2uuid(&uuid, argv[1]) < 0) {
+               printf("Invalid UUID: %s\n", argv[1]);
+               exit(EXIT_FAILURE);
+       }
+
+       memset(&cp, 0, sizeof(cp));
+
+       uuid_to_uuid128(&uuid128, &uuid);
+       ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
+       htob128(&uint128, (uint128_t *) cp.uuid);
+
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_REMOVE_UUID, index,
+                               &cp, sizeof(cp), class_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send remove_uuid cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void cmd_clr_uuids(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       char *uuid_any = "00000000-0000-0000-0000-000000000000";
+       char *rm_argv[] = { "rm-uuid", uuid_any, NULL };
+
+       cmd_remove_uuid(mgmt_sk, index, 2, rm_argv);
+}
+
+static void did_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, "Set Device ID failed with status 0x%02x (%s)\n",
+                                               status, mgmt_errstr(status));
+               exit(EXIT_FAILURE);
+       }
+
+       printf("Device ID successfully set\n");
+
+       exit(EXIT_SUCCESS);
+}
+
+static void did_usage(void)
+{
+       printf("Usage: btmgmt did <source>:<vendor>:<product>:<version>\n");
+       printf("       possible source values: bluetooth, usb\n");
+}
+
+static void cmd_did(int mgmt_sk, uint16_t index, int argc, char **argv)
+{
+       struct mgmt_cp_set_device_id cp;
+       uint16_t vendor, product, version , source;
+       int result;
+
+       if (argc < 2) {
+               did_usage();
+               exit(EXIT_FAILURE);
+       }
+
+       result = sscanf(argv[1], "bluetooth:%4hx:%4hx:%4hx", &vendor, &product,
+                                                               &version);
+       if (result == 3) {
+               source = 0x0001;
+               goto done;
+       }
+
+       result = sscanf(argv[1], "usb:%4hx:%4hx:%4hx", &vendor, &product,
+                                                               &version);
+       if (result == 3) {
+               source = 0x0002;
+               goto done;
+       }
+
+       did_usage();
+       exit(EXIT_FAILURE);
+
+done:
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       cp.source = htobs(source);
+       cp.vendor = htobs(vendor);
+       cp.product = htobs(product);
+       cp.version = htobs(version);
+
+       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DEVICE_ID, index,
+                               &cp, sizeof(cp), did_rsp, NULL) < 0) {
+               fprintf(stderr, "Unable to send set_dev_class 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"                },
+       { "version",    cmd_version,    "Get the MGMT Version"          },
+       { "commands",   cmd_commands,   "List supported commands"       },
        { "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"         },
+       { "linksec",    cmd_linksec,    "Toggle link level security"    },
+       { "ssp",        cmd_ssp,        "Toggle SSP mode"               },
+       { "hs",         cmd_hs,         "Toggle HS Support"             },
+       { "le",         cmd_le,         "Toggle LE Support"             },
        { "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)"     },
+       { "unpair",     cmd_unpair,     "Unpair device"                 },
        { "keys",       cmd_keys,       "Load Keys"                     },
+       { "block",      cmd_block,      "Block Device"                  },
+       { "unblock",    cmd_unblock,    "Unblock Device"                },
+       { "add-uuid",   cmd_add_uuid,   "Add UUID"                      },
+       { "rm-uuid",    cmd_add_uuid,   "Remove UUID"                   },
+       { "clr-uuids",  cmd_clr_uuids,  "Clear UUIDs",                  },
+       { "did",        cmd_did,        "Set Device ID",                },
        { NULL, NULL, 0 }
 };
 
diff --git a/monitor/bt.h b/monitor/bt.h
new file mode 100644 (file)
index 0000000..3a6735b
--- /dev/null
@@ -0,0 +1,551 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+
+#define BT_H4_CMD_PKT  0x01
+#define BT_H4_ACL_PKT  0x02
+#define BT_H4_SCO_PKT  0x03
+#define BT_H4_EVT_PKT  0x04
+
+struct bt_hci_cmd_hdr {
+       uint16_t opcode;
+       uint8_t  plen;
+} __attribute__ ((packed));
+
+struct bt_hci_evt_hdr {
+       uint8_t  evt;
+       uint8_t  plen;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_NOP                         0x0000
+
+#define BT_HCI_CMD_INQUIRY                     0x0401
+struct bt_hci_cmd_inquiry {
+       uint8_t  lap[3];
+       uint8_t  length;
+       uint8_t  num_rsp;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_INQUIRY_CANCEL              0x0402
+
+#define BT_HCI_CMD_CREATE_CONN                 0x0405
+struct bt_hci_cmd_create_conn {
+       uint8_t  bdaddr[6];
+       uint16_t pkt_type;
+       uint8_t  pscan_rep_mode;
+       uint8_t  pscan_mode;
+       uint16_t clock_offset;
+       uint8_t  role_switch;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_DISCONNECT                  0x0406
+struct bt_hci_cmd_disconnect {
+       uint16_t handle;
+       uint8_t  reason;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_ADD_SCO_CONN                        0x0407
+struct bt_hci_cmd_add_sco_conn {
+       uint16_t handle;
+       uint16_t pkt_type;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_CREATE_CONN_CANCEL          0x0408
+struct bt_hci_cmd_create_conn_cancel {
+       uint8_t  bdaddr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_ACCEPT_CONN_REQUEST         0x0409
+struct bt_hci_cmd_accept_conn_request {
+       uint8_t  bdaddr[6];
+       uint8_t  role;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_REJECT_CONN_REQUEST         0x040a
+struct bt_hci_cmd_reject_conn_request {
+       uint8_t  bdaddr[6];
+       uint8_t  reason;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_CHANGE_CONN_PKT_TYPE                0x040f
+struct bt_hci_cmd_change_conn_pkt_type {
+       uint16_t handle;
+       uint16_t pkt_type;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_REMOTE_NAME_REQUEST         0x0419
+struct bt_hci_cmd_remote_name_request {
+       uint8_t  bdaddr[6];
+       uint8_t  pscan_rep_mode;
+       uint8_t  pscan_mode;
+       uint16_t clock_offset;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_REMOTE_NAME_REQUEST_CANCEL  0x041a
+struct bt_hci_cmd_remote_name_request_cancel {
+       uint8_t  bdaddr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_REMOTE_FEATURES                0x041b
+struct bt_hci_cmd_read_remote_features {
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_REMOTE_EXT_FEATURES    0x041c
+struct bt_hci_cmd_read_remote_ext_features {
+       uint16_t handle;
+       uint8_t  page;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_REMOTE_VERSION         0x041d
+struct bt_hci_cmd_read_remote_version {
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_DEFAULT_LINK_POLICY    0x080e
+struct bt_hci_rsp_read_default_link_policy {
+       uint8_t  status;
+       uint16_t policy;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_DEFAULT_LINK_POLICY   0x080f
+struct bt_hci_cmd_write_default_link_policy {
+       uint16_t policy;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_SET_EVENT_MASK              0x0c01
+struct bt_hci_cmd_set_event_mask {
+       uint8_t  mask[8];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_RESET                       0x0c03
+
+#define BT_HCI_CMD_SET_EVENT_FILTER            0x0c05
+struct bt_hci_cmd_set_event_filter {
+       uint8_t  type;
+       uint8_t  cond_type;
+       uint8_t  cond[0];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_STORED_LINK_KEY                0x0c0d
+struct bt_hci_cmd_read_stored_link_key {
+       uint8_t  bdaddr[6];
+       uint8_t  read_all;
+} __attribute__ ((packed));
+struct bt_hci_rsp_read_stored_link_key {
+       uint8_t  status;
+       uint16_t max_num_keys;
+       uint16_t num_keys;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_STORED_LINK_KEY       0x0c11
+struct bt_hci_cmd_write_stored_link_key {
+       uint8_t  num_keys;
+} __attribute__ ((packed));
+struct bt_hci_rsp_write_stored_link_key {
+       uint8_t  status;
+       uint8_t  num_keys;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_DELETE_STORED_LINK_KEY      0x0c12
+struct bt_hci_cmd_delete_stored_link_key {
+       uint8_t  bdaddr[6];
+       uint8_t  delete_all;
+} __attribute__ ((packed));
+struct bt_hci_rsp_delete_stored_link_key {
+       uint8_t  status;
+       uint16_t num_keys;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_LOCAL_NAME            0x0c13
+struct bt_hci_cmd_write_local_name {
+       uint8_t  name[248];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_LOCAL_NAME             0x0c14
+struct bt_hci_rsp_read_local_name {
+       uint8_t  status;
+       uint8_t  name[248];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_CONN_ACCEPT_TIMEOUT    0x0c15
+struct bt_hci_rsp_read_conn_accept_timeout {
+       uint8_t  status;
+       uint16_t timeout;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_CONN_ACCEPT_TIMEOUT   0x0c16
+struct bt_hci_cmd_write_conn_accept_timeout {
+       uint16_t timeout;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_PAGE_TIMEOUT           0x0c17
+struct bt_hci_rsp_read_page_timeout {
+       uint8_t  status;
+       uint16_t timeout;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_PAGE_TIMEOUT          0x0c18
+struct bt_hci_cmd_write_page_timeout {
+       uint16_t timeout;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_SCAN_ENABLE            0x0c19
+struct bt_hci_rsp_read_scan_enable {
+       uint8_t  status;
+       uint8_t  enable;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_SCAN_ENABLE           0x0c1a
+struct bt_hci_cmd_write_scan_enable {
+       uint8_t  enable;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_AUTH_ENABLE            0x0c1f
+struct bt_hci_rsp_read_auth_enable {
+       uint8_t  status;
+       uint8_t  enable;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_AUTH_ENABLE           0x0c20
+struct bt_hci_cmd_write_auth_enable {
+       uint8_t  enable;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_CLASS_OF_DEV           0x0c23
+struct bt_hci_rsp_read_class_of_dev {
+       uint8_t  status;
+       uint8_t  dev_class[3];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_CLASS_OF_DEV          0x0c24
+struct bt_hci_cmd_write_class_of_dev {
+       uint8_t  dev_class[3];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_VOICE_SETTING          0x0c25
+struct bt_hci_rsp_read_voice_setting {
+       uint8_t  status;
+       uint16_t setting;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_VOICE_SETTING         0x0c26
+struct bt_hci_cmd_write_voice_setting {
+       uint16_t setting;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_INQUIRY_MODE           0x0c44
+struct bt_hci_rsp_read_inquiry_mode {
+       uint8_t  status;
+       uint8_t  mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_INQUIRY_MODE          0x0c45
+struct bt_hci_cmd_write_inquiry_mode {
+       uint8_t  mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_AFH_ASSESS_MODE                0x0c48
+struct bt_hci_rsp_read_afh_assess_mode {
+       uint8_t  status;
+       uint8_t  mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_AFH_ASSESS_MODE       0x0c49
+struct bt_hci_cmd_write_afh_assess_mode {
+       uint8_t  mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_EXT_INQUIRY_RSP                0x0c51
+struct bt_hci_rsp_read_ext_inquiry_rsp {
+       uint8_t  status;
+       uint8_t  fec;
+       uint8_t  data[240];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_EXT_INQUIRY_RSP       0x0c52
+struct bt_hci_cmd_write_ext_inquiry_rsp {
+       uint8_t  fec;
+       uint8_t  data[240];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_SIMPLE_PAIRING_MODE    0x0c55
+struct bt_hci_rsp_read_simple_pairing_mode {
+       uint8_t  status;
+       uint8_t  mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_SIMPLE_PAIRING_MODE   0x0c56
+struct bt_hci_cmd_write_simple_pairing_mode {
+       uint8_t  mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_INQUIRY_RSP_TX_POWER   0x0c58
+struct bt_hci_rsp_read_inquiry_rsp_tx_power {
+       uint8_t  status;
+       int8_t   level;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_LE_HOST_SUPPORTED      0x0c6c
+struct bt_hci_rsp_read_le_host_supported {
+       uint8_t  status;
+       uint8_t  supported;
+       uint8_t  simultaneous;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_LE_HOST_SUPPORTED     0x0c6d
+struct bt_hci_cmd_write_le_host_supported {
+       uint8_t  supported;
+       uint8_t  simultaneous;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_LOCAL_VERSION          0x1001
+struct bt_hci_rsp_read_local_version {
+       uint8_t  status;
+       uint8_t  hci_ver;
+       uint16_t hci_rev;
+       uint8_t  lmp_ver;
+       uint16_t manufacturer;
+       uint16_t lmp_subver;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_LOCAL_COMMANDS         0x1002
+struct bt_hci_rsp_read_local_commands {
+       uint8_t  status;
+       uint8_t  commands[64];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_LOCAL_FEATURES         0x1003
+struct bt_hci_rsp_read_local_features {
+       uint8_t  status;
+       uint8_t  features[8];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_LOCAL_EXT_FEATURES     0x1004
+struct bt_hci_cmd_read_local_ext_features {
+       uint8_t  page;
+} __attribute__ ((packed));
+struct bt_hci_rsp_read_local_ext_features {
+       uint8_t  status;
+       uint8_t  page;
+       uint8_t  max_page;
+       uint8_t  features[8];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_BUFFER_SIZE            0x1005
+struct bt_hci_rsp_read_buffer_size {
+       uint8_t  status;
+       uint16_t acl_mtu;
+       uint8_t  sco_mtu;
+       uint16_t acl_max_pkt;
+       uint16_t sco_max_pkt;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_COUNTRY_CODE           0x1007
+struct bt_hci_rsp_read_country_code {
+       uint8_t  status;
+       uint8_t  code;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_BD_ADDR                        0x1009
+struct bt_hci_rsp_read_bd_addr {
+       uint8_t  status;
+       uint8_t  bdaddr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_DATA_BLOCK_SIZE                0x100a
+struct bt_hci_rsp_read_data_block_size {
+       uint8_t  status;
+       uint16_t max_acl_len;
+       uint16_t block_len;
+       uint16_t num_blocks;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_SET_EVENT_MASK           0x2001
+struct bt_hci_cmd_le_set_event_mask {
+       uint8_t  mask[8];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_READ_BUFFER_SIZE         0x2002
+struct bt_hci_rsp_le_read_buffer_size {
+       uint8_t  status;
+        uint16_t le_mtu;
+        uint8_t  le_max_pkt;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_READ_LOCAL_FEATURES      0x2003
+struct bt_hci_rsp_le_read_local_features {
+       uint8_t  status;
+       uint8_t  features[8];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_SET_SCAN_PARAMETERS      0x200b
+struct bt_hci_cmd_le_set_scan_parameters {
+       uint8_t  type;
+       uint16_t interval;
+       uint16_t window;
+       uint8_t  own_addr_type;
+       uint8_t  filter_policy;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_SET_SCAN_ENABLE          0x200c
+struct bt_hci_cmd_le_set_scan_enable {
+       uint8_t  enable;
+       uint8_t  filter_dup;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_READ_SUPPORTED_STATES    0x201c
+struct bt_hci_rsp_le_read_supported_states {
+       uint8_t  status;
+       uint8_t  states[8];
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_INQUIRY_COMPLETE            0x01
+struct bt_hci_evt_inquiry_complete {
+       uint8_t  status;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_INQUIRY_RESULT              0x02
+struct bt_hci_evt_inquiry_result {
+       uint8_t  num_resp;
+       uint8_t  bdaddr[6];
+       uint8_t  pscan_rep_mode;
+       uint8_t  pscan_period_mode;
+       uint8_t  pscan_mode;
+       uint8_t  dev_class[3];
+       uint8_t  clock_offset;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_CONN_COMPLETE               0x03
+struct bt_hci_evt_conn_complete {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  bdaddr[6];
+       uint8_t  link_type;
+       uint8_t  encr_mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_CONN_REQUEST                        0x04
+struct bt_hci_evt_conn_request {
+       uint8_t  bdaddr[6];
+       uint8_t  dev_class[3];
+       uint8_t  link_type;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_DISCONNECT_COMPLETE         0x05
+struct bt_hci_evt_disconnect_complete {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  reason;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_REMOTE_NAME_REQUEST_COMPLETE        0x07
+struct bt_hci_evt_remote_name_req_complete {
+       uint8_t  status;
+       uint8_t  bdaddr[6];
+       uint8_t  name[248];
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_REMOTE_FEATURES_COMPLETE    0x0b
+struct bt_hci_evt_remote_features_complete {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  features[8];
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_REMOTE_VERSION_COMPLETE     0x0c
+struct bt_hci_evt_remote_version_complete {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  lmp_ver;
+       uint16_t manufacturer;
+       uint16_t lmp_subver;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_CMD_COMPLETE                        0x0e
+struct bt_hci_evt_cmd_complete {
+       uint8_t  ncmd;
+       uint16_t opcode;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_CMD_STATUS                  0x0f
+struct bt_hci_evt_cmd_status {
+       uint8_t  status;
+       uint8_t  ncmd;
+       uint16_t opcode;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_NUM_COMPLETED_PACKETS       0x13
+struct bt_hci_evt_num_completed_packets {
+       uint8_t  num_handles;
+       uint16_t handle;
+       uint16_t count;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_CONN_PKT_TYPE_CHANGED       0x1d
+struct bt_hci_evt_conn_pkt_type_changed {
+       uint8_t  status;
+       uint16_t handle;
+       uint16_t pkt_type;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI    0x22
+struct bt_hci_evt_inquiry_result_with_rssi {
+       uint8_t  num_resp;
+       uint8_t  bdaddr[6];
+       uint8_t  pscan_rep_mode;
+       uint8_t  pscan_period_mode;
+       uint8_t  dev_class[3];
+       uint16_t clock_offset;
+       int8_t   rssi;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_REMOTE_EXT_FEATURES_COMPLETE        0x23
+struct bt_hci_evt_remote_ext_features_complete {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  page;
+       uint8_t  max_page;
+       uint8_t  features[8];
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_EXT_INQUIRY_RESULT          0x2f
+struct bt_hci_evt_ext_inquiry_result {
+       uint8_t  num_resp;
+       uint8_t  bdaddr[6];
+       uint8_t  pscan_rep_mode;
+       uint8_t  pscan_period_mode;
+       uint8_t  dev_class[3];
+       uint16_t clock_offset;
+       int8_t   rssi;
+       uint8_t  data[240];
+} __attribute__ ((packed));
+
+#define BT_HCI_ERR_SUCCESS                     0x00
+#define BT_HCI_ERR_UNKNOWN_COMMAND             0x01
+#define BT_HCI_ERR_UNKNOWN_CONN_ID             0x02
+#define BT_HCI_ERR_HARDWARE_FAILURE            0x03
+#define BT_HCI_ERR_PAGE_TIMEOUT                        0x04
+#define BT_HCI_ERR_INVALID_PARAMETERS          0x12
diff --git a/monitor/btsnoop.c b/monitor/btsnoop.c
new file mode 100644 (file)
index 0000000..09c5e25
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+
+#include "btsnoop.h"
+
+static inline uint64_t ntoh64(uint64_t n)
+{
+       uint64_t h;
+       uint64_t tmp = ntohl(n & 0x00000000ffffffff);
+
+       h = ntohl(n >> 32);
+       h |= tmp << 32;
+
+       return h;
+}
+
+#define hton64(x)     ntoh64(x)
+
+struct btsnoop_hdr {
+       uint8_t         id[8];          /* Identification Pattern */
+       uint32_t        version;        /* Version Number = 1 */
+       uint32_t        type;           /* Datalink Type */
+} __attribute__ ((packed));
+#define BTSNOOP_HDR_SIZE (sizeof(struct btsnoop_hdr))
+
+struct btsnoop_pkt {
+       uint32_t        size;           /* Original Length */
+       uint32_t        len;            /* Included Length */
+       uint32_t        flags;          /* Packet Flags */
+       uint32_t        drops;          /* Cumulative Drops */
+       uint64_t        ts;             /* Timestamp microseconds */
+       uint8_t         data[0];        /* Packet Data */
+} __attribute__ ((packed));
+#define BTSNOOP_PKT_SIZE (sizeof(struct btsnoop_pkt))
+
+static const uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e,
+                                     0x6f, 0x6f, 0x70, 0x00 };
+
+static const uint32_t btsnoop_version = 1;
+static const uint32_t btsnoop_type = 1001;
+
+static int btsnoop_fd = -1;
+static uint16_t btsnoop_index = 0xffff;
+
+void btsnoop_open(const char *path)
+{
+       if (btsnoop_fd >= 0)
+               return;
+
+       btsnoop_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC,
+                               S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+}
+
+void btsnoop_write(struct timeval *tv, uint16_t index, uint32_t flags,
+                                       const void *data, uint16_t size)
+{
+       struct btsnoop_hdr hdr;
+       struct btsnoop_pkt pkt;
+       uint64_t ts;
+       ssize_t written;
+
+       if (!tv)
+               return;
+
+       if (btsnoop_fd < 0)
+               return;
+
+       if (btsnoop_index == 0xffff) {
+               memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
+               hdr.version = htonl(btsnoop_version);
+               hdr.type = htonl(btsnoop_type);
+
+               written = write(btsnoop_fd, &hdr, BTSNOOP_HDR_SIZE);
+               if (written < 0)
+                       return;
+
+               btsnoop_index = index;
+       }
+
+       if (index != btsnoop_index)
+               return;
+
+       ts = (tv->tv_sec - 946684800ll) * 1000000ll + tv->tv_usec;
+
+       pkt.size  = htonl(size);
+       pkt.len   = htonl(size);
+       pkt.flags = htonl(flags);
+       pkt.drops = htonl(0);
+       pkt.ts    = hton64(ts + 0x00E03AB44A676000ll);
+
+       written = write(btsnoop_fd, &pkt, BTSNOOP_PKT_SIZE);
+       if (written < 0)
+               return;
+
+       if (data && size > 0) {
+               written = write(btsnoop_fd, data, size);
+               if (written < 0)
+                       return;
+       }
+}
+
+void btsnoop_close(void)
+{
+       if (btsnoop_fd < 0)
+               return;
+
+       close(btsnoop_fd);
+       btsnoop_fd = -1;
+
+       btsnoop_index = 0xffff;
+}
diff --git a/monitor/btsnoop.h b/monitor/btsnoop.h
new file mode 100644 (file)
index 0000000..9472d1a
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <sys/time.h>
+
+void btsnoop_open(const char *path);
+void btsnoop_write(struct timeval *tv, uint16_t index, uint32_t flags,
+                                       const void *data, uint16_t size);
+void btsnoop_close(void);
diff --git a/monitor/control.c b/monitor/control.c
new file mode 100644 (file)
index 0000000..159ba9d
--- /dev/null
@@ -0,0 +1,647 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/mgmt.h>
+
+#include "mainloop.h"
+#include "packet.h"
+#include "control.h"
+
+struct control_data {
+       uint16_t channel;
+       int fd;
+};
+
+static void free_data(void *user_data)
+{
+       struct control_data *data = user_data;
+
+       close(data->fd);
+
+       free(data);
+}
+
+static void mgmt_index_added(uint16_t len, const void *buf)
+{
+       printf("@ Index Added\n");
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_index_removed(uint16_t len, const void *buf)
+{
+       printf("@ Index Removed\n");
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_controller_error(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_controller_error *ev = buf;
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Controller Error control\n");
+               return;
+       }
+
+       printf("@ Controller Error: 0x%2.2x\n", ev->error_code);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+#ifndef NELEM
+#define NELEM(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+static const char *settings_str[] = {
+       "powered", "connectable", "fast-connectable", "discoverable",
+       "pairable", "link-security", "ssp", "br/edr", "hs", "le"
+};
+
+static void mgmt_new_settings(uint16_t len, const void *buf)
+{
+       uint32_t settings;
+       unsigned int i;
+
+       if (len < 4) {
+               printf("* Malformed New Settings control\n");
+               return;
+       }
+
+       settings = bt_get_le32(buf);
+
+       printf("@ New Settings: 0x%4.4x\n", settings);
+
+       printf("%-12c", ' ');
+       for (i = 0; i < NELEM(settings_str); i++) {
+               if (settings & (1 << i))
+                       printf("%s ", settings_str[i]);
+       }
+       printf("\n");
+
+       buf += 4;
+       len -= 4;
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_class_of_dev_changed(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_class_of_dev_changed *ev = buf;
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Class of Device Changed control\n");
+               return;
+       }
+
+       printf("@ Class of Device Changed: 0x%2.2x%2.2x%2.2x\n",
+                                               ev->class_of_dev[2],
+                                               ev->class_of_dev[1],
+                                               ev->class_of_dev[0]);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_local_name_changed(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_local_name_changed *ev = buf;
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Local Name Changed control\n");
+               return;
+       }
+
+       printf("@ Local Name Changed: %s (%s)\n", ev->name, ev->short_name);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_new_link_key(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_new_link_key *ev = buf;
+       char str[18];
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed New Link Key control\n");
+               return;
+       }
+
+       ba2str(&ev->key.addr.bdaddr, str);
+
+       printf("@ New Link Key: %s (%d)\n", str, ev->key.addr.type);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_new_long_term_key(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_new_long_term_key *ev = buf;
+       char str[18];
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed New Long Term Key control\n");
+               return;
+       }
+
+       ba2str(&ev->key.addr.bdaddr, str);
+
+       printf("@ New Long Term Key: %s (%d)\n", str, ev->key.addr.type);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_device_connected(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_device_connected *ev = buf;
+       uint32_t flags;
+       char str[18];
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Device Connected control\n");
+               return;
+       }
+
+       flags = btohs(ev->flags);
+       ba2str(&ev->addr.bdaddr, str);
+
+       printf("@ Device Connected: %s (%d) flags 0x%4.4x\n",
+                                               str, ev->addr.type, flags);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_device_disconnected(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_device_disconnected *ev = buf;
+       char str[18];
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Device Disconnected control\n");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, str);
+
+       printf("@ Device Disconnected: %s (%d)\n", str, ev->addr.type);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_connect_failed(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_connect_failed *ev = buf;
+       char str[18];
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Connect Failed control\n");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, str);
+
+       printf("@ Connect Failed: %s (%d) status 0x%2.2x\n",
+                                       str, ev->addr.type, ev->status);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_pin_code_request(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_pin_code_request *ev = buf;
+       char str[18];
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed PIN Code Request control\n");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, str);
+
+       printf("@ PIN Code Request: %s (%d) secure 0x%2.2x\n",
+                                       str, ev->addr.type, ev->secure);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_user_confirm_request(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_user_confirm_request *ev = buf;
+       char str[18];
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed User Confirmation Request control\n");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, str);
+
+       printf("@ User Confirmation Request: %s (%d) hint %d value %d\n",
+                       str, ev->addr.type, ev->confirm_hint, ev->value);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_user_passkey_request(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_user_passkey_request *ev = buf;
+       char str[18];
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed User Passkey Request control\n");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, str);
+
+       printf("@ PIN User Passkey Request: %s (%d)\n", str, ev->addr.type);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_auth_failed(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_auth_failed *ev = buf;
+       char str[18];
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Authentication Failed control\n");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, str);
+
+       printf("@ Authentication Failed: %s (%d) status 0x%2.2x\n",
+                                       str, ev->addr.type, ev->status);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_device_found(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_device_found *ev = buf;
+       uint32_t flags;
+       char str[18];
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Device Found control\n");
+               return;
+       }
+
+       flags = btohs(ev->flags);
+       ba2str(&ev->addr.bdaddr, str);
+
+       printf("@ Device Found: %s (%d) rssi %d flags 0x%4.4x\n",
+                                       str, ev->addr.type, ev->rssi, flags);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_discovering(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_discovering *ev = buf;
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Discovering control\n");
+               return;
+       }
+
+       printf("@ Discovering: 0x%2.2x (%d)\n", ev->discovering, ev->type);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_device_blocked(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_device_blocked *ev = buf;
+       char str[18];
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Device Blocked control\n");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, str);
+
+       printf("@ Device Blocked: %s (%d)\n", str, ev->addr.type);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_device_unblocked(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_device_unblocked *ev = buf;
+       char str[18];
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Device Unblocked control\n");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, str);
+
+       printf("@ Device Unblocked: %s (%d)\n", str, ev->addr.type);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+static void mgmt_device_unpaired(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_device_unpaired *ev = buf;
+       char str[18];
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Device Unpaired control\n");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, str);
+
+       printf("@ Device Unpaired: %s (%d)\n", str, ev->addr.type);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
+void control_message(uint16_t opcode, const void *data, uint16_t size)
+{
+       switch (opcode) {
+       case MGMT_EV_INDEX_ADDED:
+               mgmt_index_added(size, data);
+               break;
+       case MGMT_EV_INDEX_REMOVED:
+               mgmt_index_removed(size, data);
+               break;
+       case MGMT_EV_CONTROLLER_ERROR:
+               mgmt_controller_error(size, data);
+               break;
+       case MGMT_EV_NEW_SETTINGS:
+               mgmt_new_settings(size, data);
+               break;
+       case MGMT_EV_CLASS_OF_DEV_CHANGED:
+               mgmt_class_of_dev_changed(size, data);
+               break;
+       case MGMT_EV_LOCAL_NAME_CHANGED:
+               mgmt_local_name_changed(size, data);
+               break;
+       case MGMT_EV_NEW_LINK_KEY:
+               mgmt_new_link_key(size, data);
+               break;
+       case MGMT_EV_NEW_LONG_TERM_KEY:
+               mgmt_new_long_term_key(size, data);
+               break;
+       case MGMT_EV_DEVICE_CONNECTED:
+               mgmt_device_connected(size, data);
+               break;
+       case MGMT_EV_DEVICE_DISCONNECTED:
+               mgmt_device_disconnected(size, data);
+               break;
+       case MGMT_EV_CONNECT_FAILED:
+               mgmt_connect_failed(size, data);
+               break;
+       case MGMT_EV_PIN_CODE_REQUEST:
+               mgmt_pin_code_request(size, data);
+               break;
+       case MGMT_EV_USER_CONFIRM_REQUEST:
+               mgmt_user_confirm_request(size, data);
+               break;
+       case MGMT_EV_USER_PASSKEY_REQUEST:
+               mgmt_user_passkey_request(size, data);
+               break;
+       case MGMT_EV_AUTH_FAILED:
+               mgmt_auth_failed(size, data);
+               break;
+       case MGMT_EV_DEVICE_FOUND:
+               mgmt_device_found(size, data);
+               break;
+       case MGMT_EV_DISCOVERING:
+               mgmt_discovering(size, data);
+               break;
+       case MGMT_EV_DEVICE_BLOCKED:
+               mgmt_device_blocked(size, data);
+               break;
+       case MGMT_EV_DEVICE_UNBLOCKED:
+               mgmt_device_unblocked(size, data);
+               break;
+       case MGMT_EV_DEVICE_UNPAIRED:
+               mgmt_device_unpaired(size, data);
+               break;
+       default:
+               printf("* Unknown control (code %d len %d)\n", opcode, size);
+               packet_hexdump(data, size);
+               break;
+       }
+}
+
+static void data_callback(int fd, uint32_t events, void *user_data)
+{
+       struct control_data *data = user_data;
+       unsigned char buf[HCI_MAX_FRAME_SIZE];
+       unsigned char control[32];
+       struct mgmt_hdr hdr;
+       struct msghdr msg;
+       struct iovec iov[2];
+
+       if (events & (EPOLLERR | EPOLLHUP)) {
+               mainloop_remove_fd(fd);
+               return;
+       }
+
+       iov[0].iov_base = &hdr;
+       iov[0].iov_len = MGMT_HDR_SIZE;
+       iov[1].iov_base = buf;
+       iov[1].iov_len = sizeof(buf);
+
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_iov = iov;
+       msg.msg_iovlen = 2;
+       msg.msg_control = control;
+       msg.msg_controllen = sizeof(control);
+
+       while (1) {
+               struct cmsghdr *cmsg;
+               struct timeval *tv = NULL;
+               uint16_t opcode, index, pktlen;
+               ssize_t len;
+
+               len = recvmsg(fd, &msg, MSG_DONTWAIT);
+               if (len < 0)
+                       break;
+
+               if (len < MGMT_HDR_SIZE)
+                       break;
+
+               for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+                                       cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+                       if (cmsg->cmsg_level != SOL_SOCKET)
+                               continue;
+
+                       if (cmsg->cmsg_type == SCM_TIMESTAMP)
+                               tv = (struct timeval *) CMSG_DATA(cmsg);
+               }
+
+               opcode = btohs(hdr.opcode);
+               index  = btohs(hdr.index);
+               pktlen = btohs(hdr.len);
+
+               switch (data->channel) {
+               case HCI_CHANNEL_CONTROL:
+                       packet_control(tv, index, opcode, buf, pktlen);
+                       break;
+               case HCI_CHANNEL_MONITOR:
+                       packet_monitor(tv, index, opcode, buf, pktlen);
+                       break;
+               }
+       }
+}
+
+static int open_socket(uint16_t channel)
+{
+       struct sockaddr_hci addr;
+       int fd, opt = 1;
+
+       fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       if (fd < 0) {
+               perror("Failed to open channel");
+               return -1;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.hci_family = AF_BLUETOOTH;
+       addr.hci_dev = HCI_DEV_NONE;
+       addr.hci_channel = channel;
+
+       if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               if (errno == EINVAL) {
+                       /* Fallback to hcidump support */
+                       close(fd);
+                       return -1;
+               }
+               perror("Failed to bind channel");
+               close(fd);
+               return -1;
+       }
+
+       if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt)) < 0) {
+               perror("Failed to enable timestamps");
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+static int open_channel(uint16_t channel)
+{
+       struct control_data *data;
+
+       data = malloc(sizeof(*data));
+       if (!data)
+               return -1;
+
+       memset(data, 0, sizeof(*data));
+       data->channel = channel;
+
+       data->fd = open_socket(channel);
+       if (data->fd < 0) {
+               free(data);
+               return -1;
+       }
+
+       mainloop_add_fd(data->fd, EPOLLIN, data_callback, data, free_data);
+
+       return 0;
+}
+
+int control_tracing(void)
+{
+       if (open_channel(HCI_CHANNEL_MONITOR) < 0)
+               return -1;
+
+       open_channel(HCI_CHANNEL_CONTROL);
+
+       return 0;
+}
similarity index 76%
rename from src/glib-compat.h
rename to monitor/control.h
index d50d5e9..961f66c 100644 (file)
@@ -2,7 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
  *
  */
 
-#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
+#include <stdint.h>
+
+int control_tracing(void);
+
+void control_message(uint16_t opcode, const void *data, uint16_t size);
diff --git a/monitor/hcidump.c b/monitor/hcidump.c
new file mode 100644 (file)
index 0000000..373d2f5
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "mainloop.h"
+#include "packet.h"
+#include "hcidump.h"
+
+struct hcidump_data {
+       uint16_t index;
+       int fd;
+};
+
+static void free_data(void *user_data)
+{
+       struct hcidump_data *data = user_data;
+
+       close(data->fd);
+
+       free(data);
+}
+
+static int open_hci_dev(uint16_t index)
+{
+       struct sockaddr_hci addr;
+       struct hci_filter flt;
+       int fd, opt = 1;
+
+       fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       if (fd < 0) {
+               perror("Failed to open channel");
+               return -1;
+       }
+
+       /* Setup filter */
+       hci_filter_clear(&flt);
+       hci_filter_all_ptypes(&flt);
+       hci_filter_all_events(&flt);
+
+       if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
+               perror("Failed to set HCI filter");
+               close(fd);
+               return -1;
+       }
+
+       if (setsockopt(fd, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) {
+               perror("Failed to enable HCI data direction info");
+               close(fd);
+               return -1;
+       }
+
+       if (setsockopt(fd, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) {
+               perror("Failed to enable HCI time stamps");
+               close(fd);
+               return -1;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.hci_family = AF_BLUETOOTH;
+       addr.hci_dev = index;
+       addr.hci_channel = HCI_CHANNEL_RAW;
+
+       if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               perror("Failed to bind channel");
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+static void device_callback(int fd, uint32_t events, void *user_data)
+{
+       struct hcidump_data *data = user_data;
+       unsigned char buf[HCI_MAX_FRAME_SIZE];
+       unsigned char control[64];
+       struct msghdr msg;
+       struct iovec iov;
+
+       if (events & (EPOLLERR | EPOLLHUP)) {
+               mainloop_remove_fd(fd);
+               return;
+       }
+
+       iov.iov_base = buf;
+       iov.iov_len = sizeof(buf);
+
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_control = control;
+       msg.msg_controllen = sizeof(control);
+
+       while (1) {
+               struct cmsghdr *cmsg;
+               struct timeval *tv = NULL;
+               int *dir = NULL;
+               ssize_t len;
+
+               len = recvmsg(fd, &msg, MSG_DONTWAIT);
+               if (len < 0)
+                       break;
+
+               for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+                                       cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+                       if (cmsg->cmsg_level != SOL_HCI)
+                               continue;
+
+                       switch (cmsg->cmsg_type) {
+                       case HCI_DATA_DIR:
+                               dir = (int *) CMSG_DATA(cmsg);
+                               break;
+                       case HCI_CMSG_TSTAMP:
+                               tv = (struct timeval *) CMSG_DATA(cmsg);
+                               break;
+                       }
+               }
+
+               if (!dir || len < 1)
+                       continue;
+
+               switch (buf[0]) {
+               case HCI_COMMAND_PKT:
+                       packet_hci_command(tv, data->index, buf + 1, len - 1);
+                       break;
+               case HCI_EVENT_PKT:
+                       packet_hci_event(tv, data->index, buf + 1, len - 1);
+                       break;
+               case HCI_ACLDATA_PKT:
+                       packet_hci_acldata(tv, data->index, !!(*dir),
+                                                       buf + 1, len - 1);
+                       break;
+               case HCI_SCODATA_PKT:
+                       packet_hci_scodata(tv, data->index, !!(*dir),
+                                                       buf + 1, len - 1);
+                       break;
+               }
+       }
+}
+
+static void open_device(uint16_t index)
+{
+       struct hcidump_data *data;
+
+       data = malloc(sizeof(*data));
+       if (!data)
+               return;
+
+       memset(data, 0, sizeof(*data));
+       data->index = index;
+
+       data->fd = open_hci_dev(index);
+       if (data->fd < 0) {
+               free(data);
+               return;
+       }
+
+       mainloop_add_fd(data->fd, EPOLLIN, device_callback, data, free_data);
+}
+
+static void device_info(int fd, uint16_t index, uint8_t *type, uint8_t *bus,
+                                               bdaddr_t *bdaddr, char *name)
+{
+       struct hci_dev_info di;
+
+       memset(&di, 0, sizeof(di));
+       di.dev_id = index;
+
+       if (ioctl(fd, HCIGETDEVINFO, (void *) &di) < 0) {
+               perror("Failed to get device information");
+               return;
+       }
+
+       *type = di.type >> 4;
+       *bus = di.type & 0x0f;
+
+       bacpy(bdaddr, &di.bdaddr);
+       memcpy(name, di.name, 8);
+}
+
+static void device_list(int fd, int max_dev)
+{
+       struct hci_dev_list_req *dl;
+       struct hci_dev_req *dr;
+       int i;
+
+       dl = malloc(max_dev * sizeof(*dr) + sizeof(*dl));
+       if (!dl) {
+               perror("Failed to allocate device list memory");
+               return;
+       }
+
+       memset(dl, 0, max_dev * sizeof(*dr) + sizeof(*dl));
+       dl->dev_num = max_dev;
+
+       dr = dl->dev_req;
+
+       if (ioctl(fd, HCIGETDEVLIST, (void *) dl) < 0) {
+               perror("Failed to get device list");
+               goto done;
+       }
+
+       for (i = 0; i < dl->dev_num; i++, dr++) {
+               struct timeval tmp_tv, *tv = NULL;
+               uint8_t type = 0xff, bus = 0xff;
+               char str[18], name[8] = "";
+               bdaddr_t bdaddr;
+
+               bacpy(&bdaddr, BDADDR_ANY);
+
+               if (!gettimeofday(&tmp_tv, NULL))
+                       tv = &tmp_tv;
+
+               device_info(fd, dr->dev_id, &type, &bus, &bdaddr, name);
+               ba2str(&bdaddr, str);
+               packet_new_index(tv, dr->dev_id, str, type, bus, name);
+               open_device(dr->dev_id);
+       }
+
+done:
+       free(dl);
+}
+
+static int open_stack_internal(void)
+{
+       struct sockaddr_hci addr;
+       struct hci_filter flt;
+       int fd, opt = 1;
+
+       fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       if (fd < 0) {
+               perror("Failed to open channel");
+               return -1;
+       }
+
+       /* Setup filter */
+       hci_filter_clear(&flt);
+       hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
+       hci_filter_set_event(EVT_STACK_INTERNAL, &flt);
+
+       if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
+               perror("Failed to set HCI filter");
+               close(fd);
+               return -1;
+       }
+
+       if (setsockopt(fd, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) {
+               perror("Failed to enable HCI time stamps");
+               close(fd);
+               return -1;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.hci_family = AF_BLUETOOTH;
+       addr.hci_dev = HCI_DEV_NONE;
+       addr.hci_channel = HCI_CHANNEL_RAW;
+
+       if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               perror("Failed to bind channel");
+               close(fd);
+               return -1;
+       }
+
+       device_list(fd, HCI_MAX_DEV);
+
+       return fd;
+}
+
+static void stack_internal_callback(int fd, uint32_t events, void *user_data)
+{
+       unsigned char buf[HCI_MAX_FRAME_SIZE];
+       unsigned char control[32];
+       struct msghdr msg;
+       struct iovec iov;
+       struct cmsghdr *cmsg;
+       ssize_t len;
+       hci_event_hdr *eh;
+       evt_stack_internal *si;
+       evt_si_device *sd;
+       struct timeval *tv = NULL;
+       uint8_t type = 0xff, bus = 0xff;
+       char str[18], name[8] = "";
+       bdaddr_t bdaddr;
+
+       bacpy(&bdaddr, BDADDR_ANY);
+
+       if (events & (EPOLLERR | EPOLLHUP)) {
+               mainloop_remove_fd(fd);
+               return;
+       }
+
+       iov.iov_base = buf;
+       iov.iov_len = sizeof(buf);
+
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_control = control;
+       msg.msg_controllen = sizeof(control);
+
+       len = recvmsg(fd, &msg, MSG_DONTWAIT);
+       if (len < 0)
+               return;
+
+       for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+                                       cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+               if (cmsg->cmsg_level != SOL_HCI)
+                       continue;
+
+               switch (cmsg->cmsg_type) {
+               case HCI_CMSG_TSTAMP:
+                       tv = (struct timeval *) CMSG_DATA(cmsg);
+                       break;
+               }
+       }
+
+       if (len < 1 + HCI_EVENT_HDR_SIZE + EVT_STACK_INTERNAL_SIZE +
+                                                       EVT_SI_DEVICE_SIZE)
+               return;
+
+       if (buf[0] != HCI_EVENT_PKT)
+               return;
+
+       eh = (hci_event_hdr *) (buf + 1);
+       if (eh->evt != EVT_STACK_INTERNAL)
+               return;
+
+       si = (evt_stack_internal *) (buf + 1 + HCI_EVENT_HDR_SIZE);
+       if (si->type != EVT_SI_DEVICE)
+               return;
+
+       sd = (evt_si_device *) &si->data;
+
+       switch (sd->event) {
+       case HCI_DEV_REG:
+               device_info(fd, sd->dev_id, &type, &bus, &bdaddr, name);
+               ba2str(&bdaddr, str);
+               packet_new_index(tv, sd->dev_id, str, type, bus, name);
+               open_device(sd->dev_id);
+               break;
+       case HCI_DEV_UNREG:
+               ba2str(&bdaddr, str);
+               packet_del_index(tv, sd->dev_id, str);
+               break;
+       }
+}
+
+int hcidump_tracing(void)
+{
+       struct hcidump_data *data;
+
+       data = malloc(sizeof(*data));
+       if (!data)
+               return -1;
+
+       memset(data, 0, sizeof(*data));
+       data->index = HCI_DEV_NONE;
+
+       data->fd = open_stack_internal();
+       if (data->fd < 0) {
+               free(data);
+               return -1;
+       }
+
+       mainloop_add_fd(data->fd, EPOLLIN, stack_internal_callback,
+                                                       data, free_data);
+
+       return 0;
+}
diff --git a/monitor/hcidump.h b/monitor/hcidump.h
new file mode 100644 (file)
index 0000000..3801c98
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int hcidump_tracing(void);
diff --git a/monitor/main.c b/monitor/main.c
new file mode 100644 (file)
index 0000000..90e32c5
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include "mainloop.h"
+#include "packet.h"
+#include "control.h"
+#include "hcidump.h"
+#include "btsnoop.h"
+
+static void signal_callback(int signum, void *user_data)
+{
+       switch (signum) {
+       case SIGINT:
+       case SIGTERM:
+               mainloop_quit();
+               break;
+       }
+}
+
+static void usage(void)
+{
+       printf("btmon - Bluetooth monitor\n"
+               "Usage:\n");
+       printf("\tbtmon [options]\n");
+       printf("options:\n"
+               "\t-b, --btsnoop <file>  Save dump in btsnoop format\n"
+               "\t-h, --help            Show help options\n");
+}
+
+static const struct option main_options[] = {
+       { "btsnoop",    required_argument, NULL, 'b'    },
+       { "version",    no_argument,       NULL, 'v'    },
+       { "help",       no_argument,       NULL, 'h'    },
+       { }
+};
+
+int main(int argc, char *argv[])
+{
+       unsigned long filter_mask = 0;
+       sigset_t mask;
+
+       mainloop_init();
+
+       for (;;) {
+               int opt;
+
+               opt = getopt_long(argc, argv, "bvh", main_options, NULL);
+               if (opt < 0)
+                       break;
+
+               switch (opt) {
+               case 'b':
+                       btsnoop_open(optarg);
+                       break;
+               case 'v':
+                       printf("%s\n", VERSION);
+                       return EXIT_SUCCESS;
+               case 'h':
+                       usage();
+                       return EXIT_SUCCESS;
+               default:
+                       return EXIT_FAILURE;
+               }
+       }
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+       sigaddset(&mask, SIGTERM);
+
+       mainloop_set_signal(&mask, signal_callback, NULL, NULL);
+
+       filter_mask |= PACKET_FILTER_SHOW_INDEX;
+       filter_mask |= PACKET_FILTER_SHOW_TIME;
+       filter_mask |= PACKET_FILTER_SHOW_ACL_DATA;
+
+       packet_set_filter(filter_mask);
+
+       printf("Bluetooth monitor ver %s\n", VERSION);
+
+       if (control_tracing() < 0) {
+               if (hcidump_tracing() < 0)
+                       return EXIT_FAILURE;
+       }
+
+       return mainloop_run();
+}
diff --git a/monitor/mainloop.c b/monitor/mainloop.c
new file mode 100644 (file)
index 0000000..1cc787e
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/signalfd.h>
+#include <sys/timerfd.h>
+#include <sys/epoll.h>
+
+#include "mainloop.h"
+
+#define MAX_EPOLL_EVENTS 10
+
+static int epoll_fd;
+static int epoll_terminate;
+
+struct mainloop_data {
+       int fd;
+       uint32_t events;
+       mainloop_event_func callback;
+       mainloop_destroy_func destroy;
+       void *user_data;
+};
+
+#define MAX_MAINLOOP_ENTRIES 128
+
+static struct mainloop_data *mainloop_list[MAX_MAINLOOP_ENTRIES];
+
+struct timeout_data {
+       int fd;
+       mainloop_timeout_func callback;
+       mainloop_destroy_func destroy;
+       void *user_data;
+};
+
+struct signal_data {
+       int fd;
+       sigset_t mask;
+       mainloop_signal_func callback;
+       mainloop_destroy_func destroy;
+       void *user_data;
+};
+
+static struct signal_data *signal_data;
+
+void mainloop_init(void)
+{
+       unsigned int i;
+
+       epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+
+       for (i = 0; i < MAX_MAINLOOP_ENTRIES; i++)
+               mainloop_list[i] = NULL;
+
+       epoll_terminate = 0;
+}
+
+void mainloop_quit(void)
+{
+       epoll_terminate = 1;
+}
+
+static void signal_callback(int fd, uint32_t events, void *user_data)
+{
+       struct signal_data *data = user_data;
+       struct signalfd_siginfo si;
+       ssize_t result;
+
+       if (events & (EPOLLERR | EPOLLHUP)) {
+               mainloop_quit();
+               return;
+       }
+
+       result = read(fd, &si, sizeof(si));
+       if (result != sizeof(si))
+               return;
+
+       if (data->callback)
+               data->callback(si.ssi_signo, data->user_data);
+}
+
+int mainloop_run(void)
+{
+       unsigned int i;
+
+       if (signal_data) {
+               if (sigprocmask(SIG_BLOCK, &signal_data->mask, NULL) < 0)
+                       return 1;
+
+               signal_data->fd = signalfd(-1, &signal_data->mask,
+                                               SFD_NONBLOCK | SFD_CLOEXEC);
+               if (signal_data->fd < 0)
+                       return 1;
+
+               if (mainloop_add_fd(signal_data->fd, EPOLLIN,
+                               signal_callback, signal_data, NULL) < 0) {
+                       close(signal_data->fd);
+                       return 1;
+               }
+       }
+
+       while (!epoll_terminate) {
+               struct epoll_event events[MAX_EPOLL_EVENTS];
+               int n, nfds;
+
+               nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, -1);
+               if (nfds < 0)
+                       continue;
+
+               for (n = 0; n < nfds; n++) {
+                       struct mainloop_data *data = events[n].data.ptr;
+
+                       data->callback(data->fd, events[n].events,
+                                                       data->user_data);
+               }
+       }
+
+       if (signal_data) {
+               mainloop_remove_fd(signal_data->fd);
+               close(signal_data->fd);
+
+               if (signal_data->destroy)
+                       signal_data->destroy(signal_data->user_data);
+       }
+
+       for (i = 0; i < MAX_MAINLOOP_ENTRIES; i++) {
+               struct mainloop_data *data = mainloop_list[i];
+
+               mainloop_list[i] = NULL;
+
+               if (data) {
+                       epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL);
+
+                       if (data->destroy)
+                               data->destroy(data->user_data);
+
+                       free(data);
+               }
+       }
+
+       close(epoll_fd);
+       epoll_fd = 0;
+
+       return 0;
+}
+
+int mainloop_add_fd(int fd, uint32_t events, mainloop_event_func callback,
+                               void *user_data, mainloop_destroy_func destroy)
+{
+       struct mainloop_data *data;
+       struct epoll_event ev;
+       int err;
+
+       if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1 || !callback)
+               return -EINVAL;
+
+       data = malloc(sizeof(*data));
+       if (!data)
+               return -ENOMEM;
+
+       memset(data, 0, sizeof(*data));
+       data->fd = fd;
+       data->events = events;
+       data->callback = callback;
+       data->destroy = destroy;
+       data->user_data = user_data;
+
+       memset(&ev, 0, sizeof(ev));
+       ev.events = events;
+       ev.data.ptr = data;
+
+       err = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, data->fd, &ev);
+       if (err < 0) {
+               free(data);
+               return err;
+       }
+
+       mainloop_list[fd] = data;
+
+       return 0;
+}
+
+int mainloop_modify_fd(int fd, uint32_t events)
+{
+       struct mainloop_data *data;
+       struct epoll_event ev;
+       int err;
+
+       if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1)
+               return -EINVAL;
+
+       data = mainloop_list[fd];
+       if (!data)
+               return -ENXIO;
+
+       if (data->events == events)
+               return 0;
+
+       memset(&ev, 0, sizeof(ev));
+       ev.events = events;
+       ev.data.ptr = data;
+
+       err = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, data->fd, &ev);
+       if (err < 0)
+               return err;
+
+       data->events = events;
+
+       return 0;
+}
+
+int mainloop_remove_fd(int fd)
+{
+       struct mainloop_data *data;
+       int err;
+
+       if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1)
+               return -EINVAL;
+
+       data = mainloop_list[fd];
+       if (!data)
+               return -ENXIO;
+
+       mainloop_list[fd] = NULL;
+
+       err = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL);
+
+       if (data->destroy)
+               data->destroy(data->user_data);
+
+       free(data);
+
+       return err;
+}
+
+static void timeout_destroy(void *user_data)
+{
+       struct timeout_data *data = user_data;
+
+       close(data->fd);
+       data->fd = -1;
+
+       if (data->destroy)
+               data->destroy(data->user_data);
+}
+
+static void timeout_callback(int fd, uint32_t events, void *user_data)
+{
+       struct timeout_data *data = user_data;
+       uint64_t expired;
+       ssize_t result;
+
+       if (events & (EPOLLERR | EPOLLHUP))
+               return;
+
+       result = read(data->fd, &expired, sizeof(expired));
+       if (result != sizeof(expired))
+               return;
+
+       if (data->callback)
+               data->callback(data->fd, data->user_data);
+}
+
+static inline int timeout_set(int fd, unsigned int seconds)
+{
+       struct itimerspec itimer;
+
+       memset(&itimer, 0, sizeof(itimer));
+       itimer.it_interval.tv_sec = 0;
+       itimer.it_interval.tv_nsec = 0;
+       itimer.it_value.tv_sec = seconds;
+       itimer.it_value.tv_nsec = 0;
+
+       return timerfd_settime(fd, 0, &itimer, NULL);
+}
+
+int mainloop_add_timeout(unsigned int seconds, mainloop_timeout_func callback,
+                               void *user_data, mainloop_destroy_func destroy)
+{
+       struct timeout_data *data;
+
+       if (!callback)
+               return -EINVAL;
+
+       data = malloc(sizeof(*data));
+       if (!data)
+               return -ENOMEM;
+
+       memset(data, 0, sizeof(*data));
+       data->callback = callback;
+       data->destroy = destroy;
+       data->user_data = user_data;
+
+       data->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
+       if (data->fd < 0) {
+               free(data);
+               return -EIO;
+       }
+
+       if (seconds > 0) {
+               if (timeout_set(data->fd, seconds) < 0) {
+                       close(data->fd);
+                       free(data);
+                       return -EIO;
+               }
+       }
+
+       if (mainloop_add_fd(data->fd, EPOLLIN | EPOLLONESHOT,
+                               timeout_callback, data, timeout_destroy) < 0) {
+               close(data->fd);
+               free(data);
+               return -EIO;
+       }
+
+       return data->fd;
+}
+
+int mainloop_modify_timeout(int id, unsigned int seconds)
+{
+       if (seconds > 0) {
+               if (timeout_set(id, seconds) < 0)
+                       return -EIO;
+       }
+
+       if (mainloop_modify_fd(id, EPOLLIN | EPOLLONESHOT) < 0)
+               return -EIO;
+
+       return 0;
+}
+
+int mainloop_remove_timeout(int id)
+{
+       return mainloop_remove_fd(id);
+}
+
+int mainloop_set_signal(sigset_t *mask, mainloop_signal_func callback,
+                               void *user_data, mainloop_destroy_func destroy)
+{
+       struct signal_data *data;
+
+       if (!mask || !callback)
+               return -EINVAL;
+
+       data = malloc(sizeof(*data));
+       if (!data)
+               return -ENOMEM;
+
+       memset(data, 0, sizeof(*data));
+       data->callback = callback;
+       data->destroy = destroy;
+       data->user_data = user_data;
+
+       data->fd = -1;
+       memcpy(&data->mask, mask, sizeof(sigset_t));
+
+       free(signal_data);
+       signal_data = data;
+
+       return 0;
+}
diff --git a/monitor/mainloop.h b/monitor/mainloop.h
new file mode 100644 (file)
index 0000000..04745d2
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <signal.h>
+#include <sys/epoll.h>
+
+typedef void (*mainloop_destroy_func) (void *user_data);
+
+typedef void (*mainloop_event_func) (int fd, uint32_t events, void *user_data);
+typedef void (*mainloop_timeout_func) (int id, void *user_data);
+typedef void (*mainloop_signal_func) (int signum, void *user_data);
+
+void mainloop_init(void);
+void mainloop_quit(void);
+int mainloop_run(void);
+
+int mainloop_add_fd(int fd, uint32_t events, mainloop_event_func callback,
+                               void *user_data, mainloop_destroy_func destroy);
+int mainloop_modify_fd(int fd, uint32_t events);
+int mainloop_remove_fd(int fd);
+
+int mainloop_add_timeout(unsigned int seconds, mainloop_timeout_func callback,
+                               void *user_data, mainloop_destroy_func destroy);
+int mainloop_modify_timeout(int fd, unsigned int seconds);
+int mainloop_remove_timeout(int id);
+
+int mainloop_set_signal(sigset_t *mask, mainloop_signal_func callback,
+                               void *user_data, mainloop_destroy_func destroy);
diff --git a/monitor/packet.c b/monitor/packet.c
new file mode 100644 (file)
index 0000000..0f14ea6
--- /dev/null
@@ -0,0 +1,664 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "control.h"
+#include "btsnoop.h"
+#include "packet.h"
+
+static unsigned long filter_mask = 0;
+
+void packet_set_filter(unsigned long filter)
+{
+       filter_mask = filter;
+}
+
+static void print_channel_header(struct timeval *tv, uint16_t index,
+                                                       uint16_t channel)
+{
+       if (filter_mask & PACKET_FILTER_SHOW_INDEX) {
+               switch (channel) {
+               case HCI_CHANNEL_CONTROL:
+                       printf("{hci%d} ", index);
+                       break;
+               case HCI_CHANNEL_MONITOR:
+                       printf("[hci%d] ", index);
+                       break;
+               }
+       }
+
+       if (tv) {
+               time_t t = tv->tv_sec;
+               struct tm tm;
+
+               localtime_r(&t, &tm);
+
+               if (filter_mask & PACKET_FILTER_SHOW_DATE)
+                       printf("%04d-%02d-%02d ", tm.tm_year + 1900,
+                                               tm.tm_mon + 1, tm.tm_mday);
+
+               if (filter_mask & PACKET_FILTER_SHOW_TIME)
+                       printf("%02d:%02d:%02d.%06lu ", tm.tm_hour,
+                                       tm.tm_min, tm.tm_sec, tv->tv_usec);
+       }
+}
+
+static void print_header(struct timeval *tv, uint16_t index)
+{
+       print_channel_header(tv, index, HCI_CHANNEL_MONITOR);
+}
+
+void packet_hexdump(const unsigned char *buf, uint16_t len)
+{
+       static const char hexdigits[] = "0123456789abcdef";
+       char str[68];
+       uint16_t i;
+
+       if (!len)
+               return;
+
+       for (i = 0; i < len; i++) {
+               str[((i % 16) * 3) + 0] = hexdigits[buf[i] >> 4];
+               str[((i % 16) * 3) + 1] = hexdigits[buf[i] & 0xf];
+               str[((i % 16) * 3) + 2] = ' ';
+               str[(i % 16) + 49] = isprint(buf[i]) ? buf[i] : '.';
+
+               if ((i + 1) % 16 == 0) {
+                       str[47] = ' ';
+                       str[48] = ' ';
+                       str[65] = '\0';
+                       printf("%-12c%s\n", ' ', str);
+                       str[0] = ' ';
+               }
+       }
+
+       if (i % 16 > 0) {
+               uint16_t j;
+               for (j = (i % 16); j < 16; j++) {
+                       str[(j * 3) + 0] = ' ';
+                       str[(j * 3) + 1] = ' ';
+                       str[(j * 3) + 2] = ' ';
+                       str[j + 49] = ' ';
+               }
+               str[47] = ' ';
+               str[48] = ' ';
+               str[65] = '\0';
+               printf("%-12c%s\n", ' ', str);
+       }
+}
+
+void packet_control(struct timeval *tv, uint16_t index, uint16_t opcode,
+                                       const void *data, uint16_t size)
+{
+       print_channel_header(tv, index, HCI_CHANNEL_CONTROL);
+
+       control_message(opcode, data, size);
+}
+
+#define MONITOR_NEW_INDEX      0
+#define MONITOR_DEL_INDEX      1
+#define MONITOR_COMMAND_PKT    2
+#define MONITOR_EVENT_PKT      3
+#define MONITOR_ACL_TX_PKT     4
+#define MONITOR_ACL_RX_PKT     5
+#define MONITOR_SCO_TX_PKT     6
+#define MONITOR_SCO_RX_PKT     7
+
+struct monitor_new_index {
+       uint8_t  type;
+       uint8_t  bus;
+       bdaddr_t bdaddr;
+       char     name[8];
+} __attribute__((packed));
+
+#define MONITOR_NEW_INDEX_SIZE 16
+
+#define MONITOR_DEL_INDEX_SIZE 0
+
+#define MAX_INDEX 16
+
+static struct monitor_new_index index_list[MAX_INDEX];
+
+void packet_monitor(struct timeval *tv, uint16_t index, uint16_t opcode,
+                                       const void *data, uint16_t size)
+{
+       const struct monitor_new_index *ni;
+       char str[18];
+
+       switch (opcode) {
+       case MONITOR_NEW_INDEX:
+               ni = data;
+
+               if (index < MAX_INDEX)
+                       memcpy(&index_list[index], ni, MONITOR_NEW_INDEX_SIZE);
+
+               ba2str(&ni->bdaddr, str);
+               packet_new_index(tv, index, str, ni->type, ni->bus, ni->name);
+               break;
+       case MONITOR_DEL_INDEX:
+               if (index < MAX_INDEX)
+                       ba2str(&index_list[index].bdaddr, str);
+               else
+                       ba2str(BDADDR_ANY, str);
+
+               packet_del_index(tv, index, str);
+               break;
+       case MONITOR_COMMAND_PKT:
+               packet_hci_command(tv, index, data, size);
+               break;
+       case MONITOR_EVENT_PKT:
+               packet_hci_event(tv, index, data, size);
+               break;
+       case MONITOR_ACL_TX_PKT:
+               packet_hci_acldata(tv, index, false, data, size);
+               break;
+       case MONITOR_ACL_RX_PKT:
+               packet_hci_acldata(tv, index, true, data, size);
+               break;
+       case MONITOR_SCO_TX_PKT:
+               packet_hci_scodata(tv, index, false, data, size);
+               break;
+       case MONITOR_SCO_RX_PKT:
+               packet_hci_scodata(tv, index, true, data, size);
+               break;
+       default:
+               print_header(tv, index);
+               printf("* Unknown packet (code %d len %d)\n", opcode, size);
+               packet_hexdump(data, size);
+               break;
+       }
+}
+
+static const struct {
+       uint16_t opcode;
+       const char *str;
+} opcode2str_table[] = {
+       /* OGF 1 - Link Control */
+       { 0x0401, "Inquiry"                             },
+       { 0x0402, "Inquiry Cancel"                      },
+       { 0x0403, "Periodic Inquiry Mode"               },
+       { 0x0404, "Exit Periodic Inquiry Mode"          },
+       { 0x0405, "Create Connection"                   },
+       { 0x0406, "Disconnect"                          },
+       { 0x0407, "Add SCO Connection"                  },
+       { 0x0408, "Create Connection Cancel"            },
+       { 0x0409, "Accept Connection Request"           },
+       { 0x040a, "Reject Connection Request"           },
+       { 0x040b, "Link Key Request Reply"              },
+       { 0x040c, "Link Key Request Negative Reply"     },
+       { 0x040d, "PIN Code Request Reply"              },
+       { 0x040e, "PIN Code Request Negative Reply"     },
+       { 0x040f, "Change Connection Packet Type"       },
+       /* reserved command */
+       { 0x0411, "Authentication Requested"            },
+       /* reserved command */
+       { 0x0413, "Set Connection Encryption"           },
+       /* reserved command */
+       { 0x0415, "Change Connection Link Key"          },
+       /* reserved command */
+       { 0x0417, "Master Link Key"                     },
+       /* reserved command */
+       { 0x0419, "Remote Name Request"                 },
+       { 0x041a, "Remote Name Request Cancel"          },
+       { 0x041b, "Read Remote Supported Features"      },
+       { 0x041c, "Read Remote Extended Features"       },
+       { 0x041d, "Read Remote Version Information"     },
+       /* reserved command */
+       { 0x041f, "Read Clock Offset"                   },
+       { 0x0420, "Read LMP Handle"                     },
+       /* reserved commands */
+       { 0x0428, "Setup Synchronous Connection"        },
+       { 0x0429, "Accept Synchronous Connection"       },
+       { 0x042a, "Reject Synchronous Connection"       },
+       { 0x042b, "IO Capability Request Reply"         },
+       { 0x042c, "User Confirmation Request Reply"     },
+       { 0x042d, "User Confirmation Request Neg Reply" },
+       { 0x042e, "User Passkey Request Reply"          },
+       { 0x042f, "User Passkey Request Negative Reply" },
+       { 0x0430, "Remote OOB Data Request Reply"       },
+       /* reserved commands */
+       { 0x0433, "Remote OOB Data Request Neg Reply"   },
+       { 0x0434, "IO Capability Request Negative Reply"},
+       { 0x0435, "Create Physical Link"                },
+       { 0x0436, "Accept Physical Link"                },
+       { 0x0437, "Disconnect Physical Link"            },
+       { 0x0438, "Create Logical Link"                 },
+       { 0x0439, "Accept Logical Link"                 },
+       { 0x043a, "Disconnect Logical Link"             },
+       { 0x043b, "Logical Link Cancel"                 },
+       { 0x043c, "Flow Specifcation Modify"            },
+
+       /* OGF 2 - Link Policy */
+       { 0x0801, "Holde Mode"                          },
+       /* reserved command */
+       { 0x0803, "Sniff Mode"                          },
+       { 0x0804, "Exit Sniff Mode"                     },
+       { 0x0805, "Park State"                          },
+       { 0x0806, "Exit Park State"                     },
+       { 0x0807, "QoS Setup"                           },
+       /* reserved command */
+       { 0x0809, "Role Discovery"                      },
+       /* reserved command */
+       { 0x080b, "Switch Role"                         },
+       { 0x080c, "Read Link Policy Settings"           },
+       { 0x080d, "Write Link Policy Settings"          },
+       { 0x080e, "Read Default Link Policy Settings"   },
+       { 0x080f, "Write Default Link Policy Settings"  },
+       { 0x0810, "Flow Specification"                  },
+       { 0x0811, "Sniff Subrating"                     },
+
+       /* OGF 3 - Host Control */
+       { 0x0c01, "Set Event Mask"                      },
+       /* reserved command */
+       { 0x0c03, "Reset"                               },
+       /* reserved command */
+       { 0x0c05, "Set Event Filter"                    },
+       /* reserved commands */
+       { 0x0c08, "Flush"                               },
+       { 0x0c09, "Read PIN Type"                       },
+       { 0x0c0a, "Write PIN Type"                      },
+       { 0x0c0b, "Create New Unit Key"                 },
+       /* reserved command */
+       { 0x0c0d, "Read Stored Link Key"                },
+       /* reserved commands */
+       { 0x0c11, "Write Stored Link Key"               },
+       { 0x0c12, "Delete Stored Link Key"              },
+       { 0x0c13, "Write Local Name"                    },
+       { 0x0c14, "Read Local Name"                     },
+       { 0x0c15, "Read Connection Accept Timeout"      },
+       { 0x0c16, "Write Connection Accept Timeout"     },
+       { 0x0c17, "Read Page Timeout"                   },
+       { 0x0c18, "Write Page Timeout"                  },
+       { 0x0c19, "Read Scan Enable"                    },
+       { 0x0c1a, "Write Scan Enable"                   },
+       { 0x0c1b, "Read Page Scan Activity"             },
+       { 0x0c1c, "Write Page Scan Activity"            },
+       { 0x0c1d, "Read Inquiry Scan Activity"          },
+       { 0x0c1e, "Write Inquiry Scan Activity"         },
+       { 0x0c1f, "Read Authentication Enable"          },
+       { 0x0c20, "Write Authentication Enable"         },
+       { 0x0c21, "Read Encryption Mode"                },
+       { 0x0c22, "Write Encryption Mode"               },
+       { 0x0c23, "Read Class of Device"                },
+       { 0x0c24, "Write Class of Device"               },
+       { 0x0c25, "Read Voice Setting"                  },
+       { 0x0c26, "Write Voice Setting"                 },
+       { 0x0c27, "Read Automatic Flush Timeout"        },
+       { 0x0c28, "Write Automatic Flush Timeout"       },
+       { 0x0c29, "Read Num Broadcast Retransmissions"  },
+       { 0x0c2a, "Write Num Broadcast Retransmissions" },
+       { 0x0c2b, "Read Hold Mode Activity"             },
+       { 0x0c2c, "Write Hold Mode Activity"            },
+       { 0x0c2d, "Read Transmit Power Level"           },
+       { 0x0c2e, "Read Sync Flow Control Enable"       },
+       { 0x0c2f, "Write Sync Flow Control Enable"      },
+       /* reserved command */
+       { 0x0c31, "Set Host Controller To Host Flow"    },
+       /* reserved command */
+       { 0x0c33, "Host Buffer Size"                    },
+       /* reserved command */
+       { 0x0c35, "Host Number of Completed Packets"    },
+       { 0x0c36, "Read Link Supervision Timeout"       },
+       { 0x0c37, "Write Link Supervision Timeout"      },
+       { 0x0c38, "Read Number of Supported IAC"        },
+       { 0x0c39, "Read Current IAC LAP"                },
+       { 0x0c3a, "Write Current IAC LAP"               },
+       { 0x0c3b, "Read Page Scan Period Mode"          },
+       { 0x0c3c, "Write Page Scan Period Mode"         },
+       { 0x0c3d, "Read Page Scan Mode"                 },
+       { 0x0c3e, "Write Page Scan Mode"                },
+       { 0x0c3f, "Set AFH Host Channel Classification" },
+       /* reserved commands */
+       { 0x0c42, "Read Inquiry Scan Type"              },
+       { 0x0c43, "Write Inquiry Scan Type"             },
+       { 0x0c44, "Read Inquiry Mode"                   },
+       { 0x0c45, "Write Inquiry Mode"                  },
+       { 0x0c46, "Read Page Scan Type"                 },
+       { 0x0c47, "Write Page Scan Type"                },
+       { 0x0c48, "Read AFH Channel Assessment Mode"    },
+       { 0x0c49, "Write AFH Channel Assessment Mode"   },
+       /* reserved commands */
+       { 0x0c51, "Read Extended Inquiry Response"      },
+       { 0x0c52, "Write Extended Inquiry Response"     },
+       { 0x0c53, "Refresh Encryption Key"              },
+       /* reserved command */
+       { 0x0c55, "Read Simple Pairing Mode"            },
+       { 0x0c56, "Write Simple Pairing Mode"           },
+       { 0x0c57, "Read Local OOB Data"                 },
+       { 0x0c58, "Read Inquiry Response TX Power Level"},
+       { 0x0c59, "Write Inquiry Transmit Power Level"  },
+       { 0x0c5a, "Read Default Erroneous Reporting"    },
+       { 0x0c5b, "Write Default Erroneous Reporting"   },
+       /* reserved commands */
+       { 0x0c5f, "Enhanced Flush"                      },
+       /* reserved command */
+       { 0x0c61, "Read Logical Link Accept Timeout"    },
+       { 0x0c62, "Write Logical Link Accept Timeout"   },
+       { 0x0c63, "Set Event Mask Page 2"               },
+       { 0x0c64, "Read Location Data"                  },
+       { 0x0c65, "Write Location Data"                 },
+       { 0x0c66, "Read Flow Control Mode"              },
+       { 0x0c67, "Write Flow Control Mode"             },
+       { 0x0c68, "Read Enhanced Transmit Power Level"  },
+       { 0x0c69, "Read Best Effort Flush Timeout"      },
+       { 0x0c6a, "Write Best Effort Flush Timeout"     },
+       { 0x0c6b, "Short Range Mode"                    },
+       { 0x0c6c, "Read LE Host Supported"              },
+       { 0x0c6d, "Write LE Host Supported"             },
+
+       /* OGF 4 - Information Parameter */
+       { 0x1001, "Read Local Version Information"      },
+       { 0x1002, "Read Local Supported Commands"       },
+       { 0x1003, "Read Local Supported Features"       },
+       { 0x1004, "Read Local Extended Features"        },
+       { 0x1005, "Read Buffer Size"                    },
+       /* reserved command */
+       { 0x1007, "Read Country Code"                   },
+       /* reserved command */
+       { 0x1009, "Read BD ADDR"                        },
+       { 0x100a, "Read Data Block Size"                },
+
+       /* OGF 5 - Status Parameter */
+       { 0x1401, "Read Failed Contact Counter"         },
+       { 0x1402, "Reset Failed Contact Counter"        },
+       { 0x1403, "Read Link Quality"                   },
+       /* reserved command */
+       { 0x1405, "Read RSSI"                           },
+       { 0x1406, "Read AFH Channel Map"                },
+       { 0x1407, "Read Clock"                          },
+       { 0x1408, "Read Encryption Key Size"            },
+       { 0x1409, "Read Local AMP Info"                 },
+       { 0x140a, "Read Local AMP ASSOC"                },
+       { 0x140b, "Write Remote AMP ASSOC"              },
+
+       /* OGF 8 - LE Control */
+       { 0x2001, "LE Set Event Mask"                   },
+       { 0x2002, "LE Read Buffer Size"                 },
+       { 0x2003, "LE Read Local Supported Features"    },
+       /* reserved command */
+       { 0x2005, "LE Set Random Address"               },
+       { 0x2006, "LE Set Advertising Parameters"       },
+       { 0x2007, "LE Read Advertising Channel TX Power"},
+       { 0x2008, "LE Set Advertising Data"             },
+       { 0x2009, "LE Set Scan Response Data"           },
+       { 0x200a, "LE Set Advertise Enable"             },
+       { 0x200b, "LE Set Scan Parameters"              },
+       { 0x200c, "LE Set Scan Enable"                  },
+       { 0x200d, "LE Create Connection"                },
+       { 0x200e, "LE Create Connection Cancel"         },
+       { 0x200f, "LE Read White List Size"             },
+       { 0x2010, "LE Clear White List"                 },
+       { 0x2011, "LE Add Device To White List"         },
+       { 0x2012, "LE Remove Device From White List"    },
+       { 0x2013, "LE Connection Update"                },
+       { 0x2014, "LE Set Host Channel Classification"  },
+       { 0x2015, "LE Read Channel Map"                 },
+       { 0x2016, "LE Read Remote Used Features"        },
+       { 0x2017, "LE Encrypt"                          },
+       { 0x2018, "LE Rand"                             },
+       { 0x2019, "LE Start Encryption"                 },
+       { 0x201a, "LE Long Term Key Request Reply"      },
+       { 0x201b, "LE Long Term Key Request Neg Reply"  },
+       { 0x201c, "LE Read Supported States"            },
+       { 0x201d, "LE Receiver Test"                    },
+       { 0x201e, "LE Transmitter Test"                 },
+       { 0x201f, "LE Test End"                         },
+       { }
+};
+
+static const char *opcode2str(uint16_t opcode)
+{
+       int i;
+
+       for (i = 0; opcode2str_table[i].str; i++) {
+               if (opcode2str_table[i].opcode == opcode)
+                       return opcode2str_table[i].str;
+       }
+
+       return "Unknown";
+}
+
+static const struct {
+       uint8_t event;
+       const char *str;
+} event2str_table[] = {
+       { 0x01, "Inquiry Complete"                      },
+       { 0x02, "Inquiry Result"                        },
+       { 0x03, "Connect Complete"                      },
+       { 0x04, "Connect Request"                       },
+       { 0x05, "Disconn Complete"                      },
+       { 0x06, "Auth Complete"                         },
+       { 0x07, "Remote Name Req Complete"              },
+       { 0x08, "Encrypt Change"                        },
+       { 0x09, "Change Connection Link Key Complete"   },
+       { 0x0a, "Master Link Key Complete"              },
+       { 0x0b, "Read Remote Supported Features"        },
+       { 0x0c, "Read Remote Version Complete"          },
+       { 0x0d, "QoS Setup Complete"                    },
+       { 0x0e, "Command Complete"                      },
+       { 0x0f, "Command Status"                        },
+       { 0x10, "Hardware Error"                        },
+       { 0x11, "Flush Occurred"                        },
+       { 0x12, "Role Change"                           },
+       { 0x13, "Number of Completed Packets"           },
+       { 0x14, "Mode Change"                           },
+       { 0x15, "Return Link Keys"                      },
+       { 0x16, "PIN Code Request"                      },
+       { 0x17, "Link Key Request"                      },
+       { 0x18, "Link Key Notification"                 },
+       { 0x19, "Loopback Command"                      },
+       { 0x1a, "Data Buffer Overflow"                  },
+       { 0x1b, "Max Slots Change"                      },
+       { 0x1c, "Read Clock Offset Complete"            },
+       { 0x1d, "Connection Packet Type Changed"        },
+       { 0x1e, "QoS Violation"                         },
+       { 0x1f, "Page Scan Mode Change"                 },
+       { 0x20, "Page Scan Repetition Mode Change"      },
+       { 0x21, "Flow Specification Complete"           },
+       { 0x22, "Inquiry Result with RSSI"              },
+       { 0x23, "Read Remote Extended Features"         },
+       /* reserved events */
+       { 0x2c, "Synchronous Connect Complete"          },
+       { 0x2d, "Synchronous Connect Changed"           },
+       { 0x2e, "Sniff Subrate"                         },
+       { 0x2f, "Extended Inquiry Result"               },
+       { 0x30, "Encryption Key Refresh Complete"       },
+       { 0x31, "IO Capability Request"                 },
+       { 0x32, "IO Capability Response"                },
+       { 0x33, "User Confirmation Request"             },
+       { 0x34, "User Passkey Request"                  },
+       { 0x35, "Remote OOB Data Request"               },
+       { 0x36, "Simple Pairing Complete"               },
+       /* reserved event */
+       { 0x38, "Link Supervision Timeout Change"       },
+       { 0x39, "Enhanced Flush Complete"               },
+       /* reserved event */
+       { 0x3b, "User Passkey Notification"             },
+       { 0x3c, "Keypress Notification"                 },
+       { 0x3d, "Remote Host Supported Features"        },
+       { 0x3e, "LE Meta Event"                         },
+       /* reserved event */
+       { 0x40, "Physical Link Complete"                },
+       { 0x41, "Channel Selected"                      },
+       { 0x42, "Disconn Physical Link Complete"        },
+       { 0x43, "Physical Link Loss Early Warning"      },
+       { 0x44, "Physical Link Recovery"                },
+       { 0x45, "Logical Link Complete"                 },
+       { 0x46, "Disconn Logical Link Complete"         },
+       { 0x47, "Flow Spec Modify Complete"             },
+       { 0x48, "Number Of Completed Data Blocks"       },
+       { 0x49, "AMP Start Test"                        },
+       { 0x4a, "AMP Test End"                          },
+       { 0x4b, "AMP Receiver Report"                   },
+       { 0x4c, "Short Range Mode Change Complete"      },
+       { 0x4d, "AMP Status Change"                     },
+       { 0xfe, "Testing"                               },
+       { 0xff, "Vendor"                                },
+       { }
+};
+
+static const char *event2str(uint8_t event)
+{
+       int i;
+
+       for (i = 0; event2str_table[i].str; i++) {
+               if (event2str_table[i].event == event)
+                       return event2str_table[i].str;
+       }
+
+       return "Unknown";
+}
+
+void packet_new_index(struct timeval *tv, uint16_t index, const char *label,
+                               uint8_t type, uint8_t bus, const char *name)
+{
+       print_header(tv, index);
+
+       printf("= New Index: %s (%s,%s,%s)\n", label,
+                               hci_typetostr(type), hci_bustostr(bus), name);
+}
+
+void packet_del_index(struct timeval *tv, uint16_t index, const char *label)
+{
+       print_header(tv, index);
+
+       printf("= Delete Index: %s\n", label);
+}
+
+void packet_hci_command(struct timeval *tv, uint16_t index,
+                                       const void *data, uint16_t size)
+{
+       const hci_command_hdr *hdr = data;
+       uint16_t opcode = btohs(hdr->opcode);
+       uint16_t ogf = cmd_opcode_ogf(opcode);
+       uint16_t ocf = cmd_opcode_ocf(opcode);
+
+       btsnoop_write(tv, index, 0x02, data, size);
+
+       print_header(tv, index);
+
+       if (size < HCI_COMMAND_HDR_SIZE) {
+               printf("* Malformed HCI Command packet\n");
+               return;
+       }
+
+       printf("< HCI Command: %s (0x%2.2x|0x%4.4x) plen %d\n",
+                               opcode2str(opcode), ogf, ocf, hdr->plen);
+
+       data += HCI_COMMAND_HDR_SIZE;
+       size -= HCI_COMMAND_HDR_SIZE;
+
+       packet_hexdump(data, size);
+}
+
+void packet_hci_event(struct timeval *tv, uint16_t index,
+                                       const void *data, uint16_t size)
+{
+       const hci_event_hdr *hdr = data;
+
+       btsnoop_write(tv, index, 0x03, data, size);
+
+       print_header(tv, index);
+
+       if (size < HCI_EVENT_HDR_SIZE) {
+               printf("* Malformed HCI Event packet\n");
+               return;
+       }
+
+       printf("> HCI Event: %s (0x%2.2x) plen %d\n",
+                               event2str(hdr->evt), hdr->evt, hdr->plen);
+
+       data += HCI_EVENT_HDR_SIZE;
+       size -= HCI_EVENT_HDR_SIZE;
+
+       packet_hexdump(data, size);
+}
+
+void packet_hci_acldata(struct timeval *tv, uint16_t index, bool in,
+                                       const void *data, uint16_t size)
+{
+       const hci_acl_hdr *hdr = data;
+       uint16_t handle = btohs(hdr->handle);
+       uint16_t dlen = btohs(hdr->dlen);
+       uint8_t flags = acl_flags(handle);
+
+       btsnoop_write(tv, index, in ? 0x01 : 0x00, data, size);
+
+       print_header(tv, index);
+
+       if (size < HCI_ACL_HDR_SIZE) {
+               printf("* Malformed ACL Data %s packet\n", in ? "RX" : "TX");
+               return;
+       }
+
+       printf("%c ACL Data: handle %d flags 0x%2.2x dlen %d\n",
+                       in ? '>' : '<', acl_handle(handle), flags, dlen);
+
+       data += HCI_ACL_HDR_SIZE;
+       size -= HCI_ACL_HDR_SIZE;
+
+       if (filter_mask & PACKET_FILTER_SHOW_ACL_DATA)
+               packet_hexdump(data, size);
+}
+
+void packet_hci_scodata(struct timeval *tv, uint16_t index, bool in,
+                                       const void *data, uint16_t size)
+{
+       const hci_sco_hdr *hdr = data;
+       uint16_t handle = btohs(hdr->handle);
+       uint8_t flags = acl_flags(handle);
+
+       print_header(tv, index);
+
+       if (size < HCI_SCO_HDR_SIZE) {
+               printf("* Malformed SCO Data %s packet\n", in ? "RX" : "TX");
+               return;
+       }
+
+       printf("%c SCO Data: handle %d flags 0x%2.2x dlen %d\n",
+                       in ? '>' : '<', acl_handle(handle), flags, hdr->dlen);
+
+       data += HCI_SCO_HDR_SIZE;
+       size -= HCI_SCO_HDR_SIZE;
+
+       if (filter_mask & PACKET_FILTER_SHOW_SCO_DATA)
+               packet_hexdump(data, size);
+}
diff --git a/monitor/packet.h b/monitor/packet.h
new file mode 100644 (file)
index 0000000..90fc7ec
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdbool.h>
+#include <sys/time.h>
+
+#define PACKET_FILTER_SHOW_INDEX       (1 << 0)
+#define PACKET_FILTER_SHOW_DATE                (1 << 1)
+#define PACKET_FILTER_SHOW_TIME                (1 << 2)
+#define PACKET_FILTER_SHOW_ACL_DATA    (1 << 3)
+#define PACKET_FILTER_SHOW_SCO_DATA    (1 << 4)
+
+void packet_set_filter(unsigned long filter);
+
+void packet_hexdump(const unsigned char *buf, uint16_t len);
+
+void packet_control(struct timeval *tv, uint16_t index, uint16_t opcode,
+                                       const void *data, uint16_t size);
+void packet_monitor(struct timeval *tv, uint16_t index, uint16_t opcode,
+                                       const void *data, uint16_t size);
+
+void packet_new_index(struct timeval *tv, uint16_t index, const char *label,
+                               uint8_t type, uint8_t bus, const char *name);
+void packet_del_index(struct timeval *tv, uint16_t index, const char *label);
+
+void packet_hci_command(struct timeval *tv, uint16_t index,
+                                       const void *data, uint16_t size);
+void packet_hci_event(struct timeval *tv, uint16_t index,
+                                       const void *data, uint16_t size);
+void packet_hci_acldata(struct timeval *tv, uint16_t index, bool in,
+                                       const void *data, uint16_t size);
+void packet_hci_scodata(struct timeval *tv, uint16_t index, bool in,
+                                       const void *data, uint16_t size);
index bc6441d..e487df8 100644 (file)
@@ -39,6 +39,7 @@
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/l2cap.h>
 #include <bluetooth/bnep.h>
+#include <bluetooth/uuid.h>
 
 #include <glib.h>
 
index fefb754..cb1f08a 100644 (file)
  *
  */
 
-#define PANU_UUID      "00001115-0000-1000-8000-00805f9b34fb"
-#define NAP_UUID       "00001116-0000-1000-8000-00805f9b34fb"
-#define GN_UUID                "00001117-0000-1000-8000-00805f9b34fb"
-#define BNEP_SVC_UUID  "0000000f-0000-1000-8000-00805f9b34fb"
-
 int bnep_init(void);
 int bnep_cleanup(void);
 
index ca1f4b2..544ec3a 100644 (file)
@@ -38,7 +38,6 @@
 #include <gdbus.h>
 
 #include "log.h"
-#include "glib-compat.h"
 #include "btio.h"
 #include "dbus-common.h"
 #include "adapter.h"
@@ -49,6 +48,8 @@
 #include "connection.h"
 
 #define NETWORK_PEER_INTERFACE "org.bluez.Network"
+#define CON_SETUP_RETRIES      3
+#define CON_SETUP_TO           9
 
 typedef enum {
        CONNECTED,
@@ -73,6 +74,8 @@ struct network_conn {
        guint           watch;          /* Disconnect watch */
        guint           dc_id;
        struct network_peer *peer;
+       guint           attempt_cnt;
+       guint           timeout_source;
 };
 
 struct __service_16 {
@@ -146,6 +149,11 @@ static void cancel_connection(struct network_conn *nc, const char *err_msg)
 {
        DBusMessage *reply;
 
+       if (nc->timeout_source > 0) {
+               g_source_remove(nc->timeout_source);
+               nc->timeout_source = 0;
+       }
+
        if (nc->watch) {
                g_dbus_remove_watch(connection, nc->watch);
                nc->watch = 0;
@@ -199,6 +207,9 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
        if (cond & G_IO_NVAL)
                return FALSE;
 
+       g_source_remove(nc->timeout_source);
+       nc->timeout_source = 0;
+
        if (cond & (G_IO_HUP | G_IO_ERR)) {
                error("Hangup or error on l2cap server socket");
                goto failed;
@@ -289,11 +300,10 @@ failed:
        return FALSE;
 }
 
-static int bnep_connect(struct network_conn *nc)
+static int bnep_send_conn_req(struct network_conn *nc)
 {
        struct bnep_setup_conn_req *req;
        struct __service_16 *s;
-       struct timeval timeo;
        unsigned char pkt[BNEP_MTU];
        int fd;
 
@@ -306,14 +316,46 @@ static int bnep_connect(struct network_conn *nc)
        s->dst = htons(nc->id);
        s->src = htons(BNEP_SVC_PANU);
 
-       memset(&timeo, 0, sizeof(timeo));
-       timeo.tv_sec = 30;
-
        fd = g_io_channel_unix_get_fd(nc->io);
-       setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
+       if (write(fd, pkt, sizeof(*req) + sizeof(*s)) < 0) {
+               int err = -errno;
+               error("bnep connection req send failed: %s", strerror(errno));
+               return err;
+       }
+
+       nc->attempt_cnt++;
+
+       return 0;
+}
+
+static gboolean bnep_conn_req_to(gpointer user_data)
+{
+       struct network_conn *nc;
+
+       nc = user_data;
+       if (nc->attempt_cnt == CON_SETUP_RETRIES) {
+               error("Too many bnep connection attempts");
+       } else {
+               error("bnep connection setup TO, retrying...");
+               if (!bnep_send_conn_req(nc))
+                       return TRUE;
+       }
+
+       cancel_connection(nc, "bnep setup failed");
+
+       return FALSE;
+}
+
+static int bnep_connect(struct network_conn *nc)
+{
+       int err;
+
+       nc->attempt_cnt = 0;
+       if ((err = bnep_send_conn_req(nc)))
+               return err;
 
-       if (send(fd, pkt, sizeof(*req) + sizeof(*s), 0) < 0)
-               return -errno;
+       nc->timeout_source = g_timeout_add_seconds(CON_SETUP_TO,
+                                                       bnep_conn_req_to, nc);
 
        g_io_add_watch(nc->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
                        (GIOFunc) bnep_setup_cb, nc);
@@ -373,6 +415,7 @@ static DBusMessage *connection_connect(DBusConnection *conn,
                                BT_IO_OPT_SOURCE_BDADDR, &peer->src,
                                BT_IO_OPT_DEST_BDADDR, &peer->dst,
                                BT_IO_OPT_PSM, BNEP_PSM,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
                                BT_IO_OPT_OMTU, BNEP_MTU,
                                BT_IO_OPT_IMTU, BNEP_MTU,
                                BT_IO_OPT_INVALID);
@@ -509,16 +552,20 @@ static void path_unregister(void *data)
        peer_free(peer);
 }
 
-static GDBusMethodTable connection_methods[] = {
-       { "Connect",            "s",    "s",    connection_connect,
-                                               G_DBUS_METHOD_FLAG_ASYNC },
-       { "Disconnect",         "",     "",     connection_disconnect   },
-       { "GetProperties",      "",     "a{sv}",connection_get_properties },
+static const GDBusMethodTable connection_methods[] = {
+       { GDBUS_ASYNC_METHOD("Connect",
+                       NULL, NULL, connection_connect) },
+       { GDBUS_METHOD("Disconnect",
+                       NULL, NULL, connection_disconnect) },
+       { GDBUS_METHOD("GetProperties",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       connection_get_properties) },
        { }
 };
 
-static GDBusSignalTable connection_signals[] = {
-       { "PropertyChanged",    "sv"    },
+static const GDBusSignalTable connection_signals[] = {
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
        { }
 };
 
index 00a55aa..7fcd8f0 100644 (file)
@@ -28,6 +28,7 @@
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/bnep.h>
 #include <bluetooth/sdp.h>
+#include <bluetooth/uuid.h>
 
 #include <glib.h>
 #include <gdbus.h>
@@ -179,7 +180,7 @@ int network_manager_init(DBusConnection *conn)
        }
 
        /*
-        * There is one socket to handle the incomming connections. NAP,
+        * There is one socket to handle the incoming connections. NAP,
         * GN and PANU servers share the same PSM. The initial BNEP message
         * (setup connection request) contains the destination service
         * field that defines which service the source is connecting to.
index 52590fb..c0b04cd 100644 (file)
@@ -34,6 +34,7 @@
 #include <bluetooth/bnep.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
 #include <netinet/in.h>
 
 #include <glib.h>
@@ -46,7 +47,6 @@
 #include "error.h"
 #include "sdpd.h"
 #include "btio.h"
-#include "glib-compat.h"
 
 #include "common.h"
 #include "server.h"
@@ -134,20 +134,6 @@ static struct network_session *find_session(GSList *list, GIOChannel *io)
 }
 #endif
 
-static void add_lang_attr(sdp_record_t *r)
-{
-       sdp_lang_attr_t base_lang;
-       sdp_list_t *langs = 0;
-
-       /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */
-       base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
-       base_lang.encoding = 106;
-       base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
-       langs = sdp_list_append(0, &base_lang);
-       sdp_set_lang_attr(r, langs);
-       sdp_list_free(langs, 0);
-}
-
 static sdp_record_t *server_record_new(const char *name, uint16_t id)
 {
        sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto;
@@ -256,7 +242,7 @@ static sdp_record_t *server_record_new(const char *name, uint16_t id)
        aproto = sdp_list_append(NULL, apseq);
        sdp_set_access_protos(record, aproto);
 
-       add_lang_attr(record);
+       sdp_add_lang_attr(record);
 
        sdp_attr_add_new(record, SDP_ATTR_SECURITY_DESC,
                                SDP_UINT16, &security_desc);
@@ -359,13 +345,13 @@ static uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req,
 
        switch (req->uuid_size) {
        case 2: /* UUID16 */
-               *dst_role = ntohs(bt_get_unaligned((uint16_t *) dest));
-               *src_role = ntohs(bt_get_unaligned((uint16_t *) source));
+               *dst_role = bt_get_be16(dest);
+               *src_role = bt_get_be16(source);
                break;
        case 4: /* UUID32 */
        case 16: /* UUID128 */
-               *dst_role = ntohl(bt_get_unaligned((uint32_t *) dest));
-               *src_role = ntohl(bt_get_unaligned((uint32_t *) source));
+               *dst_role = bt_get_be32(dest);
+               *src_role = bt_get_be32(source);
                break;
        default:
                return BNEP_CONN_INVALID_SVC;
@@ -406,7 +392,6 @@ static gboolean server_disconnected_cb(GIOChannel *chan,
 {
        struct network_server *ns = NULL;
        struct network_session *session = NULL;
-       gboolean connected = FALSE;
        char address[20] = {0};
        GError *gerr = NULL;
        const char* paddr = address;
@@ -457,9 +442,6 @@ 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__
-       gboolean connected = TRUE;
-#endif
 
        if (cond & G_IO_NVAL)
                return FALSE;
@@ -823,16 +805,22 @@ static void path_unregister(void *data)
        adapter_free(na);
 }
 
-static GDBusMethodTable server_methods[] = {
-       { "Register",   "ss",   "",     register_server         },
-       { "Unregister", "s",    "",     unregister_server       },
+static const GDBusMethodTable server_methods[] = {
+       { GDBUS_METHOD("Register",
+                       GDBUS_ARGS({ "uuid", "s" }, { "bridge", "s" }), NULL,
+                       register_server) },
+       { GDBUS_METHOD("Unregister",
+                       GDBUS_ARGS({ "uuid", "s" }), NULL,
+                       unregister_server) },
        { }
 };
 
 #ifdef  __TIZEN_PATCH__
 static GDBusSignalTable server_signals[] = {
-       { "PeerConnected",      "ss"    },
-       { "PeerDisconnected",   "ss"    },
+       { GDBUS_SIGNAL("PeerConnected",
+                       GDBUS_ARGS({ "device", "s" }, { "address", "s" })) },
+       { GDBUS_SIGNAL("PeerDisconnected",
+                       GDBUS_ARGS({ "device", "s" }, { "address", "s" })) },
        { }
 };
 #endif
index d88acab..6351f6d 100644 (file)
@@ -25,5 +25,3 @@ int server_init(DBusConnection *conn, gboolean secure);
 void server_exit(void);
 int server_register(struct btd_adapter *adapter);
 int server_unregister(struct btd_adapter *adapter);
-
-int server_find_data(const char *path, const char *pattern);
index bce2dd9..5ce1e4f 100644 (file)
@@ -1,13 +1,13 @@
-Index: bluez-4.98/Makefile.tools
+Index: bluez-4.99/Makefile.tools
 ===================================================================
---- bluez-4.98.orig/Makefile.tools     2012-03-14 18:30:05.595203885 +0900
-+++ bluez-4.98/Makefile.tools  2012-03-14 19:39:16.815200856 +0900
-@@ -60,7 +60,7 @@
+--- bluez-4.99.org/Makefile.tools      2012-05-07 19:36:32.000000000 +0530
++++ bluez-4.99/Makefile.tools  2012-05-07 19:37:09.000000000 +0530
+@@ -75,7 +75,7 @@
                                attrib/gattrib.c btio/btio.c \
                                attrib/gatttool.h attrib/interactive.c \
-                               attrib/utils.c
+                               attrib/utils.c src/log.c
 -attrib_gatttool_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @READLINE_LIBS@
 +attrib_gatttool_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @READLINE_LIBS@ -lncurses
  endif
+
  dist_man_MANS += tools/rfcomm.1 tools/l2ping.8 \
index 8ed1234..441424f 100644 (file)
@@ -1,19 +1,15 @@
 Name:       bluez
 Summary:    Bluetooth utilities
-Version: 4.98
-Release:    1
+Version:    4.101
+Release:    2
 Group:      Applications/System
 License:    GPLv2+
 URL:        http://www.bluez.org/
 Source0:    http://www.kernel.org/pub/linux/bluetooth/%{name}-%{version}.tar.gz
 Patch1 :    bluez-ncurses.patch
 Requires:   dbus >= 0.60
-Requires:   usbutils
 Requires:   pciutils
 BuildRequires:  pkgconfig(dbus-1)
-BuildRequires:  pkgconfig(alsa)
-BuildRequires:  pkgconfig(udev)
-BuildRequires:  pkgconfig(sndfile)
 BuildRequires:  pkgconfig(glib-2.0)
 BuildRequires:  flex
 BuildRequires:  bison
@@ -63,9 +59,7 @@ use in Bluetooth applications.
 %build
 
 export CFLAGS="${CFLAGS} -D__TIZEN_PATCH__ -D__BROADCOM_PATCH__ "
-%ifnarch %{arm}
-export LDFLAGS="${LDFLAGS} -lncurses -Wl,--as-needed "
-%endif
+export LDFLAGS=" -lncurses -Wl,--as-needed "
 %reconfigure --disable-static \
                        --sysconfdir=%{_prefix}/etc \
                        --localstatedir=/opt/var \
@@ -79,15 +73,14 @@ export LDFLAGS="${LDFLAGS} -lncurses -Wl,--as-needed "
                         --enable-pcmcia=no \
                         --enable-hid2hci=no \
                         --enable-alsa=no \
-                        --enable-gstreamer \
+                        --enable-gstreamer=no \
                         --disable-dfutool \
                         --disable-cups \
-                        --disable-tests \
-                        --disable-udevrules \
+                       --enable-health \
                        --enable-dbusoob \
-                       --with-telephony=tizen
+                        --with-telephony=tizen
 
-make
+make %{?jobs:-j%jobs}
 
 %install
 rm -rf %{buildroot}
@@ -121,7 +114,7 @@ install -D -m 0644 network/network.conf %{buildroot}%{_prefix}/etc/bluetooth/net
 %{_bindir}/hcitool
 %dir %{_libdir}/bluetooth/plugins
 %dir /opt/var/lib/bluetooth
-%exclude /lib/udev/rules.d/97-bluetooth.rules
+%{_datadir}/dbus-1/system-services/org.bluez.service
 
 
 %files -n libbluetooth3
@@ -134,5 +127,3 @@ install -D -m 0644 network/network.conf %{buildroot}%{_prefix}/etc/bluetooth/net
 %{_includedir}/bluetooth/*
 %{_libdir}/libbluetooth.so
 %{_libdir}/pkgconfig/bluez.pc
-
-
index e154e92..d3341b5 100644 (file)
@@ -52,7 +52,7 @@
 #define MACHINE_INFO_FILE "machine-info"
 
 static GIOChannel *inotify = NULL;
-static int watch_fd = -1;
+static int watch_d = -1;
 
 /* This file is part of systemd's hostnamed functionality:
  * http://0pointer.de/public/systemd-man/machine-info.html
@@ -292,8 +292,8 @@ static int adaptername_init(void)
        mask |= IN_MOVED_FROM;
        mask |= IN_MOVED_TO;
 
-       watch_fd = inotify_add_watch(inot_fd, MACHINE_INFO_DIR, mask);
-       if (watch_fd < 0) {
+       watch_d = inotify_add_watch(inot_fd, MACHINE_INFO_DIR, mask);
+       if (watch_d < 0) {
                error("Failed to setup watch for '%s'", MACHINE_INFO_DIR);
                close(inot_fd);
                return 0;
@@ -310,8 +310,11 @@ static int adaptername_init(void)
 
 static void adaptername_exit(void)
 {
-       if (watch_fd >= 0)
-               close(watch_fd);
+       if (watch_d >= 0 && inotify != NULL) {
+               int inot_fd = g_io_channel_unix_get_fd(inotify);
+               inotify_rm_watch(inot_fd, watch_d);
+       }
+
        if (inotify != NULL) {
                g_io_channel_shutdown(inotify, FALSE, NULL);
                g_io_channel_unref(inotify);
index 2c03780..1791342 100644 (file)
@@ -175,12 +175,19 @@ static DBusMessage *remove_remote_data(DBusConnection *conn, DBusMessage *msg,
        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 const GDBusMethodTable oob_methods[] = {
+       { GDBUS_METHOD("AddRemoteData",
+                       GDBUS_ARGS({ "address", "s" }, { "hash", "ay" },
+                                       { "randomizer", "ay" }), NULL,
+                       add_remote_data) },
+       { GDBUS_METHOD("RemoveRemoteData",
+                       GDBUS_ARGS({ "address", "s" }), NULL,
+                       remove_remote_data) },
+       { GDBUS_ASYNC_METHOD("ReadLocalData",
+                       NULL, GDBUS_ARGS({ "hash", "ay" },
+                                               { "randomizer", "ay" }),
+                       read_local_data) },
+       { }
 };
 
 static int oob_probe(struct btd_adapter *adapter)
index 701c1d7..cd2c481 100644 (file)
@@ -37,6 +37,8 @@
 #include "gattrib.h"
 #include "gatt-service.h"
 #include "att.h"
+#include "gatt.h"
+#include "att-database.h"
 #include "attrib-server.h"
 
 /* FIXME: Not defined by SIG? UUID128? */
@@ -92,7 +94,8 @@ static gint adapter_cmp(gconstpointer a, gconstpointer b)
        return -1;
 }
 
-static uint8_t battery_state_read(struct attribute *a, gpointer user_data)
+static uint8_t battery_state_read(struct attribute *a,
+                                 struct btd_device *device, gpointer user_data)
 {
        struct btd_adapter *adapter = user_data;
        uint8_t value;
@@ -105,8 +108,11 @@ static uint8_t battery_state_read(struct attribute *a, gpointer user_data)
 
 static gboolean register_battery_service(struct btd_adapter *adapter)
 {
-       return gatt_service_add(adapter, GATT_PRIM_SVC_UUID,
-                       BATTERY_STATE_SVC_UUID,
+       bt_uuid_t uuid;
+
+       bt_uuid16_create(&uuid, BATTERY_STATE_SVC_UUID);
+
+       return gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid,
                        /* battery state characteristic */
                        GATT_OPT_CHR_UUID, BATTERY_STATE_UUID,
                        GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
@@ -129,7 +135,8 @@ static void register_termometer_service(struct gatt_example_adapter *adapter,
        bt_uuid_t uuid;
        int len;
 
-       start_handle = attrib_db_find_avail(adapter->adapter, svc_size);
+       bt_uuid16_create(&uuid, THERM_HUMIDITY_SVC_UUID);
+       start_handle = attrib_db_find_avail(adapter->adapter, &uuid, svc_size);
        if (start_handle == 0) {
                error("Not enough free handles to register service");
                return;
@@ -226,10 +233,10 @@ static void register_termometer_service(struct gatt_example_adapter *adapter,
        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,
+       attrib_db_add(adapter->adapter, h, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
                                                                atval, len);
 
-       g_assert(h - start_handle == svc_size);
+       g_assert(h - start_handle + 1 == svc_size);
 
        /* Add an SDP record for the above service */
        sdp_handle = attrib_create_sdp(adapter->adapter, start_handle,
@@ -250,7 +257,8 @@ static void register_manuf1_service(struct gatt_example_adapter *adapter,
        bt_uuid_t uuid;
        int len;
 
-       start_handle = attrib_db_find_avail(adapter->adapter, svc_size);
+       bt_uuid16_create(&uuid, MANUFACTURER_SVC_UUID);
+       start_handle = attrib_db_find_avail(adapter->adapter, &uuid, svc_size);
        if (start_handle == 0) {
                error("Not enough free handles to register service");
                return;
@@ -293,10 +301,10 @@ static void register_manuf1_service(struct gatt_example_adapter *adapter,
        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,
+       attrib_db_add(adapter->adapter, h, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
                                                                atval, len);
 
-       g_assert(h - start_handle == svc_size);
+       g_assert(h - start_handle + 1 == svc_size);
 
        range[0] = start_handle;
        range[1] = start_handle + svc_size - 1;
@@ -313,7 +321,8 @@ static void register_manuf2_service(struct gatt_example_adapter *adapter,
        bt_uuid_t uuid;
        int len;
 
-       start_handle = attrib_db_find_avail(adapter->adapter, svc_size);
+       bt_uuid16_create(&uuid, MANUFACTURER_SVC_UUID);
+       start_handle = attrib_db_find_avail(adapter->adapter, &uuid, svc_size);
        if (start_handle == 0) {
                error("Not enough free handles to register service");
                return;
@@ -356,10 +365,10 @@ static void register_manuf2_service(struct gatt_example_adapter *adapter,
        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,
+       attrib_db_add(adapter->adapter, h, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
                                                                atval, len);
 
-       g_assert(h - start_handle == svc_size);
+       g_assert(h - start_handle + 1 == svc_size);
 
        range[0] = start_handle;
        range[1] = start_handle + svc_size - 1;
@@ -373,7 +382,8 @@ static void register_vendor_service(struct gatt_example_adapter *adapter,
        uint8_t atval[256];
        bt_uuid_t uuid;
 
-       start_handle = attrib_db_find_avail(adapter->adapter, svc_size);
+       bt_uuid16_create(&uuid, VENDOR_SPECIFIC_SVC_UUID);
+       start_handle = attrib_db_find_avail(adapter->adapter, &uuid, svc_size);
        if (start_handle == 0) {
                error("Not enough free handles to register service");
                return;
@@ -405,10 +415,10 @@ static void register_vendor_service(struct gatt_example_adapter *adapter,
        atval[3] = 0x64;
        atval[4] = 0x6F;
        atval[5] = 0x72;
-       attrib_db_add(adapter->adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
+       attrib_db_add(adapter->adapter, h, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
                                                                atval, 6);
 
-       g_assert(h - start_handle == svc_size);
+       g_assert(h - start_handle + 1 == svc_size);
 
        range[0] = start_handle;
        range[1] = start_handle + svc_size - 1;
@@ -424,7 +434,7 @@ static void register_weight_service(struct gatt_example_adapter *adapter,
        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;
+       uint128_t prim_weight_uuid, char_weight_uuid;
        uint16_t start_handle, h;
        const int svc_size = 6;
        uint32_t sdp_handle;
@@ -433,8 +443,9 @@ static void register_weight_service(struct gatt_example_adapter *adapter,
        int len;
 
        btoh128(&char_weight_uuid_btorder, &char_weight_uuid);
-
-       start_handle = attrib_db_find_avail(adapter->adapter, svc_size);
+       btoh128(&prim_weight_uuid_btorder, &prim_weight_uuid);
+       bt_uuid128_create(&uuid, prim_weight_uuid);
+       start_handle = attrib_db_find_avail(adapter->adapter, &uuid, svc_size);
        if (start_handle == 0) {
                error("Not enough free handles to register service");
                return;
@@ -492,10 +503,9 @@ static void register_weight_service(struct gatt_example_adapter *adapter,
        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,
+       attrib_db_add(adapter->adapter, h, &uuid, ATT_NONE, ATT_NOT_PERMITTED,
                                                                atval, len);
-
-       g_assert(h - start_handle == svc_size);
+       g_assert(h - start_handle + 1 == svc_size);
 
        /* Add an SDP record for the above service */
        sdp_handle = attrib_create_sdp(adapter->adapter, start_handle,
@@ -553,8 +563,8 @@ static struct btd_adapter_driver gatt_example_adapter_driver = {
 
 static int gatt_example_init(void)
 {
-       if (!main_opts.attrib_server) {
-               DBG("Attribute server is disabled");
+       if (!main_opts.gatt_enabled) {
+               DBG("GATT is disabled");
                return -ENOTSUP;
        }
 
@@ -563,7 +573,7 @@ static int gatt_example_init(void)
 
 static void gatt_example_exit(void)
 {
-       if (!main_opts.attrib_server)
+       if (!main_opts.gatt_enabled)
                return;
 
        btd_unregister_adapter_driver(&gatt_example_adapter_driver);
index 77d2421..d74f2ea 100644 (file)
@@ -40,7 +40,6 @@
 
 #include <glib.h>
 
-#include "glib-compat.h"
 #include "hcid.h"
 #include "sdpd.h"
 #include "btio.h"
@@ -147,6 +146,7 @@ static struct dev_info {
 
        struct hci_version ver;
 
+       uint16_t did_source;
        uint16_t did_vendor;
        uint16_t did_product;
        uint16_t did_version;
@@ -171,6 +171,9 @@ static struct dev_info {
        GSList *need_name;
 
        guint stop_scan_id;
+
+       uint16_t discoverable_timeout;
+       guint discoverable_id;
 } *devs = NULL;
 
 static int found_dev_rssi_cmp(gconstpointer a, gconstpointer b)
@@ -495,7 +498,8 @@ static int init_ssp_mode(int index)
        return 0;
 }
 
-static int hciops_set_discoverable(int index, gboolean discoverable)
+static int hciops_set_discoverable(int index, gboolean discoverable,
+                                                       uint16_t timeout)
 {
        struct dev_info *dev = &devs[index];
        uint8_t mode;
@@ -511,6 +515,8 @@ static int hciops_set_discoverable(int index, gboolean discoverable)
                                                                1, &mode) < 0)
                return -errno;
 
+       dev->discoverable_timeout = timeout;
+
        return 0;
 }
 
@@ -559,7 +565,7 @@ static void set_event_mask(int index)
        }
 
        if (dev->features[3] & LMP_RSSI_INQ)
-               events[4] |= 0x04; /* Inquiry Result with RSSI */
+               events[4] |= 0x02; /* Inquiry Result with RSSI */
 
        if (dev->features[5] & LMP_SNIFF_SUBR)
                events[5] |= 0x20; /* Sniff Subrating */
@@ -647,16 +653,116 @@ static int hciops_stop_inquiry(int index)
        return 0;
 }
 
+static void update_ext_inquiry_response(int index)
+{
+       struct dev_info *dev = &devs[index];
+       write_ext_inquiry_response_cp cp;
+
+       DBG("hci%d", index);
+
+       if (!(dev->features[6] & LMP_EXT_INQ))
+               return;
+
+       if (dev->ssp_mode == 0)
+               return;
+
+       if (dev->cache_enable)
+               return;
+
+       memset(&cp, 0, sizeof(cp));
+
+       eir_create(dev->name, dev->tx_power, dev->did_vendor, dev->did_product,
+                       dev->did_version, dev->did_source, dev->uuids,
+                       cp.data);
+
+       if (memcmp(cp.data, dev->eir, sizeof(cp.data)) == 0)
+               return;
+
+       memcpy(dev->eir, cp.data, sizeof(cp.data));
+
+       if (hci_send_cmd(dev->sk, OGF_HOST_CTL,
+                               OCF_WRITE_EXT_INQUIRY_RESPONSE,
+                               WRITE_EXT_INQUIRY_RESPONSE_CP_SIZE, &cp) < 0)
+               error("Unable to write EIR data: %s (%d)",
+                                               strerror(errno), errno);
+}
+
+static int hciops_set_name(int index, const char *name)
+{
+       struct dev_info *dev = &devs[index];
+       change_local_name_cp cp;
+
+       DBG("hci%d, name %s", index, name);
+
+       memset(&cp, 0, sizeof(cp));
+       strncpy((char *) cp.name, name, sizeof(cp.name));
+
+       if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME,
+                               CHANGE_LOCAL_NAME_CP_SIZE, &cp) < 0)
+               return -errno;
+
+       memcpy(dev->name, cp.name, 248);
+       update_ext_inquiry_response(index);
+
+       return 0;
+}
+
+static int write_class(int index, uint32_t class)
+{
+       struct dev_info *dev = &devs[index];
+       write_class_of_dev_cp cp;
+
+       DBG("hci%d class 0x%06x", index, class);
+
+       memcpy(cp.dev_class, &class, 3);
+
+       if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV,
+                                       WRITE_CLASS_OF_DEV_CP_SIZE, &cp) < 0)
+               return -errno;
+
+       dev->pending_cod = class;
+
+       return 0;
+}
+
+static int hciops_set_dev_class(int index, uint8_t major, uint8_t minor)
+{
+       struct dev_info *dev = &devs[index];
+       int err;
+
+       DBG("hci%d major %u minor %u", index, major, minor);
+
+       /* Update only the major and minor class bits keeping remaining bits
+        * intact*/
+       dev->wanted_cod &= 0xffe000;
+       dev->wanted_cod |= ((major & 0x1f) << 8) | minor;
+
+       if (dev->wanted_cod == dev->current_cod ||
+                       dev->cache_enable || dev->pending_cod)
+               return 0;
+
+       DBG("Changing Major/Minor class to 0x%06x", dev->wanted_cod);
+
+       err = write_class(index, dev->wanted_cod);
+       if (err < 0)
+               error("Adapter class update failed: %s (%d)",
+                                               strerror(-err), -err);
+
+       return err;
+}
+
 static gboolean init_adapter(int index)
 {
        struct dev_info *dev = &devs[index];
        struct btd_adapter *adapter = NULL;
        gboolean existing_adapter = dev->registered;
-       uint8_t mode, on_mode;
+       uint8_t mode, on_mode, major, minor;
        gboolean pairable, discoverable;
+       const char *name;
+       uint16_t discoverable_timeout;
 
        if (!dev->registered) {
-               adapter = btd_manager_register_adapter(index);
+               adapter = btd_manager_register_adapter(index, TRUE);
                if (adapter)
                        dev->registered = TRUE;
        } else {
@@ -668,7 +774,9 @@ static gboolean init_adapter(int index)
        if (adapter == NULL)
                return FALSE;
 
-       btd_adapter_get_mode(adapter, &mode, &on_mode, &pairable);
+       btd_adapter_get_mode(adapter, &mode, &on_mode,
+                                               &discoverable_timeout,
+                                               &pairable);
 
        if (existing_adapter)
                mode = on_mode;
@@ -679,11 +787,19 @@ static gboolean init_adapter(int index)
        }
 
        start_adapter(index);
+
+       name = btd_adapter_get_name(adapter);
+       if (name)
+               hciops_set_name(index, name);
+
+       btd_adapter_get_class(adapter, &major, &minor);
+       hciops_set_dev_class(index, major, minor);
+
        btd_adapter_start(adapter);
 
        discoverable = (mode == MODE_DISCOVERABLE);
 
-       hciops_set_discoverable(index, discoverable);
+       hciops_set_discoverable(index, discoverable, discoverable_timeout);
        hciops_set_pairable(index, pairable);
 
        if (dev->already_up)
@@ -771,13 +887,14 @@ fail:
 }
 
 static int hciops_set_did(int index, uint16_t vendor, uint16_t product,
-                                                       uint16_t version)
+                                       uint16_t version, uint16_t source)
 {
        struct dev_info *dev = &devs[index];
 
        dev->did_vendor = vendor;
        dev->did_product = product;
        dev->did_version = version;
+       dev->did_source = source;
 
        return 0;
 }
@@ -1028,12 +1145,12 @@ static void link_key_notify(int index, void *ptr)
        DBG("local auth 0x%02x and remote auth 0x%02x",
                                        conn->loc_auth, conn->rem_auth);
 
-       if (key_type == 0x06) {
+       if (key_type == HCI_LK_CHANGED_COMBINATION) {
                /* Some buggy controller combinations generate a changed
                 * combination key for legacy pairing even when there's no
                 * previous key */
                if (conn->rem_auth == 0xff && old_key_type == 0xff)
-                       key_type = 0x00;
+                       key_type = HCI_LK_COMBINATION;
                else if (old_key_type != 0xff)
                        key_type = old_key_type;
                else
@@ -1045,7 +1162,7 @@ static void link_key_notify(int index, void *ptr)
        key_info->type = key_type;
 
        /* Skip the storage check if this is a debug key */
-       if (key_type == 0x03)
+       if (key_type == HCI_LK_DEBUG_COMBINATION)
                goto done;
 
        /* Store the link key persistently if one of the following is true:
@@ -1059,7 +1176,9 @@ static void link_key_notify(int index, void *ptr)
         * If none of the above match only keep the link key around for
         * this connection and set the temporary flag for the device.
         */
-       if (key_type < 0x03 || (key_type == 0x06 && old_key_type != 0xff) ||
+       if (key_type < HCI_LK_DEBUG_COMBINATION ||
+                       (key_type == HCI_LK_CHANGED_COMBINATION
+                                       && old_key_type != HCI_LK_INVALID) ||
                        (conn->loc_auth > 0x01 && conn->rem_auth > 0x01) ||
                        (conn->loc_auth == 0x02 || conn->loc_auth == 0x03) ||
                        (conn->rem_auth == 0x02 || conn->rem_auth == 0x03)) {
@@ -1123,7 +1242,8 @@ static void return_link_keys(int index, void *ptr)
 
 /* Simple Pairing handling */
 
-static int hciops_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success)
+static int hciops_confirm_reply(int index, bdaddr_t *bdaddr, uint8_t bdaddr_type,
+                                                       gboolean success)
 {
        struct dev_info *dev = &devs[index];
        user_confirm_reply_cp cp;
@@ -1184,7 +1304,8 @@ static void user_confirm_request(int index, void *ptr)
                /* Wait 5 milliseconds before doing auto-accept */
                usleep(5000);
 
-               if (hciops_confirm_reply(index, &req->bdaddr, TRUE) < 0)
+               if (hciops_confirm_reply(index, &req->bdaddr,
+                                               BDADDR_BREDR, TRUE) < 0)
                        goto fail;
 
                return;
@@ -1491,39 +1612,6 @@ static void read_local_features_complete(int index,
                init_adapter(index);
 }
 
-static void update_ext_inquiry_response(int index)
-{
-       struct dev_info *dev = &devs[index];
-       write_ext_inquiry_response_cp cp;
-
-       DBG("hci%d", index);
-
-       if (!(dev->features[6] & LMP_EXT_INQ))
-               return;
-
-       if (dev->ssp_mode == 0)
-               return;
-
-       if (dev->cache_enable)
-               return;
-
-       memset(&cp, 0, sizeof(cp));
-
-       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;
-
-       memcpy(dev->eir, cp.data, sizeof(cp.data));
-
-       if (hci_send_cmd(dev->sk, OGF_HOST_CTL,
-                               OCF_WRITE_EXT_INQUIRY_RESPONSE,
-                               WRITE_EXT_INQUIRY_RESPONSE_CP_SIZE, &cp) < 0)
-               error("Unable to write EIR data: %s (%d)",
-                                               strerror(errno), errno);
-}
-
 static void update_name(int index, const char *name)
 {
        struct btd_adapter *adapter;
@@ -1646,38 +1734,13 @@ static inline void cmd_status(int index, void *ptr)
                cs_inquiry_evt(index, evt->status);
 }
 
-static void read_scan_complete(int index, uint8_t status, void *ptr)
-{
-       struct btd_adapter *adapter;
-       read_scan_enable_rp *rp = ptr;
-
-       DBG("hci%d status %u", index, status);
-
-       adapter = manager_find_adapter_by_id(index);
-       if (!adapter) {
-               error("Unable to find matching adapter");
-               return;
-       }
-
-       adapter_mode_changed(adapter, rp->enable);
-}
-
-static int write_class(int index, uint32_t class)
+static gboolean discoverable_timeout_handler(gpointer user_data)
 {
-       struct dev_info *dev = &devs[index];
-       write_class_of_dev_cp cp;
-
-       DBG("hci%d class 0x%06x", index, class);
-
-       memcpy(cp.dev_class, &class, 3);
-
-       if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV,
-                                       WRITE_CLASS_OF_DEV_CP_SIZE, &cp) < 0)
-               return -errno;
+       struct dev_info *dev = user_data;
 
-       dev->pending_cod = class;
+       hciops_set_discoverable(dev->id, FALSE, 0);
 
-       return 0;
+       return FALSE;
 }
 
 /* Limited Discoverable bit mask in CoD */
@@ -1717,6 +1780,65 @@ static int hciops_set_limited_discoverable(int index, gboolean limited)
        return write_class(index, dev->wanted_cod);
 }
 
+static void reset_discoverable_timeout(int index)
+{
+       struct dev_info *dev = &devs[index];
+
+       if (dev->discoverable_id > 0) {
+               g_source_remove(dev->discoverable_id);
+               dev->discoverable_id = 0;
+       }
+}
+
+static void set_discoverable_timeout(int index)
+{
+       struct dev_info *dev = &devs[index];
+
+       reset_discoverable_timeout(index);
+
+       if (dev->discoverable_timeout == 0) {
+               hciops_set_limited_discoverable(index, FALSE);
+               return;
+       }
+
+       /* Set limited discoverable if pairable and interval between 0 to 60
+          sec */
+       if (dev->pairable && dev->discoverable_timeout <= 60)
+               hciops_set_limited_discoverable(index, TRUE);
+       else
+               hciops_set_limited_discoverable(index, FALSE);
+
+       dev->discoverable_id = g_timeout_add_seconds(dev->discoverable_timeout,
+                                               discoverable_timeout_handler,
+                                               dev);
+}
+
+static void read_scan_complete(int index, uint8_t status, void *ptr)
+{
+       struct btd_adapter *adapter;
+       read_scan_enable_rp *rp = ptr;
+
+       DBG("hci%d status %u", index, status);
+
+       switch (rp->enable) {
+       case (SCAN_PAGE | SCAN_INQUIRY):
+       case SCAN_INQUIRY:
+               set_discoverable_timeout(index);
+               break;
+       default:
+               reset_discoverable_timeout(index);
+               hciops_set_limited_discoverable(index, FALSE);
+       }
+
+       adapter = manager_find_adapter_by_id(index);
+       if (!adapter) {
+               error("Unable to find matching adapter");
+               return;
+       }
+
+       adapter_mode_changed(adapter, rp->enable);
+}
+
 static void write_class_complete(int index, uint8_t status)
 {
        struct dev_info *dev = &devs[index];
@@ -1948,9 +2070,9 @@ 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)
+static void dev_found(struct dev_info *info, bdaddr_t *dba, uint8_t bdaddr_type,
+                               uint8_t *cod, int8_t rssi, uint8_t cfm_name,
+                               uint8_t *eir, size_t eir_len)
 {
        struct found_dev *dev;
        GSList *match;
@@ -1969,10 +2091,14 @@ static void dev_found(struct dev_info *info, bdaddr_t *dba, addr_type_t type,
        else
                dev->name_state = NAME_NOT_NEEDED;
 
+       if (cod && !eir_has_data_type(eir, eir_len, EIR_CLASS_OF_DEV))
+               eir_len = eir_append_data(eir, eir_len, EIR_CLASS_OF_DEV,
+                                                               cod, 3);
+
        info->found_devs = g_slist_prepend(info->found_devs, dev);
 
 event:
-       btd_event_device_found(&info->bdaddr, dba, type, cod, rssi, cfm_name,
+       btd_event_device_found(&info->bdaddr, dba, bdaddr_type, rssi, cfm_name,
                                                                eir, eir_len);
 }
 
@@ -1984,12 +2110,11 @@ static inline void inquiry_result(int index, int plen, void *ptr)
 
        for (i = 0; i < num; i++) {
                inquiry_info *info = ptr;
-               uint32_t class = info->dev_class[0] |
-                                               (info->dev_class[1] << 8) |
-                                               (info->dev_class[2] << 16);
+               uint8_t eir[5];
 
-               dev_found(dev, &info->bdaddr, ADDR_TYPE_BREDR, class, 0, 1,
-                                                               NULL, 0);
+               memset(eir, 0, sizeof(eir));
+               dev_found(dev, &info->bdaddr, BDADDR_BREDR, info->dev_class,
+                                                               0, 1, eir, 0);
                ptr += INQUIRY_INFO_SIZE;
        }
 }
@@ -1998,6 +2123,7 @@ static inline void inquiry_result_with_rssi(int index, int plen, void *ptr)
 {
        struct dev_info *dev = &devs[index];
        uint8_t num = *(uint8_t *) ptr++;
+       uint8_t eir[5];
        int i;
 
        if (!num)
@@ -2006,23 +2132,21 @@ static inline void inquiry_result_with_rssi(int index, int plen, void *ptr)
        if ((plen - 1) / num == INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE) {
                for (i = 0; i < num; i++) {
                        inquiry_info_with_rssi_and_pscan_mode *info = ptr;
-                       uint32_t class = info->dev_class[0]
-                                               | (info->dev_class[1] << 8)
-                                               | (info->dev_class[2] << 16);
 
-                       dev_found(dev, &info->bdaddr, ADDR_TYPE_BREDR, class,
-                                               info->rssi, 1, NULL, 0);
+                       memset(eir, 0, sizeof(eir));
+                       dev_found(dev, &info->bdaddr, BDADDR_BREDR,
+                                               info->dev_class, info->rssi,
+                                               1, eir, 0);
                        ptr += INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE;
                }
        } else {
                for (i = 0; i < num; i++) {
                        inquiry_info_with_rssi *info = ptr;
-                       uint32_t class = info->dev_class[0]
-                                               | (info->dev_class[1] << 8)
-                                               | (info->dev_class[2] << 16);
 
-                       dev_found(dev, &info->bdaddr, ADDR_TYPE_BREDR, class,
-                                               info->rssi, 1, NULL, 0);
+                       memset(eir, 0, sizeof(eir));
+                       dev_found(dev, &info->bdaddr, BDADDR_BREDR,
+                                               info->dev_class, info->rssi,
+                                               1, eir, 0);
                        ptr += INQUIRY_INFO_WITH_RSSI_SIZE;
                }
        }
@@ -2036,19 +2160,22 @@ static inline void extended_inquiry_result(int index, int plen, void *ptr)
 
        for (i = 0; i < num; i++) {
                extended_inquiry_info *info = ptr;
-               uint32_t class = info->dev_class[0]
-                                       | (info->dev_class[1] << 8)
-                                       | (info->dev_class[2] << 16);
+               uint8_t eir[sizeof(info->data) + 5];
                gboolean cfm_name;
+               size_t eir_len;
+
+               eir_len = eir_length(info->data, sizeof(info->data));
 
-               if (eir_has_complete_name(info->data, sizeof(info->data)))
+               memset(eir, 0, sizeof(eir));
+               memcpy(eir, info->data, eir_len);
+
+               if (eir_has_data_type(eir, eir_len, EIR_NAME_COMPLETE))
                        cfm_name = FALSE;
                else
                        cfm_name = TRUE;
 
-               dev_found(dev, &info->bdaddr, ADDR_TYPE_BREDR, class,
-                                       info->rssi, cfm_name,
-                                       info->data, sizeof(info->data));
+               dev_found(dev, &info->bdaddr, BDADDR_BREDR, info->dev_class,
+                                       info->rssi, cfm_name, eir, eir_len);
                ptr += EXTENDED_INQUIRY_INFO_SIZE;
        }
 }
@@ -2153,7 +2280,8 @@ static inline void conn_complete(int index, void *ptr)
        conn = get_connection(dev, &evt->bdaddr);
        conn->handle = btohs(evt->handle);
 
-       btd_event_conn_complete(&dev->bdaddr, &evt->bdaddr);
+       btd_event_conn_complete(&dev->bdaddr, &evt->bdaddr, BDADDR_BREDR,
+                                                               NULL, NULL);
 
        if (conn->secmode3)
                bonding_complete(dev, conn, 0);
@@ -2172,6 +2300,17 @@ static inline void conn_complete(int index, void *ptr)
                free(str);
 }
 
+static inline uint8_t le_addr_type(uint8_t bdaddr_type)
+{
+       switch (bdaddr_type) {
+       case LE_RANDOM_ADDRESS:
+               return BDADDR_LE_RANDOM;
+       case LE_PUBLIC_ADDRESS:
+       default:
+               return BDADDR_LE_PUBLIC;
+       }
+}
+
 static inline void le_conn_complete(int index, void *ptr)
 {
        struct dev_info *dev = &devs[index];
@@ -2179,6 +2318,7 @@ static inline void le_conn_complete(int index, void *ptr)
        char filename[PATH_MAX];
        char local_addr[18], peer_addr[18], *str;
        struct bt_conn *conn;
+       uint8_t bdaddr_type;
 
        if (evt->status) {
                btd_event_conn_failed(&dev->bdaddr, &evt->peer_bdaddr,
@@ -2189,7 +2329,9 @@ static inline void le_conn_complete(int index, void *ptr)
        conn = get_connection(dev, &evt->peer_bdaddr);
        conn->handle = btohs(evt->handle);
 
-       btd_event_conn_complete(&dev->bdaddr, &evt->peer_bdaddr);
+       bdaddr_type = le_addr_type(evt->peer_bdaddr_type);
+       btd_event_conn_complete(&dev->bdaddr, &evt->peer_bdaddr, bdaddr_type,
+                                                               NULL, NULL);
 
        /* check if the remote version needs be requested */
        ba2str(&dev->bdaddr, local_addr);
@@ -2263,17 +2405,6 @@ 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];
@@ -2286,8 +2417,8 @@ static inline void le_advertising_report(int index, evt_le_meta_event *meta)
        info = (le_advertising_info *) &meta->data[1];
        rssi = *(info->data + info->length);
 
-       dev_found(dev, &info->bdaddr, le_addr_type(info->bdaddr_type), 0, rssi,
-                                               0, info->data, info->length);
+       dev_found(dev, &info->bdaddr, le_addr_type(info->bdaddr_type), NULL,
+                                       rssi, 0, info->data, info->length);
 
        num_reports--;
 
@@ -2297,7 +2428,7 @@ static inline void le_advertising_report(int index, evt_le_meta_event *meta)
                rssi = *(info->data + info->length);
 
                dev_found(dev, &info->bdaddr, le_addr_type(info->bdaddr_type),
-                               0, rssi, 0, info->data, info->length);
+                               NULL, rssi, 0, info->data, info->length);
        }
 }
 
@@ -2786,6 +2917,7 @@ static void device_event(int event, int index)
                devs[index].pending_cod = 0;
                devs[index].cache_enable = TRUE;
                devs[index].discov_state = DISCOV_HALTED;
+               reset_discoverable_timeout(index);
                if (!devs[index].pending) {
                        struct btd_adapter *adapter;
 
@@ -3021,32 +3153,6 @@ static int hciops_set_powered(int index, gboolean powered)
        return err;
 }
 
-static int hciops_set_dev_class(int index, uint8_t major, uint8_t minor)
-{
-       struct dev_info *dev = &devs[index];
-       int err;
-
-       DBG("hci%d major %u minor %u", index, major, minor);
-
-       /* Update only the major and minor class bits keeping remaining bits
-        * intact*/
-       dev->wanted_cod &= 0xffe000;
-       dev->wanted_cod |= ((major & 0x1f) << 8) | minor;
-
-       if (dev->wanted_cod == dev->current_cod ||
-                       dev->cache_enable || dev->pending_cod)
-               return 0;
-
-       DBG("Changing Major/Minor class to 0x%06x", dev->wanted_cod);
-
-       err = write_class(index, dev->wanted_cod);
-       if (err < 0)
-               error("Adapter class update failed: %s (%d)",
-                                               strerror(-err), -err);
-
-       return err;
-}
-
 static int start_inquiry(int index, uint8_t length)
 {
        struct dev_info *dev = &devs[index];
@@ -3144,26 +3250,6 @@ static int hciops_stop_scanning(int index)
        return le_set_scan_enable(index, 0);
 }
 
-static int hciops_set_name(int index, const char *name)
-{
-       struct dev_info *dev = &devs[index];
-       change_local_name_cp cp;
-
-       DBG("hci%d, name %s", index, name);
-
-       memset(&cp, 0, sizeof(cp));
-       strncpy((char *) cp.name, name, sizeof(cp.name));
-
-       if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME,
-                               CHANGE_LOCAL_NAME_CP_SIZE, &cp) < 0)
-               return -errno;
-
-       memcpy(dev->name, cp.name, 248);
-       update_ext_inquiry_response(index);
-
-       return 0;
-}
-
 static int cancel_resolve_name(int index)
 {
        struct dev_info *info = &devs[index];
@@ -3294,7 +3380,8 @@ static int hciops_read_bdaddr(int index, bdaddr_t *bdaddr)
        return 0;
 }
 
-static int hciops_block_device(int index, bdaddr_t *bdaddr)
+static int hciops_block_device(int index, bdaddr_t *bdaddr,
+                                               uint8_t bdaddr_type)
 {
        struct dev_info *dev = &devs[index];
        char addr[18];
@@ -3308,7 +3395,8 @@ static int hciops_block_device(int index, bdaddr_t *bdaddr)
        return 0;
 }
 
-static int hciops_unblock_device(int index, bdaddr_t *bdaddr)
+static int hciops_unblock_device(int index, bdaddr_t *bdaddr,
+                                               uint8_t bdaddr_type)
 {
        struct dev_info *dev = &devs[index];
        char addr[18];
@@ -3341,14 +3429,15 @@ static int hciops_get_conn_list(int index, GSList **conns)
        return 0;
 }
 
-static int hciops_disconnect(int index, bdaddr_t *bdaddr)
+static int hciops_disconnect(int index, bdaddr_t *bdaddr, uint8_t bdaddr_type)
 {
        DBG("hci%d", index);
 
        return disconnect_addr(index, bdaddr, HCI_OE_USER_ENDED_CONNECTION);
 }
 
-static int hciops_remove_bonding(int index, bdaddr_t *bdaddr)
+static int hciops_remove_bonding(int index, bdaddr_t *bdaddr,
+                                                       uint8_t bdaddr_type)
 {
        struct dev_info *dev = &devs[index];
        delete_stored_link_key_cp cp;
@@ -3407,7 +3496,8 @@ static int hciops_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin,
        return err;
 }
 
-static int hciops_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey)
+static int hciops_passkey_reply(int index, bdaddr_t *bdaddr,
+                                       uint8_t bdaddr_type, uint32_t passkey)
 {
        struct dev_info *dev = &devs[index];
        char addr[18];
@@ -3556,6 +3646,7 @@ static int hciops_restore_powered(int index)
 static int hciops_load_keys(int index, GSList *keys, gboolean debug_keys)
 {
        struct dev_info *dev = &devs[index];
+       GSList *l;
 
        DBG("hci%d keys %d debug_keys %d", index, g_slist_length(keys),
                                                                debug_keys);
@@ -3563,7 +3654,16 @@ static int hciops_load_keys(int index, GSList *keys, gboolean debug_keys)
        if (dev->keys != NULL)
                return -EEXIST;
 
-       dev->keys = keys;
+       for (l = keys; l; l = l->next) {
+               struct link_key_info *orig, *dup;
+
+               orig = l->data;
+
+               dup = g_memdup(orig, sizeof(*orig));
+
+               dev->keys = g_slist_prepend(dev->keys, dup);
+       }
+
        dev->debug_keys = debug_keys;
 
        return 0;
@@ -3573,7 +3673,10 @@ static int hciops_set_io_capability(int index, uint8_t io_capability)
 {
        struct dev_info *dev = &devs[index];
 
-       dev->io_capability = io_capability;
+       /* hciops is not to be used for SMP pairing for LE devices. So
+        * change the IO capability from KeyboardDisplay to DisplayYesNo
+        * in case it is set. */
+       dev->io_capability = (io_capability == 0x04) ? 0x01 : io_capability;
 
        return 0;
 }
@@ -3625,7 +3728,8 @@ failed:
        bonding_complete(dev, conn, HCI_UNSPECIFIED_ERROR);
 }
 
-static int hciops_create_bonding(int index, bdaddr_t *bdaddr, uint8_t io_cap)
+static int hciops_create_bonding(int index, bdaddr_t *bdaddr,
+                                       uint8_t bdaddr_type, uint8_t io_cap)
 {
        struct dev_info *dev = &devs[index];
        BtIOSecLevel sec_level;
@@ -3637,7 +3741,10 @@ static int hciops_create_bonding(int index, bdaddr_t *bdaddr, uint8_t io_cap)
        if (conn->io != NULL)
                return -EBUSY;
 
-       conn->loc_cap = io_cap;
+       /* hciops is not to be used for SMP pairing for LE devices. So
+        * change the IO capability from KeyboardDisplay to DisplayYesNo
+        * in case it is set. */
+       conn->loc_cap = (io_cap == 0x04 ? 0x01 : io_cap);
 
        /* If our IO capability is NoInputNoOutput use medium security
         * level (i.e. don't require MITM protection) else use high
@@ -3743,7 +3850,7 @@ static int hciops_remove_remote_oob_data(int index, bdaddr_t *bdaddr)
 }
 
 static int hciops_confirm_name(int index, bdaddr_t *bdaddr,
-                                                       gboolean name_known)
+                               uint8_t bdaddr_type, gboolean name_known)
 {
        struct dev_info *info = &devs[index];
        struct found_dev *dev;
@@ -3777,13 +3884,17 @@ static int hciops_confirm_name(int index, bdaddr_t *bdaddr,
        return 0;
 }
 
+static int hciops_load_ltks(int index, GSList *keys)
+{
+       return -ENOSYS;
+}
+
 static struct btd_adapter_ops hci_ops = {
        .setup = hciops_setup,
        .cleanup = hciops_cleanup,
        .set_powered = hciops_set_powered,
        .set_discoverable = hciops_set_discoverable,
        .set_pairable = hciops_set_pairable,
-       .set_limited_discoverable = hciops_set_limited_discoverable,
        .start_discovery = hciops_start_discovery,
        .stop_discovery = hciops_stop_discovery,
        .set_name = hciops_set_name,
@@ -3813,6 +3924,7 @@ static struct btd_adapter_ops hci_ops = {
        .add_remote_oob_data = hciops_add_remote_oob_data,
        .remove_remote_oob_data = hciops_remove_remote_oob_data,
        .confirm_name = hciops_confirm_name,
+       .load_ltks = hciops_load_ltks,
 };
 
 static int hciops_init(void)
index 6c34116..4819af4 100644 (file)
@@ -130,7 +130,6 @@ static void read_radio_states_cb(DBusPendingCall *call, void *user_data)
                goto done;
        }
 
-       dbus_error_init(&derr);
        if (dbus_message_get_args(reply, &derr,
                                DBUS_TYPE_UINT32, &radio_states,
                                DBUS_TYPE_INVALID) == FALSE) {
index 23dc552..16a97c9 100644 (file)
 #include "device.h"
 #include "event.h"
 #include "oob.h"
+#include "eir.h"
 
 #define MGMT_BUF_SIZE 1024
 
+struct pending_uuid {
+       uuid_t uuid;
+       uint8_t svc_hint;
+};
+
 static int max_index = -1;
 static struct controller_info {
        gboolean valid;
@@ -62,6 +68,17 @@ static struct controller_info {
        uint32_t current_settings;
        uint8_t dev_class[3];
        GSList *connections;
+       uint8_t discov_type;
+
+       gboolean pending_uuid;
+       GSList *pending_uuids;
+
+       gboolean pending_class;
+       uint8_t major;
+       uint8_t minor;
+
+       gboolean pending_powered;
+       gboolean pending_cod_change;
 } *controllers = NULL;
 
 static int mgmt_sock = -1;
@@ -76,8 +93,9 @@ static void read_version_complete(int sk, void *buf, size_t len)
        struct mgmt_rp_read_version *rp = buf;
 
        if (len < sizeof(*rp)) {
-               error("Too small read version complete event");
-               return;
+               error("Too small read version complete event"
+                               " (probably an old kernel)");
+               abort();
        }
 
        mgmt_revision = btohs(bt_get_unaligned(&rp->revision));
@@ -85,6 +103,12 @@ static void read_version_complete(int sk, void *buf, size_t len)
 
        DBG("version %u revision %u", mgmt_version, mgmt_revision);
 
+       if (mgmt_version < 1) {
+               error("Version 1 of mgmt needed (kernel has version %u)",
+                                                               mgmt_version);
+               abort();
+       }
+
        memset(&hdr, 0, sizeof(hdr));
        hdr.opcode = htobs(MGMT_OP_READ_INDEX_LIST);
        hdr.index = htobs(MGMT_INDEX_NONE);
@@ -95,15 +119,19 @@ static void read_version_complete(int sk, void *buf, size_t len)
 
 static void add_controller(uint16_t index)
 {
+       struct controller_info *info;
+
        if (index > max_index) {
                size_t size = sizeof(struct controller_info) * (index + 1);
                max_index = index;
                controllers = g_realloc(controllers, size);
        }
 
-       memset(&controllers[index], 0, sizeof(struct controller_info));
+       info = &controllers[index];
+
+       memset(info, 0, sizeof(*info));
 
-       controllers[index].valid = TRUE;
+       info->valid = TRUE;
 
        DBG("Added controller %u", index);
 }
@@ -150,6 +178,9 @@ static void remove_controller(uint16_t index)
 
        btd_manager_unregister_adapter(index);
 
+       g_slist_free_full(controllers[index].pending_uuids, g_free);
+       controllers[index].pending_uuids = NULL;
+
        memset(&controllers[index], 0, sizeof(struct controller_info));
 
        DBG("Removed controller %u", index);
@@ -185,7 +216,8 @@ static int mgmt_set_connectable(int index, gboolean connectable)
        return mgmt_set_mode(index, MGMT_OP_SET_CONNECTABLE, connectable);
 }
 
-static int mgmt_set_discoverable(int index, gboolean discoverable)
+static int mgmt_set_discoverable(int index, gboolean discoverable,
+                                                       uint16_t timeout)
 {
        char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_discoverable)];
        struct mgmt_hdr *hdr = (void *) buf;
@@ -199,6 +231,7 @@ static int mgmt_set_discoverable(int index, gboolean discoverable)
        hdr->len = htobs(sizeof(*cp));
 
        cp->val = discoverable;
+       cp->timeout = timeout;
 
        if (write(mgmt_sock, buf, sizeof(buf)) < 0)
                return -errno;
@@ -270,33 +303,61 @@ static uint8_t create_mode(uint32_t settings)
        return mode;
 }
 
-static int mgmt_update_powered(struct btd_adapter *adapter, uint32_t settings)
+static void update_settings(struct btd_adapter *adapter, uint32_t settings)
 {
+       struct controller_info *info;
        gboolean pairable;
        uint8_t on_mode;
-       uint16_t index;
+       uint16_t index, discoverable_timeout;
 
-       if (!mgmt_powered(settings)) {
-               btd_adapter_stop(adapter);
-               return 0;
-       }
-
-       btd_adapter_start(adapter);
+       DBG("new settings %x", settings);
 
-       btd_adapter_get_mode(adapter, NULL, &on_mode, &pairable);
+       btd_adapter_get_mode(adapter, NULL, &on_mode, &discoverable_timeout,
+                                                               &pairable);
 
        index = adapter_get_dev_id(adapter);
 
-       if (on_mode == MODE_DISCOVERABLE && !mgmt_discoverable(settings))
-               mgmt_set_discoverable(index, TRUE);
-       else if (on_mode == MODE_CONNECTABLE && !mgmt_connectable(settings))
+       info = &controllers[index];
+
+       if (on_mode == MODE_DISCOVERABLE && !mgmt_discoverable(settings)) {
+               if(!mgmt_connectable(settings))
+                       mgmt_set_connectable(index, TRUE);
+               mgmt_set_discoverable(index, TRUE, discoverable_timeout);
+       } else if (on_mode == MODE_CONNECTABLE && !mgmt_connectable(settings)) {
                mgmt_set_connectable(index, TRUE);
-       else
+       } else if (mgmt_powered(settings)) {
                adapter_mode_changed(adapter, create_mode(settings));
+       }
 
        if (mgmt_pairable(settings) != pairable)
                mgmt_set_pairable(index, pairable);
 
+       if (mgmt_ssp(info->supported_settings) && !mgmt_ssp(settings))
+               mgmt_set_mode(index, MGMT_OP_SET_SSP, 1);
+
+       if (mgmt_low_energy(info->supported_settings) &&
+                                               !mgmt_low_energy(settings))
+               mgmt_set_mode(index, MGMT_OP_SET_LE, 1);
+}
+
+static int mgmt_update_powered(struct btd_adapter *adapter,
+                                               struct controller_info *info,
+                                               uint32_t settings)
+{
+       if (!mgmt_powered(settings)) {
+               btd_adapter_stop(adapter);
+               g_slist_free_full(info->pending_uuids, g_free);
+               info->pending_uuids = NULL;
+               info->pending_uuid = FALSE;
+               info->pending_class = FALSE;
+               info->pending_cod_change = FALSE;
+               return 0;
+       }
+
+       btd_adapter_start(adapter);
+
+       update_settings(adapter, settings);
+
        return 0;
 }
 
@@ -316,6 +377,7 @@ static void mgmt_new_settings(int sk, uint16_t index, void *buf, size_t len)
        uint32_t settings, *ev = buf;
        struct controller_info *info;
        struct btd_adapter *adapter;
+       gboolean old_power, new_power, old_pairable, new_pairable;
 
        if (len < sizeof(*ev)) {
                error("Too small new settings event");
@@ -339,12 +401,20 @@ static void mgmt_new_settings(int sk, uint16_t index, void *buf, size_t len)
 
        settings = bt_get_le32(ev);
 
-       if (mgmt_powered(settings) != mgmt_powered(info->current_settings))
-               mgmt_update_powered(adapter, settings);
-       else if (mode_changed(settings, info->current_settings))
+       old_power = mgmt_powered(info->current_settings);
+       new_power = mgmt_powered(settings);
+
+       if (new_power != old_power)
+               mgmt_update_powered(adapter, info, settings);
+       else if (new_power && mode_changed(settings, info->current_settings))
                adapter_mode_changed(adapter, create_mode(settings));
 
-       if (mgmt_pairable(settings) != mgmt_pairable(info->current_settings))
+       old_pairable = mgmt_pairable(info->current_settings);
+       new_pairable = mgmt_pairable(settings);
+
+       /* Check for pairable change, except when powered went from True
+        * to False (in which case we always get all settings as False) */
+       if ((!old_power || new_power) && new_pairable != old_pairable)
                btd_adapter_pairable_changed(adapter, mgmt_pairable(settings));
 
        info->current_settings = settings;
@@ -366,7 +436,7 @@ static void mgmt_new_link_key(int sk, uint16_t index, void *buf, size_t len)
        struct controller_info *info;
 
        if (len != sizeof(*ev)) {
-               error("new_key event size mismatch (%zu != %zu)",
+               error("mgmt_new_link_key event size mismatch (%zu != %zu)",
                                                        len, sizeof(*ev));
                return;
        }
@@ -388,17 +458,19 @@ static void mgmt_new_link_key(int sk, uint16_t index, void *buf, size_t len)
        info = &controllers[index];
 
        if (ev->store_hint)
-               btd_event_link_key_notify(&info->bdaddr, &ev->key.bdaddr,
+               btd_event_link_key_notify(&info->bdaddr, &ev->key.addr.bdaddr,
                                                ev->key.val, ev->key.type,
                                                ev->key.pin_len);
 
-       bonding_complete(info, &ev->key.bdaddr, 0);
+       bonding_complete(info, &ev->key.addr.bdaddr, 0);
 }
 
 static void mgmt_device_connected(int sk, uint16_t index, void *buf, size_t len)
 {
-       struct mgmt_addr_info *ev = buf;
+       struct mgmt_ev_device_connected *ev = buf;
+       struct eir_data eir_data;
        struct controller_info *info;
+       uint16_t eir_len;
        char addr[18];
 
        if (len < sizeof(*ev)) {
@@ -406,9 +478,15 @@ static void mgmt_device_connected(int sk, uint16_t index, void *buf, size_t len)
                return;
        }
 
-       ba2str(&ev->bdaddr, addr);
+       eir_len = bt_get_le16(&ev->eir_len);
+       if (len < sizeof(*ev) + eir_len) {
+               error("Too small device_connected event");
+               return;
+       }
 
-       DBG("hci%u device %s connected", index, addr);
+       ba2str(&ev->addr.bdaddr, addr);
+
+       DBG("hci%u device %s connected eir_len %u", index, addr, eir_len);
 
        if (index > max_index) {
                error("Unexpected index %u in device_connected event", index);
@@ -417,7 +495,16 @@ static void mgmt_device_connected(int sk, uint16_t index, void *buf, size_t len)
 
        info = &controllers[index];
 
-       btd_event_conn_complete(&info->bdaddr, &ev->bdaddr);
+       memset(&eir_data, 0, sizeof(eir_data));
+       if (eir_len > 0)
+               eir_parse(&eir_data, ev->eir, eir_len);
+
+       btd_event_conn_complete(&info->bdaddr, &ev->addr.bdaddr,
+                                               ev->addr.type,
+                                               eir_data.name,
+                                               eir_data.dev_class);
+
+       eir_data_free(&eir_data);
 }
 
 static void mgmt_device_disconnected(int sk, uint16_t index, void *buf,
@@ -495,7 +582,8 @@ static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin,
                hdr->index = htobs(index);
 
                cp = (void *) &buf[sizeof(*hdr)];
-               bacpy(&cp->bdaddr, bdaddr);
+               bacpy(&cp->addr.bdaddr, bdaddr);
+               cp->addr.type = BDADDR_BREDR;
 
                buf_len = sizeof(*hdr) + sizeof(*cp);
        } else {
@@ -509,7 +597,8 @@ static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin,
                hdr->index = htobs(index);
 
                cp = (void *) &buf[sizeof(*hdr)];
-               bacpy(&cp->bdaddr, bdaddr);
+               bacpy(&cp->addr.bdaddr, bdaddr);
+               cp->addr.type = BDADDR_BREDR;
                cp->pin_len = pin_len;
                memcpy(cp->pin_code, pin, pin_len);
 
@@ -534,7 +623,7 @@ static void mgmt_pin_code_request(int sk, uint16_t index, void *buf, size_t len)
                return;
        }
 
-       ba2str(&ev->bdaddr, addr);
+       ba2str(&ev->addr.bdaddr, addr);
 
        DBG("hci%u %s", index, addr);
 
@@ -545,14 +634,16 @@ 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, ev->secure);
+       err = btd_event_request_pin(&info->bdaddr, &ev->addr.bdaddr,
+                                                               ev->secure);
        if (err < 0) {
                error("btd_event_request_pin: %s", strerror(-err));
-               mgmt_pincode_reply(index, &ev->bdaddr, NULL, 0);
+               mgmt_pincode_reply(index, &ev->addr.bdaddr, NULL, 0);
        }
 }
 
-static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success)
+static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, uint8_t bdaddr_type,
+                                                       gboolean success)
 {
        char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_user_confirm_reply)];
        struct mgmt_hdr *hdr = (void *) buf;
@@ -573,7 +664,8 @@ static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success)
        hdr->index = htobs(index);
 
        cp = (void *) &buf[sizeof(*hdr)];
-       bacpy(&cp->bdaddr, bdaddr);
+       bacpy(&cp->addr.bdaddr, bdaddr);
+       cp->addr.type = bdaddr_type;
 
        if (write(mgmt_sock, buf, sizeof(buf)) < 0)
                return -errno;
@@ -581,7 +673,8 @@ 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)
+static int mgmt_passkey_reply(int index, bdaddr_t *bdaddr, uint8_t bdaddr_type,
+                                                       uint32_t passkey)
 {
        char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_user_passkey_reply)];
        struct mgmt_hdr *hdr = (void *) buf;
@@ -601,7 +694,8 @@ static int mgmt_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey)
                hdr->len = htobs(sizeof(*cp));
 
                cp = (void *) &buf[sizeof(*hdr)];
-               bacpy(&cp->bdaddr, bdaddr);
+               bacpy(&cp->addr.bdaddr, bdaddr);
+               cp->addr.type = bdaddr_type;
 
                buf_len = sizeof(*hdr) + sizeof(*cp);
        } else {
@@ -611,7 +705,8 @@ static int mgmt_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey)
                hdr->len = htobs(sizeof(*cp));
 
                cp = (void *) &buf[sizeof(*hdr)];
-               bacpy(&cp->bdaddr, bdaddr);
+               bacpy(&cp->addr.bdaddr, bdaddr);
+               cp->addr.type = bdaddr_type;
                cp->passkey = htobl(passkey);
 
                buf_len = sizeof(*hdr) + sizeof(*cp);
@@ -635,7 +730,7 @@ static void mgmt_passkey_request(int sk, uint16_t index, void *buf, size_t len)
                return;
        }
 
-       ba2str(&ev->bdaddr, addr);
+       ba2str(&ev->addr.bdaddr, addr);
 
        DBG("hci%u %s", index, addr);
 
@@ -646,16 +741,18 @@ static void mgmt_passkey_request(int sk, uint16_t index, void *buf, size_t len)
 
        info = &controllers[index];
 
-       err = btd_event_user_passkey(&info->bdaddr, &ev->bdaddr);
+       err = btd_event_user_passkey(&info->bdaddr, &ev->addr.bdaddr);
        if (err < 0) {
                error("btd_event_user_passkey: %s", strerror(-err));
-               mgmt_passkey_reply(index, &ev->bdaddr, INVALID_PASSKEY);
+               mgmt_passkey_reply(index, &ev->addr.bdaddr, ev->addr.type,
+                                                       INVALID_PASSKEY);
        }
 }
 
 struct confirm_data {
        int index;
        bdaddr_t bdaddr;
+       uint8_t type;
 };
 
 static gboolean confirm_accept(gpointer user_data)
@@ -668,7 +765,7 @@ static gboolean confirm_accept(gpointer user_data)
        if (data->index > max_index || !info->valid)
                return FALSE;
 
-       mgmt_confirm_reply(data->index, &data->bdaddr, TRUE);
+       mgmt_confirm_reply(data->index, &data->bdaddr, data->type, TRUE);
 
        return FALSE;
 }
@@ -686,7 +783,7 @@ static void mgmt_user_confirm_request(int sk, uint16_t index, void *buf,
                return;
        }
 
-       ba2str(&ev->bdaddr, addr);
+       ba2str(&ev->addr.bdaddr, addr);
 
        DBG("hci%u %s confirm_hint %u", index, addr, ev->confirm_hint);
 
@@ -701,7 +798,8 @@ static void mgmt_user_confirm_request(int sk, uint16_t index, void *buf,
 
                data = g_new0(struct confirm_data, 1);
                data->index = index;
-               bacpy(&data->bdaddr, &ev->bdaddr);
+               bacpy(&data->bdaddr, &ev->addr.bdaddr);
+               data->type = ev->addr.type;
 
                g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, 1,
                                                confirm_accept, data, g_free);
@@ -710,11 +808,12 @@ static void mgmt_user_confirm_request(int sk, uint16_t index, void *buf,
 
        info = &controllers[index];
 
-       err = btd_event_user_confirm(&info->bdaddr, &ev->bdaddr,
+       err = btd_event_user_confirm(&info->bdaddr, &ev->addr.bdaddr,
                                                        btohl(ev->value));
        if (err < 0) {
                error("btd_event_user_confirm: %s", strerror(-err));
-               mgmt_confirm_reply(index, &ev->bdaddr, FALSE);
+               mgmt_confirm_reply(index, &ev->addr.bdaddr, ev->addr.type,
+                                                                       FALSE);
        }
 }
 
@@ -733,11 +832,23 @@ static int mgmt_add_uuid(int index, uuid_t *uuid, uint8_t svc_hint)
        char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_add_uuid)];
        struct mgmt_hdr *hdr = (void *) buf;
        struct mgmt_cp_add_uuid *cp = (void *) &buf[sizeof(*hdr)];
+       struct controller_info *info = &controllers[index];
        uuid_t uuid128;
        uint128_t uint128;
 
        DBG("index %d", index);
 
+       if (info->pending_uuid) {
+               struct pending_uuid *pending = g_new0(struct pending_uuid, 1);
+
+               memcpy(&pending->uuid, uuid, sizeof(*uuid));
+               pending->svc_hint = svc_hint;
+
+               info->pending_uuids = g_slist_append(info->pending_uuids,
+                                                               pending);
+               return 0;
+       }
+
        uuid_to_uuid128(&uuid128, uuid);
 
        memset(buf, 0, sizeof(buf));
@@ -753,6 +864,8 @@ static int mgmt_add_uuid(int index, uuid_t *uuid, uint8_t svc_hint)
        if (write(mgmt_sock, buf, sizeof(buf)) < 0)
                return -errno;
 
+       info->pending_uuid = TRUE;
+
        return 0;
 }
 
@@ -816,23 +929,87 @@ static void read_index_list_complete(int sk, void *buf, size_t len)
                index = btohs(bt_get_unaligned(&rp->index[i]));
 
                add_controller(index);
-               get_connections(sk, index);
-               clear_uuids(index);
+               read_info(sk, index);
        }
 }
 
 static int mgmt_set_powered(int index, gboolean powered)
 {
-       DBG("index %d powered %d", index, powered);
+       struct controller_info *info = &controllers[index];
+
+       DBG("index %d powered %d pending_uuid %u", index, powered,
+                                                       info->pending_uuid);
+
+       if (powered) {
+               if (info->pending_uuid) {
+                       info->pending_powered = TRUE;
+                       return 0;
+               }
+       } else {
+               info->pending_powered = FALSE;
+       }
+
        return mgmt_set_mode(index, MGMT_OP_SET_POWERED, powered);
 }
 
+static int mgmt_set_name(int index, const char *name)
+{
+       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_local_name)];
+       struct mgmt_hdr *hdr = (void *) buf;
+       struct mgmt_cp_set_local_name *cp = (void *) &buf[sizeof(*hdr)];
+
+       DBG("index %d, name %s", index, name);
+
+       memset(buf, 0, sizeof(buf));
+       hdr->opcode = htobs(MGMT_OP_SET_LOCAL_NAME);
+       hdr->len = htobs(sizeof(*cp));
+       hdr->index = htobs(index);
+
+       strncpy((char *) cp->name, name, sizeof(cp->name) - 1);
+
+       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
+               return -errno;
+
+       return 0;
+}
+
+static int mgmt_set_dev_class(int index, uint8_t major, uint8_t minor)
+{
+       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_dev_class)];
+       struct mgmt_hdr *hdr = (void *) buf;
+       struct mgmt_cp_set_dev_class *cp = (void *) &buf[sizeof(*hdr)];
+       struct controller_info *info = &controllers[index];
+
+       DBG("index %d major %u minor %u", index, major, minor);
+
+       if (info->pending_uuid) {
+               info->major = major;
+               info->minor = minor;
+               info->pending_class = TRUE;
+               return 0;
+       }
+
+       memset(buf, 0, sizeof(buf));
+       hdr->opcode = htobs(MGMT_OP_SET_DEV_CLASS);
+       hdr->len = htobs(sizeof(*cp));
+       hdr->index = htobs(index);
+
+       cp->major = major;
+       cp->minor = minor;
+
+       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
+               return -errno;
+
+       return 0;
+}
+
 static void read_info_complete(int sk, uint16_t index, void *buf, size_t len)
 {
        struct mgmt_rp_read_info *rp = buf;
        struct controller_info *info;
        struct btd_adapter *adapter;
-       uint8_t mode;
+       const char *name;
+       uint8_t mode, major, minor;
        char addr[18];
 
        if (len < sizeof(*rp)) {
@@ -866,29 +1043,47 @@ static void read_info_complete(int sk, uint16_t index, void *buf, size_t len)
        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);
+       clear_uuids(index);
+
+       adapter = btd_manager_register_adapter(index,
+                                       mgmt_powered(info->current_settings));
        if (adapter == NULL) {
                error("mgmtops: unable to register adapter");
                return;
        }
 
-       btd_adapter_get_mode(adapter, &mode, NULL, NULL);
-       if (mode == MODE_OFF) {
+       update_settings(adapter, info->current_settings);
+
+       name = btd_adapter_get_name(adapter);
+
+       DBG("mgmtops setting name %s", name);
+
+       if (name)
+               mgmt_set_name(index, name);
+       else
+               adapter_name_changed(adapter, (char *) rp->name);
+
+       btd_adapter_get_class(adapter, &major, &minor);
+       mgmt_set_dev_class(index, major, minor);
+
+       btd_adapter_get_mode(adapter, &mode, NULL, NULL, NULL);
+       if (mode == MODE_OFF && mgmt_powered(info->current_settings)) {
                mgmt_set_powered(index, FALSE);
                return;
        }
 
-       if (mgmt_powered(info->current_settings))
-               mgmt_update_powered(adapter, info->current_settings);
-       else
+       if (mode != MODE_OFF && !mgmt_powered(info->current_settings))
                mgmt_set_powered(index, TRUE);
-
-       adapter_name_changed(adapter, (char *) rp->name);
+       else {
+               get_connections(sk, index);
+               btd_adapter_start(adapter);
+       }
 
        btd_adapter_unref(adapter);
 }
 
-static void disconnect_complete(int sk, uint16_t index, void *buf, size_t len)
+static void disconnect_complete(int sk, uint16_t index, uint8_t status,
+                                                       void *buf, size_t len)
 {
        struct mgmt_rp_disconnect *rp = buf;
        struct controller_info *info;
@@ -899,11 +1094,10 @@ static void disconnect_complete(int sk, uint16_t index, void *buf, size_t len)
                return;
        }
 
-       ba2str(&rp->bdaddr, addr);
+       ba2str(&rp->addr.bdaddr, addr);
 
-       if (rp->status != 0) {
-               error("Disconnecting %s failed with status %u",
-                                                       addr, rp->status);
+       if (status != 0) {
+               error("Disconnecting %s failed with status %u", addr, status);
                return;
        }
 
@@ -916,12 +1110,13 @@ static void disconnect_complete(int sk, uint16_t index, void *buf, size_t len)
 
        info = &controllers[index];
 
-       btd_event_disconn_complete(&info->bdaddr, &rp->bdaddr);
+       btd_event_disconn_complete(&info->bdaddr, &rp->addr.bdaddr);
 
-       bonding_complete(info, &rp->bdaddr, HCI_CONNECTION_TERMINATED);
+       bonding_complete(info, &rp->addr.bdaddr, HCI_CONNECTION_TERMINATED);
 }
 
-static void pair_device_complete(int sk, uint16_t index, void *buf, size_t len)
+static void pair_device_complete(int sk, uint16_t index, uint8_t status,
+                                                       void *buf, size_t len)
 {
        struct mgmt_rp_pair_device *rp = buf;
        struct controller_info *info;
@@ -934,7 +1129,7 @@ static void pair_device_complete(int sk, uint16_t index, void *buf, size_t len)
 
        ba2str(&rp->addr.bdaddr, addr);
 
-       DBG("hci%d %s pairing complete status %u", index, addr, rp->status);
+       DBG("hci%d %s pairing complete status %u", index, addr, status);
 
        if (index > max_index) {
                error("Unexpected index %u in pair_device complete", index);
@@ -943,7 +1138,7 @@ static void pair_device_complete(int sk, uint16_t index, void *buf, size_t len)
 
        info = &controllers[index];
 
-       bonding_complete(info, &rp->addr.bdaddr, rp->status);
+       bonding_complete(info, &rp->addr.bdaddr, status);
 }
 
 static void get_connections_complete(int sk, uint16_t index, void *buf,
@@ -975,8 +1170,6 @@ static void get_connections_complete(int sk, uint16_t index, void *buf,
                bdaddr_t *bdaddr = g_memdup(&rp->addr[i], sizeof(bdaddr_t));
                info->connections = g_slist_append(info->connections, bdaddr);
        }
-
-       read_info(sk, index);
 }
 
 static void set_local_name_complete(int sk, uint16_t index, void *buf,
@@ -1016,7 +1209,8 @@ static void read_local_oob_data_complete(int sk, uint16_t index, void *buf,
        struct btd_adapter *adapter;
 
        if (len != sizeof(*rp)) {
-               error("Wrong read_local_oob_data_complete event size");
+               error("read_local_oob_data_complete event size mismatch "
+                                       "(%zu != %zu)", len, sizeof(*rp));
                return;
        }
 
@@ -1034,6 +1228,34 @@ static void read_local_oob_data_complete(int sk, uint16_t index, void *buf,
                oob_read_local_data_complete(adapter, rp->hash, rp->randomizer);
 }
 
+static void start_discovery_complete(int sk, uint16_t index, uint8_t status,
+                                                    void *buf, size_t len)
+{
+       uint8_t *type = buf;
+       struct btd_adapter *adapter;
+
+       if (len != sizeof(*type)) {
+               error("start_discovery_complete event size mismatch "
+                                       "(%zu != %zu)", len, sizeof(*type));
+               return;
+       }
+
+       DBG("hci%u type %u status %u", index, *type, status);
+
+       if (index > max_index) {
+               error("Invalid index %u in start_discovery_complete", index);
+               return;
+       }
+
+       if (!status)
+               return;
+
+       adapter = manager_find_adapter_by_id(index);
+       if (adapter)
+               /* Start discovery failed, inform upper layers. */
+               adapter_set_discovering(adapter, FALSE);
+}
+
 static void read_local_oob_data_failed(int sk, uint16_t index)
 {
        struct btd_adapter *adapter;
@@ -1052,6 +1274,52 @@ static void read_local_oob_data_failed(int sk, uint16_t index)
                oob_read_local_data_complete(adapter, NULL, NULL);
 }
 
+static void handle_pending_uuids(uint16_t index)
+{
+       struct controller_info *info;
+       struct pending_uuid *pending;
+
+       DBG("index %d", index);
+
+       info = &controllers[index];
+
+       info->pending_uuid = FALSE;
+
+       if (g_slist_length(info->pending_uuids) == 0) {
+               if (info->pending_class) {
+                       info->pending_class = FALSE;
+                       mgmt_set_dev_class(index, info->major, info->minor);
+               }
+
+               if (info->pending_powered) {
+                       info->pending_powered = FALSE;
+                       mgmt_set_powered(index, TRUE);
+               }
+
+               return;
+       }
+
+       pending = info->pending_uuids->data;
+
+       mgmt_add_uuid(index, &pending->uuid, pending->svc_hint);
+
+       info->pending_uuids = g_slist_remove(info->pending_uuids, pending);
+       g_free(pending);
+}
+
+static void mgmt_add_uuid_complete(int sk, uint16_t index, void *buf,
+                                                               size_t len)
+{
+       DBG("index %d", index);
+
+       if (index > max_index) {
+               error("Unexpected index %u in add_uuid_complete event", index);
+               return;
+       }
+
+       handle_pending_uuids(index);
+}
+
 static void mgmt_cmd_complete(int sk, uint16_t index, void *buf, size_t len)
 {
        struct mgmt_ev_cmd_complete *ev = buf;
@@ -1090,8 +1358,14 @@ static void mgmt_cmd_complete(int sk, uint16_t index, void *buf, size_t len)
        case MGMT_OP_SET_PAIRABLE:
                mgmt_new_settings(sk, index, ev->data, len);
                break;
+       case MGMT_OP_SET_SSP:
+               DBG("set_ssp complete");
+               break;
+       case MGMT_OP_SET_LE:
+               DBG("set_le complete");
+               break;
        case MGMT_OP_ADD_UUID:
-               DBG("add_uuid complete");
+               mgmt_add_uuid_complete(sk, index, ev->data, len);
                break;
        case MGMT_OP_REMOVE_UUID:
                DBG("remove_uuid complete");
@@ -1102,12 +1376,15 @@ static void mgmt_cmd_complete(int sk, uint16_t index, void *buf, size_t len)
        case MGMT_OP_LOAD_LINK_KEYS:
                DBG("load_link_keys complete");
                break;
-       case MGMT_OP_REMOVE_KEYS:
-               DBG("remove_keys complete");
+       case MGMT_OP_CANCEL_PAIR_DEVICE:
+               DBG("cancel_pair_device complete");
+               break;
+       case MGMT_OP_UNPAIR_DEVICE:
+               DBG("unpair_device complete");
                break;
        case MGMT_OP_DISCONNECT:
                DBG("disconnect complete");
-               disconnect_complete(sk, index, ev->data, len);
+               disconnect_complete(sk, index, ev->status, ev->data, len);
                break;
        case MGMT_OP_GET_CONNECTIONS:
                get_connections_complete(sk, index, ev->data, len);
@@ -1122,7 +1399,7 @@ static void mgmt_cmd_complete(int sk, uint16_t index, void *buf, size_t len)
                DBG("set_io_capability complete");
                break;
        case MGMT_OP_PAIR_DEVICE:
-               pair_device_complete(sk, index, ev->data, len);
+               pair_device_complete(sk, index, ev->status, ev->data, len);
                break;
        case MGMT_OP_USER_CONFIRM_REPLY:
                DBG("user_confirm_reply complete");
@@ -1152,17 +1429,30 @@ static void mgmt_cmd_complete(int sk, uint16_t index, void *buf, size_t len)
                DBG("set_fast_connectable complete");
                break;
        case MGMT_OP_START_DISCOVERY:
-               DBG("start_discovery complete");
+               start_discovery_complete(sk, index, ev->status, ev->data, len);
                break;
        case MGMT_OP_STOP_DISCOVERY:
                DBG("stop_discovery complete");
                break;
+       case MGMT_OP_SET_DEVICE_ID:
+               DBG("set_did complete");
+               break;
        default:
                error("Unknown command complete for opcode %u", opcode);
                break;
        }
 }
 
+static void mgmt_add_uuid_busy(int sk, uint16_t index)
+{
+       struct controller_info *info;
+
+       DBG("index %d", index);
+
+       info = &controllers[index];
+       info->pending_cod_change = TRUE;
+}
+
 static void mgmt_cmd_status(int sk, uint16_t index, void *buf, size_t len)
 {
        struct mgmt_ev_cmd_status *ev = buf;
@@ -1175,13 +1465,27 @@ 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);
+       if (!ev->status) {
+               DBG("%s (0x%04x) cmd_status %u", mgmt_opstr(opcode), opcode,
+                                                               ev->status);
+               return;
+       }
 
        switch (opcode) {
        case MGMT_OP_READ_LOCAL_OOB_DATA:
                read_local_oob_data_failed(sk, index);
                break;
+       case MGMT_OP_ADD_UUID:
+               if (ev->status == MGMT_STATUS_BUSY) {
+                       mgmt_add_uuid_busy(sk, index);
+                       return;
+               }
+               break;
        }
+
+       error("hci%u: %s (0x%04x) failed: %s (0x%02x)", index,
+                       mgmt_opstr(opcode), opcode, mgmt_errstr(ev->status),
+                       ev->status);
 }
 
 static void mgmt_controller_error(int sk, uint16_t index, void *buf, size_t len)
@@ -1215,7 +1519,7 @@ static void mgmt_auth_failed(int sk, uint16_t index, void *buf, size_t len)
 
        info = &controllers[index];
 
-       bonding_complete(info, &ev->bdaddr, ev->status);
+       bonding_complete(info, &ev->addr.bdaddr, ev->status);
 }
 
 static void mgmt_local_name_changed(int sk, uint16_t index, void *buf, size_t len)
@@ -1243,31 +1547,25 @@ static void mgmt_local_name_changed(int sk, uint16_t index, void *buf, size_t le
                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];
+       uint32_t flags;
+       uint16_t eir_len;
        uint8_t *eir;
-       uint32_t cls;
+       gboolean confirm_name;
 
-       if (len != sizeof(*ev)) {
-               error("mgmt_device_found length %zu instead of expected %zu",
-                                                       len, sizeof(*ev));
+       if (len < sizeof(*ev)) {
+               error("mgmt_device_found too short (%zu bytes)", len);
+               return;
+       }
+
+       eir_len = bt_get_le16(&ev->eir_len);
+       if (len != sizeof(*ev) + eir_len) {
+               error("mgmt_device_found event size mismatch (%zu != %zu)",
+                                               len, sizeof(*ev) + eir_len);
                return;
        }
 
@@ -1278,52 +1576,35 @@ static void mgmt_device_found(int sk, uint16_t index, void *buf, size_t len)
 
        info = &controllers[index];
 
-       cls = ev->dev_class[0] | (ev->dev_class[1] << 8) |
-                                               (ev->dev_class[2] << 16);
-
-       if (ev->eir[0] == 0)
+       if (eir_len == 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);
-}
+       flags = btohl(ev->flags);
 
-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;
-       }
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("hci%u addr %s, rssi %d flags 0x%04x eir_len %u",
+                       index, addr, ev->rssi, flags, eir_len);
 
-       if (index > max_index) {
-               error("Unexpected index %u in remote_name event", index);
-               return;
-       }
+       if (flags & MGMT_DEV_FOUND_LEGACY_PAIRING)
+               btd_event_set_legacy_pairing(&info->bdaddr, &ev->addr.bdaddr,
+                                                                       TRUE);
+       else
+               btd_event_set_legacy_pairing(&info->bdaddr, &ev->addr.bdaddr,
+                                                                       FALSE);
 
-       info = &controllers[index];
+       confirm_name = (flags & MGMT_DEV_FOUND_CONFIRM_NAME);
 
-       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);
+       btd_event_device_found(&info->bdaddr, &ev->addr.bdaddr,
+                                               ev->addr.type,
+                                               ev->rssi, confirm_name,
+                                               eir, eir_len);
 }
 
 static void mgmt_discovering(int sk, uint16_t index, void *buf, size_t len)
 {
-       struct mgmt_mode *ev = buf;
+       struct mgmt_ev_discovering *ev = buf;
        struct controller_info *info;
        struct btd_adapter *adapter;
 
@@ -1332,7 +1613,8 @@ static void mgmt_discovering(int sk, uint16_t index, void *buf, size_t len)
                return;
        }
 
-       DBG("Controller %u discovering %u", index, ev->val);
+       DBG("Controller %u type %u discovering %u", index,
+                                       ev->type, ev->discovering);
 
        if (index > max_index) {
                error("Unexpected index %u in discovering event", index);
@@ -1345,7 +1627,7 @@ static void mgmt_discovering(int sk, uint16_t index, void *buf, size_t len)
        if (!adapter)
                return;
 
-       adapter_set_discovering(adapter, ev->val);
+       adapter_set_discovering(adapter, ev->discovering);
 }
 
 static void mgmt_device_blocked(int sk, uint16_t index, void *buf, size_t len)
@@ -1359,7 +1641,7 @@ static void mgmt_device_blocked(int sk, uint16_t index, void *buf, size_t len)
                return;
        }
 
-       ba2str(&ev->bdaddr, addr);
+       ba2str(&ev->addr.bdaddr, addr);
        DBG("Device blocked, index %u, addr %s", index, addr);
 
        if (index > max_index) {
@@ -1369,7 +1651,7 @@ static void mgmt_device_blocked(int sk, uint16_t index, void *buf, size_t len)
 
        info = &controllers[index];
 
-       btd_event_device_blocked(&info->bdaddr, &ev->bdaddr);
+       btd_event_device_blocked(&info->bdaddr, &ev->addr.bdaddr);
 }
 
 static void mgmt_device_unblocked(int sk, uint16_t index, void *buf, size_t len)
@@ -1383,7 +1665,7 @@ static void mgmt_device_unblocked(int sk, uint16_t index, void *buf, size_t len)
                return;
        }
 
-       ba2str(&ev->bdaddr, addr);
+       ba2str(&ev->addr.bdaddr, addr);
        DBG("Device unblocked, index %u, addr %s", index, addr);
 
        if (index > max_index) {
@@ -1393,7 +1675,82 @@ static void mgmt_device_unblocked(int sk, uint16_t index, void *buf, size_t len)
 
        info = &controllers[index];
 
-       btd_event_device_unblocked(&info->bdaddr, &ev->bdaddr);
+       btd_event_device_unblocked(&info->bdaddr, &ev->addr.bdaddr);
+}
+
+static void mgmt_device_unpaired(int sk, uint16_t index, void *buf, size_t len)
+{
+       struct controller_info *info;
+       struct mgmt_ev_device_unpaired *ev = buf;
+       char addr[18];
+
+       if (len < sizeof(*ev)) {
+               error("Too small mgmt_device_unpaired event packet");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("Device upaired, index %u, addr %s", index, addr);
+
+       if (index > max_index) {
+               error("Unexpected index %u in device_unpaired event", index);
+               return;
+       }
+
+       info = &controllers[index];
+
+       btd_event_device_unpaired(&info->bdaddr, &ev->addr.bdaddr);
+}
+
+static void mgmt_new_ltk(int sk, uint16_t index, void *buf, size_t len)
+{
+       struct mgmt_ev_new_long_term_key *ev = buf;
+       struct controller_info *info;
+
+       if (len != sizeof(*ev)) {
+               error("mgmt_new_ltk event size mismatch (%zu != %zu)",
+                                                       len, sizeof(*ev));
+               return;
+       }
+
+       DBG("Controller %u new LTK authenticated %u enc_size %u", index,
+                               ev->key.authenticated, ev->key.enc_size);
+
+       if (index > max_index) {
+               error("Unexpected index %u in new_key event", index);
+               return;
+       }
+
+       info = &controllers[index];
+
+       if (ev->store_hint) {
+               btd_event_ltk_notify(&info->bdaddr, &ev->key.addr.bdaddr,
+                               ev->key.addr.type, ev->key.val, ev->key.master,
+                               ev->key.authenticated, ev->key.enc_size,
+                               ev->key.ediv, ev->key.rand);
+       }
+
+       if (ev->key.master)
+               bonding_complete(info, &ev->key.addr.bdaddr, 0);
+}
+
+static void mgmt_cod_changed(int sk, uint16_t index)
+{
+       struct controller_info *info;
+
+       DBG("index %d", index);
+
+       if (index > max_index) {
+               error("Unexpected index %u in mgmt_cod_changed event", index);
+               return;
+       }
+
+       info = &controllers[index];
+
+       if (info->pending_cod_change) {
+               info->pending_cod_change = FALSE;
+               handle_pending_uuids(index);
+       }
 }
 
 static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data)
@@ -1458,6 +1815,9 @@ static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data
        case MGMT_EV_NEW_SETTINGS:
                mgmt_new_settings(sk, index, buf + MGMT_HDR_SIZE, len);
                break;
+       case MGMT_EV_CLASS_OF_DEV_CHANGED:
+               mgmt_cod_changed(sk, index);
+               break;
        case MGMT_EV_NEW_LINK_KEY:
                mgmt_new_link_key(sk, index, buf + MGMT_HDR_SIZE, len);
                break;
@@ -1485,9 +1845,6 @@ static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data
        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;
@@ -1497,9 +1854,15 @@ static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data
        case MGMT_EV_DEVICE_UNBLOCKED:
                mgmt_device_unblocked(sk, index, buf + MGMT_HDR_SIZE, len);
                break;
+       case MGMT_EV_DEVICE_UNPAIRED:
+               mgmt_device_unpaired(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;
+       case MGMT_EV_NEW_LONG_TERM_KEY:
+               mgmt_new_ltk(sk, index, buf + MGMT_HDR_SIZE, len);
+               break;
        default:
                error("Unknown Management opcode %u (index %u)", opcode, index);
                break;
@@ -1571,50 +1934,31 @@ static void mgmt_cleanup(void)
        }
 }
 
-static int mgmt_set_dev_class(int index, uint8_t major, uint8_t minor)
-{
-       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_dev_class)];
-       struct mgmt_hdr *hdr = (void *) buf;
-       struct mgmt_cp_set_dev_class *cp = (void *) &buf[sizeof(*hdr)];
-
-       DBG("index %d major %u minor %u", index, major, minor);
-
-       memset(buf, 0, sizeof(buf));
-       hdr->opcode = htobs(MGMT_OP_SET_DEV_CLASS);
-       hdr->len = htobs(sizeof(*cp));
-       hdr->index = htobs(index);
-
-       cp->major = major;
-       cp->minor = minor;
-
-       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int mgmt_set_limited_discoverable(int index, gboolean limited)
-{
-       DBG("index %d limited %d", index, limited);
-       return -ENOSYS;
-}
-
 static int mgmt_start_discovery(int index)
 {
        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)];
+       struct controller_info *info = &controllers[index];
 
        DBG("index %d", index);
 
+       info->discov_type = 0;
+
+       if (mgmt_bredr(info->current_settings))
+               hci_set_bit(BDADDR_BREDR, &info->discov_type);
+
+       if (mgmt_low_energy(info->current_settings)) {
+               hci_set_bit(BDADDR_LE_PUBLIC, &info->discov_type);
+               hci_set_bit(BDADDR_LE_RANDOM, &info->discov_type);
+       }
+
        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);
+       cp->type = info->discov_type;
 
        if (write(mgmt_sock, buf, sizeof(buf)) < 0)
                return -errno;
@@ -1624,34 +1968,19 @@ static int mgmt_start_discovery(int index)
 
 static int mgmt_stop_discovery(int index)
 {
-       struct mgmt_hdr hdr;
-
-       DBG("index %d", index);
-
-       memset(&hdr, 0, sizeof(hdr));
-       hdr.opcode = htobs(MGMT_OP_STOP_DISCOVERY);
-       hdr.index = htobs(index);
-
-       if (write(mgmt_sock, &hdr, sizeof(hdr)) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int mgmt_set_name(int index, const char *name)
-{
-       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_local_name)];
+       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_start_discovery)];
        struct mgmt_hdr *hdr = (void *) buf;
-       struct mgmt_cp_set_local_name *cp = (void *) &buf[sizeof(*hdr)];
+       struct mgmt_cp_start_discovery *cp = (void *) &buf[sizeof(*hdr)];
+       struct controller_info *info = &controllers[index];
 
-       DBG("index %d, name %s", index, name);
+       DBG("index %d", index);
 
        memset(buf, 0, sizeof(buf));
-       hdr->opcode = htobs(MGMT_OP_SET_LOCAL_NAME);
+       hdr->opcode = htobs(MGMT_OP_STOP_DISCOVERY);
        hdr->len = htobs(sizeof(*cp));
        hdr->index = htobs(index);
 
-       strncpy((char *) cp->name, name, sizeof(cp->name) - 1);
+       cp->type = info->discov_type;
 
        if (write(mgmt_sock, buf, sizeof(buf)) < 0)
                return -errno;
@@ -1708,7 +2037,7 @@ static int mgmt_read_bdaddr(int index, bdaddr_t *bdaddr)
        return 0;
 }
 
-static int mgmt_block_device(int index, bdaddr_t *bdaddr)
+static int mgmt_block_device(int index, bdaddr_t *bdaddr, uint8_t bdaddr_type)
 {
        char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_block_device)];
        struct mgmt_hdr *hdr = (void *) buf;
@@ -1726,7 +2055,8 @@ static int mgmt_block_device(int index, bdaddr_t *bdaddr)
        hdr->index = htobs(index);
 
        cp = (void *) &buf[sizeof(*hdr)];
-       bacpy(&cp->bdaddr, bdaddr);
+       bacpy(&cp->addr.bdaddr, bdaddr);
+       cp->addr.type = bdaddr_type;
 
        buf_len = sizeof(*hdr) + sizeof(*cp);
 
@@ -1736,7 +2066,8 @@ static int mgmt_block_device(int index, bdaddr_t *bdaddr)
        return 0;
 }
 
-static int mgmt_unblock_device(int index, bdaddr_t *bdaddr)
+static int mgmt_unblock_device(int index, bdaddr_t *bdaddr,
+                                                       uint8_t bdaddr_type)
 {
        char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_unblock_device)];
        struct mgmt_hdr *hdr = (void *) buf;
@@ -1754,7 +2085,8 @@ static int mgmt_unblock_device(int index, bdaddr_t *bdaddr)
        hdr->index = htobs(index);
 
        cp = (void *) &buf[sizeof(*hdr)];
-       bacpy(&cp->bdaddr, bdaddr);
+       bacpy(&cp->addr.bdaddr, bdaddr);
+       cp->addr.type = bdaddr_type;
 
        buf_len = sizeof(*hdr) + sizeof(*cp);
 
@@ -1776,7 +2108,7 @@ static int mgmt_get_conn_list(int index, GSList **conns)
        return 0;
 }
 
-static int mgmt_disconnect(int index, bdaddr_t *bdaddr)
+static int mgmt_disconnect(int index, bdaddr_t *bdaddr, uint8_t bdaddr_type)
 {
        char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_disconnect)];
        struct mgmt_hdr *hdr = (void *) buf;
@@ -1791,7 +2123,8 @@ static int mgmt_disconnect(int index, bdaddr_t *bdaddr)
        hdr->len = htobs(sizeof(*cp));
        hdr->index = htobs(index);
 
-       bacpy(&cp->bdaddr, bdaddr);
+       bacpy(&cp->addr.bdaddr, bdaddr);
+       cp->addr.type = bdaddr_type;
 
        if (write(mgmt_sock, buf, sizeof(buf)) < 0)
                error("write: %s (%d)", strerror(errno), errno);
@@ -1799,22 +2132,23 @@ static int mgmt_disconnect(int index, bdaddr_t *bdaddr)
        return 0;
 }
 
-static int mgmt_remove_bonding(int index, bdaddr_t *bdaddr)
+static int mgmt_unpair_device(int index, bdaddr_t *bdaddr, uint8_t bdaddr_type)
 {
-       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_remove_keys)];
+       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_unpair_device)];
        struct mgmt_hdr *hdr = (void *) buf;
-       struct mgmt_cp_remove_keys *cp = (void *) &buf[sizeof(*hdr)];
+       struct mgmt_cp_unpair_device *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_KEYS);
+       hdr->opcode = htobs(MGMT_OP_UNPAIR_DEVICE);
        hdr->len = htobs(sizeof(*cp));
        hdr->index = htobs(index);
 
-       bacpy(&cp->bdaddr, bdaddr);
+       bacpy(&cp->addr.bdaddr, bdaddr);
+       cp->addr.type = bdaddr_type;
        cp->disconnect = 1;
 
        if (write(mgmt_sock, buf, sizeof(buf)) < 0)
@@ -1835,11 +2169,29 @@ static int mgmt_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb,
 }
 
 static int mgmt_set_did(int index, uint16_t vendor, uint16_t product,
-                                                       uint16_t version)
+                                       uint16_t version, uint16_t source)
 {
-       DBG("index %d vendor %u product %u version %u",
-                                       index, vendor, product, version);
-       return -ENOSYS;
+       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_device_id)];
+       struct mgmt_hdr *hdr = (void *) buf;
+       struct mgmt_cp_set_device_id *cp = (void *) &buf[sizeof(*hdr)];
+
+       DBG("index %d source %x vendor %x product %x version %x",
+                               index, source, vendor, product, version);
+
+       memset(buf, 0, sizeof(buf));
+       hdr->opcode = htobs(MGMT_OP_SET_DEVICE_ID);
+       hdr->len = htobs(sizeof(*cp));
+       hdr->index = htobs(index);
+
+       cp->source = htobs(source);
+       cp->vendor = htobs(vendor);
+       cp->product = htobs(product);
+       cp->version = htobs(version);
+
+       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
+               return -errno;
+
+       return 0;
 }
 
 static int mgmt_disable_cod_cache(int index)
@@ -1876,8 +2228,6 @@ static int mgmt_load_link_keys(int index, GSList *keys, gboolean debug_keys)
        if (buf == NULL)
                return -ENOMEM;
 
-       memset(buf, 0, sizeof(buf));
-
        hdr = (void *) buf;
        hdr->opcode = htobs(MGMT_OP_LOAD_LINK_KEYS);
        hdr->len = htobs(cp_size);
@@ -1890,7 +2240,8 @@ static int mgmt_load_link_keys(int index, GSList *keys, gboolean debug_keys)
        for (l = keys, key = cp->keys; l != NULL; l = g_slist_next(l), key++) {
                struct link_key_info *info = l->data;
 
-               bacpy(&key->bdaddr, &info->bdaddr);
+               bacpy(&key->addr.bdaddr, &info->bdaddr);
+               key->addr.type = BDADDR_BREDR;
                key->type = info->type;
                memcpy(key->val, info->key, 16);
                key->pin_len = info->pin_len;
@@ -1927,7 +2278,7 @@ static int mgmt_set_io_capability(int index, uint8_t io_capability)
        return 0;
 }
 
-static int mgmt_create_bonding(int index, bdaddr_t *bdaddr, uint8_t io_cap)
+static int mgmt_create_bonding(int index, bdaddr_t *bdaddr, uint8_t addr_type, uint8_t io_cap)
 {
        char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_pair_device)];
        struct mgmt_hdr *hdr = (void *) buf;
@@ -1943,6 +2294,7 @@ static int mgmt_create_bonding(int index, bdaddr_t *bdaddr, uint8_t io_cap)
        hdr->index = htobs(index);
 
        bacpy(&cp->addr.bdaddr, bdaddr);
+       cp->addr.type = addr_type;
        cp->io_cap = io_cap;
 
        if (write(mgmt_sock, &buf, sizeof(buf)) < 0)
@@ -1953,12 +2305,25 @@ static int mgmt_create_bonding(int index, bdaddr_t *bdaddr, uint8_t io_cap)
 
 static int mgmt_cancel_bonding(int index, bdaddr_t *bdaddr)
 {
+       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_addr_info)];
+       struct mgmt_hdr *hdr = (void *) buf;
+       struct mgmt_addr_info *cp = (void *) &buf[sizeof(*hdr)];
        char addr[18];
 
        ba2str(bdaddr, addr);
        DBG("hci%d bdaddr %s", index, addr);
 
-       return -ENOSYS;
+       memset(buf, 0, sizeof(buf));
+       hdr->opcode = htobs(MGMT_OP_CANCEL_PAIR_DEVICE);
+       hdr->len = htobs(sizeof(*cp));
+       hdr->index = htobs(index);
+
+       bacpy(&cp->bdaddr, bdaddr);
+
+       if (write(mgmt_sock, &buf, sizeof(buf)) < 0)
+               return -errno;
+
+       return 0;
 }
 
 static int mgmt_read_local_oob_data(int index)
@@ -1994,7 +2359,7 @@ static int mgmt_add_remote_oob_data(int index, bdaddr_t *bdaddr,
        hdr->index = htobs(index);
        hdr->len = htobs(sizeof(*cp));
 
-       bacpy(&cp->bdaddr, bdaddr);
+       bacpy(&cp->addr.bdaddr, bdaddr);
        memcpy(cp->hash, hash, 16);
        memcpy(cp->randomizer, randomizer, 16);
 
@@ -2020,7 +2385,7 @@ static int mgmt_remove_remote_oob_data(int index, bdaddr_t *bdaddr)
        hdr->index = htobs(index);
        hdr->len = htobs(sizeof(*cp));
 
-       bacpy(&cp->bdaddr, bdaddr);
+       bacpy(&cp->addr.bdaddr, bdaddr);
 
        if (write(mgmt_sock, &buf, sizeof(buf)) < 0)
                return -errno;
@@ -2028,7 +2393,8 @@ static int mgmt_remove_remote_oob_data(int index, bdaddr_t *bdaddr)
        return 0;
 }
 
-static int mgmt_confirm_name(int index, bdaddr_t *bdaddr, gboolean name_known)
+static int mgmt_confirm_name(int index, bdaddr_t *bdaddr, uint8_t bdaddr_type,
+                                                       gboolean name_known)
 {
        char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_confirm_name)];
        struct mgmt_hdr *hdr = (void *) buf;
@@ -2044,7 +2410,8 @@ static int mgmt_confirm_name(int index, bdaddr_t *bdaddr, gboolean name_known)
        hdr->index = htobs(index);
        hdr->len = htobs(sizeof(*cp));
 
-       bacpy(&cp->bdaddr, bdaddr);
+       bacpy(&cp->addr.bdaddr, bdaddr);
+       cp->addr.type = bdaddr_type;
        cp->name_known = name_known;
 
        if (write(mgmt_sock, &buf, sizeof(buf)) < 0)
@@ -2053,13 +2420,63 @@ static int mgmt_confirm_name(int index, bdaddr_t *bdaddr, gboolean name_known)
        return 0;
 }
 
+static int mgmtops_load_ltks(int index, GSList *keys)
+{
+       char *buf;
+       struct mgmt_hdr *hdr;
+       struct mgmt_cp_load_long_term_keys *cp;
+       struct mgmt_ltk_info *key;
+       size_t key_count, cp_size;
+       GSList *l;
+       int err;
+
+       key_count = g_slist_length(keys);
+
+       DBG("index %d keys %zu", index, key_count);
+
+       cp_size = sizeof(*cp) + (key_count * sizeof(*key));
+
+       buf = g_try_malloc0(sizeof(*hdr) + cp_size);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       hdr = (void *) buf;
+       hdr->opcode = htobs(MGMT_OP_LOAD_LONG_TERM_KEYS);
+       hdr->len = htobs(cp_size);
+       hdr->index = htobs(index);
+
+       cp = (void *) (buf + sizeof(*hdr));
+       cp->key_count = htobs(key_count);
+
+       for (l = keys, key = cp->keys; l != NULL; l = g_slist_next(l), key++) {
+               struct smp_ltk_info *info = l->data;
+
+               bacpy(&key->addr.bdaddr, &info->bdaddr);
+               key->addr.type = info->bdaddr_type;
+               memcpy(key->val, info->val, sizeof(info->val));
+               memcpy(key->rand, info->rand, sizeof(info->rand));
+               memcpy(&key->ediv, &info->ediv, sizeof(key->ediv));
+               key->authenticated = info->authenticated;
+               key->master = info->master;
+               key->enc_size = info->enc_size;
+       }
+
+       if (write(mgmt_sock, buf, sizeof(*hdr) + cp_size) < 0)
+               err = -errno;
+       else
+               err = 0;
+
+       g_free(buf);
+
+       return err;
+}
+
 static struct btd_adapter_ops mgmt_ops = {
        .setup = mgmt_setup,
        .cleanup = mgmt_cleanup,
        .set_powered = mgmt_set_powered,
        .set_discoverable = mgmt_set_discoverable,
        .set_pairable = mgmt_set_pairable,
-       .set_limited_discoverable = mgmt_set_limited_discoverable,
        .start_discovery = mgmt_start_discovery,
        .stop_discovery = mgmt_stop_discovery,
        .set_name = mgmt_set_name,
@@ -2071,7 +2488,7 @@ static struct btd_adapter_ops mgmt_ops = {
        .unblock_device = mgmt_unblock_device,
        .get_conn_list = mgmt_get_conn_list,
        .disconnect = mgmt_disconnect,
-       .remove_bonding = mgmt_remove_bonding,
+       .remove_bonding = mgmt_unpair_device,
        .pincode_reply = mgmt_pincode_reply,
        .confirm_reply = mgmt_confirm_reply,
        .passkey_reply = mgmt_passkey_reply,
@@ -2089,6 +2506,7 @@ static struct btd_adapter_ops mgmt_ops = {
        .add_remote_oob_data = mgmt_add_remote_oob_data,
        .remove_remote_oob_data = mgmt_remove_remote_oob_data,
        .confirm_name = mgmt_confirm_name,
+       .load_ltks = mgmtops_load_ltks,
 };
 
 static int mgmt_init(void)
index 2d73910..3c611a9 100644 (file)
@@ -39,6 +39,7 @@
 #include <bluetooth/rfcomm.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
 
 #include <glib.h>
 
@@ -54,7 +55,6 @@
 #define PNATD "/usr/bin/phonet-at"
 
 #define DUN_CHANNEL 1
-#define DUN_UUID "00001103-0000-1000-8000-00805F9B34FB"
 
 #define TTY_TIMEOUT 100
 #define TTY_TRIES 10
@@ -347,7 +347,7 @@ static void confirm_cb(GIOChannel *io, gpointer user_data)
                return;
        }
 
-       if (btd_request_authorization(&server->bda, &client->bda, DUN_UUID,
+       if (btd_request_authorization(&server->bda, &client->bda, DUN_GW_UUID,
                                                auth_cb, user_data) < 0) {
                error("Requesting DUN authorization failed");
                return;
index 14a5cb6..288f849 100644 (file)
@@ -696,13 +696,22 @@ done:
        return dbus_message_new_method_return(msg);
 }
 
-static GDBusMethodTable service_methods[] = {
-       { "AddRecord",          "s",    "u",    add_service_record      },
-       { "UpdateRecord",       "us",   "",     update_service_record   },
-       { "RemoveRecord",       "u",    "",     remove_service_record   },
-       { "RequestAuthorization","su",  "",     request_authorization,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "CancelAuthorization", "",    "",     cancel_authorization    },
+static const GDBusMethodTable service_methods[] = {
+       { GDBUS_METHOD("AddRecord",
+               GDBUS_ARGS({ "record", "s" }),
+               GDBUS_ARGS({ "handle", "u" }),
+               add_service_record) },
+       { GDBUS_METHOD("UpdateRecord",
+               GDBUS_ARGS({ "handle", "u" }, { "record", "s" }), NULL,
+               update_service_record) },
+       { GDBUS_METHOD("RemoveRecord",
+               GDBUS_ARGS({ "handle", "u" }), NULL,
+               remove_service_record) },
+       { GDBUS_ASYNC_METHOD("RequestAuthorization",
+               GDBUS_ARGS({ "address", "s" }, { "handle", "u"}), NULL,
+               request_authorization) },
+       { GDBUS_METHOD("CancelAuthorization",
+               NULL, NULL, cancel_authorization) },
        { }
 };
 
index 1ae638b..9c69c6d 100644 (file)
@@ -26,6 +26,7 @@
 #endif
 
 #include <bluetooth/bluetooth.h>
+#include <glib.h>
 
 #include "plugin.h"
 #include "adapter.h"
  */
 
 static ssize_t wii_pincb(struct btd_adapter *adapter, struct btd_device *device,
-                                                               char *pinbuf)
+                                               char *pinbuf, gboolean *display)
 {
        uint16_t vendor, product;
        bdaddr_t sba, dba;
-       char addr[18];
+       char addr[18], name[25];
 
        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) {
+
+       device_get_name(device, name, sizeof(name));
+       name[sizeof(name) - 1] = 0;
+
+       if (g_str_equal(name, "Nintendo RVL-CNT-01") ||
+                               (vendor == 0x057e && product == 0x0306)) {
                DBG("Forcing fixed pin on detected wiimote %s", addr);
                memcpy(pinbuf, &sba, 6);
                return 6;
diff --git a/proximity/immalert.c b/proximity/immalert.c
new file mode 100644 (file)
index 0000000..1540b61
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments 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 <glib.h>
+#include <bluetooth/uuid.h>
+#include <adapter.h>
+
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "log.h"
+#include "gattrib.h"
+#include "att.h"
+#include "gatt.h"
+#include "att-database.h"
+#include "gatt-service.h"
+#include "attrib-server.h"
+#include "device.h"
+#include "attio.h"
+#include "dbus-common.h"
+#include "reporter.h"
+#include "immalert.h"
+
+struct imm_alert_adapter {
+       struct btd_adapter *adapter;
+       DBusConnection *conn;
+       GSList *connected_devices;
+};
+
+struct connected_device {
+       struct btd_device *device;
+       struct imm_alert_adapter *adapter;
+       uint8_t alert_level;
+       guint callback_id;
+};
+
+static GSList *imm_alert_adapters;
+
+static int imdevice_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct connected_device *condev = a;
+       const struct btd_device *device = b;
+
+       if (condev->device == device)
+               return 0;
+
+       return -1;
+}
+
+static struct connected_device *
+find_connected_device(struct imm_alert_adapter *ia, struct btd_device *device)
+{
+       GSList *l = g_slist_find_custom(ia->connected_devices, device,
+                                                               imdevice_cmp);
+       if (!l)
+               return NULL;
+
+       return l->data;
+}
+
+static int imadapter_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct imm_alert_adapter *imadapter = a;
+       const struct btd_adapter *adapter = b;
+
+       if (imadapter->adapter == adapter)
+               return 0;
+
+       return -1;
+}
+
+static struct imm_alert_adapter *
+find_imm_alert_adapter(struct btd_adapter *adapter)
+{
+       GSList *l = g_slist_find_custom(imm_alert_adapters, adapter,
+                                                               imadapter_cmp);
+       if (!l)
+               return NULL;
+
+       return l->data;
+}
+
+const char *imm_alert_get_level(struct btd_device *device)
+{
+       struct imm_alert_adapter *imadapter;
+       struct connected_device *condev;
+
+       if (!device)
+               return get_alert_level_string(NO_ALERT);
+
+       imadapter = find_imm_alert_adapter(device_get_adapter(device));
+       if (!imadapter)
+               return get_alert_level_string(NO_ALERT);
+
+       condev = find_connected_device(imadapter, device);
+       if (!condev)
+               return get_alert_level_string(NO_ALERT);
+
+       return get_alert_level_string(condev->alert_level);
+}
+
+static void imm_alert_emit_alert_signal(struct connected_device *condev,
+                                                       uint8_t alert_level)
+{
+       struct imm_alert_adapter *adapter;
+       const char *path, *alert_level_str;
+
+       if (!condev)
+               return;
+
+       adapter = condev->adapter;
+       path = device_get_path(condev->device);
+       alert_level_str = get_alert_level_string(alert_level);
+
+       DBG("alert %s remote %s", alert_level_str, path);
+
+       emit_property_changed(adapter->conn, path,
+                       PROXIMITY_REPORTER_INTERFACE, "ImmediateAlertLevel",
+                       DBUS_TYPE_STRING, &alert_level_str);
+}
+
+static void imm_alert_remove_condev(struct connected_device *condev)
+{
+       struct imm_alert_adapter *ia;
+
+       if (!condev)
+               return;
+
+       ia = condev->adapter;
+
+       if (condev->callback_id && condev->device)
+               btd_device_remove_attio_callback(condev->device,
+                                                       condev->callback_id);
+
+       if (condev->device)
+               btd_device_unref(condev->device);
+
+       ia->connected_devices = g_slist_remove(ia->connected_devices, condev);
+       g_free(condev);
+}
+
+/* condev can be NULL */
+static void imm_alert_disc_cb(gpointer user_data)
+{
+       struct connected_device *condev = user_data;
+
+       if (!condev)
+               return;
+
+       DBG("immediate alert remove device %p", condev->device);
+
+       imm_alert_emit_alert_signal(condev, NO_ALERT);
+       imm_alert_remove_condev(condev);
+}
+
+static uint8_t imm_alert_alert_lvl_write(struct attribute *a,
+                               struct btd_device *device, gpointer user_data)
+{
+       uint8_t value;
+       struct imm_alert_adapter *ia = user_data;
+       struct connected_device *condev = NULL;
+
+       if (!device)
+               goto set_error;
+
+       condev = find_connected_device(ia, device);
+
+       if (a->len == 0) {
+               DBG("Illegal alert level length");
+               goto set_error;
+       }
+
+       value = a->data[0];
+       if (value != NO_ALERT && value != MILD_ALERT && value != HIGH_ALERT) {
+               DBG("Illegal alert value");
+               goto set_error;
+       }
+
+       /* Register a disconnect cb if the alert level is non-zero */
+       if (value != NO_ALERT && !condev) {
+               condev = g_new0(struct connected_device, 1);
+               condev->device = btd_device_ref(device);
+               condev->adapter = ia;
+               condev->callback_id = btd_device_add_attio_callback(device,
+                                       NULL, imm_alert_disc_cb, condev);
+               ia->connected_devices = g_slist_append(ia->connected_devices,
+                                                               condev);
+               DBG("added connected dev %p", device);
+       }
+
+       if (value != NO_ALERT) {
+               condev->alert_level = value;
+               imm_alert_emit_alert_signal(condev, value);
+       }
+
+       /*
+        * Emit NO_ALERT if the alert level was non-zero before. This is
+        * guaranteed when there's a condev.
+        */
+       if (value == NO_ALERT && condev)
+               imm_alert_disc_cb(condev);
+
+       DBG("alert level set to %d by device %p", value, device);
+       return 0;
+
+set_error:
+       error("Set immediate alert level for dev %p", device);
+       /* remove alerts by erroneous devices */
+       imm_alert_disc_cb(condev);
+       return ATT_ECODE_IO;
+}
+
+void imm_alert_register(struct btd_adapter *adapter, DBusConnection *conn)
+{
+       gboolean svc_added;
+       bt_uuid_t uuid;
+       struct imm_alert_adapter *imadapter;
+
+       bt_uuid16_create(&uuid, IMMEDIATE_ALERT_SVC_UUID);
+
+       imadapter = g_new0(struct imm_alert_adapter, 1);
+       imadapter->adapter = adapter;
+       imadapter->conn = dbus_connection_ref(conn);
+
+       imm_alert_adapters = g_slist_append(imm_alert_adapters, imadapter);
+
+       /* Immediate Alert Service */
+       svc_added = gatt_service_add(adapter,
+                               GATT_PRIM_SVC_UUID, &uuid,
+                               /* Alert level characteristic */
+                               GATT_OPT_CHR_UUID, ALERT_LEVEL_CHR_UUID,
+                               GATT_OPT_CHR_PROPS,
+                                       ATT_CHAR_PROPER_WRITE_WITHOUT_RESP,
+                               GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE,
+                                       imm_alert_alert_lvl_write, imadapter,
+                               GATT_OPT_INVALID);
+
+       if (!svc_added) {
+               imm_alert_unregister(adapter);
+               return;
+       }
+
+       DBG("Immediate Alert service added");
+}
+
+static void remove_condev_list_item(gpointer data, gpointer user_data)
+{
+       struct connected_device *condev = data;
+
+       imm_alert_remove_condev(condev);
+}
+
+void imm_alert_unregister(struct btd_adapter *adapter)
+{
+       struct imm_alert_adapter *imadapter;
+
+       imadapter = find_imm_alert_adapter(adapter);
+       if (!imadapter)
+               return;
+
+       g_slist_foreach(imadapter->connected_devices, remove_condev_list_item,
+                                                                       NULL);
+       dbus_connection_unref(imadapter->conn);
+
+       imm_alert_adapters = g_slist_remove(imm_alert_adapters, imadapter);
+       g_free(imadapter);
+}
diff --git a/proximity/immalert.h b/proximity/immalert.h
new file mode 100644 (file)
index 0000000..dd28eaa
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Texas Instruments 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
+ *
+ */
+
+void imm_alert_register(struct btd_adapter *adapter, DBusConnection *conn);
+void imm_alert_unregister(struct btd_adapter *adapter);
+const char *imm_alert_get_level(struct btd_device *device);
diff --git a/proximity/linkloss.c b/proximity/linkloss.c
new file mode 100644 (file)
index 0000000..14403cb
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Texas Instruments 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 <glib.h>
+#include <bluetooth/uuid.h>
+#include <adapter.h>
+
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include "log.h"
+#include "att-database.h"
+#include "gattrib.h"
+#include "att.h"
+#include "gatt.h"
+#include "gatt-service.h"
+#include "attrib-server.h"
+#include "device.h"
+#include "attio.h"
+#include "dbus-common.h"
+#include "reporter.h"
+#include "linkloss.h"
+
+#define BLUEZ_SERVICE "org.bluez"
+
+struct link_loss_adapter {
+       struct btd_adapter *adapter;
+       uint16_t alert_lvl_value_handle;
+       DBusConnection *conn;
+       GSList *connected_devices;
+};
+
+struct connected_device {
+       struct btd_device *device;
+       struct link_loss_adapter *adapter;
+       uint8_t alert_level;
+       guint callback_id;
+       guint local_disc_id;
+};
+
+static GSList *link_loss_adapters;
+
+static int lldevice_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct connected_device *llcondev = a;
+       const struct btd_device *device = b;
+
+       if (llcondev->device == device)
+               return 0;
+
+       return -1;
+}
+
+static struct connected_device *
+find_connected_device(struct link_loss_adapter *la, struct btd_device *device)
+{
+       GSList *l = g_slist_find_custom(la->connected_devices, device,
+                                                               lldevice_cmp);
+       if (!l)
+               return NULL;
+
+       return l->data;
+}
+
+static int lladapter_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct link_loss_adapter *lladapter = a;
+       const struct btd_adapter *adapter = b;
+
+       if (lladapter->adapter == adapter)
+               return 0;
+
+       return -1;
+}
+
+static struct link_loss_adapter *
+find_link_loss_adapter(struct btd_adapter *adapter)
+{
+       GSList *l = g_slist_find_custom(link_loss_adapters, adapter,
+                                                       lladapter_cmp);
+       if (!l)
+               return NULL;
+
+       return l->data;
+}
+
+const char *link_loss_get_alert_level(struct btd_device *device)
+{
+       struct link_loss_adapter *lladapter;
+       struct connected_device *condev;
+
+       if (!device)
+               return get_alert_level_string(NO_ALERT);
+
+       lladapter = find_link_loss_adapter(device_get_adapter(device));
+       if (!lladapter)
+               return get_alert_level_string(NO_ALERT);
+
+       condev = find_connected_device(lladapter, device);
+       if (!condev)
+               return get_alert_level_string(NO_ALERT);
+
+       return get_alert_level_string(condev->alert_level);
+}
+
+static void link_loss_emit_alert_signal(struct connected_device *condev)
+{
+       struct link_loss_adapter *adapter = condev->adapter;
+       const char *alert_level_str, *path;
+
+       if (!condev->device)
+               return;
+
+       path = device_get_path(condev->device);
+       alert_level_str = get_alert_level_string(condev->alert_level);
+
+       DBG("alert %s remote %s", alert_level_str, path);
+
+       emit_property_changed(adapter->conn, path,
+                       PROXIMITY_REPORTER_INTERFACE, "LinkLossAlertLevel",
+                       DBUS_TYPE_STRING, &alert_level_str);
+}
+
+static uint8_t link_loss_alert_lvl_read(struct attribute *a,
+                               struct btd_device *device, gpointer user_data)
+{
+       struct link_loss_adapter *la = user_data;
+       struct connected_device *condev;
+       uint8_t alert_level = NO_ALERT;
+
+       if (!device)
+               goto out;
+
+       condev = find_connected_device(la, device);
+       if (!condev)
+               goto out;
+
+       alert_level = condev->alert_level;
+
+out:
+       DBG("return alert level %d for dev %p", alert_level, device);
+
+       /* update the alert level according to the requesting device */
+       attrib_db_update(la->adapter, a->handle, NULL, &alert_level,
+                                               sizeof(alert_level), NULL);
+
+       return 0;
+}
+
+/* condev can be NULL */
+static void link_loss_remove_condev(struct connected_device *condev)
+{
+       struct link_loss_adapter *la;
+
+       if (!condev)
+               return;
+
+       la = condev->adapter;
+
+       if (condev->callback_id && condev->device)
+               btd_device_remove_attio_callback(condev->device,
+                                                       condev->callback_id);
+
+       if (condev->local_disc_id && condev->device)
+               device_remove_disconnect_watch(condev->device,
+                                                       condev->local_disc_id);
+
+       if (condev->device)
+               btd_device_unref(condev->device);
+
+       la->connected_devices = g_slist_remove(la->connected_devices, condev);
+       g_free(condev);
+}
+
+static void link_loss_disc_cb(gpointer user_data)
+{
+       struct connected_device *condev = user_data;
+
+       DBG("alert loss disconnect device %p", condev->device);
+
+       /* if an alert-level is set, emit a signal */
+       if (condev->alert_level != NO_ALERT)
+               link_loss_emit_alert_signal(condev);
+
+       /* we are open for more changes now */
+       link_loss_remove_condev(condev);
+}
+
+static void link_loss_local_disc(struct btd_device *device,
+                                       gboolean removal, void *user_data)
+{
+       struct connected_device *condev = user_data;
+
+       /* no need to alert on this device - we requested disconnection */
+       link_loss_remove_condev(condev);
+
+       DBG("alert level zeroed for locally disconnecting dev %p", device);
+}
+
+static uint8_t link_loss_alert_lvl_write(struct attribute *a,
+                               struct btd_device *device, gpointer user_data)
+{
+       uint8_t value;
+       struct link_loss_adapter *la = user_data;
+       struct connected_device *condev = NULL;
+
+       if (!device)
+               goto set_error;
+
+       /* condev might remain NULL here if nothing is found */
+       condev = find_connected_device(la, device);
+
+       if (a->len == 0) {
+               DBG("Illegal alert level length");
+               goto set_error;
+       }
+
+       value = a->data[0];
+       if (value != NO_ALERT && value != MILD_ALERT && value != HIGH_ALERT) {
+               DBG("Illegal alert value");
+               goto set_error;
+       }
+
+       /* Register a disconnect cb if the alert level is non-zero */
+       if (value != NO_ALERT && !condev) {
+               condev = g_new0(struct connected_device, 1);
+               condev->device = btd_device_ref(device);
+               condev->adapter = la;
+               condev->callback_id = btd_device_add_attio_callback(device,
+                                       NULL, link_loss_disc_cb, condev);
+               condev->local_disc_id = device_add_disconnect_watch(device,
+                                       link_loss_local_disc, condev, NULL);
+
+               la->connected_devices = g_slist_append(la->connected_devices,
+                                                               condev);
+       } else if (value == NO_ALERT && condev) {
+               link_loss_remove_condev(condev);
+               condev = NULL;
+       }
+
+       DBG("alert level set to %d by device %p", value, device);
+
+       if (condev)
+               condev->alert_level = value;
+
+       return 0;
+
+set_error:
+       error("Set link loss alert level for dev %p", device);
+       /* reset alert level on erroneous devices */
+       link_loss_remove_condev(condev);
+       return ATT_ECODE_IO;
+}
+
+void link_loss_register(struct btd_adapter *adapter, DBusConnection *conn)
+{
+       gboolean svc_added;
+       bt_uuid_t uuid;
+       struct link_loss_adapter *lladapter;
+
+       bt_uuid16_create(&uuid, LINK_LOSS_SVC_UUID);
+
+       lladapter = g_new0(struct link_loss_adapter, 1);
+       lladapter->adapter = adapter;
+       lladapter->conn = dbus_connection_ref(conn);
+
+       link_loss_adapters = g_slist_append(link_loss_adapters, lladapter);
+
+       /* Link Loss Service */
+       svc_added = gatt_service_add(adapter,
+                       GATT_PRIM_SVC_UUID, &uuid,
+                       /* Alert level characteristic */
+                       GATT_OPT_CHR_UUID, ALERT_LEVEL_CHR_UUID,
+                       GATT_OPT_CHR_PROPS,
+                               ATT_CHAR_PROPER_READ | ATT_CHAR_PROPER_WRITE,
+                       GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+                               link_loss_alert_lvl_read, lladapter,
+                       GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE,
+                               link_loss_alert_lvl_write, lladapter,
+                       GATT_OPT_CHR_VALUE_GET_HANDLE,
+                               &lladapter->alert_lvl_value_handle,
+                       GATT_OPT_INVALID);
+
+       if (!svc_added)
+               goto err;
+
+       DBG("Link Loss service added");
+       return;
+
+err:
+       error("Error adding Link Loss service");
+       link_loss_unregister(adapter);
+}
+
+static void remove_condev_list_item(gpointer data, gpointer user_data)
+{
+       struct connected_device *condev = data;
+
+       link_loss_remove_condev(condev);
+}
+
+void link_loss_unregister(struct btd_adapter *adapter)
+{
+       struct link_loss_adapter *lladapter;
+       lladapter = find_link_loss_adapter(adapter);
+       if (!lladapter)
+               return;
+
+       g_slist_foreach(lladapter->connected_devices, remove_condev_list_item,
+                       NULL);
+       dbus_connection_unref(lladapter->conn);
+
+       link_loss_adapters = g_slist_remove(link_loss_adapters, lladapter);
+       g_free(lladapter);
+}
diff --git a/proximity/linkloss.h b/proximity/linkloss.h
new file mode 100644 (file)
index 0000000..a7d83d0
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Texas Instruments 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
+ *
+ */
+
+void link_loss_register(struct btd_adapter *adapter, DBusConnection *conn);
+void link_loss_unregister(struct btd_adapter *adapter);
+const char *link_loss_get_alert_level(struct btd_device *device);
index 5f0fc12..3d5d9b2 100644 (file)
 #endif
 
 #include <errno.h>
-
+#include <stdint.h>
 #include <glib.h>
 #include <gdbus.h>
 
 #include "log.h"
 #include "plugin.h"
 #include "manager.h"
+#include "hcid.h"
 
 static DBusConnection *connection = NULL;
 static GKeyFile *config = NULL;
@@ -59,6 +60,10 @@ static GKeyFile *open_config_file(const char *file)
 
 static int proximity_init(void)
 {
+       if (!main_opts.gatt_enabled) {
+               DBG("GATT is disabled");
+               return -ENOTSUP;
+       }
 
        connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
        if (connection == NULL)
@@ -76,6 +81,9 @@ static int proximity_init(void)
 
 static void proximity_exit(void)
 {
+       if (!main_opts.gatt_enabled)
+               return;
+
        if (config)
                g_key_file_free(config);
 
index a767554..f2e49a6 100644 (file)
 #include "adapter.h"
 #include "device.h"
 #include "att.h"
+#include "gattrib.h"
+#include "gatt.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  = {
@@ -51,7 +49,7 @@ static struct enabled enabled  = {
 
 static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
 {
-       const struct att_primary *prim = a;
+       const struct gatt_primary *prim = a;
        const char *uuid = b;
 
        return g_strcmp0(prim->uuid, uuid);
@@ -59,7 +57,7 @@ static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
 
 static int attio_device_probe(struct btd_device *device, GSList *uuids)
 {
-       struct att_primary *linkloss, *txpower, *immediate;
+       struct gatt_primary *linkloss, *txpower, *immediate;
        GSList *l, *primaries;
 
        primaries = btd_device_get_primaries(device);
@@ -84,12 +82,18 @@ static void attio_device_remove(struct btd_device *device)
 }
 
 static struct btd_device_driver monitor_driver = {
-       .name = "Proximity GATT Driver",
+       .name = "Proximity GATT Monitor Driver",
        .uuids = BTD_UUIDS(IMMEDIATE_ALERT_UUID, LINK_LOSS_UUID, TX_POWER_UUID),
        .probe = attio_device_probe,
        .remove = attio_device_remove,
 };
 
+static struct btd_adapter_driver reporter_server_driver = {
+       .name = "Proximity GATT Reporter Driver",
+       .probe = reporter_init,
+       .remove = reporter_exit,
+};
+
 static void load_config_file(GKeyFile *config)
 {
        char **list;
@@ -118,19 +122,29 @@ int proximity_manager_init(DBusConnection *conn, GKeyFile *config)
 
        load_config_file(config);
 
-       /* TODO: Register Proximity Monitor/Reporter drivers */
+       connection = dbus_connection_ref(conn);
+
        ret = btd_register_device_driver(&monitor_driver);
        if (ret < 0)
-               return ret;
+               goto fail_monitor;
 
-       connection = dbus_connection_ref(conn);
+       ret = btd_register_adapter_driver(&reporter_server_driver);
+       if (ret < 0)
+               goto fail_reporter;
+
+       return 0;
 
-       return reporter_init();
+fail_reporter:
+       btd_unregister_device_driver(&monitor_driver);
+
+fail_monitor:
+       dbus_connection_unref(connection);
+       return ret;
 }
 
 void proximity_manager_exit(void)
 {
-       reporter_exit();
        btd_unregister_device_driver(&monitor_driver);
+       btd_unregister_adapter_driver(&reporter_server_driver);
        dbus_connection_unref(connection);
 }
index 76020ee..98dbcd1 100644 (file)
@@ -49,7 +49,7 @@
 #include "monitor.h"
 #include "textfile.h"
 
-#define PROXIMITY_INTERFACE "org.bluez.Proximity"
+#define PROXIMITY_INTERFACE "org.bluez.ProximityMonitor"
 
 #define ALERT_LEVEL_CHR_UUID 0x2A06
 #define POWER_LEVEL_CHR_UUID 0x2A07
@@ -168,7 +168,7 @@ static void char_discovered_cb(GSList *characteristics, guint8 status,
                                                        gpointer user_data)
 {
        struct monitor *monitor = user_data;
-       struct att_char *chr;
+       struct gatt_char *chr;
        uint8_t value = str2level(monitor->linklosslevel);
 
        if (status) {
@@ -236,7 +236,7 @@ static void tx_power_handle_cb(GSList *characteristics, guint8 status,
                                                        gpointer user_data)
 {
        struct monitor *monitor = user_data;
-       struct att_char *chr;
+       struct gatt_char *chr;
 
        if (status) {
                error("Discover Tx Power handle: %s", att_ecode2str(status));
@@ -322,7 +322,7 @@ static void immediate_handle_cb(GSList *characteristics, guint8 status,
                                                        gpointer user_data)
 {
        struct monitor *monitor = user_data;
-       struct att_char *chr;
+       struct gatt_char *chr;
 
        if (status) {
                error("Discover Immediate Alert handle: %s",
@@ -546,15 +546,19 @@ static DBusMessage *set_property(DBusConnection *conn,
        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 const GDBusMethodTable monitor_methods[] = {
+       { GDBUS_METHOD("GetProperties",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       get_properties) },
+       { GDBUS_ASYNC_METHOD("SetProperty",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
+                       set_property) },
        { }
 };
 
-static GDBusSignalTable monitor_signals[] = {
-       { "PropertyChanged",    "sv"    },
+static const GDBusSignalTable monitor_signals[] = {
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
        { }
 };
 
@@ -583,8 +587,8 @@ static void monitor_destroy(gpointer user_data)
 }
 
 int monitor_register(DBusConnection *conn, struct btd_device *device,
-               struct att_primary *linkloss, struct att_primary *txpower,
-               struct att_primary *immediate, struct enabled *enabled)
+               struct gatt_primary *linkloss, struct gatt_primary *txpower,
+               struct gatt_primary *immediate, struct enabled *enabled)
 {
        const char *path = device_get_path(device);
        struct monitor *monitor;
@@ -617,8 +621,8 @@ int monitor_register(DBusConnection *conn, struct btd_device *device,
 
        if (linkloss && enabled->linkloss) {
                monitor->linkloss = g_new0(struct att_range, 1);
-               monitor->linkloss->start = linkloss->start;
-               monitor->linkloss->end = linkloss->end;
+               monitor->linkloss->start = linkloss->range.start;
+               monitor->linkloss->end = linkloss->range.end;
 
                monitor->enabled.linkloss = TRUE;
        }
@@ -626,16 +630,16 @@ int monitor_register(DBusConnection *conn, struct btd_device *device,
        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->txpower->start = txpower->range.start;
+                       monitor->txpower->end = txpower->range.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->immediate->start = immediate->range.start;
+                       monitor->immediate->end = immediate->range.end;
                }
 
                monitor->enabled.findme = enabled->findme;
index fb79e26..b71363d 100644 (file)
@@ -29,6 +29,6 @@ struct enabled {
 };
 
 int monitor_register(DBusConnection *conn, struct btd_device *device,
-               struct att_primary *linkloss, struct att_primary *txpower,
-               struct att_primary *immediate, struct enabled *enabled);
+               struct gatt_primary *linkloss, struct gatt_primary *txpower,
+               struct gatt_primary *immediate, struct enabled *enabled);
 void monitor_unregister(DBusConnection *conn, struct btd_device *device);
index a139c7c..607de2b 100644 (file)
 #include <glib.h>
 #include <bluetooth/uuid.h>
 #include <adapter.h>
+#include <errno.h>
+
+#include <dbus/dbus.h>
+#include <gdbus.h>
 
 #include "log.h"
 
+#include "dbus-common.h"
+#include "error.h"
+#include "device.h"
 #include "hcid.h"
-#include "att.h"
 #include "gattrib.h"
+#include "att.h"
+#include "gatt.h"
+#include "att-database.h"
 #include "attrib-server.h"
 #include "reporter.h"
+#include "linkloss.h"
+#include "immalert.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
+#define BLUEZ_SERVICE "org.bluez"
 
-enum {
-       NO_ALERT = 0x00,
-       MILD_ALERT = 0x01,
-       HIGH_ALERT = 0x02,
+struct reporter_adapter {
+       DBusConnection *conn;
+       struct btd_adapter *adapter;
+       GSList *devices;
 };
 
-static uint16_t tx_power_handle;
+static GSList *reporter_adapters;
 
-static void register_link_loss(void)
+static int radapter_cmp(gconstpointer a, gconstpointer b)
 {
-       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;
-       }
+       const struct reporter_adapter *radapter = a;
+       const struct btd_adapter *adapter = b;
 
-       DBG("start_handle=0x%04x", start_handle);
+       if (radapter->adapter == adapter)
+               return 0;
 
-       h = start_handle;
+       return -1;
+}
 
-       /* 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);
+static struct reporter_adapter *
+find_reporter_adapter(struct btd_adapter *adapter)
+{
+       GSList *l = g_slist_find_custom(reporter_adapters, adapter,
+                                                               radapter_cmp);
+       if (!l)
+               return NULL;
 
-       /* 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);
+       return l->data;
+}
 
-       /* 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);
+const char *get_alert_level_string(uint8_t level)
+{
+       switch (level) {
+       case NO_ALERT:
+               return "none";
+       case MILD_ALERT:
+               return "mild";
+       case HIGH_ALERT:
+               return "high";
+       }
 
-       g_assert(h - start_handle == svc_size);
+       return "unknown";
 }
 
-static void register_tx_power(void)
+static void register_tx_power(struct btd_adapter *adapter)
 {
        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);
+       bt_uuid16_create(&uuid, TX_POWER_SVC_UUID);
+       start_handle = attrib_db_find_avail(adapter, &uuid, svc_size);
        if (start_handle == 0) {
                error("Not enough free handles to register service");
                return;
@@ -114,91 +116,191 @@ static void register_tx_power(void)
        /* 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);
+       attrib_db_add(adapter, 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);
+       attrib_db_add(adapter, 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);
+       attrib_db_add(adapter, 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);
+       attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NONE, atval, 2);
 
        g_assert(h - start_handle == svc_size);
 }
 
-static void register_immediate_alert(void)
+static DBusMessage *get_properties(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
 {
-       uint16_t start_handle, h;
-       const int svc_size = 3;
-       uint8_t atval[256];
-       bt_uuid_t uuid;
+       DBusMessageIter iter;
+       DBusMessageIter dict;
+       DBusMessage *reply = NULL;
+       const char *linkloss_level, *immalert_level;
+       struct btd_device *device = data;
 
-       /* 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;
-       }
+       reply = dbus_message_new_method_return(msg);
+       if (!reply)
+               return NULL;
 
-       DBG("start_handle=0x%04x", start_handle);
+       linkloss_level = link_loss_get_alert_level(device);
+       immalert_level = imm_alert_get_level(device);
 
-       h = start_handle;
+       dbus_message_iter_init_append(reply, &iter);
 
-       /* 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);
+       if (!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))
+               goto err;
 
-       /* 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);
+       dict_append_entry(&dict, "LinkLossAlertLevel", DBUS_TYPE_STRING,
+                                                       &linkloss_level);
+       dict_append_entry(&dict, "ImmediateAlertLevel", DBUS_TYPE_STRING,
+                                                       &immalert_level);
 
-       /* 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);
+       if (!dbus_message_iter_close_container(&iter, &dict))
+               goto err;
 
-       g_assert(h - start_handle == svc_size);
+       return reply;
+
+err:
+       if (reply)
+               dbus_message_unref(reply);
+       return btd_error_failed(msg, "not enough memory");
+}
+
+static const GDBusMethodTable reporter_methods[] = {
+       { GDBUS_METHOD("GetProperties",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       get_properties) },
+       { }
+};
+
+static const GDBusSignalTable reporter_signals[] = {
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+       { }
+};
+
+static void unregister_reporter_device(gpointer data, gpointer user_data)
+{
+       struct btd_device *device = data;
+       struct reporter_adapter *radapter = user_data;
+       const char *path = device_get_path(device);
+
+       DBG("unregister on device %s", path);
+
+       g_dbus_unregister_interface(radapter->conn, path,
+                                       PROXIMITY_REPORTER_INTERFACE);
+
+       radapter->devices = g_slist_remove(radapter->devices, device);
+       btd_device_unref(device);
+}
+
+static void register_reporter_device(struct btd_device *device,
+                                       struct reporter_adapter *radapter)
+{
+       const char *path = device_get_path(device);
+
+       DBG("register on device %s", path);
+
+       g_dbus_register_interface(radapter->conn, path,
+                                       PROXIMITY_REPORTER_INTERFACE,
+                                       reporter_methods, reporter_signals,
+                                       NULL, device, NULL);
+
+       btd_device_ref(device);
+       radapter->devices = g_slist_prepend(radapter->devices, device);
 }
 
-int reporter_init(void)
+static int reporter_device_probe(struct btd_device *device, GSList *uuids)
 {
-       if (!main_opts.attrib_server) {
-               DBG("Attribute server is disabled");
+       struct reporter_adapter *radapter;
+       struct btd_adapter *adapter = device_get_adapter(device);
+
+       radapter = find_reporter_adapter(adapter);
+       if (!radapter)
                return -1;
+
+       register_reporter_device(device, radapter);
+       return 0;
+}
+
+static void reporter_device_remove(struct btd_device *device)
+{
+       struct reporter_adapter *radapter;
+       struct btd_adapter *adapter = device_get_adapter(device);
+
+       radapter = find_reporter_adapter(adapter);
+       if (!radapter)
+               return;
+
+       unregister_reporter_device(device, radapter);
+}
+
+/* device driver for tracking remote GATT client devices */
+static struct btd_device_driver reporter_device_driver = {
+       .name = "Proximity GATT Reporter Device Tracker Driver",
+       .uuids = BTD_UUIDS(GATT_UUID),
+       .probe = reporter_device_probe,
+       .remove = reporter_device_remove,
+};
+
+int reporter_init(struct btd_adapter *adapter)
+{
+       struct reporter_adapter *radapter;
+       DBusConnection *conn;
+
+       if (!main_opts.gatt_enabled) {
+               DBG("GATT is disabled");
+               return -ENOTSUP;
        }
 
-       DBG("Proximity Reporter");
+       conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+       if (!conn)
+               return -1;
+
+       radapter = g_new0(struct reporter_adapter, 1);
+       radapter->adapter = adapter;
+       radapter->conn = conn;
+
+       link_loss_register(adapter, radapter->conn);
+       register_tx_power(adapter);
+       imm_alert_register(adapter, radapter->conn);
 
-       register_link_loss();
-       register_tx_power();
-       register_immediate_alert();
+       btd_register_device_driver(&reporter_device_driver);
+
+       reporter_adapters = g_slist_prepend(reporter_adapters, radapter);
+       DBG("Proximity Reporter for adapter %p", adapter);
 
        return 0;
 }
 
-void reporter_exit(void)
+void reporter_exit(struct btd_adapter *adapter)
 {
+       struct reporter_adapter *radapter = find_reporter_adapter(adapter);
+       if (!radapter)
+               return;
+
+       btd_unregister_device_driver(&reporter_device_driver);
+
+       g_slist_foreach(radapter->devices, unregister_reporter_device,
+                                                               radapter);
+
+       link_loss_unregister(adapter);
+       imm_alert_unregister(adapter);
+       dbus_connection_unref(radapter->conn);
+
+       reporter_adapters = g_slist_remove(reporter_adapters, radapter);
+       g_free(radapter);
 }
index ea6b83d..5ae0eb2 100644 (file)
  *
  */
 
-int reporter_init(void);
-void reporter_exit(void);
+#define PROXIMITY_REPORTER_INTERFACE "org.bluez.ProximityReporter"
+
+#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,
+};
+
+int reporter_init(struct btd_adapter *adapter);
+void reporter_exit(struct btd_adapter *adapter);
+
+const char *get_alert_level_string(uint8_t level);
index a97f434..9fa9c56 100644 (file)
 #include <config.h>
 #endif
 
-#include <errno.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <gdbus.h>
-
 #include "log.h"
 #include "adapter.h"
-#include "device.h"
 
 #include "manager.h"
 #include "server.h"
index acdec77..7ea4e92 100644 (file)
@@ -26,9 +26,6 @@
 #include <config.h>
 #endif
 
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdint.h>
 #include <glib.h>
 #include <gdbus.h>
 
 #define SAP_DUMMY_PATH "/org/bluez/test"
 
 enum {
-       SIM_DISCONNECTED= 0x00,
-       SIM_CONNECTED   = 0x01,
-       SIM_POWERED_OFF = 0x02,
-       SIM_MISSING     = 0x03
+       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 void *sap_data = NULL; /* SAP server private data. */
 static gboolean ongoing_call_status = FALSE;
 static int max_msg_size_supported = 512;
 
@@ -60,26 +57,32 @@ void sap_connect_req(void *sap_device, uint16_t maxmsgsize)
                sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED,
                                                                maxmsgsize);
                return;
-       } else if (max_msg_size_supported > maxmsgsize) {
+       }
+
+       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) {
+       }
+
+       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) {
+       }
+
+       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);
        }
+
+       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)
@@ -113,7 +116,7 @@ void sap_transfer_apdu_req(void *sap_device, struct sap_parameter *param)
                        SAP_RESULT_ERROR_NOT_ACCESSIBLE, NULL, 0);
        else
                sap_transfer_apdu_rsp(sap_device, SAP_RESULT_OK,
-                                               (uint8_t*)&apdu, sizeof(apdu));
+                                               (uint8_t *)&apdu, sizeof(apdu));
 }
 
 void sap_transfer_atr_req(void *sap_device)
@@ -133,7 +136,7 @@ void sap_transfer_atr_req(void *sap_device)
                                                                NULL, 0);
        else
                sap_transfer_atr_rsp(sap_device, SAP_RESULT_OK,
-                                               (uint8_t*)&atr, sizeof(atr));
+                                               (uint8_t *)&atr, sizeof(atr));
 }
 
 void sap_power_sim_off_req(void *sap_device)
@@ -227,10 +230,10 @@ static DBusMessage *ongoing_call(DBusConnection *conn, DBusMessage *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;
+               ongoing_call_status = FALSE;
        } else if (!ongoing_call_status && ongoing) {
                /* An ongoing call has started.*/
-               ongoing_call_status = ongoing;
+               ongoing_call_status = TRUE;
        }
 
        DBG("OngoingCall status set to %d", ongoing_call_status);
@@ -315,11 +318,18 @@ static DBusMessage *card_status(DBusConnection *conn, DBusMessage *msg,
        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},
+static const GDBusMethodTable dummy_methods[] = {
+       { GDBUS_METHOD("OngoingCall",
+                               GDBUS_ARGS({ "ongoing", "b" }), NULL,
+                               ongoing_call) },
+       { GDBUS_METHOD("MaxMessageSize",
+                               GDBUS_ARGS({ "size", "u" }), NULL,
+                               max_msg_size) },
+       { GDBUS_METHOD("DisconnectImmediate", NULL, NULL,
+                               disconnect_immediate) },
+       { GDBUS_METHOD("CardStatus",
+                               GDBUS_ARGS({ "status", "" }), NULL,
+                               card_status) },
        { }
 };
 
@@ -332,6 +342,8 @@ int sap_init(void)
                                NULL, NULL) == FALSE) {
                error("sap-dummy interface %s init failed on path %s",
                                        SAP_DUMMY_IFACE, SAP_DUMMY_PATH);
+               dbus_connection_unref(connection);
+               connection = NULL;
                return -1;
        }
 
@@ -340,6 +352,9 @@ int sap_init(void)
 
 void sap_exit(void)
 {
+       g_dbus_unregister_interface(connection, SAP_DUMMY_PATH,
+                                                       SAP_DUMMY_IFACE);
+
        dbus_connection_unref(connection);
        connection = NULL;
 }
index ef7d95c..2920cc7 100644 (file)
@@ -380,7 +380,7 @@ static void simd_close(void)
        u8500.sap_data = NULL;
 }
 
-static void recv_sim_ready()
+static void recv_sim_ready(void)
 {
        sap_info("sim is ready. Try to connect again");
 
index b8aa8a5..f5d19c4 100644 (file)
 #include <config.h>
 #endif
 
-#include <stdio.h>
 #include <errno.h>
 #include <glib.h>
-#include <netinet/in.h>
-#include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
 
 #include "adapter.h"
 #include "btio.h"
 #include "server.h"
 
 #define SAP_SERVER_INTERFACE   "org.bluez.SimAccess"
-#define SAP_UUID               "0000112D-0000-1000-8000-00805F9B34FB"
 #define SAP_SERVER_CHANNEL     8
 
-#define PADDING4(x) ((4 - (x & 0x03)) & 0x03)
+#define PADDING4(x) ((4 - ((x) & 0x03)) & 0x03)
 #define PARAMETER_SIZE(x) (sizeof(struct sap_parameter) + x + PADDING4(x))
 
 #define SAP_NO_REQ 0xFF
@@ -75,7 +72,6 @@ struct sap_connection {
 };
 
 struct sap_server {
-       bdaddr_t src;
        char *path;
        uint32_t record_id;
        GIOChannel *listen_io;
@@ -129,9 +125,6 @@ static int is_reset_sim_req_allowed(uint8_t processing_req)
 
 static int check_msg(struct sap_message *msg)
 {
-       if (!msg)
-               return -EINVAL;
-
        switch (msg->id) {
        case SAP_CONNECT_REQ:
                if (msg->nparam != 0x01)
@@ -150,7 +143,7 @@ static int check_msg(struct sap_message *msg)
                        return -EBADMSG;
 
                if (msg->param->id != SAP_PARAM_ID_COMMAND_APDU)
-                       if ( msg->param->id != SAP_PARAM_ID_COMMAND_APDU7816)
+                       if (msg->param->id != SAP_PARAM_ID_COMMAND_APDU7816)
                                return -EBADMSG;
 
                if (msg->param->len == 0x00)
@@ -233,8 +226,7 @@ static sdp_record_t *create_sap_record(uint8_t channel)
        aproto = sdp_list_append(NULL, apseq);
        sdp_set_access_protos(record, aproto);
 
-       sdp_set_info_attr(record, "SIM Access Server",
-                       NULL, NULL);
+       sdp_set_info_attr(record, "SIM Access Server", NULL, NULL);
 
        sdp_data_free(ch);
        sdp_list_free(proto[0], NULL);
@@ -282,18 +274,8 @@ static int disconnect_ind(void *sap_device, uint8_t disc_type)
        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;
@@ -866,7 +848,7 @@ int sap_reset_sim_rsp(void *sap_device, uint8_t result)
                return -EINVAL;
 
        DBG("state %d pr 0x%02x result 0x%02x", conn->state,
-                                       conn->processing_req, result);
+                                               conn->processing_req, result);
 
        if (conn->processing_req != SAP_RESET_SIM_REQ)
                return 0;
@@ -894,7 +876,7 @@ int sap_transfer_card_reader_status_rsp(void *sap_device, uint8_t result,
                return -EINVAL;
 
        DBG("state %d pr 0x%02x result 0x%02x", conn->state,
-                                       conn->processing_req, result);
+                                               conn->processing_req, result);
 
        if (conn->processing_req != SAP_TRANSFER_CARD_READER_STATUS_REQ)
                return 0;
@@ -930,7 +912,7 @@ int sap_transport_protocol_rsp(void *sap_device, uint8_t result)
                return -EINVAL;
 
        DBG("state %d pr 0x%02x result 0x%02x", conn->state,
-                                       conn->processing_req, result);
+                                               conn->processing_req, result);
 
        if (conn->processing_req != SAP_SET_TRANSPORT_PROTOCOL_REQ)
                return 0;
@@ -971,7 +953,7 @@ int sap_status_ind(void *sap_device, uint8_t status_change)
                return -EINVAL;
 
        DBG("state %d pr 0x%02x sc 0x%02x", conn->state, conn->processing_req,
-                               status_change);
+                                                               status_change);
 
        /* Might be need to change state to connected after ongoing call.*/
        if (conn->state == SAP_STATE_CONNECT_MODEM_BUSY &&
@@ -1119,28 +1101,28 @@ static gboolean sap_io_cb(GIOChannel *io, GIOCondition cond, gpointer data)
 static void sap_io_destroy(void *data)
 {
        struct sap_connection *conn = data;
+       gboolean connected = FALSE;
 
        DBG("conn %p", conn);
 
-       if (conn && conn->io) {
-               gboolean connected = FALSE;
+       if (!conn || !conn->io)
+               return;
 
-               stop_guard_timer(conn);
+       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,
+       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);
+       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);
-       }
+       sap_conn_remove(conn);
 }
 
 static void sap_connect_cb(GIOChannel *io, GError *gerr, gpointer data)
@@ -1208,7 +1190,7 @@ static void connect_confirm_cb(GIOChannel *io, gpointer data)
 
        conn = g_try_new0(struct sap_connection, 1);
        if (!conn) {
-               error("Can't allocate memory for incomming SAP connection.");
+               error("Can't allocate memory for incoming SAP connection.");
                g_io_channel_shutdown(io, TRUE, NULL);
                return;
        }
@@ -1241,7 +1223,7 @@ static void connect_confirm_cb(GIOChannel *io, gpointer data)
                return;
        }
 
-       DBG("Authorizing incomming SAP connection from %s", dstaddr);
+       DBG("Authorizing incoming SAP connection from %s", dstaddr);
 }
 
 static inline DBusMessage *message_failed(DBusMessage *msg,
@@ -1265,7 +1247,7 @@ static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg,
                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",
+               return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
                                        "There is no active connection");
 
        return dbus_message_new_method_return(msg);
@@ -1303,14 +1285,17 @@ static DBusMessage *get_properties(DBusConnection *c,
        return reply;
 }
 
-static GDBusMethodTable server_methods[] = {
-       {"GetProperties", "", "a{sv}", get_properties},
-       {"Disconnect", "", "", disconnect},
+static const GDBusMethodTable server_methods[] = {
+       { GDBUS_METHOD("GetProperties",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       get_properties) },
+       { GDBUS_METHOD("Disconnect", NULL, NULL, disconnect) },
        { }
 };
 
-static GDBusSignalTable server_signals[] = {
-       { "PropertyChanged", "sv"},
+static const GDBusSignalTable server_signals[] = {
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
        { }
 };
 
@@ -1352,7 +1337,6 @@ int sap_server_register(const char *path, bdaddr_t *src)
                return -ENOMEM;
        }
 
-       bacpy(&server->src, src);
        server->path = g_strdup(path);
 
        record = create_sap_record(SAP_SERVER_CHANNEL);
@@ -1361,7 +1345,7 @@ int sap_server_register(const char *path, bdaddr_t *src)
                goto sdp_err;
        }
 
-       if (add_record_to_server(&server->src, record) < 0) {
+       if (add_record_to_server(src, record) < 0) {
                error("Adding SAP SDP record to the SDP server failed.");
                sdp_record_free(record);
                goto sdp_err;
@@ -1371,7 +1355,7 @@ int sap_server_register(const char *path, bdaddr_t *src)
 
        io = bt_io_listen(BT_IO_RFCOMM, NULL, connect_confirm_cb, server,
                        NULL, &gerr,
-                       BT_IO_OPT_SOURCE_BDADDR, &server->src,
+                       BT_IO_OPT_SOURCE_BDADDR, src,
                        BT_IO_OPT_CHANNEL, SAP_SERVER_CHANNEL,
                        BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH,
                        BT_IO_OPT_MASTER, TRUE,
index 2f830ad..f7ec99d 100644 (file)
--- a/sbc/sbc.h
+++ b/sbc/sbc.h
@@ -60,7 +60,7 @@ extern "C" {
 #define SBC_SB_4               0x00
 #define SBC_SB_8               0x01
 
-/* Data endianess */
+/* Data endianness */
 #define SBC_LE                 0x00
 #define SBC_BE                 0x01
 
index 3fec8d5..17ad4f7 100644 (file)
@@ -31,7 +31,7 @@
 #define SBC_X_BUFFER_SIZE 328
 
 #ifdef __GNUC__
-#define SBC_ALWAYS_INLINE __attribute__((always_inline))
+#define SBC_ALWAYS_INLINE inline __attribute__((always_inline))
 #else
 #define SBC_ALWAYS_INLINE inline
 #endif
diff --git a/scripts/bluetooth.rules.in b/scripts/bluetooth.rules.in
deleted file mode 100644 (file)
index 64df69d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# Run helper every time a Bluetooth device appears
-# On remove actions, bluetoothd should go away by itself
-ACTION=="add", SUBSYSTEM=="bluetooth", RUN+="@prefix@/sbin/bluetoothd --udev"
-ACTION=="change", SUBSYSTEM=="bluetooth", RUN+="@prefix@/sbin/bluetoothd --udev"
index b609054..438ba6c 100644 (file)
@@ -45,6 +45,7 @@
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 #include <bluetooth/rfcomm.h>
+#include <bluetooth/uuid.h>
 
 #include <glib.h>
 #include <gdbus.h>
@@ -63,8 +64,6 @@
 #include "sdpd.h"
 #include "glib-helper.h"
 
-#define RFCOMM_UUID_STR                "00000003-0000-1000-8000-00805F9B34FB"
-
 static DBusConnection *connection = NULL;
 
 static int serial_probe(struct btd_device *device, const char *uuid)
index 5b76d14..f90bb6a 100644 (file)
@@ -48,7 +48,6 @@
 #include "../src/dbus-common.h"
 
 #include "log.h"
-#include "glib-compat.h"
 #include "glib-helper.h"
 #include "sdp-client.h"
 #include "btio.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 */
@@ -422,6 +417,7 @@ static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
                                BT_IO_OPT_SOURCE_BDADDR, &device->src,
                                BT_IO_OPT_DEST_BDADDR, &device->dst,
                                BT_IO_OPT_CHANNEL, port->channel,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
                                BT_IO_OPT_INVALID);
        if (!port->io) {
                error("%s", gerr->message);
@@ -462,6 +458,7 @@ connect:
                                BT_IO_OPT_SOURCE_BDADDR, &device->src,
                                BT_IO_OPT_DEST_BDADDR, &device->dst,
                                BT_IO_OPT_CHANNEL, port->channel,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
                                BT_IO_OPT_INVALID);
        if (port->io == NULL)
                return -EIO;
@@ -494,9 +491,6 @@ 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;
@@ -566,10 +560,16 @@ static DBusMessage *port_disconnect(DBusConnection *conn,
        return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 }
 
-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 },
+static const GDBusMethodTable port_methods[] = {
+       { GDBUS_ASYNC_METHOD("Connect",
+               GDBUS_ARGS({ "pattern", "s" }), GDBUS_ARGS({ "tty", "s" }),
+               port_connect) },
+       { GDBUS_ASYNC_METHOD("ConnectFD",
+               GDBUS_ARGS({ "pattern", "s" }), GDBUS_ARGS({ "fd", "s" }),
+               port_connect) },
+       { GDBUS_METHOD("Disconnect",
+               GDBUS_ARGS({ "device", "s" }), NULL,
+               port_disconnect) },
        { }
 };
 
index 736f690..dd38317 100644 (file)
@@ -130,20 +130,6 @@ static void proxy_free(struct serial_proxy *prx)
        g_free(prx);
 }
 
-static void add_lang_attr(sdp_record_t *r)
-{
-       sdp_lang_attr_t base_lang;
-       sdp_list_t *langs = 0;
-
-       /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */
-       base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
-       base_lang.encoding = 106;
-       base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
-       langs = sdp_list_append(0, &base_lang);
-       sdp_set_lang_attr(r, langs);
-       sdp_list_free(langs, 0);
-}
-
 static sdp_record_t *proxy_record_new(const char *uuid128, uint8_t channel)
 {
        sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id;
@@ -186,7 +172,7 @@ static sdp_record_t *proxy_record_new(const char *uuid128, uint8_t channel)
        aproto = sdp_list_append(NULL, apseq);
        sdp_set_access_protos(record, aproto);
 
-       add_lang_attr(record);
+       sdp_add_lang_attr(record);
 
        sdp_set_info_attr(record, "Serial Proxy", NULL, "Serial Proxy");
 
@@ -742,11 +728,16 @@ static DBusMessage *proxy_set_serial_params(DBusConnection *conn,
        return dbus_message_new_method_return(msg);
 }
 
-static GDBusMethodTable proxy_methods[] = {
-       { "Enable",                     "",     "",     proxy_enable },
-       { "Disable",                    "",     "",     proxy_disable },
-       { "GetInfo",                    "",     "a{sv}",proxy_get_info },
-       { "SetSerialParameters",        "syys", "",     proxy_set_serial_params },
+static const GDBusMethodTable proxy_methods[] = {
+       { GDBUS_METHOD("Enable", NULL, NULL, proxy_enable) },
+       { GDBUS_METHOD("Disable", NULL, NULL, proxy_disable) },
+       { GDBUS_METHOD("GetInfo",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       proxy_get_info) },
+       { GDBUS_METHOD("SetSerialParameters",
+                       GDBUS_ARGS({ "rate", "s" }, { "data", "y" },
+                                       { "stop", "y" }, { "parity", "s" }),
+                       NULL, proxy_set_serial_params) },
        { },
 };
 
@@ -1125,16 +1116,24 @@ static void manager_path_unregister(void *data)
        g_free(adapter);
 }
 
-static GDBusMethodTable manager_methods[] = {
-       { "CreateProxy",                "ss",   "s",    create_proxy },
-       { "ListProxies",                "",     "as",   list_proxies },
-       { "RemoveProxy",                "s",    "",     remove_proxy },
+static const GDBusMethodTable manager_methods[] = {
+       { GDBUS_METHOD("CreateProxy",
+                       GDBUS_ARGS({ "pattern", "s" },
+                                       { "address", "s" }),
+                       GDBUS_ARGS({ "path", "s" }),
+                       create_proxy) },
+       { GDBUS_METHOD("ListProxies",
+                       NULL, GDBUS_ARGS({ "paths", "as" }),
+                       list_proxies) },
+       { GDBUS_METHOD("RemoveProxy",
+                       GDBUS_ARGS({ "path", "s" }), NULL,
+                       remove_proxy) },
        { },
 };
 
-static GDBusSignalTable manager_signals[] = {
-       { "ProxyCreated",               "s"     },
-       { "ProxyRemoved",               "s"     },
+static const GDBusSignalTable manager_signals[] = {
+       { GDBUS_SIGNAL("ProxyCreated", GDBUS_ARGS({ "path", "s" })) },
+       { GDBUS_SIGNAL("ProxyRemoved", GDBUS_ARGS({ "path", "s" })) },
        { }
 };
 
index 7e4bbb6..f922876 100644 (file)
 #include "device.h"
 #include "dbus-common.h"
 #include "error.h"
-#include "glib-compat.h"
 #include "glib-helper.h"
 #include "agent.h"
 #include "storage.h"
 #include "gattrib.h"
 #include "att.h"
+#include "gatt.h"
 #include "attrib-server.h"
 #include "eir.h"
 
@@ -74,6 +74,7 @@
 #define IO_CAPABILITY_DISPLAYYESNO     0x01
 #define IO_CAPABILITY_KEYBOARDONLY     0x02
 #define IO_CAPABILITY_NOINPUTNOOUTPUT  0x03
+#define IO_CAPABILITY_KEYBOARDDISPLAY  0x04
 #define IO_CAPABILITY_INVALID          0xFF
 
 #define check_address(address) bachk(address)
@@ -113,7 +114,6 @@ struct btd_adapter {
        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) */
        guint pairable_timeout_id;      /* pairable timeout id */
@@ -167,9 +167,9 @@ static void dev_info_free(void *data)
 }
 
 int btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
-                                                               uint8_t minor)
+                                                       uint8_t minor)
 {
-       return adapter_ops->set_dev_class(adapter->dev_id, major, minor);
+       return adapter_ops->set_dev_class(adapter->dev_id, major, minor);
 }
 
 static const char *mode2str(uint8_t mode)
@@ -206,62 +206,6 @@ static uint8_t get_mode(const bdaddr_t *bdaddr, const char *mode)
                return MODE_UNKNOWN;
 }
 
-static void adapter_set_limited_discoverable(struct btd_adapter *adapter,
-                                                       gboolean limited)
-{
-       DBG("%s", limited ? "TRUE" : "FALSE");
-
-       adapter_ops->set_limited_discoverable(adapter->dev_id, limited);
-}
-
-static void adapter_remove_discov_timeout(struct btd_adapter *adapter)
-{
-       if (!adapter)
-               return;
-
-       if (adapter->discov_timeout_id == 0)
-               return;
-
-       g_source_remove(adapter->discov_timeout_id);
-       adapter->discov_timeout_id = 0;
-}
-
-static gboolean discov_timeout_handler(gpointer user_data)
-{
-       struct btd_adapter *adapter = user_data;
-
-       adapter->discov_timeout_id = 0;
-
-       adapter_ops->set_discoverable(adapter->dev_id, FALSE);
-
-       return FALSE;
-}
-
-static void adapter_set_discov_timeout(struct btd_adapter *adapter,
-                                       guint interval)
-{
-       if (adapter->discov_timeout_id) {
-               g_source_remove(adapter->discov_timeout_id);
-               adapter->discov_timeout_id = 0;
-       }
-
-       if (interval == 0) {
-               adapter_set_limited_discoverable(adapter, FALSE);
-               return;
-       }
-
-       /* Set limited discoverable if pairable and interval between 0 to 60
-          sec */
-       if (adapter->pairable && interval <= 60)
-               adapter_set_limited_discoverable(adapter, TRUE);
-       else
-               adapter_set_limited_discoverable(adapter, FALSE);
-
-       adapter->discov_timeout_id = g_timeout_add_seconds(interval,
-                                                       discov_timeout_handler,
-                                                       adapter);
-}
-
 static struct session_req *session_ref(struct session_req *req)
 {
        req->refcount++;
@@ -301,22 +245,12 @@ static int adapter_set_mode(struct btd_adapter *adapter, uint8_t mode)
        int err;
 
        if (mode == MODE_CONNECTABLE)
-               err = adapter_ops->set_discoverable(adapter->dev_id, FALSE);
+               err = adapter_ops->set_discoverable(adapter->dev_id, FALSE, 0);
        else
-               err = adapter_ops->set_discoverable(adapter->dev_id, TRUE);
-
-       if (err < 0)
-               return err;
-
-       if (mode == MODE_CONNECTABLE)
-               return 0;
-
-       adapter_remove_discov_timeout(adapter);
-
-       if (adapter->discov_timeout)
-               adapter_set_discov_timeout(adapter, adapter->discov_timeout);
+               err = adapter_ops->set_discoverable(adapter->dev_id, TRUE,
+                                               adapter->discov_timeout);
 
-       return 0;
+       return err;
 }
 
 static struct session_req *find_session_by_msg(GSList *list, const DBusMessage *msg)
@@ -538,7 +472,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->type == ADDR_TYPE_BREDR) {
+               if (dev->bdaddr_type == BDADDR_BREDR) {
                        dev_info_free(dev);
                        continue;
                }
@@ -574,7 +508,8 @@ static void stop_discovery(struct btd_adapter *adapter)
                return;
        }
 
-       adapter_ops->stop_discovery(adapter->dev_id);
+       if (adapter->up)
+               adapter_ops->stop_discovery(adapter->dev_id);
 }
 
 static void session_remove(struct session_req *req)
@@ -709,7 +644,7 @@ static DBusMessage *set_discoverable_timeout(DBusConnection *conn,
                return dbus_message_new_method_return(msg);
 
        if (adapter->scan_mode & SCAN_INQUIRY)
-               adapter_set_discov_timeout(adapter, timeout);
+               adapter_ops->set_discoverable(adapter->dev_id, TRUE, timeout);
 
        adapter->discov_timeout = timeout;
 
@@ -763,7 +698,7 @@ void btd_adapter_class_changed(struct btd_adapter *adapter, uint32_t new_class)
 
        adapter->dev_class = new_class;
 
-       if (main_opts.attrib_server) {
+       if (main_opts.gatt_enabled) {
                /* Removes service class */
                class[1] = class[1] & 0x1f;
                attrib_gap_set(adapter, GATT_CHARAC_APPEARANCE, class, 2);
@@ -787,7 +722,7 @@ void adapter_name_changed(struct btd_adapter *adapter, const char *name)
                                        ADAPTER_INTERFACE, "Name",
                                        DBUS_TYPE_STRING, &name);
 
-       if (main_opts.attrib_server)
+       if (main_opts.gatt_enabled)
                attrib_gap_set(adapter, GATT_CHARAC_DEVICE_NAME,
                                (const uint8_t *) name, strlen(name));
 }
@@ -810,6 +745,9 @@ int adapter_set_name(struct btd_adapter *adapter, const char *name)
                int err = adapter_ops->set_name(adapter->dev_id, maxname);
                if (err < 0)
                        return err;
+       } else {
+               g_free(adapter->name);
+               adapter->name = g_strdup(maxname);
        }
 
        write_local_name(&adapter->bdaddr, maxname);
@@ -988,14 +926,14 @@ void adapter_service_remove(struct btd_adapter *adapter, void *r)
 static struct btd_device *adapter_create_device(DBusConnection *conn,
                                                struct btd_adapter *adapter,
                                                const char *address,
-                                               addr_type_t type)
+                                               uint8_t bdaddr_type)
 {
        struct btd_device *device;
        const char *path;
 
        DBG("%s", address);
 
-       device = device_create(conn, adapter, address, type);
+       device = device_create(conn, adapter, address, bdaddr_type);
        if (!device)
                return NULL;
 
@@ -1055,7 +993,7 @@ struct btd_device *adapter_get_device(DBusConnection *conn,
                return device;
 
        return adapter_create_device(conn, adapter, address,
-                                               ADDR_TYPE_BREDR);
+                                               BDADDR_BREDR);
 }
 
 static gboolean discovery_cb(gpointer user_data)
@@ -1236,13 +1174,9 @@ static DBusMessage *get_properties(DBusConnection *conn,
 static DBusMessage *set_property(DBusConnection *conn,
                                        DBusMessage *msg, void *data)
 {
-       struct btd_adapter *adapter = data;
        DBusMessageIter iter;
        DBusMessageIter sub;
        const char *property;
-       char srcaddr[18];
-
-       ba2str(&adapter->bdaddr, srcaddr);
 
        if (!dbus_message_iter_init(msg, &iter))
                return btd_error_invalid_args(msg);
@@ -1383,9 +1317,6 @@ static DBusMessage *list_devices(DBusConnection *conn,
        DBusMessageIter array_iter;
        const gchar *dev_path;
 
-       if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
-               return btd_error_invalid_args(msg);
-
        reply = dbus_message_new_method_return(msg);
        if (!reply)
                return NULL;
@@ -1448,17 +1379,17 @@ static struct btd_device *create_device_internal(DBusConnection *conn,
        struct remote_dev_info *dev;
        struct btd_device *device;
        bdaddr_t addr;
-       addr_type_t type;
+       uint8_t bdaddr_type;
 
        str2ba(address, &addr);
 
        dev = adapter_search_found_devices(adapter, &addr);
        if (dev)
-               type = dev->type;
+               bdaddr_type = dev->bdaddr_type;
        else
-               type = ADDR_TYPE_BREDR;
+               bdaddr_type = BDADDR_BREDR;
 
-       device = adapter_create_device(conn, adapter, address, type);
+       device = adapter_create_device(conn, adapter, address, bdaddr_type);
        if (!device && err)
                *err = -ENOMEM;
 
@@ -1533,6 +1464,8 @@ static uint8_t parse_io_capability(const char *capability)
                return IO_CAPABILITY_KEYBOARDONLY;
        if (g_str_equal(capability, "NoInputNoOutput"))
                return IO_CAPABILITY_NOINPUTNOOUTPUT;
+       if (g_str_equal(capability, "KeyboardDisplay"))
+               return IO_CAPABILITY_KEYBOARDDISPLAY;
        return IO_CAPABILITY_INVALID;
 }
 
@@ -1575,15 +1508,7 @@ static DBusMessage *create_paired_device(DBusConnection *conn,
                        return btd_error_failed(msg, strerror(-err));
        }
 
-       if (device_is_bredr(device))
-               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;
+       return device_create_bonding(device, conn, msg, agent_path, cap);
 }
 
 static gint device_path_cmp(struct btd_device *device, const gchar *path)
@@ -1674,7 +1599,6 @@ static DBusMessage *register_agent(DBusConnection *conn, DBusMessage *msg,
                                                                void *data)
 {
        const char *path, *name, *capability;
-       struct agent *agent;
        struct btd_adapter *adapter = data;
        uint8_t cap;
 
@@ -1691,12 +1615,8 @@ static DBusMessage *register_agent(DBusConnection *conn, DBusMessage *msg,
 
        name = dbus_message_get_sender(msg);
 
-       agent = agent_create(adapter, name, path, cap,
+       adapter->agent = agent_create(adapter, name, path, cap,
                                (agent_remove_cb) agent_removed, adapter);
-       if (!agent)
-               return btd_error_failed(msg, "Failed to create a new agent");
-
-       adapter->agent = agent;
 
        DBG("Agent registered for hci%d at %s:%s", adapter->dev_id, name,
                        path);
@@ -1727,38 +1647,65 @@ static DBusMessage *unregister_agent(DBusConnection *conn, DBusMessage *msg,
        return dbus_message_new_method_return(msg);
 }
 
-static GDBusMethodTable adapter_methods[] = {
-       { "GetProperties",      "",     "a{sv}",get_properties          },
-       { "SetProperty",        "sv",   "",     set_property,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "RequestSession",     "",     "",     request_session,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "ReleaseSession",     "",     "",     release_session         },
-       { "StartDiscovery",     "",     "",     adapter_start_discovery },
-       { "StopDiscovery",      "",     "",     adapter_stop_discovery,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "ListDevices",        "",     "ao",   list_devices,
-                                               G_DBUS_METHOD_FLAG_DEPRECATED},
-       { "CreateDevice",       "s",    "o",    create_device,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "CreatePairedDevice", "sos",  "o",    create_paired_device,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "CancelDeviceCreation","s",   "",     cancel_device_creation,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "RemoveDevice",       "o",    "",     remove_device,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "FindDevice",         "s",    "o",    find_device             },
-       { "RegisterAgent",      "os",   "",     register_agent          },
-       { "UnregisterAgent",    "o",    "",     unregister_agent        },
+static const GDBusMethodTable adapter_methods[] = {
+       { GDBUS_METHOD("GetProperties",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       get_properties) },
+       { GDBUS_ASYNC_METHOD("SetProperty",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
+                       set_property) },
+       { GDBUS_ASYNC_METHOD("RequestSession", NULL, NULL,
+                       request_session) },
+       { GDBUS_METHOD("ReleaseSession", NULL, NULL,
+                       release_session) },
+       { GDBUS_METHOD("StartDiscovery", NULL, NULL,
+                       adapter_start_discovery) },
+       { GDBUS_ASYNC_METHOD("StopDiscovery", NULL, NULL,
+                       adapter_stop_discovery) },
+       { GDBUS_DEPRECATED_METHOD("ListDevices",
+                       NULL, GDBUS_ARGS({ "devices", "ao" }),
+                       list_devices) },
+       { GDBUS_ASYNC_METHOD("CreateDevice",
+                       GDBUS_ARGS({ "address", "s" }),
+                       GDBUS_ARGS({ "device", "o" }),
+                       create_device) },
+       { GDBUS_ASYNC_METHOD("CreatePairedDevice",
+                       GDBUS_ARGS({ "address", "s" }, { "agent", "o" },
+                                                       { "capability", "s" }),
+                       GDBUS_ARGS({ "device", "o" }),
+                       create_paired_device) },
+       { GDBUS_ASYNC_METHOD("CancelDeviceCreation",
+                       GDBUS_ARGS({ "address", "s" }), NULL,
+                       cancel_device_creation) },
+       { GDBUS_ASYNC_METHOD("RemoveDevice",
+                       GDBUS_ARGS({ "device", "o" }), NULL,
+                       remove_device) },
+       { GDBUS_METHOD("FindDevice",
+                       GDBUS_ARGS({ "address", "s" }),
+                       GDBUS_ARGS({ "device", "o" }),
+                       find_device) },
+       { GDBUS_METHOD("RegisterAgent",
+                       GDBUS_ARGS({ "agent", "o" },
+                                       { "capability", "s" }), NULL,
+                       register_agent) },
+       { GDBUS_METHOD("UnregisterAgent",
+                       GDBUS_ARGS({ "agent", "o" }), NULL,
+                       unregister_agent) },
        { }
 };
 
-static GDBusSignalTable adapter_signals[] = {
-       { "PropertyChanged",            "sv"            },
-       { "DeviceCreated",              "o"             },
-       { "DeviceRemoved",              "o"             },
-       { "DeviceFound",                "sa{sv}"        },
-       { "DeviceDisappeared",          "s"             },
+static const GDBusSignalTable adapter_signals[] = {
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+       { GDBUS_SIGNAL("DeviceCreated",
+                       GDBUS_ARGS({ "device", "o" })) },
+       { GDBUS_SIGNAL("DeviceRemoved",
+                       GDBUS_ARGS({ "device", "o" })) },
+       { GDBUS_SIGNAL("DeviceFound",
+                       GDBUS_ARGS({ "address", "s" },
+                                               { "values", "a{sv}" })) },
+       { GDBUS_SIGNAL("DeviceDisappeared",
+                       GDBUS_ARGS({ "address", "s" })) },
        { }
 };
 
@@ -1773,7 +1720,7 @@ static void create_stored_device_from_profiles(char *key, char *value,
                                key, (GCompareFunc) device_address_cmp))
                return;
 
-       device = device_create(connection, adapter, key, ADDR_TYPE_BREDR);
+       device = device_create(connection, adapter, key, BDADDR_BREDR);
        if (!device)
                return;
 
@@ -1794,12 +1741,28 @@ struct adapter_keys {
        GSList *keys;
 };
 
+static int str2buf(const char *str, uint8_t *buf, size_t blen)
+{
+       int i, dlen;
+
+       if (str == NULL)
+               return -EINVAL;
+
+       memset(buf, 0, blen);
+
+       dlen = MIN((strlen(str) / 2), blen);
+
+       for (i = 0; i < dlen; i++)
+               sscanf(str + (i * 2), "%02hhX", &buf[i]);
+
+       return 0;
+}
+
 static struct link_key_info *get_key_info(const char *addr, const char *value)
 {
        struct link_key_info *info;
        char tmp[3];
        long int l;
-       int i;
 
        if (strlen(value) < 36) {
                error("Unexpectedly short (%zu) link key line", strlen(value));
@@ -1810,12 +1773,7 @@ static struct link_key_info *get_key_info(const char *addr, const char *value)
 
        str2ba(addr, &info->bdaddr);
 
-       memset(tmp, 0, sizeof(tmp));
-
-       for (i = 0; i < 16; i++) {
-               memcpy(tmp, value + (i * 2), 2);
-               info->key[i] = (uint8_t) strtol(tmp, NULL, 16);
-       }
+       str2buf(value, info->key, sizeof(info->key));
 
        memcpy(tmp, value + 33, 2);
        info->type = (uint8_t) strtol(tmp, NULL, 10);
@@ -1829,6 +1787,42 @@ static struct link_key_info *get_key_info(const char *addr, const char *value)
        return info;
 }
 
+static struct smp_ltk_info *get_ltk_info(const char *addr, uint8_t bdaddr_type,
+                                                       const char *value)
+{
+       struct smp_ltk_info *ltk;
+       char *ptr;
+       int i, ret;
+
+       if (strlen(value) < 60) {
+               error("Unexpectedly short (%zu) LTK", strlen(value));
+               return NULL;
+       }
+
+       ltk = g_new0(struct smp_ltk_info, 1);
+
+       str2ba(addr, &ltk->bdaddr);
+
+       ltk->bdaddr_type = bdaddr_type;
+
+       str2buf(value, ltk->val, sizeof(ltk->val));
+
+       ptr = (char *) value + 2 * sizeof(ltk->val) + 1;
+
+       ret = sscanf(ptr, " %hhd %hhd %hhd %hd %n",
+                    &ltk->authenticated, &ltk->master, &ltk->enc_size,
+                                                       &ltk->ediv, &i);
+       if (ret < 2) {
+               g_free(ltk);
+               return NULL;
+       }
+       ptr += i;
+
+       str2buf(ptr, ltk->rand, sizeof(ltk->rand));
+
+       return ltk;
+}
+
 static void create_stored_device_from_linkkeys(char *key, char *value,
                                                        void *user_data)
 {
@@ -1845,7 +1839,44 @@ static void create_stored_device_from_linkkeys(char *key, char *value,
                                        (GCompareFunc) device_address_cmp))
                return;
 
-       device = device_create(connection, adapter, key, ADDR_TYPE_BREDR);
+       device = device_create(connection, adapter, key, BDADDR_BREDR);
+       if (device) {
+               device_set_temporary(device, FALSE);
+               adapter->devices = g_slist_append(adapter->devices, device);
+       }
+}
+
+static void create_stored_device_from_ltks(char *key, char *value,
+                                                       void *user_data)
+{
+       struct adapter_keys *keys = user_data;
+       struct btd_adapter *adapter = keys->adapter;
+       struct btd_device *device;
+       struct smp_ltk_info *info;
+       char address[18], srcaddr[18];
+       uint8_t bdaddr_type;
+       bdaddr_t src;
+
+       if (sscanf(key, "%17s#%hhu", address, &bdaddr_type) < 2)
+               return;
+
+       info = get_ltk_info(address, bdaddr_type, value);
+       if (info == NULL)
+               return;
+
+       keys->keys = g_slist_append(keys->keys, info);
+
+       if (g_slist_find_custom(adapter->devices, address,
+                                       (GCompareFunc) device_address_cmp))
+               return;
+
+       adapter_get_address(adapter, &src);
+       ba2str(&src, srcaddr);
+
+       if (g_strcmp0(srcaddr, address) == 0)
+               return;
+
+       device = device_create(connection, adapter, address, bdaddr_type);
        if (device) {
                device_set_temporary(device, FALSE);
                adapter->devices = g_slist_append(adapter->devices, device);
@@ -1862,7 +1893,7 @@ static void create_stored_device_from_blocked(char *key, char *value,
                                key, (GCompareFunc) device_address_cmp))
                return;
 
-       device = device_create(connection, adapter, key, ADDR_TYPE_BREDR);
+       device = device_create(connection, adapter, key, BDADDR_BREDR);
        if (device) {
                device_set_temporary(device, FALSE);
                adapter->devices = g_slist_append(adapter->devices, device);
@@ -1883,13 +1914,13 @@ static GSList *string_to_primary_list(char *str)
                return NULL;
 
        for (i = 0; services[i]; i++) {
-               struct att_primary *prim;
+               struct gatt_primary *prim;
                int ret;
 
-               prim = g_new0(struct att_primary, 1);
+               prim = g_new0(struct gatt_primary, 1);
 
-               ret = sscanf(services[i], "%04hX#%04hX#%s", &prim->start,
-                                                       &prim->end, prim->uuid);
+               ret = sscanf(services[i], "%04hX#%04hX#%s", &prim->range.start,
+                                                       &prim->range.end, prim->uuid);
 
                if (ret < 3) {
                        g_free(prim);
@@ -1904,19 +1935,23 @@ static GSList *string_to_primary_list(char *str)
        return l;
 }
 
-static void create_stored_device_from_primary(char *key, char *value,
+static void create_stored_device_from_primaries(char *key, char *value,
                                                        void *user_data)
 {
        struct btd_adapter *adapter = user_data;
        struct btd_device *device;
        GSList *services, *uuids, *l;
+       char address[18];
+       uint8_t bdaddr_type;
+
+       if (sscanf(key, "%17s#%hhu", address, &bdaddr_type) < 2)
+               return;
 
        if (g_slist_find_custom(adapter->devices,
-                       key, (GCompareFunc) device_address_cmp))
+                       address, (GCompareFunc) device_address_cmp))
                return;
 
-       /* FIXME: Get the correct LE addr type (public/random) */
-       device = device_create(connection, adapter, key, ADDR_TYPE_LE_PUBLIC);
+       device = device_create(connection, adapter, address, bdaddr_type);
        if (!device)
                return;
 
@@ -1928,7 +1963,7 @@ static void create_stored_device_from_primary(char *key, char *value,
                return;
 
        for (l = services, uuids = NULL; l; l = l->next) {
-               struct att_primary *prim = l->data;
+               struct gatt_primary *prim = l->data;
                uuids = g_slist_append(uuids, prim->uuid);
        }
 
@@ -1939,6 +1974,13 @@ static void create_stored_device_from_primary(char *key, char *value,
        g_slist_free(uuids);
 }
 
+static void smp_key_free(void *data)
+{
+       struct smp_ltk_info *info = data;
+
+       g_free(info);
+}
+
 static void load_devices(struct btd_adapter *adapter)
 {
        char filename[PATH_MAX + 1];
@@ -1952,8 +1994,8 @@ static void load_devices(struct btd_adapter *adapter)
        textfile_foreach(filename, create_stored_device_from_profiles,
                                                                adapter);
 
-       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "primary");
-       textfile_foreach(filename, create_stored_device_from_primary,
+       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "primaries");
+       textfile_foreach(filename, create_stored_device_from_primaries,
                                                                adapter);
 
        create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "linkkeys");
@@ -1961,31 +2003,45 @@ static void load_devices(struct btd_adapter *adapter)
 
        err = adapter_ops->load_keys(adapter->dev_id, keys.keys,
                                                        main_opts.debug_keys);
-       if (err < 0) {
+       if (err < 0)
                error("Unable to load keys to adapter_ops: %s (%d)",
                                                        strerror(-err), -err);
-               g_slist_free_full(keys.keys, g_free);
-       }
+
+       g_slist_free_full(keys.keys, g_free);
+       keys.keys = NULL;
+
+       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "longtermkeys");
+       textfile_foreach(filename, create_stored_device_from_ltks, &keys);
+
+       err = adapter_ops->load_ltks(adapter->dev_id, keys.keys);
+       if (err < 0)
+               error("Unable to load keys to adapter_ops: %s (%d)",
+                                                       strerror(-err), -err);
+       g_slist_free_full(keys.keys, smp_key_free);
+       keys.keys = NULL;
 
        create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "blocked");
        textfile_foreach(filename, create_stored_device_from_blocked, adapter);
 }
 
-int btd_adapter_block_address(struct btd_adapter *adapter, bdaddr_t *bdaddr)
+int btd_adapter_block_address(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+                                                       uint8_t bdaddr_type)
 {
-       return adapter_ops->block_device(adapter->dev_id, bdaddr);
+       return adapter_ops->block_device(adapter->dev_id, bdaddr, bdaddr_type);
 }
 
-int btd_adapter_unblock_address(struct btd_adapter *adapter, bdaddr_t *bdaddr)
+int btd_adapter_unblock_address(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+                                                       uint8_t bdaddr_type)
 {
-       return adapter_ops->unblock_device(adapter->dev_id, bdaddr);
+       return adapter_ops->unblock_device(adapter->dev_id, bdaddr,
+                                                               bdaddr_type);
 }
 
 static void clear_blocked(struct btd_adapter *adapter)
 {
        int err;
 
-       err = adapter_ops->unblock_device(adapter->dev_id, BDADDR_ANY);
+       err = adapter_ops->unblock_device(adapter->dev_id, BDADDR_ANY, 0);
        if (err < 0)
                error("Clearing blocked list failed: %s (%d)",
                                                strerror(-err), -err);
@@ -1996,9 +2052,6 @@ static void probe_driver(struct btd_adapter *adapter, gpointer user_data)
        struct btd_adapter_driver *driver = user_data;
        int err;
 
-       if (!adapter->up)
-               return;
-
        if (driver->probe == NULL)
                return;
 
@@ -2098,7 +2151,9 @@ static void emit_device_disappeared(gpointer data, gpointer user_data)
 }
 
 void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode,
-                                       uint8_t *on_mode, gboolean *pairable)
+                                               uint8_t *on_mode,
+                                               uint16_t *discoverable_timeout,
+                                               gboolean *pairable)
 {
        char str[14], address[18];
 
@@ -2116,14 +2171,35 @@ void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode,
        if (on_mode)
                *on_mode = get_mode(&adapter->bdaddr, "on");
 
+       if (discoverable_timeout)
+               *discoverable_timeout = get_discoverable_timeout(address);
+
        if (pairable)
                *pairable = adapter->pairable;
 }
 
+void btd_adapter_get_class(struct btd_adapter *adapter, uint8_t *major,
+                                                               uint8_t *minor)
+{
+       uint8_t cls[3];
+
+       if (read_local_class(&adapter->bdaddr, cls) < 0) {
+               uint32_t class = htobl(main_opts.class);
+               memcpy(cls, &class, 3);
+       }
+
+       *major = cls[1];
+       *minor = cls[0];
+}
+
+const char *btd_adapter_get_name(struct btd_adapter *adapter)
+{
+       return adapter->name;
+}
+
 void btd_adapter_start(struct btd_adapter *adapter)
 {
        char address[18];
-       uint8_t cls[3];
        gboolean powered;
 
        ba2str(&adapter->bdaddr, address);
@@ -2133,19 +2209,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->mode = MODE_CONNECTABLE;
        adapter->off_timer = 0;
 
-       /* 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);
-               memcpy(cls, &class, 3);
-       }
-
-       btd_adapter_set_class(adapter, cls[1], cls[0]);
+       if (adapter->scan_mode & SCAN_INQUIRY)
+               adapter->mode = MODE_DISCOVERABLE;
+       else
+               adapter->mode = MODE_CONNECTABLE;
 
        powered = TRUE;
        emit_property_changed(connection, adapter->path,
@@ -2246,15 +2315,11 @@ int btd_adapter_stop(struct btd_adapter *adapter)
 {
        gboolean prop_false = FALSE;
 
-       /* cancel pending timeout */
-       if (adapter->discov_timeout_id) {
-               g_source_remove(adapter->discov_timeout_id);
-               adapter->discov_timeout_id = 0;
-       }
-
        /* check pending requests */
        reply_pending_requests(adapter);
 
+       adapter->up = FALSE;
+
        stop_discovery(adapter);
 
        if (adapter->disc_sessions) {
@@ -2285,7 +2350,7 @@ int btd_adapter_stop(struct btd_adapter *adapter)
        emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE,
                                "Powered", DBUS_TYPE_BOOLEAN, &prop_false);
 
-       adapter->up = FALSE;
+       adapter->discovering = FALSE;
        adapter->scan_mode = SCAN_DISABLED;
        adapter->mode = MODE_OFF;
        adapter->off_requested = FALSE;
@@ -2358,11 +2423,9 @@ void btd_adapter_unref(struct btd_adapter *adapter)
        g_free(path);
 }
 
-gboolean adapter_init(struct btd_adapter *adapter)
+gboolean adapter_init(struct btd_adapter *adapter, gboolean up)
 {
-       /* adapter_ops makes sure that newly registered adapters always
-        * start off as powered */
-       adapter->up = TRUE;
+       adapter->up = up;
 
        adapter->allow_name_changes = TRUE;
 
@@ -2375,7 +2438,7 @@ gboolean adapter_init(struct btd_adapter *adapter)
 
        sdp_init_services_list(&adapter->bdaddr);
 
-       if (main_opts.attrib_server)
+       if (main_opts.gatt_enabled)
                btd_adapter_gatt_server_start(adapter);
 
        load_drivers(adapter);
@@ -2437,7 +2500,7 @@ void adapter_remove(struct btd_adapter *adapter)
        g_slist_free(adapter->devices);
 
        unload_drivers(adapter);
-       if (main_opts.attrib_server)
+       if (main_opts.gatt_enabled)
                btd_adapter_gatt_server_stop(adapter);
 
        g_slist_free(adapter->pin_callbacks);
@@ -2491,11 +2554,10 @@ void adapter_set_discovering(struct btd_adapter *adapter,
        if (!adapter_has_discov_sessions(adapter) || adapter->discov_suspended)
                return;
 
-       DBG("hci%u enabling timer, disc_sessions %u", adapter->dev_id,
+       DBG("hci%u restarting discovery, disc_sessions %u", adapter->dev_id,
                                        g_slist_length(adapter->disc_sessions));
 
-       adapter->discov_id = g_timeout_add_seconds(main_opts.discov_interval,
-                                                       discovery_cb, adapter);
+       adapter->discov_id = g_idle_add(discovery_cb, adapter);
 }
 
 static void suspend_discovery(struct btd_adapter *adapter)
@@ -2663,8 +2725,9 @@ void adapter_emit_device_found(struct btd_adapter *adapter,
        } else
                alias = g_strdup(dev->alias);
 
-       if (dev->type != ADDR_TYPE_BREDR) {
+       if (dev->bdaddr_type != BDADDR_BREDR) {
                gboolean broadcaster;
+               uint16_t app;
 
                if (dev->flags & (EIR_LIM_DISC | EIR_GEN_DISC))
                        broadcaster = FALSE;
@@ -2673,8 +2736,16 @@ void adapter_emit_device_found(struct btd_adapter *adapter,
 
                dev->legacy = FALSE;
 
+               if (read_remote_appearance(&adapter->bdaddr, &dev->bdaddr,
+                                               dev->bdaddr_type, &app) == 0)
+                       icon = gap_appearance_to_icon(app);
+               else
+                       icon = 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,
@@ -2704,7 +2775,7 @@ void adapter_emit_device_found(struct btd_adapter *adapter,
 }
 
 static struct remote_dev_info *found_device_new(const bdaddr_t *bdaddr,
-                                       addr_type_t type, const char *name,
+                                       uint8_t bdaddr_type, const char *name,
                                        const char *alias, uint32_t class,
                                        gboolean legacy, int flags)
 {
@@ -2712,7 +2783,7 @@ static struct remote_dev_info *found_device_new(const bdaddr_t *bdaddr,
 
        dev = g_new0(struct remote_dev_info, 1);
        bacpy(&dev->bdaddr, bdaddr);
-       dev->type = type;
+       dev->bdaddr_type = bdaddr_type;
        dev->name = g_strdup(name);
        dev->alias = g_strdup(alias);
        dev->class = class;
@@ -2781,15 +2852,15 @@ static char *read_stored_data(bdaddr_t *local, bdaddr_t *peer, const char *file)
 }
 
 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,
+                                       bdaddr_t *bdaddr, uint8_t bdaddr_type,
+                                       int8_t rssi, uint8_t confirm_name,
                                        uint8_t *data, uint8_t data_len)
 {
        struct remote_dev_info *dev;
        struct eir_data eir_data;
        char *alias, *name;
        gboolean legacy, name_known;
+       uint32_t dev_class;
        int err;
 
        memset(&eir_data, 0, sizeof(eir_data));
@@ -2799,6 +2870,15 @@ void adapter_update_found_devices(struct btd_adapter *adapter,
                return;
        }
 
+       dev_class = eir_data.dev_class[0] | (eir_data.dev_class[1] << 8) |
+                                               (eir_data.dev_class[2] << 16);
+       if (dev_class != 0)
+               write_remote_class(&adapter->bdaddr, bdaddr, dev_class);
+
+       if (eir_data.appearance != 0)
+               write_remote_appearance(&adapter->bdaddr, bdaddr, bdaddr_type,
+                                                       eir_data.appearance);
+
        if (eir_data.name != NULL && eir_data.name_complete)
                write_device_name(&adapter->bdaddr, bdaddr, eir_data.name);
 
@@ -2806,6 +2886,15 @@ void adapter_update_found_devices(struct btd_adapter *adapter,
        if (dev) {
                adapter->oor_devices = g_slist_remove(adapter->oor_devices,
                                                        dev);
+
+               /* If an existing device had no name but the newly received EIR
+                * data has (complete or not), we want to present it to the
+                * user. */
+               if (dev->name == NULL && eir_data.name != NULL) {
+                       dev->name = g_strdup(eir_data.name);
+                       goto done;
+               }
+
                if (dev->rssi != rssi)
                        goto done;
 
@@ -2818,7 +2907,7 @@ void adapter_update_found_devices(struct btd_adapter *adapter,
 
        name = read_stored_data(&adapter->bdaddr, bdaddr, "names");
 
-       if (type == ADDR_TYPE_BREDR) {
+       if (bdaddr_type == BDADDR_BREDR) {
                legacy = pairing_is_legacy(&adapter->bdaddr, bdaddr, data,
                                                                        name);
 
@@ -2833,12 +2922,13 @@ void adapter_update_found_devices(struct btd_adapter *adapter,
        }
 
        if (confirm_name)
-               adapter_ops->confirm_name(adapter->dev_id, bdaddr, name_known);
+               adapter_ops->confirm_name(adapter->dev_id, bdaddr, bdaddr_type,
+                                                               name_known);
 
        alias = read_stored_data(&adapter->bdaddr, bdaddr, "aliases");
 
-       dev = found_device_new(bdaddr, type, name, alias, class, legacy,
-                                                       eir_data.flags);
+       dev = found_device_new(bdaddr, bdaddr_type, name, alias, dev_class,
+                                               legacy, eir_data.flags);
        free(name);
        free(alias);
 
@@ -2868,8 +2958,6 @@ void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode)
        if (adapter->scan_mode == scan_mode)
                return;
 
-       adapter_remove_discov_timeout(adapter);
-
        switch (scan_mode) {
        case SCAN_DISABLED:
                adapter->mode = MODE_OFF;
@@ -2885,18 +2973,7 @@ void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode)
                adapter->mode = MODE_DISCOVERABLE;
                discoverable = TRUE;
                pairable = adapter->pairable;
-               if (adapter->discov_timeout != 0)
-                       adapter_set_discov_timeout(adapter,
-                                               adapter->discov_timeout);
                break;
-       case SCAN_INQUIRY:
-               /* Address the scenario where a low-level application like
-                * hciconfig changed the scan mode */
-               if (adapter->discov_timeout != 0)
-                       adapter_set_discov_timeout(adapter,
-                                               adapter->discov_timeout);
-
-               /* ignore, this event should not be sent */
        default:
                /* ignore, reserved */
                return;
@@ -2908,9 +2985,6 @@ void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode)
                                        ADAPTER_INTERFACE, "Pairable",
                                        DBUS_TYPE_BOOLEAN, &pairable);
 
-       if (!discoverable)
-               adapter_set_limited_discoverable(adapter, FALSE);
-
        emit_property_changed(connection, path,
                                ADAPTER_INTERFACE, "Discoverable",
                                DBUS_TYPE_BOOLEAN, &discoverable);
@@ -3038,7 +3112,7 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
 
        /* Device connected? */
        if (!g_slist_find(adapter->connections, device))
-               return -ENOTCONN;
+               error("Authorization request for non-connected device!?");
 
        if (adapter->auth_idle_id)
                return -EBUSY;
@@ -3061,6 +3135,7 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
 
        agent = device_get_agent(device);
        if (!agent) {
+               warn("Can't find device agent");
                g_free(auth);
                return -EPERM;
        }
@@ -3299,7 +3374,7 @@ void btd_adapter_unregister_pin_cb(struct btd_adapter *adapter,
 }
 
 ssize_t btd_adapter_get_pin(struct btd_adapter *adapter, struct btd_device *dev,
-                                                               char *pin_buf)
+                                       char *pin_buf, gboolean *display)
 {
        GSList *l;
        btd_adapter_pin_cb_t cb;
@@ -3308,7 +3383,7 @@ ssize_t btd_adapter_get_pin(struct btd_adapter *adapter, struct btd_device *dev,
 
        for (l = adapter->pin_callbacks; l != NULL; l = g_slist_next(l)) {
                cb = l->data;
-               ret = cb(adapter, dev, pin_buf);
+               ret = cb(adapter, dev, pin_buf, display);
                if (ret > 0)
                        return ret;
        }
@@ -3403,14 +3478,18 @@ int btd_adapter_read_clock(struct btd_adapter *adapter, bdaddr_t *bdaddr,
                                                timeout, clock, accuracy);
 }
 
-int btd_adapter_disconnect_device(struct btd_adapter *adapter, bdaddr_t *bdaddr)
+int btd_adapter_disconnect_device(struct btd_adapter *adapter,
+                                       bdaddr_t *bdaddr, uint8_t bdaddr_type)
+
 {
-       return adapter_ops->disconnect(adapter->dev_id, bdaddr);
+       return adapter_ops->disconnect(adapter->dev_id, bdaddr, bdaddr_type);
 }
 
-int btd_adapter_remove_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr)
+int btd_adapter_remove_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+                                                       uint8_t bdaddr_type)
 {
-       return adapter_ops->remove_bonding(adapter->dev_id, bdaddr);
+       return adapter_ops->remove_bonding(adapter->dev_id, bdaddr,
+                                                               bdaddr_type);
 }
 
 int btd_adapter_pincode_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
@@ -3421,15 +3500,17 @@ int btd_adapter_pincode_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
 }
 
 int btd_adapter_confirm_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                                       gboolean success)
+                                       uint8_t bdaddr_type, gboolean success)
 {
-       return adapter_ops->confirm_reply(adapter->dev_id, bdaddr, success);
+       return adapter_ops->confirm_reply(adapter->dev_id, bdaddr, bdaddr_type,
+                                                               success);
 }
 
 int btd_adapter_passkey_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                                       uint32_t passkey)
+                                       uint8_t bdaddr_type, uint32_t passkey)
 {
-       return adapter_ops->passkey_reply(adapter->dev_id, bdaddr, passkey);
+       return adapter_ops->passkey_reply(adapter->dev_id, bdaddr, bdaddr_type,
+                                                               passkey);
 }
 
 int btd_adapter_encrypt_link(struct btd_adapter *adapter, bdaddr_t *bdaddr,
@@ -3439,16 +3520,19 @@ int btd_adapter_encrypt_link(struct btd_adapter *adapter, bdaddr_t *bdaddr,
 }
 
 int btd_adapter_set_did(struct btd_adapter *adapter, uint16_t vendor,
-                                       uint16_t product, uint16_t version)
+                                       uint16_t product, uint16_t version,
+                                       uint16_t source)
 {
-       return adapter_ops->set_did(adapter->dev_id, vendor, product, version);
+       return adapter_ops->set_did(adapter->dev_id, vendor, product, version,
+                                                               source);
 }
 
 int adapter_create_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                                               uint8_t io_cap)
+                                       uint8_t addr_type, uint8_t io_cap)
 {
        suspend_discovery(adapter);
-       return adapter_ops->create_bonding(adapter->dev_id, bdaddr, io_cap);
+       return adapter_ops->create_bonding(adapter->dev_id, bdaddr,
+                                               addr_type, io_cap);
 }
 
 int adapter_cancel_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr)
index fb1dcdf..b7ea62b 100644 (file)
 /* Invalid SSP passkey value used to indicate negative replies */
 #define INVALID_PASSKEY                0xffffffff
 
-typedef enum {
-       ADDR_TYPE_BREDR,
-       ADDR_TYPE_LE_PUBLIC,
-       ADDR_TYPE_LE_RANDOM,
-} addr_type_t;
-
 struct btd_adapter;
 
 struct link_key_info {
@@ -56,9 +50,20 @@ struct link_key_info {
        uint8_t pin_len;
 };
 
+struct smp_ltk_info {
+       bdaddr_t bdaddr;
+       uint8_t bdaddr_type;
+       uint8_t authenticated;
+       uint8_t master;
+       uint8_t enc_size;
+       uint16_t ediv;
+       uint8_t rand[8];
+       uint8_t val[16];
+};
+
 struct remote_dev_info {
        bdaddr_t bdaddr;
-       addr_type_t type;
+       uint8_t bdaddr_type;
        int8_t rssi;
        uint32_t class;
        char *name;
@@ -67,7 +72,6 @@ struct remote_dev_info {
        char **uuids;
        size_t uuid_count;
        GSList *services;
-       uint8_t bdaddr_type;
        uint8_t flags;
 };
 
@@ -76,8 +80,13 @@ void btd_adapter_start(struct btd_adapter *adapter);
 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);
+                                               uint8_t *on_mode,
+                                               uint16_t *discoverable_timeout,
+                                               gboolean *pairable);
 
+void btd_adapter_get_class(struct btd_adapter *adapter, uint8_t *major,
+                                                       uint8_t *minor);
+const char *btd_adapter_get_name(struct btd_adapter *adapter);
 struct btd_device *adapter_get_device(DBusConnection *conn,
                                struct btd_adapter *adapter, const char *address);
 
@@ -88,7 +97,7 @@ void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,
                                                gboolean remove_storage);
 
 struct btd_adapter *adapter_create(DBusConnection *conn, int id);
-gboolean adapter_init(struct btd_adapter *adapter);
+gboolean adapter_init(struct btd_adapter *adapter, gboolean up);
 void adapter_remove(struct btd_adapter *adapter);
 void adapter_set_allow_name_changes(struct btd_adapter *adapter,
                                                gboolean allow_name_changes);
@@ -97,14 +106,11 @@ void adapter_set_discovering(struct btd_adapter *adapter,
 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);
 struct remote_dev_info *adapter_search_found_devices(struct btd_adapter *adapter,
                                                        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,
+                                       bdaddr_t *bdaddr, uint8_t bdaddr_type,
+                                       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);
@@ -157,13 +163,13 @@ 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);
+                       struct btd_device *dev, char *out, gboolean *display);
 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);
+                                       char *pin_buf, gboolean *display);
 
 typedef void (*bt_hci_result_t) (uint8_t status, gpointer user_data);
 
@@ -171,9 +177,9 @@ struct btd_adapter_ops {
        int (*setup) (void);
        void (*cleanup) (void);
        int (*set_powered) (int index, gboolean powered);
-       int (*set_discoverable) (int index, gboolean discoverable);
+       int (*set_discoverable) (int index, gboolean discoverable,
+                                                       uint16_t timeout);
        int (*set_pairable) (int index, gboolean pairable);
-       int (*set_limited_discoverable) (int index, gboolean limited);
        int (*start_discovery) (int index);
        int (*stop_discovery) (int index);
 
@@ -183,32 +189,37 @@ struct btd_adapter_ops {
        int (*read_clock) (int index, bdaddr_t *bdaddr, int which, int timeout,
                                        uint32_t *clock, uint16_t *accuracy);
        int (*read_bdaddr) (int index, bdaddr_t *bdaddr);
-       int (*block_device) (int index, bdaddr_t *bdaddr);
-       int (*unblock_device) (int index, bdaddr_t *bdaddr);
+       int (*block_device) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type);
+       int (*unblock_device) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type);
        int (*get_conn_list) (int index, GSList **conns);
-       int (*disconnect) (int index, bdaddr_t *bdaddr);
-       int (*remove_bonding) (int index, bdaddr_t *bdaddr);
+       int (*disconnect) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type);
+       int (*remove_bonding) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type);
        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 (*confirm_reply) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type,
+                                                       gboolean success);
+       int (*passkey_reply) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type,
+                                                       uint32_t passkey);
        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,
-                                                       uint16_t version);
+                                       uint16_t version, uint16_t source);
        int (*add_uuid) (int index, uuid_t *uuid, uint8_t svc_hint);
        int (*remove_uuid) (int index, uuid_t *uuid);
        int (*disable_cod_cache) (int index);
        int (*restore_powered) (int index);
        int (*load_keys) (int index, GSList *keys, gboolean debug_keys);
        int (*set_io_capability) (int index, uint8_t io_capability);
-       int (*create_bonding) (int index, bdaddr_t *bdaddr, uint8_t io_cap);
+       int (*create_bonding) (int index, bdaddr_t *bdaddr,
+                                       uint8_t bdaddr_type, 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 (*confirm_name) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type,
+                                                       gboolean name_known);
+       int (*load_ltks) (int index, GSList *keys);
 };
 
 int btd_register_adapter_ops(struct btd_adapter_ops *ops, gboolean priority);
@@ -232,29 +243,33 @@ int btd_adapter_read_clock(struct btd_adapter *adapter, bdaddr_t *bdaddr,
                                int which, int timeout, uint32_t *clock,
                                uint16_t *accuracy);
 
-int btd_adapter_block_address(struct btd_adapter *adapter, bdaddr_t *bdaddr);
-int btd_adapter_unblock_address(struct btd_adapter *adapter, bdaddr_t *bdaddr);
+int btd_adapter_block_address(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+                                                       uint8_t bdaddr_type);
+int btd_adapter_unblock_address(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+                                                       uint8_t bdaddr_type);
 
 int btd_adapter_disconnect_device(struct btd_adapter *adapter,
-                                                       bdaddr_t *bdaddr);
+                                       bdaddr_t *bdaddr, uint8_t bdaddr_type);
 
-int btd_adapter_remove_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr);
+int btd_adapter_remove_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+                                                       uint8_t bdaddr_type);
 
 int btd_adapter_pincode_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
                                        const char *pin, size_t pin_len);
 int btd_adapter_confirm_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                                       gboolean success);
+                                       uint8_t bdaddr_type, gboolean success);
 int btd_adapter_passkey_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                                       uint32_t passkey);
+                                       uint8_t bdaddr_type, uint32_t passkey);
 
 int btd_adapter_encrypt_link(struct btd_adapter *adapter, bdaddr_t *bdaddr,
                                bt_hci_result_t cb, gpointer user_data);
 
 int btd_adapter_set_did(struct btd_adapter *adapter, uint16_t vendor,
-                                       uint16_t product, uint16_t version);
+                                       uint16_t product, uint16_t version,
+                                       uint16_t source);
 
 int adapter_create_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                                       uint8_t io_cap);
+                               uint8_t bdaddr_type, uint8_t io_cap);
 
 int adapter_cancel_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr);
 
index 19dccb5..e542425 100644 (file)
@@ -52,7 +52,8 @@ typedef enum {
        AGENT_REQUEST_CONFIRMATION,
        AGENT_REQUEST_PINCODE,
        AGENT_REQUEST_AUTHORIZE,
-       AGENT_REQUEST_CONFIRM_MODE
+       AGENT_REQUEST_CONFIRM_MODE,
+       AGENT_REQUEST_DISPLAY_PINCODE,
 } agent_request_type_t;
 
 struct agent {
@@ -152,6 +153,7 @@ void agent_free(struct agent *agent)
        if (agent->request) {
                DBusError err;
                agent_pincode_cb pincode_cb;
+               agent_passkey_cb passkey_cb;
                agent_cb cb;
 
                dbus_error_init(&err);
@@ -162,6 +164,10 @@ void agent_free(struct agent *agent)
                        pincode_cb = agent->request->cb;
                        pincode_cb(agent, &err, NULL, agent->request->user_data);
                        break;
+               case AGENT_REQUEST_PASSKEY:
+                       passkey_cb = agent->request->cb;
+                       passkey_cb(agent, &err, 0, agent->request->user_data);
+                       break;
                default:
                        cb = agent->request->cb;
                        cb(agent, &err, agent->request->user_data);
@@ -258,12 +264,6 @@ static void simple_agent_reply(DBusPendingCall *call, void *user_data)
                error("Agent replied with an error: %s, %s",
                                err.name, err.message);
 
-#ifdef __TIZEN_PATCH__
-               if (strcmp(err.message, "CanceledbyUser") == 0)
-               {
-                       set_cancel_from_authentication_req(req->user_data);
-               }
-#endif
                cb(agent, &err, req->user_data);
 
                if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
@@ -277,7 +277,6 @@ static void simple_agent_reply(DBusPendingCall *call, void *user_data)
                goto done;
        }
 
-       dbus_error_init(&err);
        if (!dbus_message_get_args(message, &err, DBUS_TYPE_INVALID)) {
                error("Wrong reply signature: %s", err.message);
                cb(agent, &err, req->user_data);
@@ -373,19 +372,11 @@ static void pincode_reply(DBusPendingCall *call, void *user_data)
                error("Agent %s replied with an error: %s, %s",
                                agent->path, err.name, err.message);
 
-#ifdef __TIZEN_PATCH__
-               if (strcmp(err.message, "CanceledbyUser") == 0)
-               {
-                       set_cancel_from_authentication_req(req->user_data);
-               }
-#endif
-
                cb(agent, &err, NULL, req->user_data);
                dbus_error_free(&err);
                goto done;
        }
 
-       dbus_error_init(&err);
        if (!dbus_message_get_args(message, &err,
                                DBUS_TYPE_STRING, &pin,
                                DBUS_TYPE_INVALID)) {
@@ -397,7 +388,6 @@ static void pincode_reply(DBusPendingCall *call, void *user_data)
 
        len = strlen(pin);
 
-       dbus_error_init(&err);
        if (len > 16 || len < 1) {
                error("Invalid PIN length (%zu) from agent", len);
                dbus_set_error_const(&err, "org.bluez.Error.InvalidArgs",
@@ -469,11 +459,7 @@ int agent_request_pincode(struct agent *agent, struct btd_device *device,
        return 0;
 
 failed:
-#ifdef __TIZEN_PATCH__
        agent_request_free(req, FALSE);
-#else
-       g_free(req);
-#endif
        return err;
 }
 
@@ -549,19 +535,11 @@ static void passkey_reply(DBusPendingCall *call, void *user_data)
        if (dbus_set_error_from_message(&err, message)) {
                error("Agent replied with an error: %s, %s",
                                                err.name, err.message);
-#ifdef __TIZEN_PATCH__
-               if (strcmp(err.message, "CanceledbyUser") == 0)
-               {
-                       set_cancel_from_authentication_req(req->user_data);
-               }
-#endif
-
                cb(agent, &err, 0, req->user_data);
                dbus_error_free(&err);
                goto done;
        }
 
-       dbus_error_init(&err);
        if (!dbus_message_get_args(message, &err,
                                DBUS_TYPE_UINT32, &passkey,
                                DBUS_TYPE_INVALID)) {
@@ -715,9 +693,6 @@ int agent_display_passkey(struct agent *agent, struct btd_device *device,
                                DBUS_TYPE_INVALID);
 
        if (!g_dbus_send_message(connection, message)) {
-#ifndef __TIZEN_PATCH__
-               dbus_message_unref(message);
-#endif
                error("D-Bus send failed");
                return -1;
        }
@@ -725,6 +700,114 @@ int agent_display_passkey(struct agent *agent, struct btd_device *device,
        return 0;
 }
 
+static void display_pincode_reply(DBusPendingCall *call, void *user_data)
+{
+       struct agent_request *req = user_data;
+       struct agent *agent = req->agent;
+       DBusMessage *message;
+       DBusError err;
+       agent_cb cb = req->cb;
+
+       /* clear agent->request early; our callback will likely try
+        * another request */
+       agent->request = NULL;
+
+       /* steal_reply will always return non-NULL since the callback
+        * is only called after a reply has been received */
+       message = dbus_pending_call_steal_reply(call);
+
+       dbus_error_init(&err);
+       if (dbus_set_error_from_message(&err, message)) {
+               error("Agent replied with an error: %s, %s",
+                                               err.name, err.message);
+
+               cb(agent, &err, req->user_data);
+
+               if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
+                       agent_cancel(agent);
+                       dbus_message_unref(message);
+                       dbus_error_free(&err);
+                       return;
+               }
+
+               dbus_error_free(&err);
+               goto done;
+       }
+
+       if (!dbus_message_get_args(message, &err, DBUS_TYPE_INVALID)) {
+               error("Wrong reply signature: %s", err.message);
+               cb(agent, &err, req->user_data);
+               dbus_error_free(&err);
+               goto done;
+       }
+
+       cb(agent, NULL, req->user_data);
+done:
+       dbus_message_unref(message);
+
+       agent_request_free(req, TRUE);
+}
+
+static int display_pincode_request_new(struct agent_request *req,
+                                       const char *device_path,
+                                       const char *pincode)
+{
+       struct agent *agent = req->agent;
+
+       req->msg = dbus_message_new_method_call(agent->name, agent->path,
+                                       "org.bluez.Agent", "DisplayPinCode");
+       if (req->msg == NULL) {
+               error("Couldn't allocate D-Bus message");
+               return -ENOMEM;
+       }
+
+       dbus_message_append_args(req->msg,
+                                       DBUS_TYPE_OBJECT_PATH, &device_path,
+                                       DBUS_TYPE_STRING, &pincode,
+                                       DBUS_TYPE_INVALID);
+
+       if (dbus_connection_send_with_reply(connection, req->msg,
+                               &req->call, REQUEST_TIMEOUT) == FALSE) {
+               error("D-Bus send failed");
+               return -EIO;
+       }
+
+       dbus_pending_call_set_notify(req->call, display_pincode_reply,
+                                                               req, NULL);
+
+       return 0;
+}
+
+int agent_display_pincode(struct agent *agent, struct btd_device *device,
+                               const char *pincode, agent_cb cb,
+                               void *user_data, GDestroyNotify destroy)
+{
+       struct agent_request *req;
+       const gchar *dev_path = device_get_path(device);
+       int err;
+
+       if (agent->request)
+               return -EBUSY;
+
+       DBG("Calling Agent.DisplayPinCode: name=%s, path=%s, pincode=%s",
+                                       agent->name, agent->path, pincode);
+
+       req = agent_request_new(agent, AGENT_REQUEST_DISPLAY_PINCODE, cb,
+                                                       user_data, destroy);
+
+       err = display_pincode_request_new(req, dev_path, pincode);
+       if (err < 0)
+               goto failed;
+
+       agent->request = req;
+
+       return 0;
+
+failed:
+       agent_request_free(req, FALSE);
+       return err;
+}
+
 uint8_t agent_get_io_capability(struct agent *agent)
 {
        return agent->capability;
index f62bf3b..320b92d 100644 (file)
@@ -64,6 +64,10 @@ int agent_request_confirmation(struct agent *agent, struct btd_device *device,
 int agent_display_passkey(struct agent *agent, struct btd_device *device,
                                uint32_t passkey);
 
+int agent_display_pincode(struct agent *agent, struct btd_device *device,
+                               const char *pincode, agent_cb cb,
+                               void *user_data, GDestroyNotify destroy);
+
 int agent_cancel(struct agent *agent);
 
 gboolean agent_is_busy(struct agent *agent, void *user_data);
@@ -74,4 +78,3 @@ gboolean agent_matches(struct agent *agent, const char *name, const char *path);
 
 void agent_init(void);
 void agent_exit(void);
-
index 36a398f..5adbf92 100644 (file)
 
 #include "log.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 "att.h"
+#include "gatt.h"
+#include "att-database.h"
 #include "storage.h"
 
 #include "attrib-server.h"
@@ -60,7 +61,7 @@ struct gatt_server {
        GIOChannel *le_io;
        uint32_t gatt_sdp_handle;
        uint32_t gap_sdp_handle;
-       GSList *database;
+       GList *database;
        GSList *clients;
        uint16_t name_handle;
        uint16_t appearance_handle;
@@ -75,6 +76,8 @@ struct gatt_channel {
        guint id;
        gboolean encrypted;
        struct gatt_server *server;
+       guint cleanup_id;
+       struct btd_device *device;
 };
 
 struct group_elem {
@@ -107,14 +110,20 @@ static void attrib_free(void *data)
 
 static void channel_free(struct gatt_channel *channel)
 {
-       g_attrib_unref(channel->attrib);
 
+       if (channel->cleanup_id)
+               g_source_remove(channel->cleanup_id);
+
+       if (channel->device)
+               btd_device_unref(channel->device);
+
+       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);
+       g_list_free_full(server->database, attrib_free);
 
        if (server->l2cap_io != NULL) {
                g_io_channel_unref(server->l2cap_io);
@@ -171,7 +180,7 @@ static struct gatt_server *find_gatt_server(const bdaddr_t *bdaddr)
                char addr[18];
 
                ba2str(bdaddr, addr);
-               error("Not GATT adapter found for address %s", addr);
+               error("No GATT server found in %s", addr);
                return NULL;
        }
 
@@ -249,24 +258,25 @@ static int attribute_cmp(gconstpointer a1, gconstpointer a2)
        return attrib1->handle - attrib2->handle;
 }
 
-static struct attribute *find_primary_range(struct gatt_server *server,
-                                               uint16_t start, uint16_t *end)
+static struct attribute *find_svc_range(struct gatt_server *server,
+                                       uint16_t start, uint16_t *end)
 {
        struct attribute *attrib;
        guint h = start;
-       GSList *l;
+       GList *l;
 
        if (end == NULL)
                return NULL;
 
-       l = g_slist_find_custom(server->database, GUINT_TO_POINTER(h),
+       l = g_list_find_custom(server->database, GUINT_TO_POINTER(h),
                                                                handle_cmp);
        if (!l)
                return NULL;
 
        attrib = l->data;
 
-       if (bt_uuid_cmp(&attrib->uuid, &prim_uuid) != 0)
+       if (bt_uuid_cmp(&attrib->uuid, &prim_uuid) != 0 &&
+                       bt_uuid_cmp(&attrib->uuid, &snd_uuid) != 0)
                return NULL;
 
        *end = start;
@@ -293,7 +303,7 @@ static uint32_t attrib_create_sdp_new(struct gatt_server *server,
        uuid_t svc, gap_uuid;
        bdaddr_t addr;
 
-       a = find_primary_range(server, handle, &end);
+       a = find_svc_range(server, handle, &end);
 
        if (a == NULL)
                return 0;
@@ -336,7 +346,7 @@ static struct attribute *attrib_db_add_new(struct gatt_server *server,
 
        DBG("handle=0x%04x", handle);
 
-       if (g_slist_find_custom(server->database, GUINT_TO_POINTER(h),
+       if (g_list_find_custom(server->database, GUINT_TO_POINTER(h),
                                                                handle_cmp))
                return NULL;
 
@@ -348,7 +358,7 @@ static struct attribute *attrib_db_add_new(struct gatt_server *server,
        a->read_reqs = read_reqs;
        a->write_reqs = write_reqs;
 
-       server->database = g_slist_insert_sorted(server->database, a,
+       server->database = g_list_insert_sorted(server->database, a,
                                                                attribute_cmp);
 
        return a;
@@ -395,7 +405,8 @@ 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, *database;
+       GSList *l, *groups;
+       GList *dl, *database;
        uint16_t length, last_handle, last_size = 0;
        uint8_t status;
        int i;
@@ -416,9 +427,9 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
 
        last_handle = end;
        database = channel->server->database;
-       for (l = database, groups = NULL, cur = NULL; l; l = l->next) {
+       for (dl = database, groups = NULL, cur = NULL; dl; dl = dl->next) {
 
-               a = l->data;
+               a = dl->data;
 
                if (a->handle < start)
                        continue;
@@ -447,7 +458,8 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
                                                                a->read_reqs);
 
                if (status == 0x00 && a->read_cb)
-                       status = a->read_cb(a, a->cb_user_data);
+                       status = a->read_cb(a, channel->device,
+                                                       a->cb_user_data);
 
                if (status) {
                        g_slist_free_full(groups, g_free);
@@ -472,7 +484,7 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
                return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, start,
                                        ATT_ECODE_ATTR_NOT_FOUND, pdu, len);
 
-       if (l == NULL)
+       if (dl == NULL)
                cur->end = a->handle;
        else
                cur->end = last_handle;
@@ -507,7 +519,8 @@ 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, *database;
+       GSList *l, *types;
+       GList *dl, *database;
        struct attribute *a;
        uint16_t num, length;
        uint8_t status;
@@ -518,9 +531,9 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
                                        ATT_ECODE_INVALID_HANDLE, pdu, len);
 
        database = channel->server->database;
-       for (l = database, length = 0, types = NULL; l; l = l->next) {
+       for (dl = database, length = 0, types = NULL; dl; dl = dl->next) {
 
-               a = l->data;
+               a = dl->data;
 
                if (a->handle < start)
                        continue;
@@ -535,7 +548,8 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
                                                                a->read_reqs);
 
                if (status == 0x00 && a->read_cb)
-                       status = a->read_cb(a, a->cb_user_data);
+                       status = a->read_cb(a, channel->device,
+                                                       a->cb_user_data);
 
                if (status) {
                        g_slist_free(types);
@@ -589,7 +603,8 @@ static int find_info(struct gatt_channel *channel, uint16_t start, uint16_t end,
 {
        struct attribute *a;
        struct att_data_list *adl;
-       GSList *l, *info, *database;
+       GSList *l, *info;
+       GList *dl, *database;
        uint8_t format, last_type = BT_UUID_UNSPEC;
        uint16_t length, num;
        int i;
@@ -599,8 +614,8 @@ static int find_info(struct gatt_channel *channel, uint16_t start, uint16_t end,
                                        ATT_ECODE_INVALID_HANDLE, pdu, len);
 
        database = channel->server->database;
-       for (l = database, info = NULL, num = 0; l; l = l->next) {
-               a = l->data;
+       for (dl = database, info = NULL, num = 0; dl; dl = dl->next) {
+               a = dl->data;
 
                if (a->handle < start)
                        continue;
@@ -664,7 +679,8 @@ static int find_by_type(struct gatt_channel *channel, uint16_t start,
 {
        struct attribute *a;
        struct att_range *range;
-       GSList *l, *matches, *database;
+       GSList *matches;
+       GList *dl, *database;
        int len;
 
        if (start > end || start == 0x0000)
@@ -673,8 +689,8 @@ static int find_by_type(struct gatt_channel *channel, uint16_t start,
 
        /* Searching first requested handle number */
        database = channel->server->database;
-       for (l = database, matches = NULL, range = NULL; l; l = l->next) {
-               a = l->data;
+       for (dl = database, matches = NULL, range = NULL; dl; dl = dl->next) {
+               a = dl->data;
 
                if (a->handle < start)
                        continue;
@@ -721,11 +737,12 @@ static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
 {
        struct attribute *a;
        uint8_t status;
-       GSList *l;
+       GList *l;
        uint16_t cccval;
+       uint8_t bdaddr_type;
        guint h = handle;
 
-       l = g_slist_find_custom(channel->server->database,
+       l = g_list_find_custom(channel->server->database,
                                        GUINT_TO_POINTER(h), handle_cmp);
        if (!l)
                return enc_error_resp(ATT_OP_READ_REQ, handle,
@@ -733,9 +750,11 @@ static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
 
        a = l->data;
 
+       bdaddr_type = device_get_addr_type(channel->device);
+
        if (bt_uuid_cmp(&ccc_uuid, &a->uuid) == 0 &&
-               read_device_ccc(&channel->src, &channel->dst,
-                                       handle, &cccval) == 0) {
+               read_device_ccc(&channel->src, &channel->dst, bdaddr_type,
+                                                       handle, &cccval) == 0) {
                uint8_t config[2];
 
                att_put_u16(cccval, config);
@@ -745,7 +764,7 @@ static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
        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);
+               status = a->read_cb(a, channel->device, a->cb_user_data);
 
        if (status)
                return enc_error_resp(ATT_OP_READ_REQ, handle, status, pdu,
@@ -759,11 +778,12 @@ static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle,
 {
        struct attribute *a;
        uint8_t status;
-       GSList *l;
+       GList *l;
        uint16_t cccval;
+       uint8_t bdaddr_type;
        guint h = handle;
 
-       l = g_slist_find_custom(channel->server->database,
+       l = g_list_find_custom(channel->server->database,
                                        GUINT_TO_POINTER(h), handle_cmp);
        if (!l)
                return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle,
@@ -775,9 +795,11 @@ 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);
 
+       bdaddr_type = device_get_addr_type(channel->device);
+
        if (bt_uuid_cmp(&ccc_uuid, &a->uuid) == 0 &&
-               read_device_ccc(&channel->src, &channel->dst,
-                                       handle, &cccval) == 0) {
+               read_device_ccc(&channel->src, &channel->dst, bdaddr_type,
+                                                       handle, &cccval) == 0) {
                uint8_t config[2];
 
                att_put_u16(cccval, config);
@@ -788,7 +810,7 @@ static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle,
        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);
+               status = a->read_cb(a, channel->device, a->cb_user_data);
 
        if (status)
                return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle, status,
@@ -803,10 +825,10 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
 {
        struct attribute *a;
        uint8_t status;
-       GSList *l;
+       GList *l;
        guint h = handle;
 
-       l = g_slist_find_custom(channel->server->database,
+       l = g_list_find_custom(channel->server->database,
                                        GUINT_TO_POINTER(h), handle_cmp);
        if (!l)
                return enc_error_resp(ATT_OP_WRITE_REQ, handle,
@@ -825,14 +847,18 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
                                                        value, vlen, NULL);
 
                if (a->write_cb) {
-                       status = a->write_cb(a, a->cb_user_data);
+                       status = a->write_cb(a, channel->device,
+                                                       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);
+               uint8_t bdaddr_type = device_get_addr_type(channel->device);
+
+               write_device_ccc(&channel->src, &channel->dst, bdaddr_type,
+                                                               handle, cccval);
        }
 
        return enc_write_resp(pdu, len);
@@ -841,29 +867,45 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
 static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
                uint8_t *pdu, int len)
 {
-       guint old_mtu = channel->mtu;
+       GError *gerr = NULL;
+       GIOChannel *io;
+       uint16_t imtu;
 
        if (mtu < ATT_DEFAULT_LE_MTU)
-               channel->mtu = ATT_DEFAULT_LE_MTU;
-       else
-               channel->mtu = MIN(mtu, channel->mtu);
+               return enc_error_resp(ATT_OP_MTU_REQ, 0,
+                                       ATT_ECODE_REQ_NOT_SUPP, pdu, len);
+
+       io = g_attrib_get_channel(channel->attrib);
 
-       bt_io_set(channel->server->le_io, BT_IO_L2CAP, NULL,
-                       BT_IO_OPT_OMTU, channel->mtu,
+       bt_io_get(io, BT_IO_L2CAP, &gerr,
+                       BT_IO_OPT_IMTU, &imtu,
                        BT_IO_OPT_INVALID);
 
-       return enc_mtu_resp(old_mtu, pdu, len);
+       if (gerr)
+               return enc_error_resp(ATT_OP_MTU_REQ, 0,
+                                       ATT_ECODE_UNLIKELY, pdu, len);
+
+       channel->mtu = MIN(mtu, imtu);
+       g_attrib_set_mtu(channel->attrib, channel->mtu);
+
+       return enc_mtu_resp(imtu, pdu, len);
 }
 
-static void channel_disconnect(void *user_data)
+static void channel_remove(struct gatt_channel *channel)
 {
-       struct gatt_channel *channel = user_data;
-
        channel->server->clients = g_slist_remove(channel->server->clients,
                                                                channel);
        channel_free(channel);
 }
 
+static gboolean channel_watch_cb(GIOChannel *io, GIOCondition cond,
+                                               gpointer user_data)
+{
+       channel_remove(user_data);
+
+       return FALSE;
+}
+
 static void channel_handler(const uint8_t *ipdu, uint16_t len,
                                                        gpointer user_data)
 {
@@ -967,6 +1009,10 @@ static void channel_handler(const uint8_t *ipdu, uint16_t len,
                break;
        case ATT_OP_HANDLE_CNF:
                return;
+       case ATT_OP_HANDLE_IND:
+       case ATT_OP_HANDLE_NOTIFY:
+               /* The attribute client is already handling these */
+               return;
        case ATT_OP_READ_MULTI_REQ:
        case ATT_OP_PREP_WRITE_REQ:
        case ATT_OP_EXEC_WRITE_REQ:
@@ -988,7 +1034,7 @@ done:
                                                        NULL, NULL, NULL);
 }
 
-guint attrib_channel_attach(GAttrib *attrib, gboolean out)
+guint attrib_channel_attach(GAttrib *attrib)
 {
        struct gatt_server *server;
        struct btd_device *device;
@@ -997,6 +1043,7 @@ guint attrib_channel_attach(GAttrib *attrib, gboolean out)
        GError *gerr = NULL;
        char addr[18];
        uint16_t cid;
+       guint mtu = 0;
 
        io = g_attrib_get_channel(attrib);
 
@@ -1006,7 +1053,7 @@ guint attrib_channel_attach(GAttrib *attrib, gboolean out)
                        BT_IO_OPT_SOURCE_BDADDR, &channel->src,
                        BT_IO_OPT_DEST_BDADDR, &channel->dst,
                        BT_IO_OPT_CID, &cid,
-                       BT_IO_OPT_OMTU, &channel->mtu,
+                       BT_IO_OPT_IMTU, &mtu,
                        BT_IO_OPT_INVALID);
        if (gerr) {
                error("bt_io_get: %s", gerr->message);
@@ -1016,33 +1063,39 @@ guint attrib_channel_attach(GAttrib *attrib, gboolean out)
        }
 
        server = find_gatt_server(&channel->src);
-       if (server == NULL)
+       if (server == NULL) {
+               char src[18];
+
+               ba2str(&channel->src, src);
+               error("No GATT server found in %s", src);
+               g_free(channel);
                return 0;
+       }
 
        channel->server = server;
 
        ba2str(&channel->dst, addr);
-       device = adapter_find_device(server->adapter, addr);
 
-       if (device_is_bonded(device) == FALSE)
+       device = adapter_find_device(server->adapter, addr);
+       if (device == NULL || 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 != ATT_CID)
+       if (cid != ATT_CID) {
                channel->le = FALSE;
-       else
+               channel->mtu = mtu;
+       } else {
                channel->le = TRUE;
-
+               channel->mtu = ATT_DEFAULT_LE_MTU;
+       }
 
        channel->attrib = g_attrib_ref(attrib);
        channel->id = g_attrib_register(channel->attrib, GATTRIB_ALL_REQS,
                                        channel_handler, channel, NULL);
 
-       if (out == FALSE)
-               g_attrib_set_disconnect_function(channel->attrib,
-                                               channel_disconnect, channel);
+       channel->cleanup_id = g_io_add_watch(io, G_IO_HUP, channel_watch_cb,
+                                                               channel);
+
+       channel->device = btd_device_ref(device);
 
        server->clients = g_slist_append(server->clients, channel);
 
@@ -1089,8 +1142,7 @@ gboolean attrib_channel_detach(GAttrib *attrib, guint id)
        channel = l->data;
 
        g_attrib_unregister(channel->attrib, channel->id);
-
-       channel_disconnect(channel);
+       channel_remove(channel);
 
        return TRUE;
 }
@@ -1105,8 +1157,7 @@ static void connect_event(GIOChannel *io, GError *gerr, void *user_data)
        }
 
        attrib = g_attrib_new(io);
-       attrib_channel_attach(attrib, FALSE);
-       g_io_channel_unref(io);
+       attrib_channel_attach(attrib);
        g_attrib_unref(attrib);
 }
 
@@ -1270,29 +1321,36 @@ void attrib_free_sdp(uint32_t sdp_handle)
        remove_record_from_server(sdp_handle);
 }
 
-uint16_t attrib_db_find_avail(struct btd_adapter *adapter, uint16_t nitems)
+static uint16_t find_uuid16_avail(struct btd_adapter *adapter, uint16_t nitems)
 {
        struct gatt_server *server;
        uint16_t handle;
        GSList *l;
-
-       g_assert(nitems > 0);
+       GList *dl;
 
        l = g_slist_find_custom(servers, adapter, adapter_cmp);
        if (l == NULL)
                return 0;
 
        server = l->data;
+       if (server->database == NULL)
+               return 0x0001;
 
-       for (l = server->database, handle = 0; l; l = l->next) {
-               struct attribute *a = l->data;
+       for (dl = server->database, handle = 0x0001; dl; dl = dl->next) {
+               struct attribute *a = dl->data;
 
-               if (handle && (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
+               if ((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;
 
+               if (a->len == 16 && (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
+                               bt_uuid_cmp(&a->uuid, &snd_uuid) == 0)) {
+                       /* 128 bit UUID service definition */
+                       return 0;
+               }
+
                if (a->handle == 0xffff)
                        return 0;
 
@@ -1305,6 +1363,71 @@ uint16_t attrib_db_find_avail(struct btd_adapter *adapter, uint16_t nitems)
        return 0;
 }
 
+static uint16_t find_uuid128_avail(struct btd_adapter *adapter, uint16_t nitems)
+{
+       uint16_t handle = 0, end = 0xffff;
+       struct gatt_server *server;
+       GList *dl;
+       GSList *l;
+
+       l = g_slist_find_custom(servers, adapter, adapter_cmp);
+       if (l == NULL)
+               return 0;
+
+       server = l->data;
+       if (server->database == NULL)
+               return 0xffff - nitems + 1;
+
+       for (dl = g_list_last(server->database); dl; dl = dl->prev) {
+               struct attribute *a = dl->data;
+
+               if (handle == 0)
+                       handle = a->handle;
+
+               if (bt_uuid_cmp(&a->uuid, &prim_uuid) != 0 &&
+                               bt_uuid_cmp(&a->uuid, &snd_uuid) != 0)
+                       continue;
+
+               if (end - handle >= nitems)
+                       return end - nitems + 1;
+
+               if (a->len == 2) {
+                       /* 16 bit UUID service definition */
+                       return 0;
+               }
+
+               if (a->handle == 0x0001)
+                       return 0;
+
+               end = a->handle - 1;
+               handle = 0;
+       }
+
+       if (end - 0x0001 >= nitems)
+               return end - nitems + 1;
+
+       return 0;
+}
+
+uint16_t attrib_db_find_avail(struct btd_adapter *adapter, bt_uuid_t *svc_uuid,
+                                                               uint16_t nitems)
+{
+       g_assert(nitems > 0);
+
+       if (svc_uuid->type == BT_UUID16)
+               return find_uuid16_avail(adapter, nitems);
+       else if (svc_uuid->type == BT_UUID128)
+               return find_uuid128_avail(adapter, nitems);
+       else {
+               char uuidstr[MAX_LEN_UUID_STR];
+
+               bt_uuid_to_string(svc_uuid, uuidstr, MAX_LEN_UUID_STR);
+               error("Service uuid: %s is neither a 16-bit nor a 128-bit uuid",
+                                                               uuidstr);
+               return 0;
+       }
+}
+
 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)
@@ -1326,6 +1449,7 @@ int attrib_db_update(struct btd_adapter *adapter, uint16_t handle,
        struct gatt_server *server;
        struct attribute *a;
        GSList *l;
+       GList *dl;
        guint h = handle;
 
        l = g_slist_find_custom(servers, adapter, adapter_cmp);
@@ -1336,15 +1460,15 @@ int attrib_db_update(struct btd_adapter *adapter, uint16_t handle,
 
        DBG("handle=0x%04x", handle);
 
-       l = g_slist_find_custom(server->database, GUINT_TO_POINTER(h),
+       dl = g_list_find_custom(server->database, GUINT_TO_POINTER(h),
                                                                handle_cmp);
-       if (!l)
+       if (dl == NULL)
                return -ENOENT;
 
-       a = l->data;
+       a = dl->data;
 
        a->data = g_try_realloc(a->data, len);
-       if (a->data == NULL)
+       if (len && a->data == NULL)
                return -ENOMEM;
 
        a->len = len;
@@ -1364,6 +1488,7 @@ int attrib_db_del(struct btd_adapter *adapter, uint16_t handle)
        struct gatt_server *server;
        struct attribute *a;
        GSList *l;
+       GList *dl;
        guint h = handle;
 
        l = g_slist_find_custom(servers, adapter, adapter_cmp);
@@ -1374,13 +1499,13 @@ int attrib_db_del(struct btd_adapter *adapter, uint16_t handle)
 
        DBG("handle=0x%04x", handle);
 
-       l = g_slist_find_custom(server->database, GUINT_TO_POINTER(h),
+       dl = g_list_find_custom(server->database, GUINT_TO_POINTER(h),
                                                                handle_cmp);
-       if (!l)
+       if (dl == NULL)
                return -ENOENT;
 
-       a = l->data;
-       server->database = g_slist_remove(server->database, a);
+       a = dl->data;
+       server->database = g_list_remove(server->database, a);
        g_free(a->data);
        g_free(a);
 
index 2c6f428..7af0cfa 100644 (file)
@@ -22,7 +22,8 @@
  *
  */
 
-uint16_t attrib_db_find_avail(struct btd_adapter *adapter, uint16_t nitems);
+uint16_t attrib_db_find_avail(struct btd_adapter *adapter, bt_uuid_t *svc_uuid,
+                                                       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);
@@ -35,5 +36,5 @@ int attrib_gap_set(struct btd_adapter *adapter, uint16_t uuid,
 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);
+guint attrib_channel_attach(GAttrib *attrib);
 gboolean attrib_channel_detach(GAttrib *attrib, guint id);
index 21e0e33..664dbd9 100644 (file)
-<?xml version="1.0"?><!--*-nxml-*-->
+<!-- This configuration file specifies the required security policies
+     for Bluetooth core daemon to work. -->
 
 <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-
 <busconfig>
-       <policy user="root">
-               <allow own="org.projectx.bluetooth"/>
-               <allow send_interface="org.projectx.bluetooth"/>
-               <allow send_destination="org.projectx.bluetooth"/>
-               <allow own="org.bluez.frwk_agent"/>
-               <allow send_interface="org.bluez.frwk_agent"/>
-               <allow send_destination="org.bluez.frwk_agent"/>
-               <allow own="org.bluez.Agent"/>
-               <allow send_interface="org.bluez.Agent"/>
-               <allow send_destination="org.bluez.Agent"/>
-               <allow own="org.bluez.Adapter"/>
-               <allow send_interface="org.bluez.Adapter"/>
-               <allow send_destination="org.bluez.Adapter"/>
-               <allow own="org.bluez.Manager"/>
-               <allow send_interface="org.bluez.Manager"/>
-               <allow send_destination="org.bluez.Manager"/>
-               <allow own="org.bluez.Device"/>
-               <allow send_interface="org.bluez.Device"/>
-               <allow send_destination="org.bluez.Device"/>
-               <allow own="org.bluez.Serial"/>
-               <allow send_interface="org.bluez.Serial"/>
-               <allow send_destination="org.bluez.Serial"/>
-               <allow own="org.bluez.SerialProxyManager"/>
-               <allow send_interface="org.bluez.SerialProxyManager"/>
-               <allow send_destination="org.bluez.SerialProxyManager"/>
-               <allow own="org.bluez.SerialProxy"/>
-               <allow send_interface="org.bluez.SerialProxy"/>
-               <allow send_destination="org.bluez.SerialProxy"/>
-               <allow own="org.bluez.NetworkServer"/>
-               <allow send_interface="org.bluez.NetworkServer"/>
-               <allow send_destination="org.bluez.NetworkServer"/>
-               <allow own="org.bluez.Network"/>
-               <allow send_interface="org.bluez.Network"/>
-               <allow send_destination="org.bluez.Network"/>
-               <allow own="org.bluez.AudioSink"/>
-               <allow send_interface="org.bluez.AudioSink"/>
-               <allow send_destination="org.bluez.AudioSink"/>
-               <allow own="org.bluez.Input"/>
-               <allow send_interface="org.bluez.Input"/>
-               <allow send_destination="org.bluez.Input"/>
-       </policy>
-       <policy group="bt_use">
-               <allow send_interface="org.projectx.bluetooth"/>
-               <allow send_destination="org.projectx.bluetooth"/>
-               <allow send_interface="org.bluez.frwk_agent"/>
-               <allow send_destination="org.bluez.frwk_agent"/>
-               <allow send_interface="org.bluez.Agent"/>
-               <allow send_destination="org.bluez.Agent"/>
-               <allow send_interface="org.bluez.Adapter"/>
-               <allow send_destination="org.bluez.Adapter"/>
-               <allow send_interface="org.bluez.Manager"/>
-               <allow send_destination="org.bluez.Manager"/>
-               <allow send_interface="org.bluez.Device"/>
-               <allow send_destination="org.bluez.Device"/>
-               <allow send_interface="org.bluez.Serial"/>
-               <allow send_destination="org.bluez.Serial"/>
-               <allow send_interface="org.bluez.SerialProxyManager"/>
-               <allow send_destination="org.bluez.SerialProxyManager"/>
-               <allow send_interface="org.bluez.SerialProxy"/>
-               <allow send_destination="org.bluez.SerialProxy"/>
-               <allow send_interface="org.bluez.NetworkServer"/>
-               <allow send_destination="org.bluez.NetworkServer"/>
-               <allow send_interface="org.bluez.Network"/>
-               <allow send_destination="org.bluez.Network"/>
-               <allow send_interface="org.bluez.AudioSink"/>
-               <allow send_destination="org.bluez.AudioSink"/>
-               <allow send_interface="org.bluez.Input"/>
-               <allow send_destination="org.bluez.Input"/>
-       </policy>
-       <policy context="default">
-               <deny send_interface="org.projectx.bluetooth"/>
-               <deny send_destination="org.projectx.bluetooth"/>
-               <deny send_interface="org.bluez.frwk_agent"/>
-               <deny send_destination="org.bluez.frwk_agent"/>
-               <deny send_interface="org.bluez.Agent"/>
-               <deny send_destination="org.bluez.Agent"/>
-               <deny send_interface="org.bluez.Adapter"/>
-               <deny send_destination="org.bluez.Adapter"/>
-               <deny send_interface="org.bluez.Manager"/>
-               <deny send_destination="org.bluez.Manager"/>
-               <deny send_interface="org.bluez.Device"/>
-               <deny send_destination="org.bluez.Device"/>
-               <deny send_interface="org.bluez.Serial"/>
-               <deny send_destination="org.bluez.Serial"/>
-               <deny send_interface="org.bluez.SerialProxyManager"/>
-               <deny send_destination="org.bluez.SerialProxyManager"/>
-               <deny send_interface="org.bluez.SerialProxy"/>
-               <deny send_destination="org.bluez.SerialProxy"/>
-               <deny send_interface="org.bluez.NetworkServer"/>
-               <deny send_destination="org.bluez.NetworkServer"/>
-               <deny send_interface="org.bluez.Network"/>
-               <deny send_destination="org.bluez.Network"/>
-               <deny send_interface="org.bluez.AudioSink"/>
-               <deny send_destination="org.bluez.AudioSink"/>
-               <deny send_interface="org.bluez.Input"/>
-               <deny send_destination="org.bluez.Input"/>
-       </policy>
+
+  <!-- ../system.conf have denied everything, so we just punch some holes -->
+
+  <policy user="root">
+    <allow own="org.bluez"/>
+    <allow send_destination="org.bluez"/>
+    <allow send_interface="org.bluez.Agent"/>
+    <allow send_interface="org.bluez.HandsfreeAgent"/>
+    <allow send_interface="org.bluez.MediaEndpoint"/>
+    <allow send_interface="org.bluez.MediaPlayer"/>
+    <allow send_interface="org.bluez.Watcher"/>
+    <allow send_interface="org.bluez.ThermometerWatcher"/>
+  </policy>
+
+  <policy at_console="true">
+    <allow send_destination="org.bluez"/>
+  </policy>
+
+  <!-- allow users of lp group (printing subsystem) to 
+       communicate with bluetoothd -->
+  <policy group="lp">
+    <allow send_destination="org.bluez"/>
+  </policy>
+
+  <policy context="default">
+    <deny send_destination="org.bluez"/>
+  </policy>
+
 </busconfig>
index 02b6707..2a576a3 100644 (file)
@@ -1,12 +1,11 @@
 [Unit]
 Description=Bluetooth service
-After=syslog.target
 
 [Service]
 Type=dbus
 BusName=org.bluez
 ExecStart=@prefix@/sbin/bluetoothd -n
-StandardOutput=syslog
 
 [Install]
 WantedBy=bluetooth.target
+Alias=dbus-org.bluez.service
index ef3b375..7e1bc94 100644 (file)
@@ -243,3 +243,36 @@ const char *class_to_icon(uint32_t class)
 
        return NULL;
 }
+
+const char *gap_appearance_to_icon(uint16_t appearance)
+{
+       switch ((appearance & 0xffc0) >> 6) {
+       case 0x01:
+               return "phone";
+       case 0x02:
+               return "computer";
+       case 0x05:
+               return "video-display";
+       case 0x0a:
+               return "multimedia-player";
+       case 0x0b:
+               return "scanner";
+       case 0x0f: /* HID Generic */
+               switch (appearance & 0x3f) {
+               case 0x01:
+                       return "input-keyboard";
+               case 0x02:
+                       return "input-mouse";
+               case 0x03:
+               case 0x04:
+                       return "input-gaming";
+               case 0x05:
+                       return "input-tablet";
+               case 0x08:
+                       return "scanner";
+               }
+               break;
+       }
+
+       return NULL;
+}
index b196a1b..b9531f2 100644 (file)
@@ -45,3 +45,4 @@ void set_dbus_connection(DBusConnection *conn);
 DBusConnection *get_dbus_connection(void);
 
 const char *class_to_icon(uint32_t class);
+const char *gap_appearance_to_icon(uint16_t appearance);
index 22e59b5..97b9082 100644 (file)
@@ -44,7 +44,6 @@
 #include <gdbus.h>
 
 #include "log.h"
-#include "textfile.h"
 
 #include "att.h"
 #include "hcid.h"
@@ -54,7 +53,6 @@
 #include "device.h"
 #include "dbus-common.h"
 #include "error.h"
-#include "glib-compat.h"
 #include "glib-helper.h"
 #include "sdp-client.h"
 #include "gatt.h"
@@ -73,6 +71,8 @@
 /* When all services should trust a remote device */
 #define GLOBAL_TRUST "[all]"
 
+#define APPEARANCE_CHR_UUID 0x2a01
+
 struct btd_disconnect_data {
        guint id;
        disconnect_watch watch;
@@ -83,10 +83,9 @@ struct btd_disconnect_data {
 struct bonding_req {
        DBusConnection *conn;
        DBusMessage *msg;
-       GIOChannel *io;
        guint listener_id;
 #ifdef __TIZEN_PATCH__
-       guint cancel_by_user;
+       gboolean cancel_by_user;
 #endif
        struct btd_device *device;
 };
@@ -97,14 +96,13 @@ struct authentication_req {
        struct agent *agent;
        struct btd_device *device;
        uint32_t passkey;
+       char *pincode;
        gboolean secure;
 };
 
 struct browse_req {
        DBusConnection *conn;
        DBusMessage *msg;
-       GIOChannel *io;
-       GAttrib *attrib;
        struct btd_device *device;
        GSList *match_uuids;
        GSList *profiles_added;
@@ -122,12 +120,22 @@ struct attio_data {
        gpointer user_data;
 };
 
+typedef void (*attio_error_cb) (const GError *gerr, gpointer user_data);
+typedef void (*attio_success_cb) (gpointer user_data);
+
+struct att_callbacks {
+       attio_error_cb error;           /* Callback for error */
+       attio_success_cb success;       /* Callback for success */
+       gpointer user_data;
+};
+
 struct btd_device {
        bdaddr_t        bdaddr;
-       addr_type_t     type;
+       uint8_t         bdaddr_type;
        gchar           *path;
        char            name[MAX_NAME_LENGTH + 1];
        char            *alias;
+       uint16_t        vendor_src;
        uint16_t        vendor;
        uint16_t        product;
        uint16_t        version;
@@ -163,6 +171,9 @@ struct btd_device {
 
        gboolean        authorizing;
        gint            ref;
+
+       GIOChannel      *att_io;
+       guint           cleanup_id;
 };
 
 static uint16_t uuid_list[] = {
@@ -174,17 +185,10 @@ static uint16_t uuid_list[] = {
 
 static GSList *device_drivers = NULL;
 
-static void browse_request_free(struct browse_req *req, gboolean shutdown)
+static void browse_request_free(struct browse_req *req)
 {
        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)
@@ -199,6 +203,30 @@ static void browse_request_free(struct browse_req *req, gboolean shutdown)
        g_free(req);
 }
 
+static void att_cleanup(struct btd_device *device)
+{
+       if (device->attachid) {
+               attrib_channel_detach(device->attrib, device->attachid);
+               device->attachid = 0;
+       }
+
+       if (device->cleanup_id) {
+               g_source_remove(device->cleanup_id);
+               device->cleanup_id = 0;
+       }
+
+       if (device->att_io) {
+               g_io_channel_shutdown(device->att_io, FALSE, NULL);
+               g_io_channel_unref(device->att_io);
+               device->att_io = NULL;
+       }
+
+       if (device->attrib) {
+               g_attrib_unref(device->attrib);
+               device->attrib = NULL;
+       }
+}
+
 static void browse_request_cancel(struct browse_req *req)
 {
        struct btd_device *device = req->device;
@@ -212,8 +240,10 @@ static void browse_request_cancel(struct browse_req *req)
 
        bt_cancel_discovery(&src, &device->bdaddr);
 
+       att_cleanup(device);
+
        device->browse = NULL;
-       browse_request_free(req, TRUE);
+       browse_request_free(req);
 }
 
 static void device_free(gpointer user_data)
@@ -235,7 +265,7 @@ static void device_free(gpointer user_data)
        g_slist_free_full(device->attios, g_free);
        g_slist_free_full(device->attios_offline, g_free);
 
-       g_attrib_unref(device->attrib);
+       att_cleanup(device);
 
        if (device->tmp_records)
                sdp_list_free(device->tmp_records,
@@ -252,6 +282,8 @@ static void device_free(gpointer user_data)
 
        DBG("%p", device);
 
+       if (device->authr)
+               g_free(device->authr->pincode);
        g_free(device->authr);
        g_free(device->path);
        g_free(device->alias);
@@ -260,12 +292,12 @@ static void device_free(gpointer user_data)
 
 gboolean device_is_bredr(struct btd_device *device)
 {
-       return (device->type == ADDR_TYPE_BREDR);
+       return (device->bdaddr_type == BDADDR_BREDR);
 }
 
 gboolean device_is_le(struct btd_device *device)
 {
-       return (device->type != ADDR_TYPE_BREDR);
+       return (device->bdaddr_type != BDADDR_BREDR);
 }
 
 gboolean device_is_paired(struct btd_device *device)
@@ -294,9 +326,10 @@ static DBusMessage *get_properties(DBusConnection *conn,
        bdaddr_t src;
        char name[MAX_NAME_LENGTH + 1], srcaddr[18], dstaddr[18];
        char **str;
-       const char *ptr;
+       const char *ptr, *icon = NULL;
        dbus_bool_t boolean;
        uint32_t class;
+       uint16_t app;
        int i;
        GSList *l;
 
@@ -338,27 +371,33 @@ static DBusMessage *get_properties(DBusConnection *conn,
 
        /* Class */
        if (read_remote_class(&src, &device->bdaddr, &class) == 0) {
-               const char *icon = class_to_icon(class);
+               icon = class_to_icon(class);
 
                dict_append_entry(&dict, "Class", DBUS_TYPE_UINT32, &class);
+       } else if (read_remote_appearance(&src, &device->bdaddr,
+                                               device->bdaddr_type, &app) == 0)
+               /* Appearance */
+               icon = gap_appearance_to_icon(app);
 
-               if (icon)
-                       dict_append_entry(&dict, "Icon",
-                                               DBUS_TYPE_STRING, &icon);
-       }
+       dict_append_entry(&dict, "Icon", DBUS_TYPE_STRING, &icon);
 
        /* Vendor */
        if (device->vendor)
                dict_append_entry(&dict, "Vendor", DBUS_TYPE_UINT16,
                                                        &device->vendor);
 
+       /* Vendor Source*/
+       if (device->vendor_src)
+               dict_append_entry(&dict, "VendorSource", DBUS_TYPE_UINT16,
+                                                       &device->vendor_src);
+
        /* Product */
        if (device->product)
                dict_append_entry(&dict, "Product", DBUS_TYPE_UINT16,
                                                        &device->product);
 
        /* Version */
-       if (device->product)
+       if (device->version)
                dict_append_entry(&dict, "Version", DBUS_TYPE_UINT16,
                                                        &device->version);
 
@@ -478,7 +517,8 @@ static gboolean do_disconnect(gpointer user_data)
 
        device->disconn_timer = 0;
 
-       btd_adapter_disconnect_device(device->adapter, &device->bdaddr);
+       btd_adapter_disconnect_device(device->adapter, &device->bdaddr,
+                                                       device->bdaddr_type);
 
        return FALSE;
 }
@@ -498,7 +538,8 @@ int device_block(DBusConnection *conn, struct btd_device *device,
        g_slist_foreach(device->drivers, (GFunc) driver_remove, device);
 
        if (!update_only)
-               err = btd_adapter_block_address(device->adapter, &device->bdaddr);
+               err = btd_adapter_block_address(device->adapter,
+                                       &device->bdaddr, device->bdaddr_type);
 
        if (err < 0)
                return err;
@@ -529,7 +570,8 @@ int device_unblock(DBusConnection *conn, struct btd_device *device,
                return 0;
 
        if (!update_only)
-               err = btd_adapter_unblock_address(device->adapter, &device->bdaddr);
+               err = btd_adapter_unblock_address(device->adapter,
+                                       &device->bdaddr, device->bdaddr_type);
 
        if (err < 0)
                return err;
@@ -837,20 +879,26 @@ static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg,
        return NULL;
 }
 
-static GDBusMethodTable device_methods[] = {
-       { "GetProperties",      "",     "a{sv}",        get_properties  },
-       { "SetProperty",        "sv",   "",             set_property    },
-       { "DiscoverServices",   "s",    "a{us}",        discover_services,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "CancelDiscovery",    "",     "",             cancel_discover },
-       { "Disconnect",         "",     "",             disconnect,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
+static const GDBusMethodTable device_methods[] = {
+       { GDBUS_METHOD("GetProperties",
+                               NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                               get_properties) },
+       { GDBUS_METHOD("SetProperty",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
+                       set_property) },
+       { GDBUS_ASYNC_METHOD("DiscoverServices",
+                       GDBUS_ARGS({ "pattern", "s" }),
+                       GDBUS_ARGS({ "services", "a{us}" }),
+                       discover_services) },
+       { GDBUS_METHOD("CancelDiscovery", NULL, NULL, cancel_discover) },
+       { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, disconnect) },
        { }
 };
 
-static GDBusSignalTable device_signals[] = {
-       { "PropertyChanged",            "sv"    },
-       { "DisconnectRequested",        ""      },
+static const GDBusSignalTable device_signals[] = {
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+       { GDBUS_SIGNAL("DisconnectRequested", NULL) },
        { }
 };
 
@@ -955,6 +1003,19 @@ static void device_set_vendor(struct btd_device *device, uint16_t value)
                                DBUS_TYPE_UINT16, &value);
 }
 
+static void device_set_vendor_src(struct btd_device *device, uint16_t value)
+{
+       DBusConnection *conn = get_dbus_connection();
+
+       if (device->vendor_src == value)
+               return;
+
+       device->vendor_src = value;
+
+       emit_property_changed(conn, device->path, DEVICE_INTERFACE,
+                               "VendorSource", DBUS_TYPE_UINT16, &value);
+}
+
 static void device_set_product(struct btd_device *device, uint16_t value)
 {
        DBusConnection *conn = get_dbus_connection();
@@ -983,7 +1044,7 @@ static void device_set_version(struct btd_device *device, uint16_t value)
 
 struct btd_device *device_create(DBusConnection *conn,
                                struct btd_adapter *adapter,
-                               const gchar *address, addr_type_t type)
+                               const gchar *address, uint8_t bdaddr_type)
 {
        gchar *address_up;
        struct btd_device *device;
@@ -1012,7 +1073,7 @@ struct btd_device *device_create(DBusConnection *conn,
 
        str2ba(address, &device->bdaddr);
        device->adapter = adapter;
-       device->type = type;
+       device->bdaddr_type = bdaddr_type;
        adapter_get_address(adapter, &src);
        ba2str(&src, srcaddr);
        read_device_name(srcaddr, address, device->name);
@@ -1028,6 +1089,12 @@ struct btd_device *device_create(DBusConnection *conn,
                device_set_bonded(device, TRUE);
        }
 
+       if (device_is_le(device) && has_longtermkeys(&src, &device->bdaddr,
+                                                       device->bdaddr_type)) {
+               device_set_paired(device, TRUE);
+               device_set_bonded(device, TRUE);
+       }
+
        if (read_device_id(srcaddr, address, NULL, &vendor, &product, &version)
                                                                        == 0) {
                device_set_vendor(device, vendor);
@@ -1069,6 +1136,11 @@ uint16_t btd_device_get_vendor(struct btd_device *device)
        return device->vendor;
 }
 
+uint16_t btd_device_get_vendor_src(struct btd_device *device)
+{
+       return device->vendor_src;
+}
+
 uint16_t btd_device_get_product(struct btd_device *device)
 {
        return device->product;
@@ -1082,23 +1154,33 @@ uint16_t btd_device_get_version(struct btd_device *device)
 static void device_remove_stored(struct btd_device *device)
 {
        bdaddr_t src;
-       char addr[18];
+       char key[20];
        DBusConnection *conn = get_dbus_connection();
 
        adapter_get_address(device->adapter, &src);
-       ba2str(&device->bdaddr, addr);
+       ba2str(&device->bdaddr, key);
+
+       /* key: address only */
+       delete_entry(&src, "profiles", key);
+       delete_entry(&src, "trusts", key);
 
        if (device_is_bonded(device)) {
-               delete_entry(&src, "linkkeys", addr);
-               delete_entry(&src, "aliases", addr);
+               delete_entry(&src, "linkkeys", key);
+               delete_entry(&src, "aliases", key);
+
+               /* key: address#type */
+               sprintf(&key[17], "#%hhu", device->bdaddr_type);
+
+               delete_entry(&src, "longtermkeys", key);
+
                device_set_bonded(device, FALSE);
                device->paired = FALSE;
-               btd_adapter_remove_bonding(device->adapter, &device->bdaddr);
+               btd_adapter_remove_bonding(device->adapter, &device->bdaddr,
+                                                       device->bdaddr_type);
        }
-       delete_entry(&src, "profiles", addr);
-       delete_entry(&src, "trusts", addr);
+
        delete_all_records(&src, &device->bdaddr);
-       delete_device_service(&src, &device->bdaddr);
+       delete_device_service(&src, &device->bdaddr, device->bdaddr_type);
 
        if (device->blocked)
                device_unblock(conn, device, TRUE, FALSE);
@@ -1496,7 +1578,7 @@ GSList *device_services_from_record(struct btd_device *device, GSList *profiles)
        for (l = profiles; l; l = l->next) {
                const char *profile_uuid = l->data;
                const sdp_record_t *rec;
-               struct att_primary *prim;
+               struct gatt_primary *prim;
                uint16_t start = 0, end = 0, psm = 0;
                uuid_t prim_uuid;
 
@@ -1510,9 +1592,9 @@ GSList *device_services_from_record(struct btd_device *device, GSList *profiles)
                if (!gatt_parse_record(rec, &prim_uuid, &psm, &start, &end))
                        continue;
 
-               prim = g_new0(struct att_primary, 1);
-               prim->start = start;
-               prim->end = end;
+               prim = g_new0(struct gatt_primary, 1);
+               prim->range.start = start;
+               prim->range.end = end;
                sdp_uuid2strn(&prim_uuid, prim->uuid, sizeof(prim->uuid));
 
                prim_list = g_slist_append(prim_list, prim);
@@ -1604,7 +1686,7 @@ cleanup:
        }
 
        device->browse = NULL;
-       browse_request_free(req, FALSE);
+       browse_request_free(req);
 }
 
 static void browse_cb(sdp_list_t *recs, int err, gpointer user_data)
@@ -1665,13 +1747,13 @@ static char *primary_list_to_string(GSList *primary_list)
        services = g_string_new(NULL);
 
        for (l = primary_list; l; l = l->next) {
-               struct att_primary *primary = l->data;
+               struct gatt_primary *primary = l->data;
                char service[64];
 
                memset(service, 0, sizeof(service));
 
                snprintf(service, sizeof(service), "%04X#%04X#%s ",
-                               primary->start, primary->end, primary->uuid);
+                               primary->range.start, primary->range.end, primary->uuid);
 
                services = g_string_append(services, service);
        }
@@ -1688,7 +1770,7 @@ static void store_services(struct btd_device *device)
        adapter_get_address(adapter, &sba);
        device_get_address(device, &dba, NULL);
 
-       write_device_services(&sba, &dba, str);
+       write_device_services(&sba, &dba, device->bdaddr_type, str);
 
        g_free(str);
 }
@@ -1719,137 +1801,196 @@ static void att_connect_dispatched(gpointer user_data)
 
 static gboolean att_connect(gpointer user_data);
 
-static void attrib_disconnected(gpointer user_data)
+static gboolean attrib_disconnected_cb(GIOChannel *io, GIOCondition cond,
+                                                       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);
+       if (device->browse)
+               goto done;
+
        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;
+       if (device->auto_connect == FALSE || err != ETIMEDOUT)
+               goto done;
 
        device->auto_id = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT_IDLE,
                                                AUTO_CONNECTION_INTERVAL,
                                                att_connect, device,
                                                att_connect_dispatched);
+
+done:
+       att_cleanup(device);
+
+       return FALSE;
+}
+
+static void appearance_cb(guint8 status, const guint8 *pdu, guint16 plen,
+                                                       gpointer user_data)
+{
+       struct btd_device *device = user_data;
+       struct btd_adapter *adapter = device->adapter;
+       struct att_data_list *list =  NULL;
+       uint16_t app;
+       bdaddr_t src;
+       uint8_t *atval;
+
+       if (status != 0) {
+               DBG("Read characteristics by UUID failed: %s\n",
+                                                       att_ecode2str(status));
+               goto done;
+       }
+
+       list = dec_read_by_type_resp(pdu, plen);
+       if (list == NULL)
+               goto done;
+
+       if (list->len != 4) {
+               DBG("Appearance value: invalid data");
+               goto done;
+       }
+
+       /* A device shall have only one instance of the
+       Appearance characteristic. */
+       atval = list->data[0] + 2; /* skip handle value */
+       app = att_get_u16(atval);
+
+       adapter_get_address(adapter, &src);
+       write_remote_appearance(&src, &device->bdaddr, device->bdaddr_type,
+                                                                       app);
+
+done:
+       att_data_list_free(list);
+       if (device->attios == NULL && device->attios_offline == NULL)
+               att_cleanup(device);
 }
 
 static void primary_cb(GSList *services, guint8 status, gpointer user_data)
 {
        struct browse_req *req = user_data;
        struct btd_device *device = req->device;
+       struct gatt_primary *gap_prim = NULL;
        GSList *l, *uuids = NULL;
-       gboolean shutdown;
 
        if (status) {
-               DBusMessage *reply;
-               reply = btd_error_failed(req->msg, att_ecode2str(status));
-               g_dbus_send_message(req->conn, reply);
-               shutdown = TRUE;
+               if (req->msg) {
+                       DBusMessage *reply;
+                       reply = btd_error_failed(req->msg,
+                                                       att_ecode2str(status));
+                       g_dbus_send_message(req->conn, reply);
+               }
                goto done;
        }
 
        device_set_temporary(device, FALSE);
 
        for (l = services; l; l = l->next) {
-               struct att_primary *prim = l->data;
+               struct gatt_primary *prim = l->data;
+
+               if (strcmp(prim->uuid, GAP_SVC_UUID) == 0)
+                       gap_prim = prim;
+
                uuids = g_slist_append(uuids, prim->uuid);
        }
 
-       /*
-        * 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);
+       if (gap_prim) {
+               /* Read appearance characteristic */
+               bt_uuid_t uuid;
+
+               bt_uuid16_create(&uuid, APPEARANCE_CHR_UUID);
+
+               gatt_read_char_by_uuid(device->attrib, gap_prim->range.start,
+                       gap_prim->range.end, &uuid, appearance_cb, device);
+       } else if (device->attios == NULL && device->attios_offline == NULL)
+               att_cleanup(device);
 
        g_slist_free(uuids);
 
        services_changed(device);
-       create_device_reply(device, req);
+       if (req->msg)
+               create_device_reply(device, req);
 
        store_services(device);
-       shutdown = FALSE;
 
 done:
        device->browse = NULL;
-       browse_request_free(req, shutdown);
+       browse_request_free(req);
 }
 
 static void att_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
 {
-       struct btd_device *device = user_data;
-       struct browse_req *req = device->browse;
+       struct att_callbacks *attcb = user_data;
+       struct btd_device *device = attcb->user_data;
        GAttrib *attrib;
 
-       if (gerr) {
-               DBusMessage *reply;
+       g_io_channel_unref(device->att_io);
+       device->att_io = NULL;
 
+       if (gerr) {
                DBG("%s", gerr->message);
 
-               if (req) {
-                       reply = btd_error_failed(req->msg, gerr->message);
-                       g_dbus_send_message(req->conn, reply);
+               if (attcb->error)
+                       attcb->error(gerr, user_data);
 
-                       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;
+               goto done;
        }
 
        attrib = g_attrib_new(io);
-       device->attachid = attrib_channel_attach(attrib, TRUE);
+       device->attachid = attrib_channel_attach(attrib);
        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);
-       }
+       device->attrib = attrib;
+       device->cleanup_id = g_io_add_watch(io, G_IO_HUP,
+                                       attrib_disconnected_cb, device);
+
+       if (attcb->success)
+               attcb->success(user_data);
+done:
+       g_free(attcb);
+}
+
+static void att_error_cb(const GError *gerr, gpointer user_data)
+{
+       struct att_callbacks *attcb = user_data;
+       struct btd_device *device = attcb->user_data;
+
+       if (device->auto_connect == FALSE)
+               return;
+
+       device->auto_id = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT_IDLE,
+                                               AUTO_CONNECTION_INTERVAL,
+                                               att_connect, device,
+                                               att_connect_dispatched);
+
+       DBG("Enabling automatic connections");
+}
+
+static void att_success_cb(gpointer user_data)
+{
+       struct att_callbacks *attcb = user_data;
+       struct btd_device *device = attcb->user_data;
+
+       if (device->attios == NULL)
+               return;
+
+       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;
+       struct att_callbacks *attcb;
        GIOChannel *io;
        GError *gerr = NULL;
        char addr[18];
@@ -1860,9 +2001,14 @@ static gboolean att_connect(gpointer user_data)
 
        DBG("Connection attempt to: %s", addr);
 
+       attcb = g_new0(struct att_callbacks, 1);
+       attcb->error = att_error_cb;
+       attcb->success = att_success_cb;
+       attcb->user_data = device;
+
        if (device_is_bredr(device)) {
                io = bt_io_connect(BT_IO_L2CAP, att_connect_cb,
-                                       device, NULL, &gerr,
+                                       attcb, NULL, &gerr,
                                        BT_IO_OPT_SOURCE_BDADDR, &sba,
                                        BT_IO_OPT_DEST_BDADDR, &device->bdaddr,
                                        BT_IO_OPT_PSM, ATT_PSM,
@@ -1870,29 +2016,58 @@ static gboolean att_connect(gpointer user_data)
                                        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);
+                               attcb, NULL, &gerr,
+                               BT_IO_OPT_SOURCE_BDADDR, &sba,
+                               BT_IO_OPT_DEST_BDADDR, &device->bdaddr,
+                               BT_IO_OPT_DEST_TYPE, device->bdaddr_type,
+                               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);
+               g_free(attcb);
                return FALSE;
        }
 
-       g_io_channel_unref(io);
+       device->att_io = io;
 
        return FALSE;
 }
 
+static void att_browse_error_cb(const GError *gerr, gpointer user_data)
+{
+       struct att_callbacks *attcb = user_data;
+       struct btd_device *device = attcb->user_data;
+       struct browse_req *req = device->browse;
+
+       if (req->msg) {
+               DBusMessage *reply;
+
+               reply = btd_error_failed(req->msg, gerr->message);
+               g_dbus_send_message(req->conn, reply);
+       }
+
+       device->browse = NULL;
+       browse_request_free(req);
+}
+
+static void att_browse_cb(gpointer user_data)
+{
+       struct att_callbacks *attcb = user_data;
+       struct btd_device *device = attcb->user_data;
+
+       gatt_discover_primary(device->attrib, NULL, primary_cb,
+                                                       device->browse);
+}
+
 int device_browse_primary(struct btd_device *device, DBusConnection *conn,
                                DBusMessage *msg, gboolean secure)
 {
        struct btd_adapter *adapter = device->adapter;
+       struct att_callbacks *attcb;
        struct browse_req *req;
        BtIOSecLevel sec_level;
        bdaddr_t src;
@@ -1900,28 +2075,53 @@ int device_browse_primary(struct btd_device *device, DBusConnection *conn,
        if (device->browse)
                return -EBUSY;
 
+       /* FIXME: GATT service updates (implemented in update_services() for
+        * SDP) are not supported yet. It will be supported once client side
+        * "Services Changed" characteristic handling is implemented. */
+       if (device->primaries) {
+               error("Could not update GATT services");
+               return -ENOSYS;
+       }
+
        req = g_new0(struct browse_req, 1);
        req->device = btd_device_ref(device);
-
        adapter_get_address(adapter, &src);
 
+       device->browse = req;
+
+       if (device->attrib) {
+               gatt_discover_primary(device->attrib, NULL, primary_cb, req);
+               goto done;
+       }
+
        sec_level = secure ? BT_IO_SEC_HIGH : BT_IO_SEC_LOW;
 
-       req->io = bt_io_connect(BT_IO_L2CAP, att_connect_cb,
-                               device, NULL, NULL,
+       attcb = g_new0(struct att_callbacks, 1);
+       attcb->error = att_browse_error_cb;
+       attcb->success = att_browse_cb;
+       attcb->user_data = device;
+
+       device->att_io = bt_io_connect(BT_IO_L2CAP, att_connect_cb,
+                               attcb, NULL, NULL,
                                BT_IO_OPT_SOURCE_BDADDR, &src,
                                BT_IO_OPT_DEST_BDADDR, &device->bdaddr,
+                               BT_IO_OPT_DEST_TYPE, device->bdaddr_type,
                                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, FALSE);
+       if (device->att_io == NULL) {
+               device->browse = NULL;
+               browse_request_free(req);
+               g_free(attcb);
                return -EIO;
        }
 
+done:
+       if (conn == NULL)
+               conn = get_dbus_connection();
+
        req->conn = dbus_connection_ref(conn);
-       device->browse = req;
 
        if (msg) {
                const char *sender = dbus_message_get_sender(msg);
@@ -1966,7 +2166,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, FALSE);
+               browse_request_free(req);
                return err;
        }
 
@@ -2000,11 +2200,24 @@ struct btd_adapter *device_get_adapter(struct btd_device *device)
 }
 
 void device_get_address(struct btd_device *device, bdaddr_t *bdaddr,
-                                                       addr_type_t *type)
+                                                       uint8_t *bdaddr_type)
 {
        bacpy(bdaddr, &device->bdaddr);
-       if (type != NULL)
-               *type = device->type;
+       if (bdaddr_type != NULL)
+               *bdaddr_type = device->bdaddr_type;
+}
+
+void device_set_addr_type(struct btd_device *device, uint8_t bdaddr_type)
+{
+       if (device == NULL)
+               return;
+
+       device->bdaddr_type = bdaddr_type;
+}
+
+uint8_t device_get_addr_type(struct btd_device *device)
+{
+       return device->bdaddr_type;
 }
 
 const gchar *device_get_path(struct btd_device *device)
@@ -2097,7 +2310,10 @@ static gboolean start_discovery(gpointer user_data)
 {
        struct btd_device *device = user_data;
 
-       device_browse_sdp(device, NULL, NULL, NULL, TRUE);
+       if (device_is_bredr(device))
+               device_browse_sdp(device, NULL, NULL, NULL, TRUE);
+       else
+               device_browse_primary(device, NULL, NULL, FALSE);
 
        device->discov_timer = 0;
 
@@ -2181,9 +2397,6 @@ static void bonding_request_free(struct bonding_req *bonding)
        if (bonding->conn)
                dbus_connection_unref(bonding->conn);
 
-       if (bonding->io)
-               g_io_channel_unref(bonding->io);
-
        device = bonding->device;
        g_free(bonding);
 
@@ -2208,7 +2421,8 @@ void device_set_paired(struct btd_device *device, gboolean value)
                return;
 
        if (!value)
-               btd_adapter_remove_bonding(device->adapter, &device->bdaddr);
+               btd_adapter_remove_bonding(device->adapter, &device->bdaddr,
+                                                       device->bdaddr_type);
 
        device->paired = value;
 
@@ -2240,7 +2454,6 @@ static struct bonding_req *bonding_request_new(DBusConnection *conn,
 {
        struct bonding_req *bonding;
        const char *name = dbus_message_get_sender(msg);
-       struct agent *agent;
        char addr[18];
 
        ba2str(&device->bdaddr, addr);
@@ -2249,16 +2462,10 @@ static struct bonding_req *bonding_request_new(DBusConnection *conn,
        if (!agent_path)
                goto proceed;
 
-       agent = agent_create(device->adapter, name, agent_path,
+       device->agent = agent_create(device->adapter, name, agent_path,
                                        capability,
                                        device_agent_removed,
                                        device);
-       if (!agent) {
-               error("Unable to create a new agent");
-               return NULL;
-       }
-
-       device->agent = agent;
 
        DBG("Temporary agent registered for %s at %s:%s",
                        addr, name, agent_path);
@@ -2288,17 +2495,6 @@ static void create_bond_req_exit(DBusConnection *conn, void *user_data)
                device_request_disconnect(device, NULL);
        }
 }
-#ifdef __TIZEN_PATCH__
-void set_cancel_from_authentication_req(void *user_data)
-{
-       struct authentication_req *auth = (struct authentication_req *)user_data;
-
-       if (auth && auth->device && auth->device->bonding)
-       {
-               auth->device->bonding->cancel_by_user = 1;
-       }
-}
-#endif
 
 DBusMessage *device_create_bonding(struct btd_device *device,
                                        DBusConnection *conn,
@@ -2306,40 +2502,53 @@ DBusMessage *device_create_bonding(struct btd_device *device,
                                        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;
        int err;
 
-       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);
+       if (device_is_bonded(device))
                return btd_error_already_exists(msg);
+
+       if (device_is_le(device)) {
+               struct att_callbacks *attcb;
+               GError *gerr = NULL;
+               bdaddr_t sba;
+
+               adapter_get_address(adapter, &sba);
+
+               attcb = g_new0(struct att_callbacks, 1);
+               attcb->user_data = device;
+
+               device->att_io = bt_io_connect(BT_IO_L2CAP, att_connect_cb,
+                               attcb, NULL, &gerr,
+                               BT_IO_OPT_SOURCE_BDADDR, &sba,
+                               BT_IO_OPT_DEST_BDADDR, &device->bdaddr,
+                               BT_IO_OPT_DEST_TYPE, device->bdaddr_type,
+                               BT_IO_OPT_CID, ATT_CID,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                               BT_IO_OPT_INVALID);
+
+               if (device->att_io == NULL) {
+                       DBusMessage *reply = btd_error_failed(msg,
+                                                               gerr->message);
+
+                       error("Bonding bt_io_connect(): %s", gerr->message);
+                       g_error_free(gerr);
+                       g_free(attcb);
+                       return reply;
+               }
        }
 
-       err = adapter_create_bonding(adapter, &device->bdaddr, capability);
+       err = adapter_create_bonding(adapter, &device->bdaddr,
+                                       device->bdaddr_type, capability);
        if (err < 0)
                return btd_error_failed(msg, strerror(-err));
 
        bonding = bonding_request_new(conn, msg, device, agent_path,
                                        capability);
-       if (!bonding) {
-               adapter_cancel_bonding(adapter, &device->bdaddr);
-               return NULL;
-       }
 
        bonding->listener_id = g_dbus_add_disconnect_watch(conn,
                                                dbus_message_get_sender(msg),
@@ -2356,12 +2565,15 @@ void device_simple_pairing_complete(struct btd_device *device, uint8_t status)
 {
        struct authentication_req *auth = device->authr;
 
-       if (auth && auth->type == AUTH_TYPE_NOTIFY && auth->agent)
+       if (auth && (auth->type == AUTH_TYPE_NOTIFY_PASSKEY
+                    || auth->type == AUTH_TYPE_NOTIFY_PINCODE) && auth->agent)
                agent_cancel(auth->agent);
 }
 
 static void device_auth_req_free(struct btd_device *device)
 {
+       if (device->authr)
+               g_free(device->authr->pincode);
        g_free(device->authr);
        device->authr = NULL;
 }
@@ -2373,7 +2585,8 @@ void device_bonding_complete(struct btd_device *device, uint8_t status)
 
        DBG("bonding %p status 0x%02x", bonding, status);
 
-       if (auth && auth->type == AUTH_TYPE_NOTIFY && auth->agent)
+       if (auth && (auth->type == AUTH_TYPE_NOTIFY_PASSKEY
+                    || auth->type == AUTH_TYPE_NOTIFY_PINCODE) && auth->agent)
                agent_cancel(auth->agent);
 
        if (status) {
@@ -2403,8 +2616,12 @@ void device_bonding_complete(struct btd_device *device, uint8_t status)
                        device->discov_timer = 0;
                }
 
-               device_browse_sdp(device, bonding->conn, bonding->msg,
-                               NULL, FALSE);
+               if (device_is_bredr(device))
+                       device_browse_sdp(device, bonding->conn, bonding->msg,
+                                                               NULL, FALSE);
+               else
+                       device_browse_primary(device, bonding->conn,
+                                                       bonding->msg, FALSE);
 
                bonding_request_free(bonding);
        } else {
@@ -2474,12 +2691,10 @@ void device_cancel_bonding(struct btd_device *device, uint8_t status)
                device_cancel_authentication(device, FALSE);
 
 #ifdef __TIZEN_PATCH__
-       if (bonding->cancel_by_user)
-       {
+       if (bonding->cancel_by_user) {
                info("Bonding Cancel by user");
                reply = new_authentication_return(bonding->msg, 0x2a);
-       }
-       else
+       } else
 #endif
        reply = new_authentication_return(bonding->msg, status);
        g_dbus_send_message(bonding->conn, reply);
@@ -2495,10 +2710,18 @@ static void pincode_cb(struct agent *agent, DBusError *err,
        struct btd_device *device = auth->device;
        struct btd_adapter *adapter = device_get_adapter(device);
        struct agent *adapter_agent = adapter_get_agent(adapter);
+#ifdef __TIZEN_PATCH__
+       struct bonding_req *bonding = device->bonding;
+
+       if (err == NULL)
+               goto done;
 
+       if (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) ||
+                       g_str_equal(DBUS_ERROR_NO_REPLY, err->name)) {
+#else
        if (err && (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) ||
                                g_str_equal(DBUS_ERROR_NO_REPLY, err->name))) {
-
+#endif
                if (auth->agent == adapter_agent || adapter_agent == NULL)
                        goto done;
 
@@ -2510,6 +2733,11 @@ static void pincode_cb(struct agent *agent, DBusError *err,
                return;
        }
 
+#ifdef __TIZEN_PATCH__
+       if (bonding)
+               bonding->cancel_by_user = TRUE;
+#endif
+
 done:
        /* No need to reply anything if the authentication already failed */
        if (auth->cb == NULL)
@@ -2527,10 +2755,18 @@ static void confirm_cb(struct agent *agent, DBusError *err, void *data)
        struct btd_device *device = auth->device;
        struct btd_adapter *adapter = device_get_adapter(device);
        struct agent *adapter_agent = adapter_get_agent(adapter);
+#ifdef __TIZEN_PATCH__
+       struct bonding_req *bonding = device->bonding;
 
+       if (err == NULL)
+               goto done;
+
+       if (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) ||
+                       g_str_equal(DBUS_ERROR_NO_REPLY, err->name)) {
+#else
        if (err && (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) ||
                                g_str_equal(DBUS_ERROR_NO_REPLY, err->name))) {
-
+#endif
                if (auth->agent == adapter_agent || adapter_agent == NULL)
                        goto done;
 
@@ -2543,6 +2779,11 @@ static void confirm_cb(struct agent *agent, DBusError *err, void *data)
                return;
        }
 
+#ifdef __TIZEN_PATCH__
+       if (bonding)
+               bonding->cancel_by_user = TRUE;
+#endif
+
 done:
        /* No need to reply anything if the authentication already failed */
        if (auth->cb == NULL)
@@ -2561,9 +2802,18 @@ static void passkey_cb(struct agent *agent, DBusError *err,
        struct btd_device *device = auth->device;
        struct btd_adapter *adapter = device_get_adapter(device);
        struct agent *adapter_agent = adapter_get_agent(adapter);
+#ifdef __TIZEN_PATCH__
+       struct bonding_req *bonding = device->bonding;
 
+       if (err == NULL)
+               goto done;
+
+       if (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) ||
+                       g_str_equal(DBUS_ERROR_NO_REPLY, err->name)) {
+#else
        if (err && (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) ||
                                g_str_equal(DBUS_ERROR_NO_REPLY, err->name))) {
+#endif
 
                if (auth->agent == adapter_agent || adapter_agent == NULL)
                        goto done;
@@ -2576,6 +2826,11 @@ static void passkey_cb(struct agent *agent, DBusError *err,
                return;
        }
 
+#ifdef __TIZEN_PATCH__
+       if (bonding)
+               bonding->cancel_by_user = TRUE;
+#endif
+
 done:
        /* No need to reply anything if the authentication already failed */
        if (auth->cb == NULL)
@@ -2587,8 +2842,60 @@ done:
        device->authr->agent = NULL;
 }
 
+static void display_pincode_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);
+#ifdef __TIZEN_PATCH__
+       struct bonding_req *bonding = device->bonding;
+
+       if (err == NULL)
+               goto done;
+
+       if (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) ||
+                       g_str_equal(DBUS_ERROR_NO_REPLY, err->name)) {
+#else
+       if (err && (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) ||
+                               g_str_equal(DBUS_ERROR_NO_REPLY, err->name))) {
+#endif
+
+               /* Request a pincode if we fail to display one */
+               if (auth->agent == adapter_agent || adapter_agent == NULL) {
+                       if (agent_request_pincode(agent, device, pincode_cb,
+                                               auth->secure, auth, NULL) < 0)
+                               goto done;
+                       return;
+               }
+
+               if (agent_display_pincode(adapter_agent, device, auth->pincode,
+                                       display_pincode_cb, auth, NULL) < 0)
+                       goto done;
+
+               auth->agent = adapter_agent;
+               return;
+       }
+#ifdef __TIZEN_PATCH__
+       if (bonding)
+               bonding->cancel_by_user = TRUE;
+#endif
+
+done:
+       /* No need to reply anything if the authentication already failed */
+       if (auth->cb == NULL)
+               return;
+
+       ((agent_pincode_cb) auth->cb)(agent, err, auth->pincode, device);
+
+       g_free(device->authr->pincode);
+       device->authr->pincode = NULL;
+       device->authr->cb = NULL;
+       device->authr->agent = NULL;
+}
+
 int device_request_authentication(struct btd_device *device, auth_type_t type,
-                               uint32_t passkey, gboolean secure, void *cb)
+                                       void *data, gboolean secure, void *cb)
 {
        struct authentication_req *auth;
        struct agent *agent;
@@ -2614,7 +2921,6 @@ 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;
 
@@ -2628,11 +2934,18 @@ int device_request_authentication(struct btd_device *device, auth_type_t type,
                                                                auth, NULL);
                break;
        case AUTH_TYPE_CONFIRM:
-               err = agent_request_confirmation(agent, device, passkey,
+               auth->passkey = *((uint32_t *) data);
+               err = agent_request_confirmation(agent, device, auth->passkey,
                                                confirm_cb, auth, NULL);
                break;
-       case AUTH_TYPE_NOTIFY:
-               err = agent_display_passkey(agent, device, passkey);
+       case AUTH_TYPE_NOTIFY_PASSKEY:
+               auth->passkey = *((uint32_t *) data);
+               err = agent_display_passkey(agent, device, auth->passkey);
+               break;
+       case AUTH_TYPE_NOTIFY_PINCODE:
+               auth->pincode = g_strdup((const char *) data);
+               err = agent_display_pincode(agent, device, auth->pincode,
+                                               display_pincode_cb, auth, NULL);
                break;
        default:
                err = -EINVAL;
@@ -2671,9 +2984,12 @@ static void cancel_authentication(struct authentication_req *auth)
        case AUTH_TYPE_PASSKEY:
                ((agent_passkey_cb) auth->cb)(agent, &err, 0, device);
                break;
-       case AUTH_TYPE_NOTIFY:
+       case AUTH_TYPE_NOTIFY_PASSKEY:
                /* User Notify doesn't require any reply */
                break;
+       case AUTH_TYPE_NOTIFY_PINCODE:
+               ((agent_pincode_cb) auth->cb)(agent, &err, NULL, device);
+               break;
        }
 
        dbus_error_free(&err);
@@ -2853,14 +3169,16 @@ guint btd_device_add_attio_callback(struct btd_device *device,
                device->attios_offline = g_slist_append(device->attios_offline,
                                                                        attio);
                g_idle_add(notify_attios, device);
-       } else {
+               return attio->id;
+       }
+
+       device->attios = g_slist_append(device->attios, attio);
+
+       if (device->auto_id == 0)
                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;
 }
 
@@ -2898,15 +3216,22 @@ gboolean btd_device_remove_attio_callback(struct btd_device *device, guint id)
        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->auto_id) {
+               g_source_remove(device->auto_id);
+               device->auto_id = 0;
        }
 
-       if (device->attrib) {
-               g_attrib_unref(device->attrib);
-               device->attrib = NULL;
-       }
+       att_cleanup(device);
 
        return TRUE;
 }
+
+void device_set_pnpid(struct btd_device *device, uint8_t vendor_id_src,
+                       uint16_t vendor_id, uint16_t product_id,
+                       uint16_t product_ver)
+{
+       device_set_vendor(device, vendor_id);
+       device_set_vendor_src(device, vendor_id_src);
+       device_set_product(device, product_id);
+       device_set_version(device, product_ver);
+}
index e75a06d..26e17f7 100644 (file)
@@ -30,15 +30,17 @@ typedef enum {
        AUTH_TYPE_PINCODE,
        AUTH_TYPE_PASSKEY,
        AUTH_TYPE_CONFIRM,
-       AUTH_TYPE_NOTIFY,
+       AUTH_TYPE_NOTIFY_PASSKEY,
+       AUTH_TYPE_NOTIFY_PINCODE,
 } auth_type_t;
 
 struct btd_device *device_create(DBusConnection *conn,
                                        struct btd_adapter *adapter,
-                                       const char *address, addr_type_t type);
+                                       const char *address, uint8_t bdaddr_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);
 uint16_t btd_device_get_vendor(struct btd_device *device);
+uint16_t btd_device_get_vendor_src(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);
@@ -58,7 +60,9 @@ GSList *device_services_from_record(struct btd_device *device,
 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,
-                                                       addr_type_t *type);
+                                                       uint8_t *bdaddr_type);
+void device_set_addr_type(struct btd_device *device, uint8_t bdaddr_type);
+uint8_t device_get_addr_type(struct btd_device *device);
 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);
@@ -73,9 +77,6 @@ void device_set_temporary(struct btd_device *device, gboolean temporary);
 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);
-#ifdef __TIZEN_PATCH__
-void set_cancel_from_authentication_req(void *user_data);
-#endif
 DBusMessage *device_create_bonding(struct btd_device *device,
                                DBusConnection *conn, DBusMessage *msg,
                                const char *agent_path, uint8_t capability);
@@ -85,7 +86,7 @@ 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, gboolean secure, void *cb);
+                                       void *data, 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);
@@ -122,3 +123,6 @@ 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);
+void device_set_pnpid(struct btd_device *device, uint8_t vendor_id_src,
+                       uint16_t vendor_id, uint16_t product_id,
+                       uint16_t product_ver);
index 1b68949..9d42917 100644 (file)
--- a/src/eir.c
+++ b/src/eir.c
 #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);
@@ -119,7 +106,7 @@ int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len)
 
        while (len < eir_len - 1) {
                uint8_t field_len = eir_data[0];
-               uint8_t name_len;
+               uint8_t data_len, *data = &eir_data[2];
 
                /* Check for the end of EIR */
                if (field_len == 0)
@@ -127,51 +114,60 @@ int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len)
 
                len += field_len + 1;
 
-               /* Bail out if got incorrect length */
-               if (len > eir_len) {
-                       eir_data_free(eir);
-                       return -EINVAL;
-               }
+               /* Do not continue EIR Data parsing if got incorrect length */
+               if (len > eir_len)
+                       break;
+
+               data_len = field_len - 1;
 
                switch (eir_data[1]) {
                case EIR_UUID16_SOME:
                case EIR_UUID16_ALL:
-                       eir_parse_uuid16(eir, &eir_data[2], field_len);
+                       eir_parse_uuid16(eir, data, data_len);
                        break;
 
                case EIR_UUID32_SOME:
                case EIR_UUID32_ALL:
-                       eir_parse_uuid32(eir, &eir_data[2], field_len);
+                       eir_parse_uuid32(eir, data, data_len);
                        break;
 
                case EIR_UUID128_SOME:
                case EIR_UUID128_ALL:
-                       eir_parse_uuid128(eir, &eir_data[2], field_len);
+                       eir_parse_uuid128(eir, data, data_len);
                        break;
 
                case EIR_FLAGS:
-                       eir->flags = eir_data[2];
+                       if (data_len > 0)
+                               eir->flags = *data;
                        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 (data_len > 0 && data[data_len - 1] == '\0')
+                               data_len--;
 
-                       while (name_len > 0 && eir_data[name_len - 1] == '\0')
-                               name_len--;
-
-                       if (!g_utf8_validate((char *) &eir_data[2],
-                                                               name_len, NULL))
+                       if (!g_utf8_validate((char *) data, data_len, NULL))
                                break;
 
                        g_free(eir->name);
 
-                       eir->name = g_strndup((char *) &eir_data[2],
-                                                               field_len - 1);
+                       eir->name = g_strndup((char *) data, data_len);
                        eir->name_complete = eir_data[1] == EIR_NAME_COMPLETE;
                        break;
+
+               case EIR_CLASS_OF_DEV:
+                       if (data_len < 3)
+                               break;
+                       memcpy(eir->dev_class, data, 3);
+                       break;
+
+               case EIR_GAP_APPEARANCE:
+                       if (data_len < 2)
+                               break;
+                       eir->appearance = bt_get_le16(data);
+                       break;
                }
 
                eir_data += field_len + 1;
@@ -240,7 +236,7 @@ static void eir_generate_uuid128(GSList *list, uint8_t *ptr, uint16_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)
+                       uint16_t did_source, GSList *uuids, uint8_t *data)
 {
        GSList *l;
        uint8_t *ptr = data;
@@ -277,11 +273,10 @@ void eir_create(const char *name, int8_t tx_power, uint16_t did_vendor,
        }
 
        if (did_vendor != 0x0000) {
-               uint16_t source = 0x0002;
                *ptr++ = 9;
                *ptr++ = EIR_DEVICE_ID;
-               *ptr++ = (source & 0x00ff);
-               *ptr++ = (source & 0xff00) >> 8;
+               *ptr++ = (did_source & 0x00ff);
+               *ptr++ = (did_source & 0xff00) >> 8;
                *ptr++ = (did_vendor & 0x00ff);
                *ptr++ = (did_vendor & 0xff00) >> 8;
                *ptr++ = (did_product & 0x00ff);
@@ -342,12 +337,12 @@ void eir_create(const char *name, int8_t tx_power, uint16_t did_vendor,
                eir_generate_uuid128(uuids, ptr, &eir_len);
 }
 
-gboolean eir_has_complete_name(uint8_t *data, size_t len)
+gboolean eir_has_data_type(uint8_t *data, size_t len, uint8_t type)
 {
        uint8_t field_len;
-       size_t parsed;
+       size_t parsed = 0;
 
-       for (parsed = 0; parsed < len - 1; parsed += field_len) {
+       while (parsed < len - 1) {
                field_len = data[0];
 
                if (field_len == 0)
@@ -358,7 +353,7 @@ gboolean eir_has_complete_name(uint8_t *data, size_t len)
                if (parsed > len)
                        break;
 
-               if (data[1] == EIR_NAME_COMPLETE)
+               if (data[1] == type)
                        return TRUE;
 
                data += field_len + 1;
@@ -366,3 +361,37 @@ gboolean eir_has_complete_name(uint8_t *data, size_t len)
 
        return FALSE;
 }
+
+size_t eir_append_data(uint8_t *eir, size_t eir_len, uint8_t type,
+                                               uint8_t *data, size_t data_len)
+{
+       eir[eir_len++] = sizeof(type) + data_len;
+       eir[eir_len++] = type;
+       memcpy(&eir[eir_len], data, data_len);
+       eir_len += data_len;
+
+       return eir_len;
+}
+
+size_t eir_length(uint8_t *eir, size_t maxlen)
+{
+       uint8_t field_len;
+       size_t parsed = 0, length = 0;
+
+       while (parsed < maxlen - 1) {
+               field_len = eir[0];
+
+               if (field_len == 0)
+                       break;
+
+               parsed += field_len + 1;
+
+               if (parsed > maxlen)
+                       break;
+
+               length = parsed;
+               eir += field_len + 1;
+       }
+
+       return length;
+}
index 47c2258..3c81024 100644 (file)
--- a/src/eir.h
+++ b/src/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_CLASS_OF_DEV            0x0D  /* Class of Device */
+#define EIR_DEVICE_ID               0x10  /* device ID */
+#define EIR_GAP_APPEARANCE          0x19  /* GAP appearance */
+
 struct uuid_info {
        uuid_t uuid;
        uint8_t svc_hint;
@@ -31,6 +45,8 @@ struct eir_data {
        GSList *services;
        int flags;
        char *name;
+       uint8_t dev_class[3];
+       uint16_t appearance;
        gboolean name_complete;
 };
 
@@ -38,6 +54,10 @@ 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);
+                       uint16_t did_source, GSList *uuids, uint8_t *data);
+
+gboolean eir_has_data_type(uint8_t *data, size_t len, uint8_t type);
 
-gboolean eir_has_complete_name(uint8_t *data, size_t len);
+size_t eir_append_data(uint8_t *eir, size_t eir_len, uint8_t type,
+                                               uint8_t *data, size_t data_len);
+size_t eir_length(uint8_t *eir, size_t maxlen);
index 6854990..ec5926f 100644 (file)
@@ -119,18 +119,24 @@ int btd_event_request_pin(bdaddr_t *sba, bdaddr_t *dba, gboolean secure)
        struct btd_device *device;
        char pin[17];
        ssize_t pinlen;
+       gboolean display = FALSE;
 
        if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE))
                return -ENODEV;
 
        memset(pin, 0, sizeof(pin));
-       pinlen = btd_adapter_get_pin(adapter, device, pin);
+       pinlen = btd_adapter_get_pin(adapter, device, pin, &display);
        if (pinlen > 0 && (!secure || pinlen == 16)) {
+               if (display && device_is_bonding(device, NULL))
+                       return device_request_authentication(device,
+                                               AUTH_TYPE_NOTIFY_PINCODE, pin,
+                                               secure, pincode_cb);
+
                btd_adapter_pincode_reply(adapter, dba, pin, pinlen);
                return 0;
        }
 
-       return device_request_authentication(device, AUTH_TYPE_PINCODE, 0,
+       return device_request_authentication(device, AUTH_TYPE_PINCODE, NULL,
                                                        secure, pincode_cb);
 }
 
@@ -138,10 +144,12 @@ static int confirm_reply(struct btd_adapter *adapter,
                                struct btd_device *device, gboolean success)
 {
        bdaddr_t bdaddr;
+       uint8_t bdaddr_type;
 
-       device_get_address(device, &bdaddr, NULL);
+       device_get_address(device, &bdaddr, &bdaddr_type);
 
-       return btd_adapter_confirm_reply(adapter, &bdaddr, success);
+       return btd_adapter_confirm_reply(adapter, &bdaddr, bdaddr_type,
+                                                               success);
 }
 
 static void confirm_cb(struct agent *agent, DBusError *err, void *user_data)
@@ -159,13 +167,14 @@ static void passkey_cb(struct agent *agent, DBusError *err, uint32_t passkey,
        struct btd_device *device = user_data;
        struct btd_adapter *adapter = device_get_adapter(device);
        bdaddr_t bdaddr;
+       uint8_t bdaddr_type;
 
-       device_get_address(device, &bdaddr, NULL);
+       device_get_address(device, &bdaddr, &bdaddr_type);
 
        if (err)
                passkey = INVALID_PASSKEY;
 
-       btd_adapter_passkey_reply(adapter, &bdaddr, passkey);
+       btd_adapter_passkey_reply(adapter, &bdaddr, bdaddr_type, passkey);
 }
 
 int btd_event_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey)
@@ -177,7 +186,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, FALSE, confirm_cb);
+                                               &passkey, FALSE, confirm_cb);
 }
 
 int btd_event_user_passkey(bdaddr_t *sba, bdaddr_t *dba)
@@ -188,7 +197,7 @@ int btd_event_user_passkey(bdaddr_t *sba, bdaddr_t *dba)
        if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE))
                return -ENODEV;
 
-       return device_request_authentication(device, AUTH_TYPE_PASSKEY, 0,
+       return device_request_authentication(device, AUTH_TYPE_PASSKEY, NULL,
                                                        FALSE, passkey_cb);
 }
 
@@ -200,8 +209,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,
-                                                               FALSE, NULL);
+       return device_request_authentication(device, AUTH_TYPE_NOTIFY_PASSKEY,
+                                                       &passkey, FALSE, NULL);
 }
 
 void btd_event_simple_pairing_complete(bdaddr_t *local, bdaddr_t *peer,
@@ -246,10 +255,9 @@ 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, addr_type_t type,
-                                       uint32_t class, int8_t rssi,
-                                       uint8_t confirm_name, uint8_t *data,
-                                       uint8_t data_len)
+void btd_event_device_found(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type,
+                                       int8_t rssi, uint8_t confirm_name,
+                                       uint8_t *data, uint8_t data_len)
 {
        struct btd_adapter *adapter;
 
@@ -260,12 +268,11 @@ void btd_event_device_found(bdaddr_t *local, bdaddr_t *peer, addr_type_t type,
        }
 
        update_lastseen(local, peer);
-       write_remote_class(local, peer, class);
 
        if (data)
-               write_remote_eir(local, peer, data);
+               write_remote_eir(local, peer, data, data_len);
 
-       adapter_update_found_devices(adapter, peer, type, class, rssi,
+       adapter_update_found_devices(adapter, peer, bdaddr_type, rssi,
                                                confirm_name, data, data_len);
 }
 
@@ -311,7 +318,6 @@ 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, char *name)
 {
        struct btd_adapter *adapter;
-       char srcaddr[18];
        struct btd_device *device;
        struct remote_dev_info *dev_info;
 
@@ -332,8 +338,6 @@ void btd_event_remote_name(bdaddr_t *local, bdaddr_t *peer, char *name)
        if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE))
                return;
 
-       ba2str(local, srcaddr);
-
        dev_info = adapter_search_found_devices(adapter, peer);
        if (dev_info) {
                g_free(dev_info->name);
@@ -345,6 +349,56 @@ void btd_event_remote_name(bdaddr_t *local, bdaddr_t *peer, char *name)
                device_set_name(device, name);
 }
 
+static char *buf2str(uint8_t *data, int datalen)
+{
+       char *buf;
+       int i;
+
+       buf = g_try_new0(char, (datalen * 2) + 1);
+       if (buf == NULL)
+               return NULL;
+
+       for (i = 0; i < datalen; i++)
+               sprintf(buf + (i * 2), "%2.2x", data[i]);
+
+       return buf;
+}
+
+static int store_longtermkey(bdaddr_t *local, bdaddr_t *peer,
+                               uint8_t bdaddr_type, unsigned char *key,
+                               uint8_t master, uint8_t authenticated,
+                               uint8_t enc_size, uint16_t ediv, uint8_t rand[8])
+{
+       GString *newkey;
+       char *val, *str;
+       int err;
+
+       val = buf2str(key, 16);
+       if (val == NULL)
+               return -ENOMEM;
+
+       newkey = g_string_new(val);
+       g_free(val);
+
+       g_string_append_printf(newkey, " %d %d %d %d ", authenticated, master,
+                                                               enc_size, ediv);
+
+       str = buf2str(rand, 8);
+       if (str == NULL) {
+               g_string_free(newkey, TRUE);
+               return -ENOMEM;
+       }
+
+       newkey = g_string_append(newkey, str);
+       g_free(str);
+
+       err = write_longtermkeys(local, peer, bdaddr_type, newkey->str);
+
+       g_string_free(newkey, TRUE);
+
+       return err;
+}
+
 int btd_event_link_key_notify(bdaddr_t *local, bdaddr_t *peer,
                                uint8_t *key, uint8_t key_type,
                                uint8_t pin_length)
@@ -370,7 +424,32 @@ int btd_event_link_key_notify(bdaddr_t *local, bdaddr_t *peer,
        return ret;
 }
 
-void btd_event_conn_complete(bdaddr_t *local, bdaddr_t *peer)
+int btd_event_ltk_notify(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type,
+                                       uint8_t *key, uint8_t master,
+                                       uint8_t authenticated, uint8_t enc_size,
+                                       uint16_t ediv, uint8_t rand[8])
+{
+       struct btd_adapter *adapter;
+       struct btd_device *device;
+       int ret;
+
+       if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE))
+               return -ENODEV;
+
+       ret = store_longtermkey(local, peer, bdaddr_type, key, master,
+                                       authenticated, enc_size, ediv, rand);
+       if (ret == 0) {
+               device_set_bonded(device, TRUE);
+
+               if (device_is_temporary(device))
+                       device_set_temporary(device, FALSE);
+       }
+
+       return ret;
+}
+
+void btd_event_conn_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type,
+                                               char *name, uint8_t *dev_class)
 {
        struct btd_adapter *adapter;
        struct btd_device *device;
@@ -380,7 +459,20 @@ void btd_event_conn_complete(bdaddr_t *local, bdaddr_t *peer)
 
        update_lastused(local, peer);
 
+       if (dev_class != NULL) {
+               uint32_t class = dev_class[0] | (dev_class[1] << 8) |
+                                                       (dev_class[2] << 16);
+
+               if (class != 0)
+                       write_remote_class(local, peer, class);
+       }
+
+       device_set_addr_type(device, bdaddr_type);
+
        adapter_add_connection(adapter, device);
+
+       if (name != NULL)
+               btd_event_remote_name(local, peer, name);
 }
 
 void btd_event_conn_failed(bdaddr_t *local, bdaddr_t *peer, uint8_t status)
@@ -430,7 +522,8 @@ void btd_event_device_blocked(bdaddr_t *local, bdaddr_t *peer)
        if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE))
                return;
 
-       device_block(conn, device, TRUE);
+       if (device)
+               device_block(conn, device, TRUE);
 }
 
 void btd_event_device_unblocked(bdaddr_t *local, bdaddr_t *peer)
@@ -443,7 +536,25 @@ void btd_event_device_unblocked(bdaddr_t *local, bdaddr_t *peer)
        if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE))
                return;
 
-       device_unblock(conn, device, FALSE, TRUE);
+       if (device)
+               device_unblock(conn, device, FALSE, TRUE);
+}
+
+void btd_event_device_unpaired(bdaddr_t *local, bdaddr_t *peer)
+{
+       struct btd_adapter *adapter;
+       struct btd_device *device;
+       DBusConnection *conn = get_dbus_connection();
+
+       if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE))
+               return;
+
+       device_set_temporary(device, TRUE);
+
+       if (device_is_connected(device))
+               device_request_disconnect(device, NULL);
+       else
+               adapter_remove_device(conn, adapter, device, TRUE);
 }
 
 /* Section reserved to device HCI callbacks */
index 708eeb9..dfc158d 100644 (file)
  */
 
 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_device_found(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type,
+                                       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, char *name);
-void btd_event_conn_complete(bdaddr_t *local, bdaddr_t *peer);
+void btd_event_conn_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type,
+                                       char *name, uint8_t *dev_class);
 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_simple_pairing_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t status);
@@ -39,5 +40,10 @@ 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);
+void btd_event_device_unpaired(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);
+int btd_event_ltk_notify(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type,
+                                       uint8_t *key, uint8_t master,
+                                       uint8_t authenticated, uint8_t enc_size,
+                                       uint16_t ediv, uint8_t rand[8]);
index 8189a09..419c655 100644 (file)
@@ -35,7 +35,6 @@
 #include <glib.h>
 
 #include "btio.h"
-#include "glib-compat.h"
 #include "glib-helper.h"
 
 char *bt_uuid2string(uuid_t *uuid)
index 1987b7d..1e5e15a 100644 (file)
@@ -38,18 +38,18 @@ struct main_opts {
        gboolean        reverse_sdp;
        gboolean        name_resolv;
        gboolean        debug_keys;
-       gboolean        attrib_server;
+       gboolean        gatt_enabled;
 
        uint8_t         mode;
-       uint8_t         discov_interval;
-       char            deviceid[15]; /* FIXME: */
+
+       uint16_t        did_source;
+       uint16_t        did_vendor;
+       uint16_t        did_product;
+       uint16_t        did_version;
 };
 
 enum {
-       HCID_SET_NAME,
-       HCID_SET_CLASS,
        HCID_SET_PAGETO,
-       HCID_SET_DISCOVTO,
 };
 
 extern struct main_opts main_opts;
index 4a50117..75a98a9 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -44,6 +44,17 @@ void info(const char *format, ...)
        va_end(ap);
 }
 
+void warn(const char *format, ...)
+{
+       va_list ap;
+
+       va_start(ap, format);
+
+       vsyslog(LOG_WARNING, format, ap);
+
+       va_end(ap);
+}
+
 void error(const char *format, ...)
 {
        va_list ap;
index b43b2b7..3d34fa3 100644 (file)
--- a/src/log.h
+++ b/src/log.h
@@ -22,6 +22,7 @@
  */
 
 void info(const char *format, ...) __attribute__((format(printf, 1, 2)));
+void warn(const char *format, ...) __attribute__((format(printf, 1, 2)));
 void error(const char *format, ...) __attribute__((format(printf, 1, 2)));
 
 void btd_debug(const char *format, ...) __attribute__((format(printf, 1, 2)));
@@ -56,4 +57,3 @@ void __btd_enable_debug(struct btd_debug_desc *start,
        if (__btd_debug_desc.flags & BTD_DEBUG_FLAG_PRINT) \
                btd_debug("%s:%s() " fmt,  __FILE__, __FUNCTION__ , ## arg); \
 } while (0)
-
index 74ec3fa..286baa0 100644 (file)
 #include "agent.h"
 #include "manager.h"
 
-#ifdef HAVE_CAPNG
-#include <cap-ng.h>
-#endif
-
 #define BLUEZ_NAME "org.bluez"
 
 #define LAST_ADAPTER_EXIT_TIMEOUT 30
@@ -87,6 +83,36 @@ static GKeyFile *load_config(const char *file)
        return keyfile;
 }
 
+static void parse_did(const char *did)
+{
+       int result;
+       uint16_t vendor, product, version , source;
+
+       /* version and source are optional */
+       version = 0x0000;
+       source = 0x0002;
+
+       result = sscanf(did, "bluetooth:%4hx:%4hx:%4hx", &vendor, &product, &version);
+       if (result != EOF && result >= 2) {
+               source = 0x0001;
+               goto done;
+       }
+
+       result = sscanf(did, "usb:%4hx:%4hx:%4hx", &vendor, &product, &version);
+       if (result != EOF && result >= 2)
+               goto done;
+
+       result = sscanf(did, "%4hx:%4hx:%4hx", &vendor, &product, &version);
+       if (result == EOF || result < 2)
+               return;
+
+done:
+       main_opts.did_source = source;
+       main_opts.did_vendor = vendor;
+       main_opts.did_product = product;
+       main_opts.did_version = version;
+}
+
 static void parse_config(GKeyFile *config)
 {
        GError *err = NULL;
@@ -107,7 +133,6 @@ static void parse_config(GKeyFile *config)
        } else {
                DBG("discovto=%d", val);
                main_opts.discovto = val;
-               main_opts.flags |= 1 << HCID_SET_DISCOVTO;
        }
 
        val = g_key_file_get_integer(config, "General",
@@ -148,7 +173,6 @@ static void parse_config(GKeyFile *config)
                DBG("name=%s", str);
                g_free(main_opts.name);
                main_opts.name = g_strdup(str);
-               main_opts.flags |= 1 << HCID_SET_NAME;
                g_free(str);
        }
 
@@ -159,20 +183,9 @@ static void parse_config(GKeyFile *config)
        } else {
                DBG("class=%s", str);
                main_opts.class = strtol(str, NULL, 16);
-               main_opts.flags |= 1 << HCID_SET_CLASS;
                g_free(str);
        }
 
-       val = g_key_file_get_integer(config, "General",
-                                       "DiscoverSchedulerInterval", &err);
-       if (err) {
-               DBG("%s", err->message);
-               g_clear_error(&err);
-       } else {
-               DBG("discov_interval=%d", val);
-               main_opts.discov_interval = val;
-       }
-
        boolean = g_key_file_get_boolean(config, "General",
                                                "InitiallyPowered", &err);
        if (err) {
@@ -195,8 +208,7 @@ static void parse_config(GKeyFile *config)
                g_clear_error(&err);
        } else {
                DBG("deviceid=%s", str);
-               strncpy(main_opts.deviceid, str,
-                                       sizeof(main_opts.deviceid) - 1);
+               parse_did(str);
                g_free(str);
        }
 
@@ -223,11 +235,11 @@ static void parse_config(GKeyFile *config)
                main_opts.debug_keys = boolean;
 
        boolean = g_key_file_get_boolean(config, "General",
-                                               "AttributeServer", &err);
+                                               "EnableGatt", &err);
        if (err)
                g_clear_error(&err);
        else
-               main_opts.attrib_server = boolean;
+               main_opts.gatt_enabled = boolean;
 
        main_opts.link_mode = HCI_LM_ACCEPT;
 
@@ -446,15 +458,6 @@ int main(int argc, char *argv[])
 
        init_defaults();
 
-#ifdef HAVE_CAPNG
-       /* Drop capabilities */
-       capng_clear(CAPNG_SELECT_BOTH);
-       capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
-                                       CAP_NET_BIND_SERVICE, CAP_NET_ADMIN,
-                                               CAP_NET_RAW, CAP_IPC_LOCK, -1);
-       capng_apply(CAPNG_SELECT_BOTH);
-#endif
-
        context = g_option_context_new(NULL);
        g_option_context_add_main_entries(context, options, NULL);
 
@@ -519,7 +522,7 @@ int main(int argc, char *argv[])
                }
        }
 
-       start_sdp_server(mtu, main_opts.deviceid, SDP_SERVER_COMPAT);
+       start_sdp_server(mtu, SDP_SERVER_COMPAT);
 
        /* 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
index 2b3738c..e5b7d39 100644 (file)
@@ -30,10 +30,6 @@ PairableTimeout = 0
 # which is 16384 (10 seconds).
 PageTimeout = 8192
 
-# Discover scheduler interval used in Adapter.DiscoverDevices
-# 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
@@ -45,11 +41,17 @@ AutoConnectTimeout = 60
 InitiallyPowered = true
 
 # Remember the previously stored Powered state when initializing adapters
-RememberPowered = true
+#ifdef __TIZEN_PATCH__
+RememberPowered = false
+#else
+#RememberPowered = true
+#endif
 
-# Use vendor, product and version information for DID profile support.
-# The values are separated by ":" and VID, PID and version.
-#DeviceID = 1234:5678:abcd
+# Use vendor id source (assigner), vendor, product and version information for
+# DID profile support. The values are separated by ":" and assigner, VID, PID
+# and version.
+# Possible vendor id source values: bluetooth, usb (defaults to usb)
+#DeviceID = bluetooth:1234:5678:abcd
 
 # Do reverse service discovery for previously unknown devices that connect to
 # us. This option is really only needed for qualification since the BITE tester
@@ -66,6 +68,5 @@ NameResolving = true
 # that they were created for.
 DebugKeys = false
 
-# Enable the GATT Attribute Server. Default is false, because it is only
-# useful for testing.
-AttributeServer = false
+# Enable the GATT functionality. Default is false
+EnableGatt = false
index 1d44c66..385354d 100644 (file)
@@ -196,20 +196,32 @@ static DBusMessage *get_properties(DBusConnection *conn,
        return reply;
 }
 
-static GDBusMethodTable manager_methods[] = {
-       { "GetProperties",      "",     "a{sv}",get_properties  },
-       { "DefaultAdapter",     "",     "o",    default_adapter },
-       { "FindAdapter",        "s",    "o",    find_adapter    },
-       { "ListAdapters",       "",     "ao",   list_adapters,
-                                               G_DBUS_METHOD_FLAG_DEPRECATED},
+static const GDBusMethodTable manager_methods[] = {
+       { GDBUS_METHOD("GetProperties",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       get_properties) },
+       { GDBUS_METHOD("DefaultAdapter",
+                       NULL, GDBUS_ARGS({ "adapter", "o" }),
+                       default_adapter) },
+       { GDBUS_METHOD("FindAdapter",
+                       GDBUS_ARGS({ "pattern", "s" }),
+                       GDBUS_ARGS({ "adapter", "o" }),
+                       find_adapter) },
+       { GDBUS_ASYNC_METHOD("ListAdapters",
+                       NULL, GDBUS_ARGS({ "adapters", "ao" }),
+                       list_adapters) },
        { }
 };
 
-static GDBusSignalTable manager_signals[] = {
-       { "PropertyChanged",            "sv"    },
-       { "AdapterAdded",               "o"     },
-       { "AdapterRemoved",             "o"     },
-       { "DefaultAdapterChanged",      "o"     },
+static const GDBusSignalTable manager_signals[] = {
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+       { GDBUS_SIGNAL("AdapterAdded",
+                       GDBUS_ARGS({ "adapter", "o" })) },
+       { GDBUS_SIGNAL("AdapterRemoved",
+                       GDBUS_ARGS({ "adapter", "o" })) },
+       { GDBUS_SIGNAL("DefaultAdapterChanged",
+                       GDBUS_ARGS({ "adapter", "o" })) },
        { }
 };
 
@@ -377,7 +389,7 @@ void manager_add_adapter(const char *path)
        btd_stop_exit_timer();
 }
 
-struct btd_adapter *btd_manager_register_adapter(int id)
+struct btd_adapter *btd_manager_register_adapter(int id, gboolean up)
 {
        struct btd_adapter *adapter;
        const char *path;
@@ -394,7 +406,7 @@ struct btd_adapter *btd_manager_register_adapter(int id)
 
        adapters = g_slist_append(adapters, adapter);
 
-       if (!adapter_init(adapter)) {
+       if (!adapter_init(adapter, up)) {
                adapters = g_slist_remove(adapters, adapter);
                btd_adapter_unref(adapter);
                return NULL;
@@ -413,6 +425,12 @@ struct btd_adapter *btd_manager_register_adapter(int id)
        if (default_adapter_id < 0)
                manager_set_default_adapter(id);
 
+       if (main_opts.did_source)
+               btd_adapter_set_did(adapter, main_opts.did_vendor,
+                                               main_opts.did_product,
+                                               main_opts.did_version,
+                                               main_opts.did_source);
+
        DBG("Adapter %s registered", path);
 
        return btd_adapter_ref(adapter);
@@ -435,14 +453,3 @@ int btd_manager_unregister_adapter(int id)
 
        return 0;
 }
-
-void btd_manager_set_did(uint16_t vendor, uint16_t product, uint16_t version)
-{
-       GSList *l;
-
-       for (l = adapters; l != NULL; l = g_slist_next(l)) {
-               struct btd_adapter *adapter = l->data;
-
-               btd_adapter_set_did(adapter, vendor, product, version);
-       }
-}
index 4f92d2f..264cd25 100644 (file)
@@ -38,7 +38,6 @@ 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);
+struct btd_adapter *btd_manager_register_adapter(int id, gboolean up);
 int btd_manager_unregister_adapter(int id);
 void manager_add_adapter(const char *path);
-void btd_manager_set_did(uint16_t vendor, uint16_t product, uint16_t version);
diff --git a/src/org.bluez.service b/src/org.bluez.service
new file mode 100644 (file)
index 0000000..dd7ae8f
--- /dev/null
@@ -0,0 +1,5 @@
+[D-BUS Service]
+Name=org.bluez
+Exec=/bin/false
+User=root
+SystemdService=dbus-org.bluez.service
index f119313..55e59c2 100644 (file)
@@ -61,7 +61,7 @@ static gboolean cached_session_expired(gpointer user_data)
        return FALSE;
 }
 
-static sdp_session_t *get_sdp_session(const bdaddr_t *src, const bdaddr_t *dst)
+static sdp_session_t *get_cached_sdp_session(const bdaddr_t *src, const bdaddr_t *dst)
 {
        GSList *l;
 
@@ -82,6 +82,17 @@ static sdp_session_t *get_sdp_session(const bdaddr_t *src, const bdaddr_t *dst)
                return session;
        }
 
+       return NULL;
+}
+
+static sdp_session_t *get_sdp_session(const bdaddr_t *src, const bdaddr_t *dst)
+{
+       sdp_session_t *session;
+
+       session = get_cached_sdp_session(src, dst);
+       if (session)
+               return session;
+
        return sdp_connect(src, dst, SDP_NON_BLOCKING);
 }
 
@@ -367,3 +378,11 @@ int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst)
        return 0;
 }
 
+void bt_clear_cached_session(const bdaddr_t *src, const bdaddr_t *dst)
+{
+       sdp_session_t *session;
+
+       session = get_cached_sdp_session(src, dst);
+       if (session)
+               sdp_close(session);
+}
index 13d9121..9191594 100644 (file)
@@ -28,3 +28,4 @@ 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);
+void bt_clear_cached_session(const bdaddr_t *src, const bdaddr_t *dst);
index ff00df7..6a903c6 100644 (file)
@@ -748,7 +748,7 @@ static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf)
                        cstate_size = sdp_set_cstate_pdu(buf, &newState);
                } else {
                        if (buf->data_size == 0)
-                               sdp_append_to_buf(buf, 0, 0);
+                               sdp_append_to_buf(buf, NULL, 0);
                        cstate_size = sdp_set_cstate_pdu(buf, NULL);
                }
        }
@@ -1037,7 +1037,7 @@ send_rsp:
        if (send(req->sock, rsp.data, rsp.data_size, 0) < 0)
                error("send: %s (%d)", strerror(errno), errno);
 
-       SDPDBG("Bytes Sent : %d", sent);
+       SDPDBG("Bytes Sent : %d", rsp.data_size);
 
        free(rsp.data);
        free(req->buf);
index a92ae2c..1d9509e 100644 (file)
@@ -45,6 +45,7 @@
 
 #include <glib.h>
 
+#include "hcid.h"
 #include "log.h"
 #include "sdpd.h"
 
@@ -227,7 +228,7 @@ static gboolean io_accept_event(GIOChannel *chan, GIOCondition cond, gpointer da
        return TRUE;
 }
 
-int start_sdp_server(uint16_t mtu, const char *did, uint32_t flags)
+int start_sdp_server(uint16_t mtu, uint32_t flags)
 {
        int compat = flags & SDP_SERVER_COMPAT;
        int master = flags & SDP_SERVER_MASTER;
@@ -240,20 +241,8 @@ int start_sdp_server(uint16_t mtu, const char *did, uint32_t flags)
                return -1;
        }
 
-       if (did && strlen(did) > 0) {
-               const char *ptr = did;
-               uint16_t vid = 0x0000, pid = 0x0000, ver = 0x0000;
-
-               vid = (uint16_t) strtol(ptr, NULL, 16);
-               ptr = strchr(ptr, ':');
-               if (ptr) {
-                       pid = (uint16_t) strtol(ptr + 1, NULL, 16);
-                       ptr = strchr(ptr + 1, ':');
-                       if (ptr)
-                               ver = (uint16_t) strtol(ptr + 1, NULL, 16);
-                       register_device_id(vid, pid, ver);
-               }
-       }
+       if (main_opts.did_source > 0)
+               register_device_id();
 
        io = g_io_channel_unix_new(l2cap_sock);
        g_io_channel_set_close_on_unref(io, TRUE);
index de11562..39e05ab 100644 (file)
@@ -44,6 +44,7 @@
 #include <glib.h>
 #include <dbus/dbus.h>
 
+#include "hcid.h"
 #include "sdpd.h"
 #include "log.h"
 #include "adapter.h"
@@ -172,10 +173,9 @@ void register_server_service(void)
        update_db_timestamp();
 }
 
-void register_device_id(const uint16_t vendor, const uint16_t product,
-                                               const uint16_t version)
+void register_device_id(void)
 {
-       const uint16_t spec = 0x0102, source = 0x0002;
+       const uint16_t spec = 0x0103;
        const uint8_t primary = 1;
        sdp_list_t *class_list, *group_list, *profile_list;
        uuid_t class_uuid, group_uuid;
@@ -184,9 +184,9 @@ void register_device_id(const uint16_t vendor, const uint16_t product,
        sdp_profile_desc_t profile;
        sdp_record_t *record = sdp_record_alloc();
 
-       info("Adding device id record for %04x:%04x", vendor, product);
-
-       btd_manager_set_did(vendor, product, version);
+       info("Adding device id record for %04x:%04x:%04x:%04x",
+                               main_opts.did_source, main_opts.did_vendor,
+                               main_opts.did_product, main_opts.did_version);
 
        record->handle = sdp_next_handle();
 
@@ -213,19 +213,19 @@ void register_device_id(const uint16_t vendor, const uint16_t product,
        spec_data = sdp_data_alloc(SDP_UINT16, &spec);
        sdp_attr_add(record, 0x0200, spec_data);
 
-       vendor_data = sdp_data_alloc(SDP_UINT16, &vendor);
+       vendor_data = sdp_data_alloc(SDP_UINT16, &main_opts.did_vendor);
        sdp_attr_add(record, 0x0201, vendor_data);
 
-       product_data = sdp_data_alloc(SDP_UINT16, &product);
+       product_data = sdp_data_alloc(SDP_UINT16, &main_opts.did_product);
        sdp_attr_add(record, 0x0202, product_data);
 
-       version_data = sdp_data_alloc(SDP_UINT16, &version);
+       version_data = sdp_data_alloc(SDP_UINT16, &main_opts.did_version);
        sdp_attr_add(record, 0x0203, version_data);
 
        primary_data = sdp_data_alloc(SDP_BOOL, &primary);
        sdp_attr_add(record, 0x0204, primary_data);
 
-       source_data = sdp_data_alloc(SDP_UINT16, &source);
+       source_data = sdp_data_alloc(SDP_UINT16, &main_opts.did_source);
        sdp_attr_add(record, 0x0205, source_data);
 
        update_db_timestamp();
@@ -277,6 +277,10 @@ int remove_record_from_server(uint32_t handle)
 {
        sdp_record_t *rec;
 
+       /* Refuse to remove the server's own record */
+       if (handle == SDP_SERVER_RECORD_HANDLE)
+               return -EINVAL;
+
        DBG("Removing record with handle 0x%05x", handle);
 
        rec = sdp_record_find(handle);
index 9f5415f..83d2b03 100644 (file)
@@ -53,8 +53,7 @@ int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp);
 
 void register_public_browse_group(void);
 void register_server_service(void);
-void register_device_id(const uint16_t vendor, const uint16_t product,
-                                               const uint16_t version);
+void register_device_id(void);
 
 int record_sort(const void *r1, const void *r2);
 void sdp_svcdb_reset(void);
@@ -74,7 +73,7 @@ uint32_t sdp_get_time(void);
 #define SDP_SERVER_COMPAT (1 << 0)
 #define SDP_SERVER_MASTER (1 << 1)
 
-int start_sdp_server(uint16_t mtu, const char *did, uint32_t flags);
+int start_sdp_server(uint16_t mtu, uint32_t flags);
 void stop_sdp_server(void);
 
 int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec);
index a47720a..17e8001 100644 (file)
@@ -41,9 +41,9 @@
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
+#include <bluetooth/uuid.h>
 
 #include "textfile.h"
-#include "glib-compat.h"
 #include "glib-helper.h"
 #include "storage.h"
 
@@ -282,6 +282,47 @@ int read_local_class(bdaddr_t *bdaddr, uint8_t *class)
        return 0;
 }
 
+int read_remote_appearance(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type,
+                                                       uint16_t *appearance)
+{
+       char filename[PATH_MAX + 1], key[20], *str;
+
+       create_filename(filename, PATH_MAX, local, "appearances");
+
+       ba2str(peer, key);
+       sprintf(&key[17], "#%hhu", bdaddr_type);
+
+       str = textfile_get(filename, key);
+       if (!str)
+               return -ENOENT;
+
+       if (sscanf(str, "%hx", appearance) != 1) {
+               free(str);
+               return -ENOENT;
+       }
+
+       free(str);
+
+       return 0;
+}
+
+int write_remote_appearance(bdaddr_t *local, bdaddr_t *peer,
+                               uint8_t bdaddr_type, uint16_t appearance)
+{
+       char filename[PATH_MAX + 1], key[20], str[7];
+
+       create_filename(filename, PATH_MAX, local, "appearances");
+
+       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+       ba2str(peer, key);
+       sprintf(&key[17], "#%hhu", bdaddr_type);
+
+       sprintf(str, "0x%4.4x", appearance);
+
+       return textfile_put(filename, key, str);
+}
+
 int write_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class)
 {
        char filename[PATH_MAX + 1], addr[18], str[9];
@@ -359,13 +400,14 @@ int read_device_name(const char *src, const char *dst, char *name)
        return 0;
 }
 
-int write_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data)
+int write_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data,
+                                                       uint8_t data_len)
 {
        char filename[PATH_MAX + 1], addr[18], str[481];
        int i;
 
        memset(str, 0, sizeof(str));
-       for (i = 0; i < HCI_MAX_EIR_LENGTH; i++)
+       for (i = 0; i < data_len; i++)
                sprintf(str + (i * 2), "%2.2X", data[i]);
 
        create_filename(filename, PATH_MAX, local, "eir");
@@ -694,7 +736,7 @@ int write_trust(const char *src, const char *addr, const char *service,
        else {
                char *new_str = service_list_to_string(services);
                ret = textfile_caseput(filename, addr, new_str);
-               free(new_str);
+               g_free(new_str);
        }
 
        g_slist_free(services);
@@ -779,7 +821,7 @@ int store_record(const gchar *src, const gchar *dst, sdp_record_t *rec)
        err = textfile_put(filename, key, str);
 
        free(buf.data);
-       free(str);
+       g_free(str);
 
        return err;
 }
@@ -801,7 +843,7 @@ sdp_record_t *record_from_string(const gchar *str)
        }
 
        rec = sdp_extract_pdu(pdata, size, &len);
-       free(pdata);
+       g_free(pdata);
 
        return rec;
 }
@@ -1124,17 +1166,18 @@ int write_blocked(const bdaddr_t *local, const bdaddr_t *remote,
 }
 
 int write_device_services(const bdaddr_t *sba, const bdaddr_t *dba,
-                                                       const char *services)
+                         uint8_t bdaddr_type, const char *services)
 {
-       char filename[PATH_MAX + 1], addr[18];
+       char filename[PATH_MAX + 1], key[20];
 
-       create_filename(filename, PATH_MAX, sba, "primary");
+       create_filename(filename, PATH_MAX, sba, "primaries");
 
        create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 
-       ba2str(dba, addr);
+       ba2str(dba, key);
+       sprintf(&key[17], "#%hhu", bdaddr_type);
 
-       return textfile_put(filename, addr, services);
+       return textfile_put(filename, key, services);
 }
 
 static void filter_keys(char *key, char *value, void *data)
@@ -1167,82 +1210,87 @@ done:
        g_slist_free_full(match.keys, g_free);
 }
 
-int delete_device_service(const bdaddr_t *sba, const bdaddr_t *dba)
+int delete_device_service(const bdaddr_t *sba, const bdaddr_t *dba,
+                                               uint8_t bdaddr_type)
 {
-       char filename[PATH_MAX + 1], address[18];
+       char filename[PATH_MAX + 1], key[20];
+
+       memset(key, 0, sizeof(key));
 
-       memset(address, 0, sizeof(address));
-       ba2str(dba, address);
+       ba2str(dba, key);
+       sprintf(&key[17], "#%hhu", bdaddr_type);
 
-       /* Deleting all characteristics of a given address */
-       create_filename(filename, PATH_MAX, sba, "characteristic");
-       delete_by_pattern(filename, address);
+       /* Deleting all characteristics of a given key */
+       create_filename(filename, PATH_MAX, sba, "characteristics");
+       delete_by_pattern(filename, key);
 
-       /* Deleting all attributes values of a given address */
+       /* Deleting all attributes values of a given key */
        create_filename(filename, PATH_MAX, sba, "attributes");
-       delete_by_pattern(filename, address);
+       delete_by_pattern(filename, key);
 
-       /* Deleting all CCC values of a given address */
+       /* Deleting all CCC values of a given key */
        create_filename(filename, PATH_MAX, sba, "ccc");
-       delete_by_pattern(filename, address);
+       delete_by_pattern(filename, key);
+
+       create_filename(filename, PATH_MAX, sba, "primaries");
 
-       create_filename(filename, PATH_MAX, sba, "primary");
-       return textfile_del(filename, address);
+       return textfile_del(filename, key);
 }
 
-char *read_device_services(const bdaddr_t *sba, const bdaddr_t *dba)
+char *read_device_services(const bdaddr_t *sba, const bdaddr_t *dba,
+                                                       uint8_t bdaddr_type)
 {
-       char filename[PATH_MAX + 1], addr[18];
+       char filename[PATH_MAX + 1], key[20];
 
-       create_filename(filename, PATH_MAX, sba, "primary");
+       create_filename(filename, PATH_MAX, sba, "primaries");
 
-       ba2str(dba, addr);
+       ba2str(dba, key);
+       sprintf(&key[17], "#%hhu", bdaddr_type);
 
-       return textfile_caseget(filename, addr);
+       return textfile_caseget(filename, key);
 }
 
 int write_device_characteristics(const bdaddr_t *sba, const bdaddr_t *dba,
-                                       uint16_t handle, const char *chars)
+                                       uint8_t bdaddr_type, uint16_t handle,
+                                                             const char *chars)
 {
-       char filename[PATH_MAX + 1], addr[18], key[23];
+       char filename[PATH_MAX + 1], addr[18], key[25];
 
-       create_filename(filename, PATH_MAX, sba, "characteristic");
+       create_filename(filename, PATH_MAX, sba, "characteristics");
 
        create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 
        ba2str(dba, addr);
-
-       snprintf(key, sizeof(key), "%17s#%04X", addr, handle);
+       snprintf(key, sizeof(key), "%17s#%hhu#%04X", addr, bdaddr_type, handle);
 
        return textfile_put(filename, key, chars);
 }
 
 char *read_device_characteristics(const bdaddr_t *sba, const bdaddr_t *dba,
-                                                       uint16_t handle)
+                                       uint8_t bdaddr_type, uint16_t handle)
 {
-       char filename[PATH_MAX + 1], addr[18], key[23];
+       char filename[PATH_MAX + 1], addr[18], key[25];
 
-       create_filename(filename, PATH_MAX, sba, "characteristic");
+       create_filename(filename, PATH_MAX, sba, "characteristics");
 
        ba2str(dba, addr);
-
-       snprintf(key, sizeof(key), "%17s#%04X", addr, handle);
+       snprintf(key, sizeof(key), "%17s#%hhu#%04X", addr, bdaddr_type, handle);
 
        return textfile_caseget(filename, key);
 }
 
 int write_device_attribute(const bdaddr_t *sba, const bdaddr_t *dba,
-                                       uint16_t handle, const char *chars)
+                               uint8_t bdaddr_type, uint16_t handle,
+                                                       const char *chars)
 {
-       char filename[PATH_MAX + 1], addr[18], key[23];
+       char filename[PATH_MAX + 1], addr[18], key[25];
 
        create_filename(filename, PATH_MAX, sba, "attributes");
 
        create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 
        ba2str(dba, addr);
-
-       snprintf(key, sizeof(key), "%17s#%04X", addr, handle);
+       snprintf(key, sizeof(key), "%17s#%hhu#%04X", addr, bdaddr_type, handle);
 
        return textfile_put(filename, key, chars);
 }
@@ -1256,10 +1304,10 @@ int read_device_attributes(const bdaddr_t *sba, textfile_cb func, void *data)
        return textfile_foreach(filename, func, data);
 }
 
-int read_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint16_t handle,
-                                                       uint16_t *value)
+int read_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type,
+                                       uint16_t handle, uint16_t *value)
 {
-       char filename[PATH_MAX + 1], addr[18], key[23];
+       char filename[PATH_MAX + 1], addr[18], key[25];
        char *str;
        unsigned int config;
        int err = 0;
@@ -1267,7 +1315,7 @@ int read_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint16_t handle,
        create_filename(filename, PATH_MAX, local, "ccc");
 
        ba2str(peer, addr);
-       snprintf(key, sizeof(key), "%17s#%04X", addr, handle);
+       snprintf(key, sizeof(key), "%17s#%hhu#%04X", addr, bdaddr_type, handle);
 
        str = textfile_caseget(filename, key);
        if (str == NULL)
@@ -1283,18 +1331,18 @@ int read_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint16_t handle,
        return err;
 }
 
-int write_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint16_t handle,
-                                                       uint16_t value)
+int write_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type,
+                                       uint16_t handle, uint16_t value)
 {
-       char filename[PATH_MAX + 1], addr[18], key[23], config[5];
+       char filename[PATH_MAX + 1], addr[18], key[25], config[5];
 
        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#%hhu#%04X", addr, bdaddr_type, handle);
 
-       snprintf(key, sizeof(key), "%17s#%04X", addr, handle);
        snprintf(config, sizeof(config), "%04X", value);
 
        return textfile_put(filename, key, config);
@@ -1310,3 +1358,39 @@ void delete_device_ccc(bdaddr_t *local, bdaddr_t *peer)
        create_filename(filename, PATH_MAX, local, "ccc");
        delete_by_pattern(filename, addr);
 }
+
+int write_longtermkeys(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type,
+                                                               const char *key)
+{
+       char filename[PATH_MAX + 1], addr[20];
+
+       if (!key)
+               return -EINVAL;
+
+       create_filename(filename, PATH_MAX, local, "longtermkeys");
+
+       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+       ba2str(peer, addr);
+       sprintf(&addr[17], "#%hhu", bdaddr_type);
+
+       return textfile_put(filename, addr, key);
+}
+
+gboolean has_longtermkeys(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type)
+{
+       char filename[PATH_MAX + 1], key[20], *str;
+
+       create_filename(filename, PATH_MAX, local, "longtermkeys");
+
+       ba2str(peer, key);
+       sprintf(&key[17], "#%hhu", bdaddr_type);
+
+       str = textfile_caseget(filename, key);
+       if (str) {
+               free(str);
+               return TRUE;
+       }
+
+       return FALSE;
+}
index 51259f6..cc00e97 100644 (file)
@@ -36,11 +36,16 @@ int write_local_name(bdaddr_t *bdaddr, const char *name);
 int read_local_name(bdaddr_t *bdaddr, char *name);
 int write_local_class(bdaddr_t *bdaddr, uint8_t *class);
 int read_local_class(bdaddr_t *bdaddr, uint8_t *class);
+int write_remote_appearance(bdaddr_t *local, bdaddr_t *peer,
+                               uint8_t bdaddr_type, uint16_t appearance);
+int read_remote_appearance(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type,
+                                                       uint16_t *appearance);
 int write_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class);
 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);
 int read_device_name(const char *src, const char *dst, char *name);
-int write_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data);
+int write_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data,
+                                                       uint8_t data_len);
 int read_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data);
 int write_version_info(bdaddr_t *local, bdaddr_t *peer, uint16_t manufacturer, uint8_t lmp_ver, uint16_t lmp_subver);
 int write_features_info(bdaddr_t *local, bdaddr_t *peer, unsigned char *page1, unsigned char *page2);
@@ -73,21 +78,25 @@ gboolean read_blocked(const bdaddr_t *local, const bdaddr_t *remote);
 int write_blocked(const bdaddr_t *local, const bdaddr_t *remote,
                                                        gboolean blocked);
 int write_device_services(const bdaddr_t *sba, const bdaddr_t *dba,
-                                                       const char *services);
-int delete_device_service(const bdaddr_t *sba, const bdaddr_t *dba);
-char *read_device_services(const bdaddr_t *sba, const bdaddr_t *dba);
+                               uint8_t bdaddr_type, const char *services);
+int delete_device_service(const bdaddr_t *sba, const bdaddr_t *dba,
+                                               uint8_t bdaddr_type);
+char *read_device_services(const bdaddr_t *sba, const bdaddr_t *dba,
+                                                       uint8_t bdaddr_type);
 int write_device_characteristics(const bdaddr_t *sba, const bdaddr_t *dba,
-                                       uint16_t handle, const char *chars);
+                                       uint8_t bdaddr_type, uint16_t handle,
+                                                            const char *chars);
 char *read_device_characteristics(const bdaddr_t *sba, const bdaddr_t *dba,
-                                                       uint16_t handle);
+                                       uint8_t bdaddr_type, uint16_t handle);
 int write_device_attribute(const bdaddr_t *sba, const bdaddr_t *dba,
-                                        uint16_t handle, const char *chars);
+                               uint8_t bdaddr_type, uint16_t handle,
+                                                       const char *chars);
 int read_device_attributes(const bdaddr_t *sba, textfile_cb func, void *data);
-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);
+int read_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type,
+                                       uint16_t handle, uint16_t *value);
+int write_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type,
+                                       uint16_t handle, uint16_t value);
 void delete_device_ccc(bdaddr_t *local, bdaddr_t *peer);
-
-#define PNP_UUID               "00001200-0000-1000-8000-00805f9b34fb"
-
+int write_longtermkeys(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type,
+                                                       const char *key);
+gboolean has_longtermkeys(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type);
index 2712cd8..9d88fbc 100644 (file)
@@ -220,8 +220,8 @@ static int write_key(const char *pathname, const char *key, const char *value, i
        len = strlen(key);
        off = find_key(map, size, key, len, icase);
        if (!off) {
+               munmap(map, size);
                if (value) {
-                       munmap(map, size);
                        lseek(fd, size, SEEK_SET);
                        err = write_key_value(fd, key, value);
                }
index e83986b..20e0941 100644 (file)
@@ -55,7 +55,7 @@ extern "C" {
 /*
  * Keys and buttons
  *
- * Most of the keys/buttons are modeled after USB HUT 1.12
+ * Most of the keys/buttons are modelled after USB HUT 1.12
  * (see http://www.usb.org/developers/hidpage).
  * Abbreviations in the comments:
  * AC - Application Control
diff --git a/test/apitest b/test/apitest
deleted file mode 100755 (executable)
index f1d51f1..0000000
+++ /dev/null
@@ -1,448 +0,0 @@
-#!/usr/bin/env python
-
-import dbus
-import dbus.decorators
-import dbus.glib
-import gobject
-import sys
-import getopt
-from signal import *
-
-mgr_cmds = [ "InterfaceVersion", "ListAdapters", "DefaultAdapter" ]
-mgr_signals = [ "AdapterAdded", "AdapterRemoved" ]
-
-dev_cmds = [ "GetAddress",
-             "GetVersion",
-             "GetRevision",
-             "GetManufacturer",
-             "GetCompany",
-             "GetMode",
-             "SetMode",
-             "GetDiscoverableTimeout",
-             "SetDiscoverableTimeout",
-             "IsConnectable",
-             "IsDiscoverable",
-             "IsConnected",
-             "ListConnections",
-             "GetMajorClass",
-             "ListAvailableMinorClasses",
-             "GetMinorClass",
-             "SetMinorClass",
-             "GetServiceClasses",
-             "GetName",
-             "SetName",
-             "GetRemoteVersion",
-             "GetRemoteRevision",
-             "GetRemoteManufacturer",
-             "GetRemoteCompany",
-             "GetRemoteMajorClass",
-             "GetRemoteMinorClass",
-             "GetRemoteServiceClasses",
-             "GetRemoteClass",
-             "GetRemoteName",
-             "GetRemoteAlias",
-             "SetRemoteAlias",
-             "ClearRemoteAlias",
-             "LastSeen",
-             "LastUsed",
-             "DisconnectRemoteDevice",
-             "CreateBonding",
-             "CancelBondingProcess",
-             "RemoveBonding",
-             "HasBonding",
-             "ListBondings",
-             "GetPinCodeLength",
-             "GetEncryptionKeySize",
-             "DiscoverDevices",
-             "DiscoverDevicesWithoutNameResolving",
-             "CancelDiscovery",
-             "ListRemoteDevices",
-             "ListRecentRemoteDevices" ]
-dev_signals = [ "ModeChanged",
-                "NameChanged",
-                "MinorClassChanged",
-                "DiscoveryStarted",
-                "DiscoveryCompleted",
-                "RemoteDeviceFound",
-                "RemoteNameUpdated",
-                "RemoteNameFailed",
-                "RemoteAliasChanged"
-                "RemoteAliasCleared",
-                "RemoteDeviceConnected",
-                "RemoteDeviceDisconnectRequested",
-                "RemoteDeviceDisconnected",
-                "BondingCreated",
-                "BondingRemoved" ]
-
-dev_signals_filter = [ "/org/bluez/hci0", "/org/bluez/hci1",
-                       "/org/bluez/hci2", "/org/bluez/hci3",
-                       "/org/bluez/hci4", "/org/bluez/hci5",
-                       "/org/bluez/hci6", "/org/bluez/hci7" ]
-
-class Tester:
-    exit_events = []
-    dev_path = None
-    need_dev = False
-    listen = False
-    at_interrupt = None
-
-    def __init__(self, argv):
-        self.name = argv[0]
-
-        self.parse_args(argv[1:])
-
-        try:
-            self.dbus_setup()
-        except dbus.DBusException, e:
-            print 'Failed to do D-Bus setup: %s' % e
-            sys.exit(1)
-
-    def parse_args(self, argv):
-        try:
-            opts, args = getopt.getopt(argv, "hli:")
-        except getopt.GetoptError:
-            self.usage()
-            sys.exit(1)
-
-        for o, a in opts:
-            if o == "-h":
-                self.usage()
-                sys.exit()
-            elif o == "-l":
-                self.listen = True
-            elif o == "-i":
-                if a[0] == '/':
-                    self.dev_path = a
-                else:
-                    self.dev_path = '/org/bluez/%s' % a
-
-        if not (args or self.listen):
-            self.usage()
-            sys.exit(1)
-
-        if args:
-            self.cmd = args[0]
-            self.cmd_args = args[1:]
-
-    def dbus_dev_setup(self):
-        if not self.dev_path:
-            try:
-                self.dbus_mgr_setup()
-                self.dev_path = self.manager.DefaultAdapter()
-            except dbus.DBusException, e:
-                print 'Failed to get default device: %s' % e
-                sys.exit(1)
-        try:
-            obj = self.bus.get_object('org.bluez', self.dev_path)
-            self.device = dbus.Interface(obj, 'org.bluez.Adapter')
-        except dbus.DBusException, e:
-            print 'Failed to setup device path: %s' % e
-            sys.exit(1)
-
-    def dbus_dev_sig_setup(self):
-        try:
-           for signal in dev_signals:
-                for path in dev_signals_filter:
-                    self.bus.add_signal_receiver(self.dev_signal_handler,
-                                             signal, 'org.bluez.Adapter',
-                                             'org.bluez', path,
-                                             message_keyword='dbus_message')
-        except dbus.DBusException, e:
-            print 'Failed to setup signal handler for device path: %s' % e
-            sys.exit(1)
-
-    def dbus_mgr_sig_setup(self):
-        try:
-            for signal in mgr_signals:
-                self.bus.add_signal_receiver(self.mgr_signal_handler,
-                                         signal,'org.bluez.Manager',
-                                         'org.bluez', '/org/bluez')
-        except dbus.DBusException, e:
-            print 'Failed to setup signal handler for manager path: %s' % e
-            sys.exit(1)
-
-    def dbus_mgr_setup(self):
-        self.manager_obj = self.bus.get_object('org.bluez', '/org/bluez')
-        self.manager = dbus.Interface(self.manager_obj, 'org.bluez.Manager')
-
-    def dbus_setup(self):
-        self.bus = dbus.SystemBus()
-
-    def usage(self):
-        print 'Usage: %s [-i <dev>] [-l] [-h] <cmd> [arg1..]' % self.name
-        print '  -i <dev>   Specify device (e.g. "hci0" or "/org/bluez/hci0")'
-        print '  -l         Listen for events (no command required)'
-        print '  -h         Show this help'
-        print 'Manager commands:'
-        for cmd in mgr_cmds:
-            print '\t%s' % cmd
-        print 'Adapter commands:'
-        for cmd in dev_cmds:
-            print '\t%s' % cmd
-
-    #@dbus.decorators.explicitly_pass_message
-    def dev_signal_handler(*args, **keywords):
-        dbus_message = keywords["dbus_message"]
-        print '%s - %s: ' % (dbus_message.get_member(), dbus_message.get_path()),
-        for arg in args[1:]:
-            print '%s   ' % arg,
-        print
-
-    #@dbus.decorators.explicitly_pass_message
-    def mgr_signal_handler(*args, **keywords):
-        dbus_message = keywords["dbus_message"]
-        print '%s: ' % dbus_message.get_member()
-        for arg in args[1:]:
-            print '%s   ' % arg,
-        print
-
-    def signal_cb(self, sig, frame):
-        print 'Caught signal, exiting'
-        if self.at_interrupt:
-            self.at_interrupt()
-        self.main_loop.quit()
-
-    def call_mgr_dbus_func(self):
-        if self.cmd == 'InterfaceVersion':
-            try:
-                print self.manager.InterfaceVersion()
-            except dbus.DBusException, e:
-                print 'Sending %s failed: %s' % (self.cmd, e)
-        if self.cmd == 'ListAdapters':
-            try:
-                devices = self.manager.ListAdapters()
-            except dbus.DBusException, e:
-                print 'Sending %s failed: %s' % (self.cmd, e)
-                sys.exit(1)
-            for device in devices:
-                print device
-        elif self.cmd == 'DefaultAdapter':
-            try:
-                print self.manager.DefaultAdapter()
-            except dbus.DBusException, e:
-                print 'Sending %s failed: %s' % (self.cmd, e)
-                sys.exit(1)
-
-    def call_dev_dbus_func(self):
-       try:
-           if self.cmd == 'GetAddress':
-               print self.device.GetAddress()
-           elif self.cmd == 'GetManufacturer':
-               print self.device.GetManufacturer()
-           elif self.cmd == 'GetVersion':
-               print self.device.GetVersion()
-           elif self.cmd == 'GetRevision':
-               print self.device.GetRevision()
-           elif self.cmd == 'GetCompany':
-               print self.device.GetCompany()
-           elif self.cmd == 'GetMode':
-               print self.device.GetMode()
-           elif self.cmd == 'SetMode':
-               if len(self.cmd_args) == 1:
-                   self.device.SetMode(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> SetMode scan_mode' % self.name
-           elif self.cmd == 'GetDiscoverableTimeout':
-               print '%u' % (self.device.GetDiscoverableTimeout())
-           elif self.cmd == 'SetDiscoverableTimeout':
-               if len(self.cmd_args) == 1:
-                   self.device.SetDiscoverableTimeout(dbus.UInt32(self.cmd_args[0]))
-               else:
-                   print 'Usage: %s -i <dev> SetDiscoverableTimeout timeout' % self.name
-           elif self.cmd == 'IsConnectable':
-               print self.device.IsConnectable()
-           elif self.cmd == 'IsDiscoverable':
-               print self.device.IsDiscoverable()
-           elif self.cmd == 'IsConnected':
-               if len(self.cmd_args) == 1:
-                   print self.device.IsConnected(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> IsConnected address' % self.name
-           elif self.cmd == 'ListConnections':
-               print self.device.ListConnections()
-           elif self.cmd == 'GetMajorClass':
-               print self.device.GetMajorClass()
-           elif self.cmd == 'ListAvailableMinorClasses':
-               print self.device.ListAvailableMinorClasses()
-           elif self.cmd == 'GetMinorClass':
-               print self.device.GetMinorClass()
-           elif self.cmd == 'SetMinorClass':
-               if len(self.cmd_args) == 1:
-                   self.device.SetMinorClass(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> SetMinorClass minor' % self.name
-           elif self.cmd == 'GetServiceClasses':
-               classes = self.device.GetServiceClasses()
-               for clas in classes: 
-                   print clas,
-           elif self.cmd == 'GetName':
-               print self.device.GetName()
-           elif self.cmd == 'SetName':
-               if len(self.cmd_args) == 1:
-                   self.device.SetName(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> SetName newname' % self.name
-           elif self.cmd == 'GetRemoteName':
-               if len(self.cmd_args) == 1:
-                   print self.device.GetRemoteName(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> GetRemoteName address' % self.name
-           elif self.cmd == 'GetRemoteVersion':
-               if len(self.cmd_args) == 1:
-                   print self.device.GetRemoteVersion(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> GetRemoteVersion address' % self.name
-           elif self.cmd == 'GetRemoteRevision':
-               if len(self.cmd_args) == 1:
-                   print self.device.GetRemoteRevision(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> GetRemoteRevision address' % self.name
-           elif self.cmd == 'GetRemoteManufacturer':
-               if len(self.cmd_args) == 1:
-                   print self.device.GetRemoteManufacturer(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> GetRemoteManufacturer address' % self.name
-           elif self.cmd == 'GetRemoteCompany':
-               if len(self.cmd_args) == 1:
-                   print self.device.GetRemoteCompany(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> GetRemoteCompany address' % self.name
-           elif self.cmd == 'GetRemoteAlias':
-               if len(self.cmd_args) == 1:
-                   print self.device.GetRemoteAlias(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> GetRemoteAlias address' % self.name
-           elif self.cmd == 'GetRemoteMajorClass':
-               if len(self.cmd_args) == 1:
-                   print self.device.GetRemoteMajorClass(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> GetRemoteMajorClass address' % self.name
-           elif self.cmd == 'GetRemoteMinorClass':
-               if len(self.cmd_args) == 1:
-                   print self.device.GetRemoteMinorClass(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> GetRemoteMinorClass address' % self.name
-           elif self.cmd == 'GetRemoteServiceClasses':
-               if len(self.cmd_args) == 1:
-                   print self.device.GetRemoteServiceClasses(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> GetRemoteServiceClasses address' % self.name
-           elif self.cmd == 'SetRemoteAlias':
-               if len(self.cmd_args) == 2:
-                   self.device.SetRemoteAlias(self.cmd_args[0], self.cmd_args[1])
-               else:
-                   print 'Usage: %s -i <dev> SetRemoteAlias address alias' % self.name
-           elif self.cmd == 'ClearRemoteAlias':
-               if len(self.cmd_args) == 1:
-                   print self.device.ClearRemoteAlias(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> ClearRemoteAlias address' % self.name
-           elif self.cmd == 'LastSeen':
-               if len(self.cmd_args) == 1:
-                   print self.device.LastSeen(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> LastSeen address' % self.name
-           elif self.cmd == 'LastUsed':
-               if len(self.cmd_args) == 1:
-                   print self.device.LastUsed(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> LastUsed address' % self.name
-           elif self.cmd == 'DisconnectRemoteDevice':
-               if len(self.cmd_args) == 1:
-                   print self.device.LastUsed(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> DisconnectRemoteDevice address' % self.name
-           elif self.cmd == 'CreateBonding':
-               if len(self.cmd_args) == 1:
-                   print self.device.CreateBonding(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> CreateBonding address' % self.name
-           elif self.cmd == 'RemoveBonding':
-               if len(self.cmd_args) == 1:
-                   print self.device.RemoveBonding(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> RemoveBonding address' % self.name
-           elif self.cmd == 'CancelBondingProcess':
-               if len(self.cmd_args) == 1:
-                   print self.device.CancelBondingProcess(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> CancelBondingProcess address' % self.name
-           elif self.cmd == 'HasBonding':
-               if len(self.cmd_args) == 1:
-                   print self.device.HasBonding(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> HasBonding address' % self.name
-           elif self.cmd == 'ListBondings':
-               bondings = self.device.ListBondings()
-               for bond in bondings: 
-                   print bond,
-           elif self.cmd == 'GetPinCodeLength':
-               if len(self.cmd_args) == 1:
-                   print self.device.GetPinCodeLength(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> GetPinCodeLength address' % self.name
-           elif self.cmd == 'GetEncryptionKeySize':
-               if len(self.cmd_args) == 1:
-                   print self.device.GetEncryptionKeySize(self.cmd_args[0])
-               else:
-                   print 'Usage: %s -i <dev> GetEncryptionKeySize address' % self.name
-           elif self.cmd == 'DiscoverDevices':
-               print self.device.DiscoverDevices()
-           elif self.cmd == 'DiscoverDevicesWithoutNameResolving':
-               print self.device.DiscoverDevicesWithoutNameResolving()
-           elif self.cmd == 'ListRemoteDevices':
-               devices = self.device.ListRemoteDevices()
-               for device in devices: 
-                   print device,
-           elif self.cmd == 'ListRecentRemoteDevices':
-               if len(self.cmd_args) == 1:
-                   devices = self.device.ListRecentRemoteDevices(self.cmd_args[0])
-                   for device in devices: 
-                       print device,
-               else:
-                   print 'Usage: %s -i <dev> ListRecentRemoteDevices date' % self.name
-           else:
-                # FIXME: remove at future version
-                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)
-
-    def run(self):
-        # Manager methods
-        if self.listen:
-            self.dbus_mgr_sig_setup()
-            self.dbus_dev_sig_setup()
-            print 'Listening for events...'
-
-        if self.cmd in mgr_cmds:
-            try:
-                self.dbus_mgr_setup()
-            except dbus.DBusException, e:
-                print 'Failed to setup manager interface: %s' % e
-                sys.exit(1)
-            self.call_mgr_dbus_func()
-        elif self.cmd in dev_cmds:
-            try:
-                self.dbus_dev_setup()
-            except dbus.DBusException, e:
-                print 'Failed to setup device interface: %s' % e
-                sys.exit(1)
-            self.call_dev_dbus_func()
-        elif not self.listen:
-            print 'Unknown command: %s' % self.cmd
-            self.usage()
-            sys.exit(1)
-
-        if self.listen:
-            signal(SIGINT, self.signal_cb)
-            signal(SIGTERM, self.signal_cb)
-            self.main_loop = gobject.MainLoop()
-            self.main_loop.run()
-
-if __name__ == '__main__':
-    gobject.threads_init()
-    dbus.glib.init_threads()
-
-    tester = Tester(sys.argv)
-    tester.run()
index 91fc1d5..66a7dd2 100644 (file)
@@ -33,6 +33,7 @@
 #include "btio.h"
 
 #define DEFAULT_ACCEPT_TIMEOUT 2
+static gint opt_update_sec = 0;
 
 struct io_data {
        guint ref;
@@ -94,6 +95,32 @@ static gboolean disconn_timeout(gpointer user_data)
        return FALSE;
 }
 
+static void update_sec_level(struct io_data *data)
+{
+       GError *err = NULL;
+       int sec_level;
+
+       if (!bt_io_get(data->io, data->type, &err,
+                                       BT_IO_OPT_SEC_LEVEL, &sec_level,
+                                       BT_IO_OPT_INVALID)) {
+               printf("bt_io_get(OPT_SEC_LEVEL): %s\n", err->message);
+               g_clear_error(&err);
+               return;
+       }
+
+       printf("sec_level=%d\n", sec_level);
+
+       if (opt_update_sec == sec_level)
+               return;
+
+       if (!bt_io_set(data->io, data->type, &err,
+                                       BT_IO_OPT_SEC_LEVEL, opt_update_sec,
+                                       BT_IO_OPT_INVALID)) {
+               printf("bt_io_set(OPT_SEC_LEVEL): %s\n", err->message);
+               g_clear_error(&err);
+       }
+}
+
 static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
 {
        struct io_data *data = user_data;
@@ -135,6 +162,19 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
                        printf("imtu=%u, omtu=%u\n", imtu, omtu);
        }
 
+       if (data->type == BT_IO_L2CAP) {
+               uint8_t key_size;
+
+               if (!bt_io_get(io, data->type, &err,
+                                       BT_IO_OPT_KEY_SIZE, &key_size,
+                                       BT_IO_OPT_INVALID)) {
+                       printf("Unable to get L2CAP Key size: %s\n",
+                                                               err->message);
+                       g_clear_error(&err);
+               } else
+                       printf("key_size=%u\n", key_size);
+       }
+
        if (data->disconn == 0) {
                g_io_channel_shutdown(io, TRUE, NULL);
                printf("Disconnected\n");
@@ -153,6 +193,10 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
 
 
        io_data_ref(data);
+
+       if (opt_update_sec > 0)
+               update_sec_level(data);
+
        cond = G_IO_NVAL | G_IO_HUP | G_IO_ERR;
        g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, io_watch, data,
                                        (GDestroyNotify) io_data_unref);
@@ -172,6 +216,9 @@ static gboolean confirm_timeout(gpointer user_data)
 
        io_data_ref(data);
 
+       if (opt_update_sec > 0)
+               update_sec_level(data);
+
        if (!bt_io_accept(data->io, connect_cb, data,
                                (GDestroyNotify) io_data_unref, NULL)) {
                printf("bt_io_accept() failed\n");
@@ -225,8 +272,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 prio)
+                                               uint16_t cid, gint disconn,
+                                               gint sec, gint prio)
 {
        struct io_data *data;
        GError *err = NULL;
@@ -242,6 +289,7 @@ static void l2cap_connect(const char *src, const char *dst, uint16_t psm,
                                                BT_IO_OPT_SOURCE, src,
                                                BT_IO_OPT_DEST, dst,
                                                BT_IO_OPT_PSM, psm,
+                                               BT_IO_OPT_CID, cid,
                                                BT_IO_OPT_SEC_LEVEL, sec,
                                                BT_IO_OPT_PRIORITY, prio,
                                                BT_IO_OPT_INVALID);
@@ -251,6 +299,7 @@ static void l2cap_connect(const char *src, const char *dst, uint16_t psm,
                                                &err,
                                                BT_IO_OPT_DEST, dst,
                                                BT_IO_OPT_PSM, psm,
+                                               BT_IO_OPT_CID, cid,
                                                BT_IO_OPT_SEC_LEVEL, sec,
                                                BT_IO_OPT_PRIORITY, prio,
                                                BT_IO_OPT_INVALID);
@@ -470,6 +519,7 @@ static gint opt_accept = DEFAULT_ACCEPT_TIMEOUT;
 static gint opt_sec = 0;
 static gboolean opt_master = FALSE;
 static gint opt_priority = 0;
+static gint opt_cid = 0;
 
 static GMainLoop *main_loop;
 
@@ -478,12 +528,16 @@ static GOptionEntry options[] = {
                                "RFCOMM channel" },
        { "psm", 'p', 0, G_OPTION_ARG_INT, &opt_psm,
                                "L2CAP PSM" },
+       { "cid", 'j', 0, G_OPTION_ARG_INT, &opt_cid,
+                               "L2CAP CID" },
        { "sco", 's', 0, G_OPTION_ARG_NONE, &opt_sco,
                                "Use SCO" },
        { "defer", 'd', 0, G_OPTION_ARG_NONE, &opt_defer,
                                "Use DEFER_SETUP for incoming connections" },
        { "sec-level", 'S', 0, G_OPTION_ARG_INT, &opt_sec,
                                "Security level" },
+       { "update-sec-level", 'U', 0, G_OPTION_ARG_INT, &opt_update_sec,
+                               "Update security level" },
        { "dev", 'i', 0, G_OPTION_ARG_STRING, &opt_dev,
                                "Which HCI device to use" },
        { "reject", 'r', 0, G_OPTION_ARG_INT, &opt_reject,
@@ -518,15 +572,14 @@ int main(int argc, char *argv[])
 
        g_option_context_free(context);
 
-       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);
+       printf("accept=%d, reject=%d, discon=%d, defer=%d, sec=%d,"
+               " update_sec=%d, prio=%d\n", opt_accept, opt_reject,
+               opt_disconn, opt_defer, opt_sec, opt_update_sec, opt_priority);
 
-       if (opt_psm) {
+       if (opt_psm || opt_cid) {
                if (argc > 1)
-                       l2cap_connect(opt_dev, argv[1], opt_psm,
-                                                       opt_disconn, opt_sec,
-                                                       opt_priority);
+                       l2cap_connect(opt_dev, argv[1], opt_psm, opt_cid,
+                                       opt_disconn, opt_sec, opt_priority);
                else
                        l2cap_listen(opt_dev, opt_psm, opt_defer, opt_reject,
                                        opt_disconn, opt_accept, opt_sec,
index 7eb8814..4c62223 100644 (file)
@@ -58,9 +58,13 @@ struct vhci_device {
        uint8_t         features[8];
        uint8_t         name[248];
        uint8_t         dev_class[3];
+       uint8_t         scan_enable;
+       uint8_t         ssp_mode;
        uint8_t         inq_mode;
        uint8_t         eir_fec;
        uint8_t         eir_data[HCI_MAX_EIR_LENGTH];
+       uint8_t         le_mode;
+       uint8_t         le_simul;
        uint16_t        acl_cnt;
        bdaddr_t        bdaddr;
        int             dev_fd;
@@ -220,6 +224,40 @@ static struct vhci_conn *conn_get_by_bdaddr(bdaddr_t *ba)
        return NULL;
 }
 
+static void reset_vdev(void)
+{
+       /* Device settings */
+       vdev.features[0] = 0xff;
+       vdev.features[1] = 0xff;
+       vdev.features[2] = 0x8f;
+       vdev.features[3] = 0xfe;
+       vdev.features[4] = 0x9b;
+       vdev.features[5] = 0xf9;
+       vdev.features[6] = 0x00;
+       vdev.features[7] = 0x80;
+
+       vdev.features[4] |= 0x40;       /* LE Supported */
+       vdev.features[6] |= 0x01;       /* Extended Inquiry Response */
+       vdev.features[6] |= 0x02;       /* BR/EDR and LE */
+       vdev.features[6] |= 0x08;       /* Secure Simple Pairing */
+
+       memset(vdev.name, 0, sizeof(vdev.name));
+       strncpy((char *) vdev.name, "BlueZ (Virtual HCI)",
+                                                       sizeof(vdev.name) - 1);
+
+       vdev.dev_class[0] = 0x00;
+       vdev.dev_class[1] = 0x00;
+       vdev.dev_class[2] = 0x00;
+
+       vdev.scan_enable = 0x00;
+       vdev.ssp_mode = 0x00;
+       vdev.inq_mode = 0x00;
+       vdev.eir_fec = 0x00;
+       memset(vdev.eir_data, 0, sizeof(vdev.eir_data));
+       vdev.le_mode = 0x00;
+       vdev.le_simul = 0x00;
+}
+
 static void command_status(uint16_t ogf, uint16_t ocf, uint8_t status)
 {
        uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;
@@ -398,8 +436,9 @@ static void num_completed_pkts(struct vhci_conn *conn)
                                                strerror(errno), errno);
 }
 
-static int scan_enable(uint8_t *data)
+static uint8_t scan_enable(uint8_t *data)
 {
+#if 0
        struct epoll_event scan_event;
        struct sockaddr_in sa;
        bdaddr_t ba;
@@ -456,6 +495,9 @@ static int scan_enable(uint8_t *data)
 failed:
        close(sk);
        return 1;
+#endif
+
+       return data[0];
 }
 
 static void accept_connection(uint8_t *data)
@@ -576,8 +618,6 @@ do_connect:
 
 static void hci_link_control(uint16_t ocf, int plen, uint8_t *data)
 {
-       uint8_t status;
-
        const uint16_t ogf = OGF_LINK_CTL;
 
        switch (ocf) {
@@ -597,32 +637,31 @@ static void hci_link_control(uint16_t ocf, int plen, uint8_t *data)
                break;
 
        default:
-               status = 0x01;
-               command_complete(ogf, ocf, 1, &status);
+               command_status(ogf, ocf, 0x01);
                break;
        }
 }
 
 static void hci_link_policy(uint16_t ocf, int plen, uint8_t *data)
 {
-       uint8_t status;
-
        const uint16_t ogf = OGF_INFO_PARAM;
 
        switch (ocf) {
        default:
-               status = 0x01;
-               command_complete(ogf, ocf, 1, &status);
+               command_status(ogf, ocf, 0x01);
                break;
        }
 }
 
 static void hci_host_control(uint16_t ocf, int plen, uint8_t *data)
 {
+       read_scan_enable_rp se;
        read_local_name_rp ln;
        read_class_of_dev_rp cd;
        read_inquiry_mode_rp im;
        read_ext_inquiry_response_rp ir;
+       read_simple_pairing_mode_rp pm;
+       read_le_host_supported_rp hs;
        uint8_t status;
 
        const uint16_t ogf = OGF_HOST_CTL;
@@ -630,6 +669,7 @@ static void hci_host_control(uint16_t ocf, int plen, uint8_t *data)
        switch (ocf) {
        case OCF_RESET:
                status = 0x00;
+               reset_vdev();
                command_complete(ogf, ocf, 1, &status);
                break;
 
@@ -656,8 +696,15 @@ static void hci_host_control(uint16_t ocf, int plen, uint8_t *data)
                command_complete(ogf, ocf, 1, &status);
                break;
 
+       case OCF_READ_SCAN_ENABLE:
+               se.status = 0x00;
+               se.enable = vdev.scan_enable;
+               command_complete(ogf, ocf, sizeof(se), &se);
+               break;
+
        case OCF_WRITE_SCAN_ENABLE:
-               status = scan_enable(data);
+               status = 0x00;
+               vdev.scan_enable = scan_enable(data);
                command_complete(ogf, ocf, 1, &status);
                break;
 
@@ -709,10 +756,35 @@ static void hci_host_control(uint16_t ocf, int plen, uint8_t *data)
                command_complete(ogf, ocf, 1, &status);
                break;
 
-       default:
-               status = 0x01;
+       case OCF_READ_SIMPLE_PAIRING_MODE:
+               pm.status = 0x00;
+               pm.mode = vdev.ssp_mode;
+               command_complete(ogf, ocf, sizeof(pm), &pm);
+               break;
+
+       case OCF_WRITE_SIMPLE_PAIRING_MODE:
+               status = 0x00;
+               vdev.ssp_mode = data[0];
+               command_complete(ogf, ocf, 1, &status);
+               break;
+
+       case OCF_READ_LE_HOST_SUPPORTED:
+               hs.status = 0x00;
+               hs.le = vdev.le_mode;
+               hs.simul = vdev.le_simul;
+               command_complete(ogf, ocf, sizeof(hs), &hs);
+               break;
+
+       case OCF_WRITE_LE_HOST_SUPPORTED:
+               status = 0x00;
+               vdev.le_mode = data[0];
+               vdev.le_simul = data[1];
                command_complete(ogf, ocf, 1, &status);
                break;
+
+       default:
+               command_status(ogf, ocf, 0x01);
+               break;
        }
 }
 
@@ -723,17 +795,16 @@ static void hci_info_param(uint16_t ocf, int plen, uint8_t *data)
        read_local_ext_features_rp ef;
        read_buffer_size_rp bs;
        read_bd_addr_rp ba;
-       uint8_t status;
 
        const uint16_t ogf = OGF_INFO_PARAM;
 
        switch (ocf) {
        case OCF_READ_LOCAL_VERSION:
                lv.status = 0x00;
-               lv.hci_ver = 0x03;
+               lv.hci_ver = 0x06;
                lv.hci_rev = htobs(0x0000);
-               lv.lmp_ver = 0x03;
-               lv.manufacturer = htobs(29);
+               lv.lmp_ver = 0x06;
+               lv.manufacturer = htobs(63);
                lv.lmp_subver = htobs(0x0000);
                command_complete(ogf, ocf, sizeof(lv), &lv);
                break;
@@ -748,8 +819,15 @@ static void hci_info_param(uint16_t ocf, int plen, uint8_t *data)
                ef.status = 0x00;
                if (*data == 0) {
                        ef.page_num = 0;
-                       ef.max_page_num = 0;
+                       ef.max_page_num = 1;
                        memcpy(ef.features, vdev.features, 8);
+               } else if (*data == 1) {
+                       ef.page_num = 1;
+                       ef.max_page_num = 1;
+                       memset(ef.features, 0, 8);
+                       ef.features[0] |= (!!vdev.ssp_mode << 0);
+                       ef.features[0] |= (!!vdev.le_mode << 1);
+                       ef.features[0] |= (!!vdev.le_simul << 2);
                } else {
                        ef.page_num = *data;
                        ef.max_page_num = 0;
@@ -774,8 +852,7 @@ static void hci_info_param(uint16_t ocf, int plen, uint8_t *data)
                break;
 
        default:
-               status = 0x01;
-               command_complete(ogf, ocf, 1, &status);
+               command_status(ogf, ocf, 0x01);
                break;
        }
 }
@@ -783,7 +860,6 @@ 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;
 
@@ -804,8 +880,27 @@ static void hci_status_param(uint16_t ocf, int plen, uint8_t *data)
                break;
 
        default:
-               status = 0x01;
-               command_complete(ogf, ocf, 1, &status);
+               command_status(ogf, ocf, 0x01);
+               break;
+       }
+}
+
+static void hci_le_control(uint16_t ocf, int plen, uint8_t *data)
+{
+       le_read_buffer_size_rp bs;
+
+       const uint16_t ogf = OGF_LE_CTL;
+
+       switch (ocf) {
+       case OCF_LE_READ_BUFFER_SIZE:
+               bs.status = 0;
+               bs.pkt_len = htobs(VHCI_ACL_MTU);
+               bs.max_pkt = htobs(VHCI_ACL_MAX_PKT);
+               command_complete(ogf, ocf, sizeof(bs), &bs);
+               break;
+
+       default:
+               command_status(ogf, ocf, 0x01);
                break;
        }
 }
@@ -843,6 +938,14 @@ static void hci_command(uint8_t *data)
        case OGF_STATUS_PARAM:
                hci_status_param(ocf, ch->plen, ptr);
                break;
+
+       case OGF_LE_CTL:
+               hci_le_control(ocf, ch->plen, ptr);
+               break;
+
+       default:
+               command_status(ogf, ocf, 0x01);
+               break;
        }
 }
 
@@ -1006,10 +1109,11 @@ static int getbdaddrbyname(char *str, bdaddr_t *ba)
        if (n == 0) {
                /* loopback port */
                in_addr_t addr = INADDR_LOOPBACK;
+               uint16_t be16 = htons(atoi(str));
                bdaddr_t b;
 
                memcpy(&b, &addr, 4);
-               *(uint16_t *) (&b.b[4]) = htons(atoi(str));
+               memcpy(&b.b[4], &be16, sizeof(be16));
                baswap(ba, &b);
 
                return 0;
@@ -1134,27 +1238,7 @@ int main(int argc, char *argv[])
                goto close_device;
        }
 
-       /* Device settings */
-       vdev.features[0] = 0xff;
-       vdev.features[1] = 0xff;
-       vdev.features[2] = 0x8f;
-       vdev.features[3] = 0xfe;
-       vdev.features[4] = 0x9b;
-       vdev.features[5] = 0xf9;
-       vdev.features[6] = 0x01;
-       vdev.features[7] = 0x80;
-
-       memset(vdev.name, 0, sizeof(vdev.name));
-       strncpy((char *) vdev.name, "BlueZ (Virtual HCI)",
-                                                       sizeof(vdev.name) - 1);
-
-       vdev.dev_class[0] = 0x00;
-       vdev.dev_class[1] = 0x00;
-       vdev.dev_class[2] = 0x00;
-
-       vdev.inq_mode = 0x00;
-       vdev.eir_fec = 0x00;
-       memset(vdev.eir_data, 0, sizeof(vdev.eir_data));
+       reset_vdev();
 
        vdev.dev_fd = device_fd;
        vdev.dd = dd;
index c5bc3d3..f66486d 100644 (file)
@@ -116,11 +116,15 @@ static int timestamp = 0;
 static int defer_setup = 0;
 static int priority = -1;
 static int rcvbuf = 0;
+static int chan_policy = -1;
+static int bdaddr_type = 0;
 
-static struct {
+struct lookup_table {
        char    *name;
        int     flag;
-} l2cap_modes[] = {
+};
+
+static struct lookup_table l2cap_modes[] = {
        { "basic",      L2CAP_MODE_BASIC        },
        /* Not implemented
        { "flowctl",    L2CAP_MODE_FLOWCTL      },
@@ -131,14 +135,39 @@ static struct {
        { 0 }
 };
 
-static void list_l2cap_modes(void)
+static struct lookup_table chan_policies[] = {
+       { "bredr",      BT_CHANNEL_POLICY_BREDR_ONLY            },
+       { "bredr_pref", BT_CHANNEL_POLICY_BREDR_PREFERRED       },
+       { "amp_pref",   BT_CHANNEL_POLICY_AMP_PREFERRED         },
+       { NULL,         0                                       },
+};
+
+static struct lookup_table bdaddr_types[] = {
+       { "bredr",      BDADDR_BREDR            },
+       { "le_public",  BDADDR_LE_PUBLIC        },
+       { "le_random",  BDADDR_LE_RANDOM        },
+       { NULL,         0                       },
+};
+
+static int get_lookup_flag(struct lookup_table *table, char *name)
 {
        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);
+       for (i = 0; table[i].name; i++)
+               if (!strcasecmp(table[i].name, name))
+                       return table[i].flag;
+
+       return -1;
+}
+
+static void print_lookup_values(struct lookup_table *table, char *header)
+{
+       int i;
+
+       printf("%s\n", header);
+
+       for (i = 0; table[i].name; i++)
+               printf("\t%s\n", table[i].name);
 }
 
 static float tv2fl(struct timeval tv)
@@ -283,6 +312,15 @@ static int do_connect(char *svr)
        }
 #endif
 
+       if (chan_policy != -1) {
+               if (setsockopt(sk, SOL_BLUETOOTH, BT_CHANNEL_POLICY,
+                               &chan_policy, sizeof(chan_policy)) < 0) {
+                       syslog(LOG_ERR, "Can't enable chan policy : %s (%d)",
+                                                       strerror(errno), errno);
+                       goto error;
+               }
+       }
+
        /* Enable SO_LINGER */
        if (linger) {
                struct linger l = { .l_onoff = 1, .l_linger = linger };
@@ -332,6 +370,7 @@ static int do_connect(char *svr)
        memset(&addr, 0, sizeof(addr));
        addr.l2_family = AF_BLUETOOTH;
        str2ba(svr, &addr.l2_bdaddr);
+       addr.l2_bdaddr_type = bdaddr_type;
        if (cid)
                addr.l2_cid = htobs(cid);
        else if (psm)
@@ -990,6 +1029,7 @@ static void info_request(char *svr)
        memset(&addr, 0, sizeof(addr));
        addr.l2_family = AF_BLUETOOTH;
        str2ba(svr, &addr.l2_bdaddr);
+       addr.l2_bdaddr_type = bdaddr_type;
 
        if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0 ) {
                perror("Can't connect socket");
@@ -1137,6 +1177,7 @@ static void do_pairing(char *svr)
        memset(&addr, 0, sizeof(addr));
        addr.l2_family = AF_BLUETOOTH;
        str2ba(svr, &addr.l2_bdaddr);
+       addr.l2_bdaddr_type = bdaddr_type;
 
        if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0 ) {
                perror("Can't connect socket");
@@ -1181,6 +1222,7 @@ static void usage(void)
                "\t[-D milliseconds] delay after sending num frames (default = 0)\n"
                "\t[-K milliseconds] delay before receiving (default = 0)\n"
                "\t[-X mode] l2cap mode (help for list, default = basic)\n"
+               "\t[-a policy] chan policy (help for list, default = bredr)\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"
@@ -1193,18 +1235,20 @@ static void usage(void)
                "\t[-E] request encryption\n"
                "\t[-S] secure connection\n"
                "\t[-M] become master\n"
-               "\t[-T] enable timestamps\n");
+               "\t[-T] enable timestamps\n"
+               "\t[-V type] address type (help for list, default = bredr)\n");
 }
 
 int main(int argc, char *argv[])
 {
        struct sigaction sa;
-       int opt, sk, i, mode = RECV, need_addr = 0;
+       int opt, sk, 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:Y:H:K:RUGAESMT")) != EOF) {
-               switch(opt) {
+       while ((opt = getopt(argc, argv, "rdscuwmntqxyzpb:a:"
+               "i:P:I:O:J:B:N:L:W:C:D:X:F:Q:Z:Y:H:K:V:RUGAESMT")) != EOF) {
+               switch (opt) {
                case 'r':
                        mode = RECV;
                        break;
@@ -1321,14 +1365,22 @@ int main(int argc, char *argv[])
                        break;
 
                case 'X':
-                       rfcmode = -1;
+                       rfcmode = get_lookup_flag(l2cap_modes, optarg);
 
-                       for (i = 0; l2cap_modes[i].name; i++)
-                               if (!strcasecmp(l2cap_modes[i].name, optarg))
-                                       rfcmode = l2cap_modes[i].flag;
+                       if (rfcmode == -1) {
+                               print_lookup_values(l2cap_modes,
+                                               "List L2CAP modes:");
+                               exit(1);
+                       }
+
+                       break;
 
-                       if (!strcasecmp(optarg, "help") || rfcmode == -1) {
-                               list_l2cap_modes();
+               case 'a':
+                       chan_policy = get_lookup_flag(chan_policies, optarg);
+
+                       if (chan_policy == -1) {
+                               print_lookup_values(chan_policies,
+                                               "List L2CAP chan policies:");
                                exit(1);
                        }
 
@@ -1390,6 +1442,17 @@ int main(int argc, char *argv[])
                        rcvbuf = atoi(optarg);
                        break;
 
+               case 'V':
+                       bdaddr_type = get_lookup_flag(bdaddr_types, optarg);
+
+                       if (bdaddr_type == -1) {
+                               print_lookup_values(bdaddr_types,
+                                               "List Address types:");
+                               exit(1);
+                       }
+
+                       break;
+
                default:
                        usage();
                        exit(1);
old mode 100755 (executable)
new mode 100644 (file)
index cb564be..7ef6511
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 import dbus
 
 bus = dbus.SystemBus()
@@ -32,19 +34,19 @@ adapter_list = manager.ListAdapters()
 for i in adapter_list:
        adapter = dbus.Interface(bus.get_object("org.bluez", i),
                                                        "org.bluez.Adapter")
-       print "[ " + i + " ]"
+       print("[ " + i + " ]")
 
        properties  = adapter.GetProperties()
        for key in properties.keys():
                value = properties[key]
                if (key == "Devices"):
                        list = extract_objects(value)
-                       print "    %s = %s" % (key, list)
+                       print("    %s = %s" % (key, list))
                elif (key == "UUIDs"):
                        list = extract_uuids(value)
-                       print "    %s = %s" % (key, list)
+                       print("    %s = %s" % (key, list))
                else:
-                       print "    %s = %s" % (key, value)
+                       print("    %s = %s" % (key, value))
 
        try:
                device_list = properties["Devices"]
@@ -54,27 +56,27 @@ for i in adapter_list:
        for n in device_list:
                device = dbus.Interface(bus.get_object("org.bluez", n),
                                                        "org.bluez.Device")
-               print "    [ " + n + " ]"
+               print("    [ " + n + " ]")
 
                properties = device.GetProperties()
                for key in properties.keys():
                        value = properties[key]
                        if (key == "Nodes"):
                                list = extract_objects(value)
-                               print "        %s = %s" % (key, list)
+                               print("        %s = %s" % (key, list))
                        elif (key == "UUIDs"):
                                list = extract_uuids(value)
-                               print "        %s = %s" % (key, list)
+                               print("        %s = %s" % (key, list))
                        elif (key == "Class"):
-                               print "        %s = 0x%06x" % (key, value)
+                               print("        %s = 0x%06x" % (key, value))
                        elif (key == "Vendor"):
-                               print "        %s = 0x%04x" % (key, value)
+                               print("        %s = 0x%04x" % (key, value))
                        elif (key == "Product"):
-                               print "        %s = 0x%04x" % (key, value)
+                               print("        %s = 0x%04x" % (key, value))
                        elif (key == "Version"):
-                               print "        %s = 0x%04x" % (key, value)
+                               print("        %s = 0x%04x" % (key, value))
                        else:
-                               print "        %s = %s" % (key, value)
+                               print("        %s = %s" % (key, value))
 
                try:
                        node_list = properties["Nodes"]
@@ -84,10 +86,10 @@ for i in adapter_list:
                for x in node_list:
                        node = dbus.Interface(bus.get_object("org.bluez", x),
                                                        "org.bluez.Node")
-                       print "        [ " + x + " ]"
+                       print("        [ " + x + " ]")
 
                        properties = node.GetProperties()
                        for key in properties.keys():
-                               print "            %s = %s" % (key, properties[key])
+                               print("            %s = %s" % (key, properties[key]))
 
-       print
+       print("")
index a5e5300..4a598e1 100755 (executable)
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 import gobject
 
 import dbus
@@ -8,12 +10,12 @@ import dbus.mainloop.glib
 def property_changed(name, value, path, interface):
        iface = interface[interface.rfind(".") + 1:]
        val = str(value)
-       print "{%s.PropertyChanged} [%s] %s = %s" % (iface, path, name, val)
+       print("{%s.PropertyChanged} [%s] %s = %s" % (iface, path, name, val))
 
 def object_signal(value, path, interface, member):
        iface = interface[interface.rfind(".") + 1:]
        val = str(value)
-       print "{%s.%s} [%s] Path = %s" % (iface, member, path, val)
+       print("{%s.%s} [%s] Path = %s" % (iface, member, path, val))
 
 if __name__ == '__main__':
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
old mode 100755 (executable)
new mode 100644 (file)
index 8d65860..a25eaf0
@@ -1,6 +1,8 @@
 #!/usr/bin/python
 
-import gobject
+from __future__ import absolute_import, print_function, unicode_literals
+
+from gi.repository import GObject
 
 import sys
 import dbus
@@ -8,6 +10,12 @@ import dbus.service
 import dbus.mainloop.glib
 from optparse import OptionParser
 
+def ask(prompt):
+       try:
+               return raw_input(prompt)
+       except:
+               return input(prompt)
+
 class Rejected(dbus.DBusException):
        _dbus_error_name = "org.bluez.Error.Rejected"
 
@@ -20,15 +28,15 @@ class Agent(dbus.service.Object):
        @dbus.service.method("org.bluez.Agent",
                                        in_signature="", out_signature="")
        def Release(self):
-               print "Release"
+               print("Release")
                if self.exit_on_release:
                        mainloop.quit()
 
        @dbus.service.method("org.bluez.Agent",
                                        in_signature="os", out_signature="")
        def Authorize(self, device, uuid):
-               print "Authorize (%s, %s)" % (device, uuid)
-               authorize = raw_input("Authorize connection (yes/no): ")
+               print("Authorize (%s, %s)" % (device, uuid))
+               authorize = ask("Authorize connection (yes/no): ")
                if (authorize == "yes"):
                        return
                raise Rejected("Connection rejected by user")
@@ -36,26 +44,31 @@ class Agent(dbus.service.Object):
        @dbus.service.method("org.bluez.Agent",
                                        in_signature="o", out_signature="s")
        def RequestPinCode(self, device):
-               print "RequestPinCode (%s)" % (device)
-               return raw_input("Enter PIN Code: ")
+               print("RequestPinCode (%s)" % (device))
+               return ask("Enter PIN Code: ")
 
        @dbus.service.method("org.bluez.Agent",
                                        in_signature="o", out_signature="u")
        def RequestPasskey(self, device):
-               print "RequestPasskey (%s)" % (device)
-               passkey = raw_input("Enter passkey: ")
+               print("RequestPasskey (%s)" % (device))
+               passkey = ask("Enter passkey: ")
                return dbus.UInt32(passkey)
 
        @dbus.service.method("org.bluez.Agent",
                                        in_signature="ou", out_signature="")
        def DisplayPasskey(self, device, passkey):
-               print "DisplayPasskey (%s, %d)" % (device, passkey)
+               print("DisplayPasskey (%s, %06d)" % (device, passkey))
+
+       @dbus.service.method("org.bluez.Agent",
+                                       in_signature="os", out_signature="")
+       def DisplayPinCode(self, device, pincode):
+               print("DisplayPinCode (%s, %s)" % (device, pincode))
 
        @dbus.service.method("org.bluez.Agent",
                                        in_signature="ou", out_signature="")
        def RequestConfirmation(self, device, passkey):
-               print "RequestConfirmation (%s, %d)" % (device, passkey)
-               confirm = raw_input("Confirm passkey (yes/no): ")
+               print("RequestConfirmation (%s, %06d)" % (device, passkey))
+               confirm = ask("Confirm passkey (yes/no): ")
                if (confirm == "yes"):
                        return
                raise Rejected("Passkey doesn't match")
@@ -63,8 +76,8 @@ class Agent(dbus.service.Object):
        @dbus.service.method("org.bluez.Agent",
                                        in_signature="s", out_signature="")
        def ConfirmModeChange(self, mode):
-               print "ConfirmModeChange (%s)" % (mode)
-               authorize = raw_input("Authorize mode change (yes/no): ")
+               print("ConfirmModeChange (%s)" % (mode))
+               authorize = ask("Authorize mode change (yes/no): ")
                if (authorize == "yes"):
                        return
                raise Rejected("Mode change by user")
@@ -72,14 +85,14 @@ class Agent(dbus.service.Object):
        @dbus.service.method("org.bluez.Agent",
                                        in_signature="", out_signature="")
        def Cancel(self):
-               print "Cancel"
+               print("Cancel")
 
 def create_device_reply(device):
-       print "New device (%s)" % (device)
+       print("New device (%s)" % (device))
        mainloop.quit()
 
 def create_device_error(error):
-       print "Creating device failed: %s" % (error)
+       print("Creating device failed: %s" % (error))
        mainloop.quit()
 
 if __name__ == '__main__':
@@ -89,7 +102,7 @@ if __name__ == '__main__':
        manager = dbus.Interface(bus.get_object("org.bluez", "/"),
                                                        "org.bluez.Manager")
 
-       capability = "DisplayYesNo"
+       capability = "KeyboardDisplay"
 
        parser = OptionParser()
        parser.add_option("-c", "--capability", action="store",
@@ -109,7 +122,7 @@ if __name__ == '__main__':
        path = "/test/agent"
        agent = Agent(bus, path)
 
-       mainloop = gobject.MainLoop()
+       mainloop = GObject.MainLoop()
 
        if len(args) > 1:
                if len(args) > 2:
@@ -118,13 +131,14 @@ if __name__ == '__main__':
 
                agent.set_exit_on_release(False)
                adapter.CreatePairedDevice(args[1], path, capability,
+                                       timeout=60000,
                                        reply_handler=create_device_reply,
                                        error_handler=create_device_error)
        else:
                adapter.RegisterAgent(path, capability)
-               print "Agent registered"
+               print("Agent registered")
 
        mainloop.run()
 
        #adapter.UnregisterAgent(path)
-       #print "Agent unregistered"
+       #print("Agent unregistered")
old mode 100755 (executable)
new mode 100644 (file)
index e09a528..20c8159
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 import sys
 import dbus
 import dbus.service
@@ -52,25 +54,25 @@ class Endpoint(dbus.service.Object):
        @dbus.service.method("org.bluez.MediaEndpoint",
                                        in_signature="", out_signature="")
        def Release(self):
-               print "Release"
+               print("Release")
                if self.exit_on_release:
                        mainloop.quit()
 
        @dbus.service.method("org.bluez.MediaEndpoint",
                                        in_signature="", out_signature="")
        def ClearConfiguration(self):
-               print "ClearConfiguration"
+               print("ClearConfiguration")
 
        @dbus.service.method("org.bluez.MediaEndpoint",
                                        in_signature="oay", out_signature="")
        def SetConfiguration(self, transport, config):
-               print "SetConfiguration (%s, %s)" % (transport, config)
+               print("SetConfiguration (%s, %s)" % (transport, config))
                return
 
        @dbus.service.method("org.bluez.MediaEndpoint",
                                        in_signature="ay", out_signature="ay")
        def SelectConfiguration(self, caps):
-               print "SelectConfiguration (%s)" % (caps)
+               print("SelectConfiguration (%s)" % (caps))
                return self.configuration
 
 if __name__ == '__main__':
@@ -119,7 +121,7 @@ if __name__ == '__main__':
                                                        "Capabilities" :  PCM_CONFIGURATION })
                        endpoint.default_configuration(dbus.Array([]))
 
-       print properties
+       print(properties)
 
        media.RegisterEndpoint(path, properties)
 
old mode 100755 (executable)
new mode 100644 (file)
index d03ec3d..ed27d0c 100755 (executable)
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 import sys
 import time
 import dbus
@@ -114,13 +116,13 @@ service = dbus.Interface(bus.get_object("org.bluez", path),
 
 handle = service.AddRecord(xml)
 
-print "Service record with handle 0x%04x added" % (handle)
+print("Service record with handle 0x%04x added" % (handle))
 
-print "Press CTRL-C to remove service record"
+print("Press CTRL-C to remove service record")
 
 try:
        time.sleep(1000)
-       print "Terminating session"
+       print("Terminating session")
 except:
        pass
 
old mode 100755 (executable)
new mode 100644 (file)
index 762ef98..4e2f029
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 import sys
 import dbus
 import time
@@ -26,28 +28,28 @@ 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 "  address"
-       print "  list"
-       print "  name [name]"
-       print "  powered [on/off]"
-       print "  pairable [on/off]"
-       print "  pairabletimeout [timeout]"
-       print "  discoverable [on/off]"
-       print "  discoverabletimeout [timeout]"
-       print "  discovering"
+       print("Usage: %s <command>" % (sys.argv[0]))
+       print("")
+       print("  address")
+       print("  list")
+       print("  name [name]")
+       print("  powered [on/off]")
+       print("  pairable [on/off]")
+       print("  pairabletimeout [timeout]")
+       print("  discoverable [on/off]")
+       print("  discoverabletimeout [timeout]")
+       print("  discovering")
        sys.exit(1)
 
 if (args[0] == "address"):
        properties = adapter.GetProperties()
-       print properties["Address"]
+       print(properties["Address"])
        sys.exit(0)
 
 if (args[0] == "name"):
        if (len(args) < 2):
                properties = adapter.GetProperties()
-               print properties["Name"]
+               print(properties["Name"])
        else:
                adapter.SetProperty("Name", args[1])
        sys.exit(0)
@@ -59,19 +61,19 @@ if (args[0] == "list"):
                        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():
+                       print(" [ %s ]" % (adapter_path))
+                       for (key, value) in prop.items():
                                if (key == "Class"):
-                                       print "    %s = 0x%06x" % (key, value)
+                                       print("    %s = 0x%06x" % (key, value))
                                else:
-                                       print "    %s = %s" % (key, value)
-                       print
+                                       print("    %s = %s" % (key, value))
+                       print()
        sys.exit(0)
 
 if (args[0] == "powered"):
        if (len(args) < 2):
                properties = adapter.GetProperties()
-               print properties["Powered"]
+               print(properties["Powered"])
        else:
                if (args[1] == "on"):
                        value = dbus.Boolean(1)
@@ -85,7 +87,7 @@ if (args[0] == "powered"):
 if (args[0] == "pairable"):
        if (len(args) < 2):
                properties = adapter.GetProperties()
-               print properties["Pairable"]
+               print(properties["Pairable"])
        else:
                if (args[1] == "on"):
                        value = dbus.Boolean(1)
@@ -99,7 +101,7 @@ if (args[0] == "pairable"):
 if (args[0] == "pairabletimeout"):
        if (len(args) < 2):
                properties = adapter.GetProperties()
-               print properties["PairableTimeout"]
+               print(properties["PairableTimeout"])
        else:
                timeout = dbus.UInt32(args[1])
                adapter.SetProperty("PairableTimeout", timeout)
@@ -108,7 +110,7 @@ if (args[0] == "pairabletimeout"):
 if (args[0] == "discoverable"):
        if (len(args) < 2):
                properties = adapter.GetProperties()
-               print properties["Discoverable"]
+               print(properties["Discoverable"])
        else:
                if (args[1] == "on"):
                        value = dbus.Boolean(1)
@@ -122,7 +124,7 @@ if (args[0] == "discoverable"):
 if (args[0] == "discoverabletimeout"):
        if (len(args) < 2):
                properties = adapter.GetProperties()
-               print properties["DiscoverableTimeout"]
+               print(properties["DiscoverableTimeout"])
        else:
                timeout = dbus.UInt32(args[1])
                adapter.SetProperty("DiscoverableTimeout", timeout)
@@ -130,8 +132,8 @@ if (args[0] == "discoverabletimeout"):
 
 if (args[0] == "discovering"):
        properties = adapter.GetProperties()
-       print properties["Discovering"]
+       print(properties["Discovering"])
        sys.exit(0)
 
-print "Unknown command"
+print("Unknown command")
 sys.exit(1)
old mode 100755 (executable)
new mode 100644 (file)
index b9e83c5..52b399c
@@ -1,4 +1,6 @@
 #!/usr/bin/python
+
+from __future__ import absolute_import, print_function, unicode_literals
 # Script for testing the Attribute D-Bus API
 
 import sys
@@ -35,12 +37,12 @@ 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 "  list"
-       print "  services <address>"
-       print "  discover <service path>"
-       print "  chars <service path>"
+       print("Usage: %s <command>" % (sys.argv[0]))
+       print("")
+       print("  list")
+       print("  services <address>")
+       print("  discover <service path>")
+       print("  chars <service path>")
        sys.exit(1)
 
 if (args[0] == "list"):
@@ -48,61 +50,61 @@ if (args[0] == "list"):
                device = dbus.Interface(bus.get_object("org.bluez", path),
                                                        "org.bluez.Device")
                devprop = device.GetProperties()
-               print "[ %s ]" % devprop["Address"]
+               print("[ %s ]" % devprop["Address"])
                for path in devprop["Services"]:
 
                        service = dbus.Interface(bus.get_object("org.bluez", path),
                                                                         "org.bluez.Characteristic")
                        srvprop = service.GetProperties()
-                       print " * %s" % (path)
-                       print " UUID: %s" % srvprop["UUID"]
-                       print " Chars: ",
+                       print(" * %s" % (path))
+                       print(" UUID: %s" % srvprop["UUID"])
+                       print(" Chars: ",)
                        for char in srvprop["Characteristics"]:
-                               print "%s " % char,
-                       print
-                       print
-               print
+                               print("%s " % char,)
+                       print()
+                       print()
+               print()
        sys.exit(0)
 
 if (args[0] == "services"):
        if (len(args) < 2):
-               print "Need address parameter"
+               print("Need address parameter")
        else:
                path = adapter.FindDevice(args[1])
                device = dbus.Interface(bus.get_object("org.bluez", path),
                                                        "org.bluez.Device")
                properties = device.GetProperties()
                for path in properties["Services"]:
-                       print path
+                       print(path)
        sys.exit(0)
 
 if (args[0] == "discover"):
        if (len(args) < 2):
-               print "Need service path parameter"
+               print("Need service path parameter")
        else:
                service = dbus.Interface(bus.get_object("org.bluez", args[1]),
                                                        "org.bluez.Characteristic")
                for path in service.DiscoverCharacteristics():
-                       print path
+                       print(path)
        sys.exit(0)
 
 if (args[0] == "chars"):
        if (len(args) < 2):
-               print "Need service path parameter"
+               print("Need service path parameter")
        else:
                service = dbus.Interface(bus.get_object("org.bluez", args[1]),
                                                                 "org.bluez.Characteristic")
                srvprop = service.GetProperties()
                for path in srvprop["Characteristics"]:
-                       print "[ %s ]" % (path)
+                       print("[ %s ]" % (path))
                        char = dbus.Interface(bus.get_object("org.bluez", path),
                                                                 "org.bluez.Characteristic")
                        charprop = char.GetProperties()
-                       print " Name: %s" % charprop["Name"]
-                       print " UUID: %s" % charprop["UUID"]
-                       print
-               print
+                       print(" Name: %s" % charprop["Name"])
+                       print(" UUID: %s" % charprop["UUID"])
+                       print()
+               print()
        sys.exit(0)
 
-print "Unknown command"
+print("Unknown command")
 sys.exit(1)
index 8b7a62d..1ba2042 100755 (executable)
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 import sys
 import dbus
 from optparse import OptionParser, make_option
@@ -25,11 +27,11 @@ adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
                                                        "org.bluez.Adapter")
 
 if len(args) < 2:
-       print """Usage: %s <command>
+       print("""Usage: %s <command>
 
        connect <bdaddr>
        disconnect <bdaddr>
-       """ % sys.argv[0]
+       """ % sys.argv[0])
        sys.exit(1)
 
 device = adapter.FindDevice(args[1])
@@ -41,5 +43,5 @@ if args[0] == "connect":
 elif args[0] == "disconnect":
        audio.Disconnect()
 else:
-       print "Unknown command"
+       print("Unknown command")
        sys.exit(1)
index 154af19..81a44f8 100755 (executable)
@@ -1,6 +1,8 @@
 #!/usr/bin/python
 
-import gobject
+from __future__ import absolute_import, print_function, unicode_literals
+
+from gi.repository import GObject
 
 import sys
 import dbus
@@ -10,7 +12,7 @@ from optparse import OptionParser, make_option
 
 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 bus = dbus.SystemBus()
-mainloop = gobject.MainLoop()
+mainloop = GObject.MainLoop()
 
 manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
 
@@ -31,19 +33,19 @@ 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 "  list"
-       print "  services <address>"
-       print "  create <address>"
-       print "  remove <address|path>"
-       print "  disconnect <address>"
-       print "  discover <address> [pattern]"
-       print "  class <address>"
-       print "  name <address>"
-       print "  alias <address> [alias]"
-       print "  trusted <address> [yes/no]"
-       print "  blocked <address> [yes/no]"
+       print("Usage: %s <command>" % (sys.argv[0]))
+       print("")
+       print("  list")
+       print("  services <address>")
+       print("  create <address>")
+       print("  remove <address|path>")
+       print("  disconnect <address>")
+       print("  discover <address> [pattern]")
+       print("  class <address>")
+       print("  name <address>")
+       print("  alias <address> [alias]")
+       print("  trusted <address> [yes/no]")
+       print("  blocked <address> [yes/no]")
        sys.exit(1)
 
 if (args[0] == "list"):
@@ -51,23 +53,23 @@ if (args[0] == "list"):
                device = dbus.Interface(bus.get_object("org.bluez", path),
                                                        "org.bluez.Device")
                properties = device.GetProperties()
-               print "%s %s" % (properties["Address"], properties["Alias"])
+               print("%s %s" % (properties["Address"], properties["Alias"]))
 
        sys.exit(0)
 
 def create_device_reply(device):
-       print "New device (%s)" % device
+       print("New device (%s)" % device)
        mainloop.quit()
        sys.exit(0)
 
 def create_device_error(error):
-       print "Creating device failed: %s" % error
+       print("Creating device failed: %s" % error)
        mainloop.quit()
        sys.exit(1)
 
 if (args[0] == "create"):
        if (len(args) < 2):
-               print "Need address parameter"
+               print("Need address parameter")
        else:
                adapter.CreateDevice(args[1],
                                reply_handler=create_device_reply,
@@ -76,7 +78,7 @@ if (args[0] == "create"):
 
 if (args[0] == "remove"):
        if (len(args) < 2):
-               print "Need address or object path parameter"
+               print("Need address or object path parameter")
        else:
                try:
                        path = adapter.FindDevice(args[1])
@@ -87,7 +89,7 @@ if (args[0] == "remove"):
 
 if (args[0] == "disconnect"):
        if (len(args) < 2):
-               print "Need address parameter"
+               print("Need address parameter")
        else:
                path = adapter.FindDevice(args[1])
                device = dbus.Interface(bus.get_object("org.bluez", path),
@@ -97,7 +99,7 @@ if (args[0] == "disconnect"):
 
 if (args[0] == "discover"):
        if (len(args) < 2):
-               print "Need address parameter"
+               print("Need address parameter")
        else:
                path = adapter.FindDevice(args[1])
                device = dbus.Interface(bus.get_object("org.bluez", path),
@@ -110,57 +112,57 @@ if (args[0] == "discover"):
                for key in services.keys():
                        p = re.compile(">.*?<")
                        xml = p.sub("><", services[key].replace("\n", ""))
-                       print "[ 0x%5x ]" % (key)
-                       print xml
-                       print
+                       print("[ 0x%5x ]" % (key))
+                       print(xml)
+                       print()
        sys.exit(0)
 
 if (args[0] == "class"):
        if (len(args) < 2):
-               print "Need address parameter"
+               print("Need address parameter")
        else:
                path = adapter.FindDevice(args[1])
                device = dbus.Interface(bus.get_object("org.bluez", path),
                                                        "org.bluez.Device")
                properties = device.GetProperties()
-               print "0x%06x" % (properties["Class"])
+               print("0x%06x" % (properties["Class"]))
        sys.exit(0)
 
 if (args[0] == "name"):
        if (len(args) < 2):
-               print "Need address parameter"
+               print("Need address parameter")
        else:
                path = adapter.FindDevice(args[1])
                device = dbus.Interface(bus.get_object("org.bluez", path),
                                                        "org.bluez.Device")
                properties = device.GetProperties()
-               print properties["Name"]
+               print(properties["Name"])
        sys.exit(0)
 
 if (args[0] == "alias"):
        if (len(args) < 2):
-               print "Need address parameter"
+               print("Need address parameter")
        else:
                path = adapter.FindDevice(args[1])
                device = dbus.Interface(bus.get_object("org.bluez", path),
                                                        "org.bluez.Device")
                if (len(args) < 3):
                        properties = device.GetProperties()
-                       print properties["Alias"]
+                       print(properties["Alias"])
                else:
                        device.SetProperty("Alias", args[2])
        sys.exit(0)
 
 if (args[0] == "trusted"):
        if (len(args) < 2):
-               print "Need address parameter"
+               print("Need address parameter")
        else:
                path = adapter.FindDevice(args[1])
                device = dbus.Interface(bus.get_object("org.bluez", path),
                                                        "org.bluez.Device")
                if (len(args) < 3):
                        properties = device.GetProperties()
-                       print properties["Trusted"]
+                       print(properties["Trusted"])
                else:
                        if (args[2] == "yes"):
                                value = dbus.Boolean(1)
@@ -173,14 +175,14 @@ if (args[0] == "trusted"):
 
 if (args[0] == "blocked"):
        if (len(args) < 2):
-               print "Need address parameter"
+               print("Need address parameter")
        else:
                path = adapter.FindDevice(args[1])
                device = dbus.Interface(bus.get_object("org.bluez", path),
                                                        "org.bluez.Device")
                if (len(args) < 3):
                        properties = device.GetProperties()
-                       print properties["Blocked"]
+                       print(properties["Blocked"])
                else:
                        if (args[2] == "yes"):
                                value = dbus.Boolean(1)
@@ -193,15 +195,15 @@ if (args[0] == "blocked"):
 
 if (args[0] == "services"):
        if (len(args) < 2):
-               print "Need address parameter"
+               print("Need address parameter")
        else:
                path = adapter.FindDevice(args[1])
                device = dbus.Interface(bus.get_object("org.bluez", path),
                                                        "org.bluez.Device")
                properties = device.GetProperties()
                for path in properties["Services"]:
-                       print path
+                       print(path)
        sys.exit(0)
 
-print "Unknown command"
+print("Unknown command")
 sys.exit(1)
index 22c88c3..269c51c 100755 (executable)
@@ -1,20 +1,26 @@
 #!/usr/bin/python
 
-import gobject
+from __future__ import absolute_import, print_function, unicode_literals
+
+from gi.repository import GObject
 
 import dbus
 import dbus.mainloop.glib
 from optparse import OptionParser, make_option
 
 def device_found(address, properties):
-       print "[ " + address + " ]"
+       print("[ " + address + " ]")
 
        for key in properties.keys():
                value = properties[key]
+               if type(value) is dbus.String:
+                       value = unicode(value).encode('ascii', 'replace')
                if (key == "Class"):
-                       print "    %s = 0x%06x" % (key, value)
+                       print("    %s = 0x%06x" % (key, value))
                else:
-                       print "    %s = %s" % (key, value)
+                       print("    %s = %s" % (key, value))
+
+       print()
 
 def property_changed(name, value):
        if (name == "Discovering" and not value):
@@ -53,5 +59,5 @@ if __name__ == '__main__':
 
        adapter.StartDiscovery()
 
-       mainloop = gobject.MainLoop()
+       mainloop = GObject.MainLoop()
        mainloop.run()
old mode 100755 (executable)
new mode 100644 (file)
index 16a5a2b..f7d4241
@@ -1,4 +1,6 @@
 #!/usr/bin/python
+
+from __future__ import absolute_import, print_function, unicode_literals
 # -*- coding: utf-8 -*-
 
 import dbus
@@ -19,15 +21,15 @@ def sig_received(*args, **kwargs):
                return;
        sig_name = kwargs["member"]
        path = kwargs["path"]
-       print sig_name
-       print path
+       print(sig_name)
+       print(path)
        if sig_name == "PropertyChanged":
                k, v = args
-               print k
-               print v
+               print(k)
+               print(v)
        else:
                ob = args[0]
-               print ob
+               print(ob)
 
 
 def enter_mainloop():
@@ -38,21 +40,21 @@ def enter_mainloop():
                                interface_keyword="interface")
 
        try:
-               print "Entering main lopp, push Ctrl+C for finish"
+               print("Entering main lopp, push Ctrl+C for finish")
 
                mainloop = gobject.MainLoop()
                mainloop.run()
        except KeyboardInterrupt:
                pass
        finally:
-               print "Exiting, bye"
+               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: ",
+       print("Select 1. source or 2. sink: ",)
        try:
                sel = int(sys.stdin.readline())
                if sel == 1:
@@ -62,20 +64,20 @@ while role == None:
                else:
                        raise ValueError
        except (TypeError, ValueError):
-               print "Wrong selection, try again: ",
+               print("Wrong selection, try again: ",)
        except KeyboardInterrupt:
                sys.exit()
 
 dtype = None
 while dtype == None:
-       print "Select a data type: ",
+       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: ",
+               print("Wrong selection, try again: ",)
        except KeyboardInterrupt:
                sys.exit()
 
@@ -83,8 +85,8 @@ pref = None
 if role == "Source":
        while pref == None:
                try:
-                       print "Select a preferred data channel type 1.",
-                       print "reliable 2. streaming: ",
+                       print("Select a preferred data channel type 1.",)
+                       print("reliable 2. streaming: ",)
                        sel = int(sys.stdin.readline())
                        if sel == 1:
                                pref = "Reliable"
@@ -94,7 +96,7 @@ if role == "Source":
                                raise ValueError
 
                except (TypeError, ValueError):
-                       print "Wrong selection, try again"
+                       print("Wrong selection, try again")
                except KeyboardInterrupt:
                        sys.exit()
 
@@ -109,19 +111,19 @@ else:
                                        "Description": "Test sink",
                                        "Role": role})
 
-print "New application created:", app_path
+print("New application created:", app_path)
 
 con = None
 while con == None:
        try:
-               print "Connect to a remote device (y/n)? ",
+               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."
+                       print("Wrong selection, try again.")
        except KeyboardInterrupt:
                sys.exit()
 
@@ -136,10 +138,10 @@ adapters = manager.ListAdapters()
 
 i = 1
 for ad in adapters:
-       print "%d. %s" % (i, ad)
+       print("%d. %s" % (i, ad))
        i = i + 1
 
-print "Select an adapter: ",
+print("Select an adapter: ",)
 select = None
 while select == None:
        try:
@@ -148,7 +150,7 @@ while select == None:
                        raise TypeError
                select = adapters[pos]
        except (TypeError, IndexError, ValueError):
-               print "Wrong selection, try again: ",
+               print("Wrong selection, try again: ",)
        except KeyboardInterrupt:
                sys.exit()
 
@@ -158,15 +160,15 @@ adapter =  dbus.Interface(bus.get_object("org.bluez", select),
 devices = adapter.ListDevices()
 
 if len(devices) == 0:
-       print "No devices available"
+       print("No devices available")
        sys.exit()
 
 i = 1
 for dev in devices:
-       print "%d. %s" % (i, dev)
+       print("%d. %s" % (i, dev))
        i = i + 1
 
-print "Select a device: ",
+print("Select a device: ",)
 select = None
 while select == None:
        try:
@@ -175,7 +177,7 @@ while select == None:
                        raise TypeError
                select = devices[pos]
        except (TypeError, IndexError, ValueError):
-               print "Wrong selection, try again: ",
+               print("Wrong selection, try again: ",)
        except KeyboardInterrupt:
                sys.exit()
 
@@ -185,32 +187,32 @@ device = dbus.Interface(bus.get_object("org.bluez", select),
 echo = None
 while echo == None:
        try:
-               print "Perform an echo (y/n)? ",
+               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."
+                       print("Wrong selection, try again.")
        except KeyboardInterrupt:
                sys.exit()
 
 if echo:
        if device.Echo():
-               print "Echo was ok"
+               print("Echo was ok")
        else:
-               print "Echo war wrong, exiting"
+               print("Echo war wrong, exiting")
                sys.exit()
 
-print "Connecting to device %s" % (select)
+print("Connecting to device %s" % (select))
 
 if role == "Source":
        chan = device.CreateChannel(app_path, "Reliable")
 else:
        chan = device.CreateChannel(app_path, "Any")
 
-print chan
+print(chan)
 
 enter_mainloop()
 
old mode 100755 (executable)
new mode 100644 (file)
index cb9d434..ce7337a
@@ -1,4 +1,6 @@
 #!/usr/bin/python
+
+from __future__ import absolute_import, print_function, unicode_literals
 # -*- coding: utf-8 -*-
 
 import dbus
@@ -17,7 +19,7 @@ hdp_manager = dbus.Interface(bus.get_object("org.bluez", "/org/bluez"),
 app_path = hdp_manager.CreateApplication({"DataType": dbus.types.UInt16(4103),
                                        "Role": "sink"})
 
-print app_path
+print(app_path)
 
 manager = dbus.Interface(bus.get_object("org.bluez", "/"),
                                                "org.bluez.Manager")
@@ -26,10 +28,10 @@ adapters = manager.ListAdapters()
 
 i = 1
 for ad in adapters:
-       print "%d. %s" % (i, ad)
+       print("%d. %s" % (i, ad))
        i = i + 1
 
-print "Select an adapter: ",
+print("Select an adapter: ",)
 select = None
 while select == None:
        try:
@@ -38,7 +40,7 @@ while select == None:
                        raise TypeError
                select = adapters[pos]
        except (TypeError, IndexError, ValueError):
-               print "Wrong selection, try again: ",
+               print("Wrong selection, try again: ",)
        except KeyboardInterrupt:
                sys.exit()
 
@@ -48,15 +50,15 @@ adapter =  dbus.Interface(bus.get_object("org.bluez", select),
 devices = adapter.ListDevices()
 
 if len(devices) == 0:
-       print "No devices available"
+       print("No devices available")
        sys.exit()
 
 i = 1
 for dev in devices:
-       print "%d. %s" % (i, dev)
+       print("%d. %s" % (i, dev))
        i = i + 1
 
-print "Select a device: ",
+print("Select a device: ",)
 select = None
 while select == None:
        try:
@@ -65,19 +67,19 @@ while select == None:
                        raise TypeError
                select = devices[pos]
        except (TypeError, IndexError, ValueError):
-               print "Wrong selection, try again: ",
+               print("Wrong selection, try again: ",)
        except KeyboardInterrupt:
                sys.exit()
 
-print "Connecting to %s" % (select)
+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(chan)
 
-print "Push Enter for finishing"
+print("Push Enter for finishing")
 sys.stdin.readline()
 
 hdp_manager.DestroyApplication(app_path)
index 405bb59..110cbef 100755 (executable)
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 import sys
 import dbus
 from optparse import OptionParser, make_option
@@ -25,11 +27,11 @@ adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
                                                        "org.bluez.Adapter")
 
 if len(args) < 2:
-       print """Usage: %s <command>
+       print("""Usage: %s <command>
 
        connect <bdaddr>
        disconnect <bdaddr>
-       """ % sys.argv[0]
+       """ % sys.argv[0])
        sys.exit(1)
 
 device = adapter.FindDevice(args[1])
@@ -41,5 +43,5 @@ if args[0] == "connect":
 elif args[0] == "disconnect":
        input.Disconnect()
 else:
-       print "Unknown command"
+       print("Unknown command")
        sys.exit(1)
index c6cf560..8a7e2f6 100755 (executable)
@@ -1,18 +1,20 @@
 #!/usr/bin/python
 
-import gobject
+from __future__ import absolute_import, print_function, unicode_literals
+
+from gi.repository import GObject
 
 import dbus
 import dbus.mainloop.glib
 
 def adapter_added(path):
-       print "Adapter with path %s added" % (path)
+       print("Adapter with path %s added" % (path))
 
 def adapter_removed(path):
-       print "Adapter with path %s removed" % (path)
+       print("Adapter with path %s removed" % (path))
 
 def default_changed(path):
-       print "Default adapter is now at path %s" % (path)
+       print("Default adapter is now at path %s" % (path))
 
 if __name__ == "__main__":
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
@@ -34,5 +36,5 @@ if __name__ == "__main__":
        except:
                pass
 
-       mainloop = gobject.MainLoop()
+       mainloop = GObject.MainLoop()
        mainloop.run()
old mode 100755 (executable)
new mode 100644 (file)
index c83d928..dc779ad
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 import sys
 import time
 import dbus
@@ -35,13 +37,13 @@ else:
 
 server.Register(service, bridge)
 
-print "Server for %s registered for %s" % (service, bridge)
+print("Server for %s registered for %s" % (service, bridge))
 
-print "Press CTRL-C to disconnect"
+print("Press CTRL-C to disconnect")
 
 try:
        time.sleep(1000)
-       print "Terminating connection"
+       print("Terminating connection")
 except:
        pass
 
index 676fb30..2ade584 100755 (executable)
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 import sys
 import time
 import dbus
@@ -27,7 +29,7 @@ adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
                                                        "org.bluez.Adapter")
 
 if (len(args) < 1):
-       print "Usage: %s <address> [service]" % (sys.argv[0])
+       print("Usage: %s <address> [service]" % (sys.argv[0]))
        sys.exit(1)
 
 address = args[0]
@@ -44,13 +46,13 @@ network = dbus.Interface(bus.get_object("org.bluez", device),
 
 iface = network.Connect(service)
 
-print "Connected %s to %s" % (device, address)
+print("Connected %s to %s" % (device, address))
 
-print "Press CTRL-C to disconnect"
+print("Press CTRL-C to disconnect")
 
 try:
        time.sleep(1000)
-       print "Terminating connection"
+       print("Terminating connection")
 except:
        pass
 
old mode 100755 (executable)
new mode 100644 (file)
index 3340c00..bec9de5
@@ -1,15 +1,17 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 import gobject
 
 import dbus.mainloop.glib
 
 def create_device_reply(device):
-       print "Pairing succeed!"
+       print("Pairing succeed!")
        mainloop.quit()
 
 def create_device_error(error):
-       print "Pairing failed."
+       print("Pairing failed.")
        mainloop.quit()
 
 if __name__ == '__main__':
@@ -31,12 +33,12 @@ if __name__ == '__main__':
 
        adapter0_address = adapter0.GetProperties()["Address"]
        adapter1_address = adapter1.GetProperties()["Address"]
-       print "Adapters:"
-       print "    hci0: " + adapter0_address
-       print "    hci1: " + adapter1_address
-       print
+       print("Adapters:")
+       print("    hci0: " + adapter0_address)
+       print("    hci1: " + adapter1_address)
+       print()
 
-       print "Removing any existing bond..."
+       print("Removing any existing bond...")
 
        try:
                device = adapter0.FindDevice(adapter1_address)
@@ -50,9 +52,9 @@ if __name__ == '__main__':
        except:
                pass
 
-       print "Done."
-       print
-       print "Reading local Out of Band data..."
+       print("Done.")
+       print()
+       print("Reading local Out of Band data...")
 
        oob_adapter0 = dbus.Interface(bus.get_object("org.bluez",
                                        adapter0_path), "org.bluez.OutOfBand")
@@ -62,16 +64,16 @@ if __name__ == '__main__':
        oob0 = oob_adapter0.ReadLocalData()
        oob1 = oob_adapter1.ReadLocalData()
 
-       print "Done."
-       print
-       print "Exchanging Out of Band data..."
+       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."
+       print("Done.")
+       print()
+       print("Starting to pair.")
        adapter1.CreatePairedDevice(adapter0_address, "/test/agent_oob",
                                        "DisplayYesNo",
                                        reply_handler=create_device_reply,
old mode 100755 (executable)
new mode 100644 (file)
index 289908e..b08a62a
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 '''
 Proximity Monitor test script
 '''
@@ -13,7 +15,7 @@ from optparse import OptionParser, make_option
 
 def property_changed(name, value):
 
-       print "PropertyChanged('%s', '%s')" % (name, value)
+       print("PropertyChanged('%s', '%s')" % (name, value))
        mainloop.quit()
 
 if __name__ == "__main__":
@@ -44,22 +46,22 @@ if __name__ == "__main__":
                                                        "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>"
+               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",
+                               dbus_interface="org.bluez.ProximityMonitor",
                                signal_name="PropertyChanged")
 
        proximity = dbus.Interface(bus.get_object("org.bluez",
-                                       device_path), "org.bluez.Proximity")
+                                       device_path), "org.bluez.ProximityMonitor")
 
-       print "Proximity SetProperty('%s', '%s')" % (args[0], args[1])
+       print("Proximity SetProperty('%s', '%s')" % (args[0], args[1]))
        proximity.SetProperty(args[0], args[1])
 
        mainloop = gobject.MainLoop()
old mode 100755 (executable)
new mode 100644 (file)
index bea6ca9..df838f6
@@ -1,11 +1,13 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 from sap import *
 import time
 
 def connect_disconnect_by_client(sap):
 
-    print "[Test] Connect - Disconnect by client \n"
+    print("[Test] Connect - Disconnect by client \n")
 
     try:
         if not sap.isConnected():
@@ -13,19 +15,19 @@ def connect_disconnect_by_client(sap):
 
         if sap.proc_connect():
             if sap.proc_disconnectByClient():
-                print "OK"
+                print("OK")
                 return 0
 
-        print "NOT OK"
+        print("NOT OK")
         return 1
 
-    except BluetoothError , e:
-        print "Error " + str(e)
+    except BluetoothError as e:
+        print("Error " + str(e))
 
 
 def connect_disconnect_by_server_gracefully(sap, timeout=0):
 
-    print "[Test] Connect - Disconnect by server with timer \n"
+    print("[Test] Connect - Disconnect by server with timer \n")
 
     try:
         if not sap.isConnected():
@@ -33,19 +35,19 @@ def connect_disconnect_by_server_gracefully(sap, timeout=0):
 
         if sap.proc_connect():
             if sap.proc_disconnectByServer(timeout):
-                print "OK"
+                print("OK")
                 return 0
 
-        print "NOT OK"
+        print("NOT OK")
         return 1
 
-    except BluetoothError , e:
-        print "Error " + str(e)
+    except BluetoothError as e:
+        print("Error " + str(e))
 
 
 def connect_txAPDU_disconnect_by_client(sap):
 
-    print "[Test] Connect - TX APDU - Disconnect by client \n"
+    print("[Test] Connect - TX APDU - Disconnect by client \n")
 
     try:
         if not sap.isConnected():
@@ -53,44 +55,44 @@ def connect_txAPDU_disconnect_by_client(sap):
 
         if sap.proc_connect():
             if not sap.proc_transferAPDU():
-                print "NOT OK 1"
+                print("NOT OK 1")
                 return 1
 
             if not sap.proc_transferAPDU():
-                print "NOT OK 2"
+                print("NOT OK 2")
                 return 1
 
             if not sap.proc_transferAPDU():
-                print "NOT OK 3"
+                print("NOT OK 3")
                 return 1
 
             if not sap.proc_transferAPDU():
-                print "NOT OK 4"
+                print("NOT OK 4")
                 return 1
 
             if sap.proc_disconnectByClient():
-                print "OK"
+                print("OK")
                 return 0
 
-        print "NOT OK"
+        print("NOT OK")
         return 1
 
-    except BluetoothError , e:
-        print "Error " + str(e)
+    except BluetoothError as 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"
+    print("[Test] Connect rfcomm only  - Disconnect by server timeout \n")
 
     if not sap.isConnected():
        sap.connect()
 
     time.sleep(40)
-    print "OK"
+    print("OK")
 
 def power_sim_off_on(sap):
 
-    print "[Test] Powe sim off \n"
+    print("[Test] Powe sim off \n")
 
     try:
         if not sap.isConnected():
@@ -98,26 +100,26 @@ def power_sim_off_on(sap):
 
         if sap.proc_connect():
             if not sap.proc_resetSim():
-                print "NOT OK"
+                print("NOT OK")
                 return 1
 
             if not sap.proc_powerSimOff():
-                print "NOT OK"
+                print("NOT OK")
                 return 1
 
             if not sap.proc_powerSimOn():
-                print "NOT OK"
+                print("NOT OK")
                 return 1
 
             if sap.proc_disconnectByClient():
-                print "OK"
+                print("OK")
                 return 0
 
-        print "NOT OK"
+        print("NOT OK")
         return 1
 
-    except BluetoothError , e:
-        print "Error " + str(e)
+    except BluetoothError as e:
+        print("Error " + str(e))
 
 
 if __name__ == "__main__":
@@ -127,8 +129,8 @@ if __name__ == "__main__":
 
     try:
         s = SAPClient(host, port)
-    except BluetoothError , e:
-        print "Error " + str(e)
+    except BluetoothError as e:
+        print("Error " + str(e))
 
     connect_disconnect_by_client(s)
     connect_disconnect_by_server_gracefully(s)
index cc496df..8858dbd 100755 (executable)
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 import sys
 import time
 import dbus
@@ -26,7 +28,7 @@ adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
                                                        "org.bluez.Adapter")
 
 if (len(args) < 1):
-       print "Usage: %s <address> [service]" % (sys.argv[0])
+       print("Usage: %s <address> [service]" % (sys.argv[0]))
        sys.exit(1)
 
 address = args[0]
@@ -43,13 +45,13 @@ serial = dbus.Interface(bus.get_object("org.bluez", path),
 
 node = serial.Connect(service)
 
-print "Connected %s to %s" % (node, address)
+print("Connected %s to %s" % (node, address))
 
-print "Press CTRL-C to disconnect"
+print("Press CTRL-C to disconnect")
 
 try:
        time.sleep(1000)
-       print "Terminating connection"
+       print("Terminating connection")
 except:
        pass
 
old mode 100755 (executable)
new mode 100644 (file)
index f6dbd6c..7963f23
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 import sys
 import time
 import dbus
@@ -27,7 +29,7 @@ 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])
+       print("Usage: %s <socket_name> [service]" % (sys.argv[0]))
        sys.exit(1)
 
 socket_name = args[0]
@@ -51,7 +53,7 @@ proxy.Enable()
 
 conn, addr = sk.accept()
 
-print "Waiting for message"
+print("Waiting for message")
 
 while 1:
        data = conn.recv(1024)
index 8958201..8eea9e2 100755 (executable)
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 import sys
 import dbus
 import time
@@ -26,22 +28,22 @@ service = dbus.Interface(bus.get_object("org.bluez", adapter_path),
                                                "org.bluez.Service")
 
 if (len(args) < 1):
-       print "Usage: %s <command>" % (sys.argv[0])
-       print ""
-       print "  addrecord <file>"
+       print("Usage: %s <command>" % (sys.argv[0]))
+       print("")
+       print("  addrecord <file>")
        sys.exit(1)
 
 if (args[0] == "addrecord"):
        if (len(args) < 2):
-               print "Need file parameter"
+               print("Need file parameter")
        else:
                f = open(args[1])
                record = f.read()
                f.close()
                handle = service.AddRecord(record)
-               print "0x%x" % (handle)
+               print("0x%x" % (handle))
                time.sleep(120)
        sys.exit(0)
 
-print "Unknown command"
+print("Unknown command")
 sys.exit(1)
index 5ef0ac8..bd7d3b2 100755 (executable)
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 import sys
 import dbus
 from optparse import OptionParser, make_option
@@ -28,7 +30,7 @@ test = dbus.Interface(bus.get_object("org.bluez", "/org/bluez/test"),
                        "org.bluez.TelephonyTest")
 
 if len(args) < 1:
-       print """Usage: %s <command>
+       print("""Usage: %s <command>
 
        connect <bdaddr>
        disconnect <bdaddr>
@@ -44,12 +46,12 @@ if len(args) < 1:
        microphonegain <bdaddr> [level]
        play <bdaddr>
        stop <bdaddr>
-       """ % sys.argv[0]
+       """ % sys.argv[0])
        sys.exit(1)
 
 if args[0] == "connect":
        if len(args) < 2:
-               print "Need device address parameter"
+               print("Need device address parameter")
                sys.exit(1)
        device = adapter.FindDevice(args[1])
        headset = dbus.Interface(bus.get_object("org.bluez", device),
@@ -59,7 +61,7 @@ if args[0] == "connect":
 
 if args[0] == "disconnect":
        if len(args) < 2:
-               print "Need device address parameter"
+               print("Need device address parameter")
                sys.exit(1)
        device = adapter.FindDevice(args[1])
        headset = dbus.Interface(bus.get_object("org.bluez", device),
@@ -69,7 +71,7 @@ if args[0] == "disconnect":
 
 if args[0] == "speakergain":
        if len(args) < 2:
-               print "Need device address parameter"
+               print("Need device address parameter")
                sys.exit(1)
        device = adapter.FindDevice(args[1])
        headset = dbus.Interface(bus.get_object("org.bluez", device),
@@ -78,13 +80,13 @@ if args[0] == "speakergain":
                headset.SetProperty('SpeakerGain', dbus.UInt16(args[2]))
        else:
                props = headset.GetProperties()
-               print props['SpeakerGain']
+               print(props['SpeakerGain'])
 
        sys.exit(0)
 
 if args[0] == "microphonegain":
        if len(args) < 2:
-               print "Need device address parameter"
+               print("Need device address parameter")
                sys.exit(1)
        device = adapter.FindDevice(args[1])
        headset = dbus.Interface(bus.get_object("org.bluez", device),
@@ -93,13 +95,13 @@ if args[0] == "microphonegain":
                headset.SetProperty('MicrophoneGain', dbus.UInt16(args[2]))
        else:
                props = headset.GetProperties()
-               print props['MicrophoneGain']
+               print(props['MicrophoneGain'])
 
        sys.exit(0)
 
 if args[0] == "play":
        if len(args) < 2:
-               print "Need device address parameter"
+               print("Need device address parameter")
                sys.exit(1)
        device = adapter.FindDevice(args[1])
        headset = dbus.Interface(bus.get_object("org.bluez", device),
@@ -110,7 +112,7 @@ if args[0] == "play":
 
 if args[0] == "stop":
        if len(args) < 2:
-               print "Need device address parameter"
+               print("Need device address parameter")
                sys.exit(1)
        device = adapter.FindDevice(args[1])
        headset = dbus.Interface(bus.get_object("org.bluez", device),
@@ -123,14 +125,14 @@ if args[0] == "outgoing":
        if len(args) > 1:
                test.OutgoingCall(args[1])
        else:
-               print "Need number parameter"
+               print("Need number parameter")
        sys.exit(0)
 
 if args[0] == "incoming":
        if len(args) > 1:
                test.IncomingCall(args[1])
        else:
-               print "Need number parameter"
+               print("Need number parameter")
        sys.exit(0)
 
 if args[0] == "cancel":
@@ -141,36 +143,36 @@ if args[0] == "signal":
        if len(args) > 1:
                test.SignalStrength(args[1])
        else:
-               print "Need signal strength parameter"
+               print("Need signal strength parameter")
        sys.exit(0)
 
 if args[0] == "battery":
        if len(args) > 1:
                test.BatteryLevel(args[1])
        else:
-               print "Need battery level parameter"
+               print("Need battery level parameter")
        sys.exit(0)
 
 if args[0] == "roaming":
        if len(args) > 1:
                test.RoamingStatus(args[1] == "yes" or False)
        else:
-               print "Need yes/no parameter"
+               print("Need yes/no parameter")
        sys.exit(0)
 
 if args[0] == "registration":
        if len(args) > 1:
                test.RegistrationStatus(args[1] == "yes" or False)
        else:
-               print "Need yes/no parameter"
+               print("Need yes/no parameter")
        sys.exit(0)
 
 if args[0] == "subscriber":
        if len(args) > 1:
                test.SetSubscriberNumber(args[1])
        else:
-               print "Need number parameter"
+               print("Need number parameter")
        sys.exit(0)
 
-print "Unknown command"
+print("Unknown command")
 sys.exit(1)
old mode 100755 (executable)
new mode 100644 (file)
index 5f9742a..9216264
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import absolute_import, print_function, unicode_literals
+
 '''
 Thermometer test script
 '''
@@ -16,19 +18,20 @@ 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"]
+               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"]
+               if "Time" in measure:
+                       print("Time: ", measure["Time"])
 
-               print "Type: ", measure["Type"]
+               if "Type" in measure:
+                       print("Type: ", measure["Type"])
 
 def property_changed(name, value):
 
-       print "PropertyChanged('%s', '%s')" % (name, value)
+       print("PropertyChanged('%s', '%s')" % (name, value))
 
 if __name__ == "__main__":
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
@@ -50,9 +53,9 @@ if __name__ == "__main__":
        (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"
+               print("Usage: %s [-i <adapter>] -b <bdaddr> [command]" % (sys.argv[0]))
+               print("Possible commands:")
+               print("\tEnableIntermediateMeasurement")
                sys.exit(1)
 
        if options.adapter:
@@ -81,7 +84,7 @@ if __name__ == "__main__":
                if args[0] == "EnableIntermediateMeasurement":
                        thermometer.EnableIntermediateMeasurement(path)
                else:
-                       print "unknown command"
+                       print("unknown command")
                        sys.exit(1)
 
        mainloop = gobject.MainLoop()
index 471764e..4447b52 100644 (file)
 #include <config.h>
 #endif
 
+#include <stdint.h>
 #include <glib.h>
 #include <errno.h>
 #include <gdbus.h>
 
 #include "plugin.h"
 #include "manager.h"
+#include "hcid.h"
+#include "log.h"
 
 static DBusConnection *connection = NULL;
 
 static int thermometer_init(void)
 {
+       if (!main_opts.gatt_enabled) {
+               DBG("GATT is disabled");
+               return -ENOTSUP;
+       }
+
        connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
        if (connection == NULL)
                return -EIO;
@@ -49,6 +57,9 @@ static int thermometer_init(void)
 
 static void thermometer_exit(void)
 {
+       if (!main_opts.gatt_enabled)
+               return;
+
        thermometer_manager_exit();
 
        dbus_connection_unref(connection);
index 6b98bca..3d5452b 100644 (file)
 #include "adapter.h"
 #include "device.h"
 #include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
 #include "thermometer.h"
 #include "manager.h"
 
-#define HEALTH_THERMOMETER_UUID                "00001809-0000-1000-8000-00805f9b34fb"
-
 static DBusConnection *connection = NULL;
 
+static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct gatt_primary *prim = a;
+       const char *uuid = b;
+
+       return g_strcmp0(prim->uuid, uuid);
+}
+
 static int thermometer_driver_probe(struct btd_device *device, GSList *uuids)
 {
-       struct att_primary *tattr;
-       GSList *list;
+       struct gatt_primary *tattr;
+       GSList *primaries, *l;
+
+       primaries = btd_device_get_primaries(device);
 
-       list = device_services_from_record(device, uuids);
-       if (list == NULL)
+       l = g_slist_find_custom(primaries, HEALTH_THERMOMETER_UUID,
+                                                       primary_uuid_cmp);
+       if (l == NULL)
                return -EINVAL;
 
-       tattr = list->data;
+       tattr = l->data;
 
        return thermometer_register(connection, device, tattr);
 }
index 9bf9881..85f0811 100644 (file)
 #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
@@ -75,7 +69,7 @@ struct thermometer {
 };
 
 struct characteristic {
-       struct att_char         attr;   /* Characteristic */
+       struct gatt_char                attr;   /* Characteristic */
        GSList                  *desc;  /* Descriptors */
        struct thermometer      *t;     /* Thermometer where the char belongs */
 };
@@ -136,14 +130,18 @@ 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 remove_watcher(gpointer user_data)
+{
+       struct watcher *watcher = user_data;
+
+       g_dbus_remove_watch(watcher->t->conn, watcher->id);
+}
+
 static void destroy_char(gpointer user_data)
 {
        struct characteristic *c = user_data;
@@ -172,7 +170,7 @@ static void destroy_thermometer(gpointer user_data)
                g_slist_free_full(t->chars, destroy_char);
 
        if (t->fwatchers != NULL)
-               g_slist_free_full(t->fwatchers, destroy_watcher);
+               g_slist_free_full(t->fwatchers, remove_watcher);
 
        dbus_connection_unref(t->conn);
        btd_device_unref(t->dev);
@@ -331,6 +329,17 @@ static void valid_range_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
        change_property(desc->ch->t, "Minimum", &min);
 }
 
+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 process_thermometer_desc(struct descriptor *desc)
 {
        struct characteristic *ch = desc->ch;
@@ -342,28 +351,35 @@ static void process_thermometer_desc(struct descriptor *desc)
        if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
                uint8_t atval[2];
                uint16_t val;
+               char *msg;
 
                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;
+                       val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
+                       msg = g_strdup("Enable Temperature Measurement "
+                                                               "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;
+                       val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
+                       msg = g_strdup("Enable Intermediate Temperature "
+                                                               "notification");
                } else if (g_strcmp0(ch->attr.uuid,
-                                       MEASUREMENT_INTERVAL_UUID) == 0)
-                       val = ATT_CLIENT_CHAR_CONF_INDICATION;
-               else
+                                       MEASUREMENT_INTERVAL_UUID) == 0) {
+                       val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
+                       msg = g_strdup("Enable Measurement Interval "
+                                                               "indication");
+               } else
                        goto done;
 
                att_put_u16(val, atval);
                gatt_write_char(ch->t->attrib, desc->handle, atval, 2,
-                                                               NULL, NULL);
+                                                       measurement_cb, msg);
                return;
        }
 
@@ -504,7 +520,7 @@ static void configure_thermometer_cb(GSList *characteristics, guint8 status,
        }
 
        for (l = characteristics; l; l = l->next) {
-               struct att_char *c = l->data;
+               struct gatt_char *c = l->data;
                struct characteristic *ch;
                uint16_t start, end;
 
@@ -522,7 +538,7 @@ static void configure_thermometer_cb(GSList *characteristics, guint8 status,
                start = c->value_handle + 1;
 
                if (l->next != NULL) {
-                       struct att_char *c = l->next->data;
+                       struct gatt_char *c = l->next->data;
                        if (start == c->handle)
                                continue;
                        end = c->handle - 1;
@@ -655,17 +671,6 @@ static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
        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;
@@ -807,7 +812,7 @@ static void watcher_exit(DBusConnection *conn, void *user_data)
        remove_int_watcher(t, watcher);
 
        t->fwatchers = g_slist_remove(t->fwatchers, watcher);
-       watcher->id = 0;
+       g_dbus_remove_watch(watcher->t->conn, watcher->id);
 
        if (g_slist_length(t->fwatchers) == 0)
                disable_final_measurement(t);
@@ -886,7 +891,7 @@ static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
        remove_int_watcher(t, watcher);
 
        t->fwatchers = g_slist_remove(t->fwatchers, watcher);
-       destroy_watcher(watcher);
+       g_dbus_remove_watch(watcher->t->conn, watcher->id);
 
        if (g_slist_length(t->fwatchers) == 0)
                disable_final_measurement(t);
@@ -949,19 +954,31 @@ static DBusMessage *disable_intermediate(DBusConnection *conn, DBusMessage *msg,
        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 const GDBusMethodTable thermometer_methods[] = {
+       { GDBUS_METHOD("GetProperties",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       get_properties) },
+       { GDBUS_ASYNC_METHOD("SetProperty",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
+                       set_property) },
+       { GDBUS_METHOD("RegisterWatcher",
+                       GDBUS_ARGS({ "agent", "o" }), NULL,
+                       register_watcher) },
+       { GDBUS_METHOD("UnregisterWatcher",
+                       GDBUS_ARGS({ "agent", "o" }), NULL,
+                       unregister_watcher) },
+       { GDBUS_METHOD("EnableIntermediateMeasurement",
+                       GDBUS_ARGS({ "agent", "o" }), NULL,
+                       enable_intermediate) },
+       { GDBUS_METHOD("DisableIntermediateMeasurement",
+                       GDBUS_ARGS({ "agent", "o" }), NULL,
+                       disable_intermediate) },
        { }
 };
 
-static GDBusSignalTable thermometer_signals[] = {
-       { "PropertyChanged",    "sv"    },
+static const GDBusSignalTable thermometer_signals[] = {
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
        { }
 };
 
@@ -1086,15 +1103,10 @@ static void proc_measurement(struct thermometer *t, const uint8_t *pdu,
                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;
+       else
+               type = NULL;
 
-       m.type = g_strdup(type);
+       m.type = type ? g_strdup(type) : NULL;
        m.value = final ? "Final" : "Intermediate";
 
        recv_measurement(t, &m);
@@ -1209,7 +1221,7 @@ static void attio_disconnected_cb(gpointer user_data)
 }
 
 int thermometer_register(DBusConnection *connection, struct btd_device *device,
-                                               struct att_primary *tattr)
+                                               struct gatt_primary *tattr)
 {
        const gchar *path = device_get_path(device);
        struct thermometer *t;
@@ -1218,8 +1230,8 @@ int thermometer_register(DBusConnection *connection, struct btd_device *device,
        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;
+       t->svc_range->start = tattr->range.start;
+       t->svc_range->end = tattr->range.end;
 
        if (!g_dbus_register_interface(t->conn, path, THERMOMETER_INTERFACE,
                                thermometer_methods, thermometer_signals,
index 298c9ad..330503c 100644 (file)
@@ -21,5 +21,5 @@
  */
 
 int thermometer_register(DBusConnection *connection, struct btd_device *device,
-                                               struct att_primary *tattr);
+                                               struct gatt_primary *tattr);
 void thermometer_unregister(struct btd_device *device);
index a4de0fe..d876725 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <stdint.h>
 #include <glib.h>
+#include <errno.h>
 
 #include "plugin.h"
 #include "hcid.h"
@@ -36,9 +37,9 @@
 
 static int time_init(void)
 {
-       if (!main_opts.attrib_server) {
-               DBG("Attribute server is disabled");
-               return -1;
+       if (!main_opts.gatt_enabled) {
+               DBG("GATT is disabled");
+               return -ENOTSUP;
        }
 
        return time_server_init();
@@ -46,7 +47,7 @@ static int time_init(void)
 
 static void time_exit(void)
 {
-       if (!main_opts.attrib_server)
+       if (!main_opts.gatt_enabled)
                return;
 
        time_server_exit();
index 0730fbb..13a7bbe 100644 (file)
 #include <bluetooth/uuid.h>
 #include <adapter.h>
 
-#include "att.h"
 #include "gattrib.h"
+#include "att.h"
+#include "gatt.h"
+#include "att-database.h"
 #include "attrib-server.h"
 #include "gatt-service.h"
 #include "log.h"
@@ -78,7 +80,8 @@ static int encode_current_time(uint8_t value[10])
        return 0;
 }
 
-static uint8_t current_time_read(struct attribute *a, gpointer user_data)
+static uint8_t current_time_read(struct attribute *a,
+                                struct btd_device *device, gpointer user_data)
 {
        uint8_t value[10];
 
@@ -91,7 +94,8 @@ static uint8_t current_time_read(struct attribute *a, gpointer user_data)
        return 0;
 }
 
-static uint8_t local_time_info_read(struct attribute *a, gpointer user_data)
+static uint8_t local_time_info_read(struct attribute *a,
+                               struct btd_device *device, gpointer user_data)
 {
        uint8_t value[2];
 
@@ -115,9 +119,13 @@ static uint8_t local_time_info_read(struct attribute *a, gpointer user_data)
 
 static void register_current_time_service(void)
 {
+       bt_uuid_t uuid;
+
+       bt_uuid16_create(&uuid, CURRENT_TIME_SVC_UUID);
+
        /* Current Time service */
        /* FIXME: Provide the adapter in next function */
-       gatt_service_add(NULL, GATT_PRIM_SVC_UUID, CURRENT_TIME_SVC_UUID,
+       gatt_service_add(NULL, GATT_PRIM_SVC_UUID, &uuid,
                                /* CT Time characteristic */
                                GATT_OPT_CHR_UUID, CT_TIME_CHR_UUID,
                                GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
index 7bfaf5a..f7afe53 100644 (file)
@@ -118,7 +118,7 @@ int csr_open_bcsp(char *device, speed_t bcsp_rate)
        while (1) {
                delay = ubcsp_poll(&activity);
 
-               if (activity & UBCSP_PACKET_RECEIVED)
+               if (activity & UBCSP_PACKET_SENT)
                        break;
 
                if (delay) {
index e0e2730..cc97cad 100644 (file)
@@ -89,6 +89,9 @@ Serial adapters using CSR chips with BCSP serial protocol
 .TP
 .B ath3k
 Atheros AR300x based serial Bluetooth device
+.TP
+.B intel
+Intel Bluetooth device
 .RE
 
 Supported IDs are (manufacturer id, product id)
index 544ef61..a32ca52 100644 (file)
@@ -42,8 +42,6 @@
 #include <sys/poll.h>
 #include <sys/param.h>
 #include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
@@ -149,6 +147,10 @@ static int uart_speed(int s)
        case 3500000:
                return B3500000;
 #endif
+#ifdef B3710000
+       case 3710000
+               return B3710000;
+#endif
 #ifdef B4000000
        case 4000000:
                return B4000000;
@@ -340,6 +342,11 @@ static int qualcomm(int fd, struct uart_t *u, struct termios *ti)
        return qualcomm_init(fd, u->speed, ti, u->bdaddr);
 }
 
+static int intel(int fd, struct uart_t *u, struct termios *ti)
+{
+       return intel_init(fd, u->init_speed, &u->speed, ti);
+}
+
 static int read_check(int fd, void *buf, int count)
 {
        int res;
@@ -1197,6 +1204,14 @@ struct uart_t uart[] = {
        { "qualcomm",   0x0000, 0x0000, HCI_UART_H4,   115200, 115200,
                        FLOW_CTL, DISABLE_PM, NULL, qualcomm, NULL },
 
+       /* Intel Bluetooth Module */
+       { "intel",      0x0000, 0x0000, HCI_UART_H4,   115200, 115200,
+                       FLOW_CTL, DISABLE_PM, NULL, intel, NULL },
+
+       /* Three-wire UART */
+       { "3wire",      0x0000, 0x0000, HCI_UART_3WIRE, 115200, 115200,
+                       0, DISABLE_PM, NULL, NULL, NULL },
+
        { NULL, 0 }
 };
 
@@ -1360,11 +1375,10 @@ int main(int argc, char *argv[])
        printpid = 0;
        raw = 0;
 #ifdef __TI_PATCH__
-       while ((opt=getopt(argc, argv, "bnprft:g:s:l")) != EOF)
+       while ((opt=getopt(argc, argv, "bnprft:g:s:l")) != EOF) {
 #else
-       while ((opt=getopt(argc, argv, "bnpt:s:lr")) != EOF)
+       while ((opt=getopt(argc, argv, "bnpt:s:lr")) != EOF) {
 #endif
-       {
                switch(opt) {
                case 'b':
                        send_break = 1;
index 29fee33..a24dbc4 100644 (file)
@@ -41,6 +41,8 @@
 #define HCI_UART_ATH3K  5
 
 #define HCI_UART_RAW_DEVICE    0
+#define HCI_UART_RESET_ON_INIT 1
+#define HCI_UART_CREATE_AMP    2
 
 int read_hci_event(int fd, unsigned char* buf, int size);
 int set_speed(int fd, struct termios *ti, int speed);
@@ -54,3 +56,4 @@ int ath3k_init(int fd, int speed, int init_speed, char *bdaddr,
                                                struct termios *ti);
 int ath3k_post(int fd, int pm);
 int qualcomm_init(int fd, int speed, struct termios *ti, const char *bdaddr);
+int intel_init(int fd, int init_speed, int *speed, struct termios *ti);
index 803cf46..23208c6 100644 (file)
@@ -900,7 +900,7 @@ int ath3k_post(int fd, int pm)
        }
 
        /* send vendor specific command with Sleep feature Enabled */
-       if (hci_send_cmd(dd, OGF_VENDOR_CMD, HCI_SLEEP_CMD_OCF, 1, &pm) < 0)
+       if (hci_send_cmd(dd, OGF_VENDOR_CMD, HCI_SLEEP_CMD_OCF, 1, &pm) < 0)
                perror("PM command failed, power management Disabled");
 
        nanosleep(&tm, NULL);
diff --git a/tools/hciattach_intel.c b/tools/hciattach_intel.c
new file mode 100644 (file)
index 0000000..9129993
--- /dev/null
@@ -0,0 +1,596 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <time.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "hciattach.h"
+
+#ifdef INTEL_DEBUG
+#define DBGPRINT(fmt, args...) printf("DBG: " fmt "\n", ## args)
+#define PRINT_PACKET(buf, len, msg)    {       \
+       int i;                                  \
+       printf("%s\n", msg);                    \
+       for (i = 0; i < len; i++)               \
+               printf("%02X ", buf[i]);        \
+       printf("\n");                           \
+       }
+#else
+#define DBGPRINT(fmt, args...)
+#define PRINT_PACKET(buf, len, msg)
+#endif
+
+#define PATCH_SEQ_EXT           ".bseq"
+#define PATCH_FILE_PATH         "/lib/firmware/intel/"
+#define PATCH_MAX_LEN           260
+#define PATCH_TYPE_CMD          1
+#define PATCH_TYPE_EVT          2
+
+#define INTEL_VER_PARAM_LEN     9
+#define INTEL_MFG_PARAM_LEN     2
+
+/**
+ * A data structure for a patch entry.
+ */
+struct patch_entry {
+       int type;
+       int len;
+       unsigned char data[PATCH_MAX_LEN];
+};
+
+/**
+ * A structure for patch context
+ */
+struct patch_ctx {
+       int dev;
+       int fd;
+       int patch_error;
+       int reset_enable_patch;
+};
+
+/**
+ * Send HCI command to the controller
+ */
+static int intel_write_cmd(int dev, unsigned char *buf, int len)
+{
+       int ret;
+
+       PRINT_PACKET(buf, len, "<----- SEND CMD: ");
+
+       ret = write(dev, buf, len);
+       if (ret < 0)
+               return -errno;
+
+       if (ret != len)
+               return -1;
+
+       return ret;
+}
+
+/**
+ * Read the event from the controller
+ */
+static int intel_read_evt(int dev, unsigned char *buf, int len)
+{
+       int ret;
+
+       ret = read_hci_event(dev, buf, len);
+       if (ret < 0)
+               return -1;
+
+       PRINT_PACKET(buf, ret, "-----> READ EVT: ");
+
+       return ret;
+}
+
+/**
+ * Validate HCI events
+ */
+static int validate_events(struct patch_entry *event,
+               struct patch_entry *entry)
+{
+       if (event == NULL || entry == NULL) {
+               DBGPRINT("invalid patch entry parameters");
+               return -1;
+       }
+
+       if (event->len != entry->len) {
+               DBGPRINT("lengths are mismatched:[%d|%d]",
+                               event->len, entry->len);
+               return -1;
+       }
+
+       if (memcmp(event->data, entry->data, event->len)) {
+               DBGPRINT("data is mismatched");
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * Read the next patch entry one line at a time
+ */
+static int get_next_patch_entry(int fd, struct patch_entry *entry)
+{
+       int len, size;
+       char rb;
+
+       if (read(fd, &rb, 1) <= 0)
+               return 0;
+
+       entry->type = rb;
+       len = 0;
+
+       switch (entry->type) {
+       case PATCH_TYPE_CMD:
+               entry->data[0] = HCI_COMMAND_PKT;
+
+               if (read(fd, &entry->data[1], 3) < 0)
+                       return -1;
+
+               size = (int)entry->data[3];
+
+               if (read(fd, &entry->data[4], size) < 0)
+                       return -1;
+
+               entry->len = HCI_TYPE_LEN + HCI_COMMAND_HDR_SIZE + size;
+
+               break;
+
+       case PATCH_TYPE_EVT:
+               entry->data[0] = HCI_EVENT_PKT;
+
+               if (read(fd, &entry->data[len], 2) < 0)
+                       return -1;
+
+               size = (int)entry->data[2];
+
+               if (read(fd, &entry->data[3], size) < 0)
+                       return -1;
+
+               entry->len = HCI_TYPE_LEN + HCI_EVENT_HDR_SIZE + size;
+
+               break;
+
+       default:
+               fprintf(stderr, "invalid patch entry(%d)\n", entry->type);
+               return -1;
+       }
+
+       return len;
+}
+
+/**
+ * Download the patch set to the controller and verify the event
+ */
+static int intel_download_patch(struct patch_ctx *ctx)
+{
+       int ret;
+       struct patch_entry entry;
+       struct patch_entry event;
+
+       DBGPRINT("start patch downloading");
+
+       do {
+               ret = get_next_patch_entry(ctx->fd, &entry);
+               if (ret <= 0) {
+                       ctx->patch_error = 1;
+                       break;
+               }
+
+               switch (entry.type) {
+               case PATCH_TYPE_CMD:
+                       ret = intel_write_cmd(ctx->dev,
+                                       entry.data,
+                                       entry.len);
+                       if (ret <= 0) {
+                               fprintf(stderr, "failed to send cmd(%d)\n",
+                                               ret);
+                               return ret;
+                       }
+                       break;
+
+               case PATCH_TYPE_EVT:
+                       ret = intel_read_evt(ctx->dev, event.data,
+                                       sizeof(event.data));
+                       if (ret <= 0) {
+                               fprintf(stderr, "failed to read evt(%d)\n",
+                                               ret);
+                               return ret;
+                       }
+                       event.len = ret;
+
+                       if (validate_events(&event, &entry) < 0) {
+                               DBGPRINT("events are mismatched");
+                               ctx->patch_error = 1;
+                               return -1;
+                       }
+                       break;
+
+               default:
+                       fprintf(stderr, "unknown patch type(%d)\n",
+                                       entry.type);
+                       return -1;
+               }
+       } while (1);
+
+       return ret;
+}
+
+static int open_patch_file(struct patch_ctx *ctx, char *fw_ver)
+{
+       char patch_file[PATH_MAX];
+
+       snprintf(patch_file, PATH_MAX, "%s%s%s", PATCH_FILE_PATH,
+                       fw_ver, PATCH_SEQ_EXT);
+       DBGPRINT("PATCH_FILE: %s", patch_file);
+
+       ctx->fd = open(patch_file, O_RDONLY);
+       if (ctx->fd < 0) {
+               DBGPRINT("cannot open patch file. go to post patch");
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * Prepare the controller for patching.
+ */
+static int pre_patch(struct patch_ctx *ctx)
+{
+       int ret, i;
+       struct patch_entry entry;
+       char fw_ver[INTEL_VER_PARAM_LEN * 2];
+
+       DBGPRINT("start pre_patch");
+
+       entry.data[0] = HCI_COMMAND_PKT;
+       entry.data[1] = 0x11;
+       entry.data[2] = 0xFC;
+       entry.data[3] = 0x02;
+       entry.data[4] = 0x01;
+       entry.data[5] = 0x00;
+       entry.len = HCI_TYPE_LEN + HCI_COMMAND_HDR_SIZE + INTEL_MFG_PARAM_LEN;
+
+       ret = intel_write_cmd(ctx->dev, entry.data, entry.len);
+       if (ret < 0) {
+               fprintf(stderr, "failed to send cmd(%d)\n", ret);
+               return ret;
+       }
+
+       ret = intel_read_evt(ctx->dev, entry.data, sizeof(entry.data));
+       if (ret < 0) {
+               fprintf(stderr, "failed to read evt(%d)\n", ret);
+               return ret;
+       }
+       entry.len = ret;
+
+       if (entry.data[6] != 0x00) {
+               DBGPRINT("command failed. status=%02x", entry.data[6]);
+               ctx->patch_error = 1;
+               return -1;
+       }
+
+       entry.data[0] = HCI_COMMAND_PKT;
+       entry.data[1] = 0x05;
+       entry.data[2] = 0xFC;
+       entry.data[3] = 0x00;
+       entry.len = HCI_TYPE_LEN + HCI_COMMAND_HDR_SIZE;
+
+       ret = intel_write_cmd(ctx->dev, entry.data, entry.len);
+       if (ret < 0) {
+               fprintf(stderr, "failed to send cmd(%d)\n", ret);
+               return ret;
+       }
+
+       ret = intel_read_evt(ctx->dev, entry.data, sizeof(entry.data));
+       if (ret < 0) {
+               fprintf(stderr, "failed to read evt(%d)\n", ret);
+               return ret;
+       }
+       entry.len = ret;
+
+       if (entry.data[6] != 0x00) {
+               DBGPRINT("command failed. status=%02x", entry.data[6]);
+               ctx->patch_error = 1;
+               return -1;
+       }
+
+       for (i = 0; i < INTEL_VER_PARAM_LEN; i++)
+               sprintf(&fw_ver[i*2], "%02x", entry.data[7+i]);
+
+       if (open_patch_file(ctx, fw_ver) < 0) {
+               ctx->patch_error = 1;
+               return -1;
+       }
+
+       return ret;
+}
+
+/*
+ * check the event is startup event
+ */
+static int is_startup_evt(unsigned char *buf)
+{
+       if (buf[1] == 0xFF && buf[2] == 0x01 && buf[3] == 0x00)
+               return 1;
+
+       return 0;
+}
+
+/**
+ * Finalize the patch process and reset the controller
+ */
+static int post_patch(struct patch_ctx *ctx)
+{
+       int ret;
+       struct patch_entry entry;
+
+       DBGPRINT("start post_patch");
+
+       entry.data[0] = HCI_COMMAND_PKT;
+       entry.data[1] = 0x11;
+       entry.data[2] = 0xFC;
+       entry.data[3] = 0x02;
+       entry.data[4] = 0x00;
+       if (ctx->reset_enable_patch)
+               entry.data[5] = 0x02;
+       else
+               entry.data[5] = 0x01;
+
+       entry.len = HCI_TYPE_LEN + HCI_COMMAND_HDR_SIZE + INTEL_MFG_PARAM_LEN;
+
+       ret = intel_write_cmd(ctx->dev, entry.data, entry.len);
+       if (ret < 0) {
+               fprintf(stderr, "failed to send cmd(%d)\n", ret);
+               return ret;
+       }
+
+       ret = intel_read_evt(ctx->dev, entry.data, sizeof(entry.data));
+       if (ret < 0) {
+               fprintf(stderr, "failed to read evt(%d)\n", ret);
+               return ret;
+       }
+       entry.len = ret;
+
+       if (entry.data[6] != 0x00) {
+               fprintf(stderr, "cmd failed. st=%02x\n", entry.data[6]);
+               return -1;
+       }
+
+       do {
+               ret = intel_read_evt(ctx->dev, entry.data,
+                                       sizeof(entry.data));
+               if (ret < 0) {
+                       fprintf(stderr, "failed to read cmd(%d)\n", ret);
+                       return ret;
+               }
+               entry.len = ret;
+       } while (!is_startup_evt(entry.data));
+
+       return ret;
+}
+
+/**
+ * Main routine that handles the device patching process.
+ */
+static int intel_patch_device(struct patch_ctx *ctx)
+{
+       int ret;
+
+       ret = pre_patch(ctx);
+       if (ret < 0) {
+               if (!ctx->patch_error) {
+                       fprintf(stderr, "I/O error: pre_patch failed\n");
+                       return ret;
+               }
+
+               DBGPRINT("patch failed. proceed to post patch");
+               goto post_patch;
+       }
+
+       ret = intel_download_patch(ctx);
+       if (ret < 0) {
+               if (!ctx->patch_error) {
+                       fprintf(stderr, "I/O error: download_patch failed\n");
+                       close(ctx->fd);
+                       return ret;
+               }
+       } else {
+               DBGPRINT("patch done");
+               ctx->reset_enable_patch = 1;
+       }
+
+       close(ctx->fd);
+
+post_patch:
+       ret = post_patch(ctx);
+       if (ret < 0) {
+               fprintf(stderr, "post_patch failed(%d)\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int set_rts(int dev, int rtsval)
+{
+       int arg;
+
+       if (ioctl(dev, TIOCMGET, &arg) < 0) {
+               perror("cannot get TIOCMGET");
+               return -errno;
+       }
+       if (rtsval)
+               arg |= TIOCM_RTS;
+       else
+               arg &= ~TIOCM_RTS;
+
+       if (ioctl(dev, TIOCMSET, &arg) == -1) {
+               perror("cannot set TIOCMGET");
+               return -errno;
+       }
+
+       return 0;
+}
+
+static unsigned char get_intel_speed(int speed)
+{
+       switch (speed) {
+       case 9600:
+               return 0x00;
+       case 19200:
+               return 0x01;
+       case 38400:
+               return 0x02;
+       case 57600:
+               return 0x03;
+       case 115200:
+               return 0x04;
+       case 230400:
+               return 0x05;
+       case 460800:
+               return 0x06;
+       case 921600:
+               return 0x07;
+       case 1843200:
+               return 0x08;
+       case 3250000:
+               return 0x09;
+       case 2000000:
+               return 0x0A;
+       case 3000000:
+               return 0x0B;
+       default:
+               return 0xFF;
+       }
+}
+
+/**
+ * if it failed to change to new baudrate, it will rollback
+ * to initial baudrate
+ */
+static int change_baudrate(int dev, int init_speed, int *speed,
+                               struct termios *ti)
+{
+       int ret;
+       unsigned char br;
+       unsigned char cmd[5];
+       unsigned char evt[7];
+
+       DBGPRINT("start baudrate change");
+
+       ret = set_rts(dev, 0);
+       if (ret < 0) {
+               fprintf(stderr, "failed to clear RTS\n");
+               return ret;
+       }
+
+       cmd[0] = HCI_COMMAND_PKT;
+       cmd[1] = 0x06;
+       cmd[2] = 0xFC;
+       cmd[3] = 0x01;
+
+       br = get_intel_speed(*speed);
+       if (br == 0xFF) {
+               fprintf(stderr, "speed %d is not supported\n", *speed);
+               return -1;
+       }
+       cmd[4] = br;
+
+       ret = intel_write_cmd(dev, cmd, sizeof(cmd));
+       if (ret < 0) {
+               fprintf(stderr, "failed to send cmd(%d)\n", ret);
+               return ret;
+       }
+
+       /*
+        *  wait for buffer to be consumed by the controller
+        */
+       usleep(300000);
+
+       if (set_speed(dev, ti, *speed) < 0) {
+               fprintf(stderr, "can't set to new baud rate\n");
+               return -1;
+       }
+
+       ret = set_rts(dev, 1);
+       if (ret < 0) {
+               fprintf(stderr, "failed to set RTS\n");
+               return ret;
+       }
+
+       ret = intel_read_evt(dev, evt, sizeof(evt));
+       if (ret < 0) {
+               fprintf(stderr, "failed to read evt(%d)\n", ret);
+               return ret;
+       }
+
+       if (evt[4] != 0x00) {
+               fprintf(stderr,
+                       "failed to change speed. use default speed %d\n",
+                       init_speed);
+               *speed = init_speed;
+       }
+
+       return 0;
+}
+
+/**
+ * An entry point for Intel specific initialization
+ */
+int intel_init(int dev, int init_speed, int *speed, struct termios *ti)
+{
+       int ret = 0;
+       struct patch_ctx ctx;
+
+       if (change_baudrate(dev, init_speed, speed, ti) < 0)
+               return -1;
+
+       ctx.dev = dev;
+       ctx.patch_error = 0;
+       ctx.reset_enable_patch = 0;
+
+       ret = intel_patch_device(&ctx);
+       if (ret < 0)
+               fprintf(stderr, "failed to initialize the device");
+
+       return ret;
+}
index e4ff5e3..0e02e1e 100644 (file)
@@ -40,8 +40,6 @@
 #include <sys/poll.h>
 #include <sys/param.h>
 #include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
index 3546d60..d8e685b 100644 (file)
@@ -36,8 +36,6 @@
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
index 1ba009c..c3caa49 100644 (file)
@@ -39,8 +39,6 @@
 #include <sys/poll.h>
 #include <sys/param.h>
 #include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
index ce65809..be67ed8 100644 (file)
@@ -503,7 +503,7 @@ static void cmd_lm(int ctl, int hdev, char *opt)
 
 static void cmd_aclmtu(int ctl, int hdev, char *opt)
 {
-       struct hci_dev_req dr = { dev_id: hdev };
+       struct hci_dev_req dr = { .dev_id = hdev };
        uint16_t mtu, mpkt;
 
        if (!opt)
@@ -523,7 +523,7 @@ static void cmd_aclmtu(int ctl, int hdev, char *opt)
 
 static void cmd_scomtu(int ctl, int hdev, char *opt)
 {
-       struct hci_dev_req dr = { dev_id: hdev };
+       struct hci_dev_req dr = { .dev_id = hdev };
        uint16_t mtu, mpkt;
 
        if (!opt)
@@ -1305,7 +1305,7 @@ static void cmd_inq_data(int ctl, int hdev, char *opt)
                                printf("\t%s service classes:",
                                        type == 0x02 ? "Shortened" : "Complete");
                                for (i = 0; i < (len - 1) / 2; i++) {
-                                       uint16_t val = btohs(bt_get_unaligned((uint16_t *) (ptr + (i * 2))));
+                                       uint16_t val = bt_get_le16((ptr + (i * 2)));
                                        printf(" 0x%4.4x", val);
                                }
                                printf("\n");
index 5189d8d..66e5c20 100644 (file)
@@ -74,7 +74,7 @@ static void usage(void);
 
 static int dev_info(int s, int dev_id, long arg)
 {
-       struct hci_dev_info di = { dev_id: dev_id };
+       struct hci_dev_info di = { .dev_id = dev_id };
        char addr[18];
 
        if (ioctl(s, HCIGETDEVINFO, (void *) &di))
index 45a3a3d..e3a5b2e 100644 (file)
@@ -291,7 +291,7 @@ int main(int argc, char *argv[])
        if (udev == NULL)
                goto exit;
 
-       snprintf(syspath, sizeof(syspath), "%s/%s", udev_get_sys_path(udev), devpath);
+       snprintf(syspath, sizeof(syspath), "/sys/%s", devpath);
        udev_dev = udev_device_new_from_syspath(udev, syspath);
        if (udev_dev == NULL) {
                fprintf(stderr, "error: could not find '%s'\n", devpath);
index 6800445..e73b0ba 100644 (file)
@@ -673,7 +673,7 @@ static void cmd_show(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
        if (strcmp(argv[0], "all") == 0)
                print_dev_list(ctl, 0);
        else {
-               struct rfcomm_dev_info di = { id: atoi(argv[0]) };
+               struct rfcomm_dev_info di = { .id = atoi(argv[0]) };
                if (ioctl(ctl, RFCOMMGETDEVINFO, &di) < 0) {
                        perror("Get info failed");
                        exit(1);
index aea4954..4e9da64 100644 (file)
@@ -226,6 +226,11 @@ static struct attrib_def audio_attrib_names[] = {
        { 0x302, "Remote audio volume control", NULL, 0 },
 };
 
+/* Name of the various GOEP attributes. See BT assigned numbers */
+static struct attrib_def goep_attrib_names[] = {
+       { 0x200, "GoepL2capPsm", NULL, 0 },
+};
+
 /* Same for the UUIDs. See BT assigned numbers */
 static struct uuid_def uuid16_names[] = {
        /* -- Protocols -- */
@@ -261,8 +266,10 @@ static struct uuid_def uuid16_names[] = {
        { 0x1102, "LANAccessUsingPPP", NULL, 0 },
        { 0x1103, "DialupNetworking (DUN)", NULL, 0 },
        { 0x1104, "IrMCSync", NULL, 0 },
-       { 0x1105, "OBEXObjectPush", NULL, 0 },
-       { 0x1106, "OBEXFileTransfer", NULL, 0 },
+       { 0x1105, "OBEXObjectPush",
+               goep_attrib_names, sizeof(goep_attrib_names)/sizeof(struct attrib_def) },
+       { 0x1106, "OBEXFileTransfer",
+               goep_attrib_names, sizeof(goep_attrib_names)/sizeof(struct attrib_def) },
        { 0x1107, "IrMCSyncCommand", NULL, 0 },
        { 0x1108, "Headset",
                audio_attrib_names, sizeof(audio_attrib_names)/sizeof(struct attrib_def) },
@@ -1141,20 +1148,6 @@ typedef struct {
        uint8_t network;
 } svc_info_t;
 
-static void add_lang_attr(sdp_record_t *r)
-{
-       sdp_lang_attr_t base_lang;
-       sdp_list_t *langs = 0;
-
-       /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */
-       base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
-       base_lang.encoding = 106;
-       base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
-       langs = sdp_list_append(0, &base_lang);
-       sdp_set_lang_attr(r, langs);
-       sdp_list_free(langs, 0);
-}
-
 static int add_sp(sdp_session_t *session, svc_info_t *si)
 {
        sdp_list_t *svclass_id, *apseq, *proto[2], *profiles, *root, *aproto;
@@ -1196,7 +1189,7 @@ static int add_sp(sdp_session_t *session, svc_info_t *si)
        aproto = sdp_list_append(0, apseq);
        sdp_set_access_protos(&record, aproto);
 
-       add_lang_attr(&record);
+       sdp_add_lang_attr(&record);
 
        sdp_set_info_attr(&record, "Serial Port", "BlueZ", "COM Port");
 
@@ -2305,7 +2298,7 @@ static int add_hid_keyb(sdp_session_t *session, svc_info_t *si)
        root = sdp_list_append(0, &root_uuid);
        sdp_set_browse_groups(&record, root);
 
-       add_lang_attr(&record);
+       sdp_add_lang_attr(&record);
 
        sdp_uuid16_create(&hidkb_uuid, HID_SVCLASS_ID);
        svclass_id = sdp_list_append(0, &hidkb_uuid);
@@ -2483,7 +2476,7 @@ static int add_hid_wiimote(sdp_session_t *session, svc_info_t *si)
        aproto = sdp_list_append(0, apseq);
        sdp_set_add_access_protos(&record, aproto);
 
-       add_lang_attr(&record);
+       sdp_add_lang_attr(&record);
 
        sdp_set_info_attr(&record, "Nintendo RVL-CNT-01",
                                        "Nintendo", "Nintendo RVL-CNT-01");
@@ -3475,7 +3468,7 @@ static int add_gatt(sdp_session_t *session, svc_info_t *si)
 
        ret = sdp_device_record_register(session, &interface, &record,
                                                        SDP_RECORD_PERSIST);
-       if (ret < 0)
+       if (ret < 0)
                printf("Service Record registration failed\n");
        else
                printf("Generic Attribute Profile Service registered\n");
diff --git a/tracer/main.c b/tracer/main.c
deleted file mode 100644 (file)
index 3b37f59..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <syslog.h>
-
-#include <glib.h>
-
-#ifdef HAVE_CAPNG
-#include <cap-ng.h>
-#endif
-
-static GMainLoop *event_loop;
-
-static void sig_term(int sig)
-{
-       g_main_loop_quit(event_loop);
-}
-
-static gboolean option_detach = TRUE;
-static gboolean option_debug = FALSE;
-
-static GOptionEntry options[] = {
-       { "nodaemon", 'n', G_OPTION_FLAG_REVERSE,
-                               G_OPTION_ARG_NONE, &option_detach,
-                               "Don't run as daemon in background" },
-       { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug,
-                               "Enable debug information output" },
-       { NULL },
-};
-
-static void debug(const char *format, ...)
-{
-       va_list ap;
-
-       if (!option_debug)
-               return;
-
-       va_start(ap, format);
-
-       vsyslog(LOG_DEBUG, format, ap);
-
-       va_end(ap);
-}
-
-static void sig_debug(int sig)
-{
-       option_debug = !option_debug;
-}
-
-int main(int argc, char *argv[])
-{
-       GOptionContext *context;
-       GError *err = NULL;
-       struct sigaction sa;
-
-#ifdef HAVE_CAPNG
-       /* Drop capabilities */
-       capng_clear(CAPNG_SELECT_BOTH);
-       capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
-                                       CAP_NET_BIND_SERVICE, CAP_NET_ADMIN,
-                                               CAP_NET_RAW, CAP_IPC_LOCK, -1);
-       capng_apply(CAPNG_SELECT_BOTH);
-#endif
-
-       context = g_option_context_new(NULL);
-       g_option_context_add_main_entries(context, options, NULL);
-
-       if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
-               if (err != NULL) {
-                       g_printerr("%s\n", err->message);
-                       g_error_free(err);
-               } else
-                       g_printerr("An unknown error occurred\n");
-               exit(1);
-       }
-
-       g_option_context_free(context);
-
-       if (option_detach == TRUE) {
-               if (daemon(0, 0)) {
-                       perror("Can't start daemon");
-                       exit(1);
-               }
-       }
-
-       umask(0077);
-
-       openlog("hcitrace", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
-
-       syslog(LOG_INFO, "HCI trace daemon %s", VERSION);
-
-       memset(&sa, 0, sizeof(sa));
-       sa.sa_flags = SA_NOCLDSTOP;
-       sa.sa_handler = sig_term;
-       sigaction(SIGTERM, &sa, NULL);
-       sigaction(SIGINT,  &sa, NULL);
-
-       sa.sa_handler = sig_debug;
-       sigaction(SIGUSR2, &sa, NULL);
-
-       sa.sa_handler = SIG_IGN;
-       sigaction(SIGPIPE, &sa, NULL);
-
-       if (option_debug == TRUE) {
-               syslog(LOG_INFO, "Enabling debug information");
-       }
-
-       event_loop = g_main_loop_new(NULL, FALSE);
-
-       debug("Entering main loop");
-
-       g_main_loop_run(event_loop);
-
-       g_main_loop_unref(event_loop);
-
-       syslog(LOG_INFO, "Exit");
-
-       closelog();
-
-       return 0;
-}